From 93bdab9daad3ae431afd41a2efaefae05a555d88 Mon Sep 17 00:00:00 2001
From: Joar Wandborg
Date: Fri, 23 Sep 2011 02:35:57 +0200
Subject: Multimedia support - Commiting from a not yet finished state -
Details below
* DONE Initially testing with arista
** DONE Video display templates
*** TODO Multi-browser support
** TODO Video thumbnails
** TODO Link to original video
** TODO Video cropping
Also contains a lot of "debug" print's
---
mediagoblin/db/migrations.py | 8 +
mediagoblin/init/celery/__init__.py | 5 +
mediagoblin/media_types/__init__.py | 70 ++++++
mediagoblin/media_types/image/__init__.py | 28 +++
mediagoblin/media_types/image/processing.py | 207 ++++++++++++++++
mediagoblin/media_types/video/__init__.py | 26 +++
mediagoblin/media_types/video/processing.py | 260 +++++++++++++++++++++
mediagoblin/storage/cloudfiles.py | 10 +-
mediagoblin/submit/views.py | 13 +-
.../mediagoblin/media_displays/image.html | 1 +
.../mediagoblin/media_displays/video.html | 8 +
.../templates/mediagoblin/user_pages/media.html | 32 +--
mediagoblin/user_pages/views.py | 6 +-
13 files changed, 650 insertions(+), 24 deletions(-)
create mode 100644 mediagoblin/media_types/__init__.py
create mode 100644 mediagoblin/media_types/image/__init__.py
create mode 100644 mediagoblin/media_types/image/processing.py
create mode 100644 mediagoblin/media_types/video/__init__.py
create mode 100644 mediagoblin/media_types/video/processing.py
create mode 100644 mediagoblin/templates/mediagoblin/media_displays/image.html
create mode 100644 mediagoblin/templates/mediagoblin/media_displays/video.html
diff --git a/mediagoblin/db/migrations.py b/mediagoblin/db/migrations.py
index 755f49c5..01df7208 100644
--- a/mediagoblin/db/migrations.py
+++ b/mediagoblin/db/migrations.py
@@ -107,3 +107,11 @@ def user_add_forgot_password_token_and_expires(database):
{'fp_token_expire': {'$exists': False}},
{'$set': {'fp_token_expire': None}},
multi=True)
+
+
+@RegisterMigration(7)
+def media_type_image_to_multimedia_type_image(database):
+ database['media_entries'].update(
+ {'media_type': 'image'},
+ {'$set': {'media_type': 'mediagoblin.media_types.image'}},
+ multi=True)
diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py
index c58b1305..05c54b05 100644
--- a/mediagoblin/init/celery/__init__.py
+++ b/mediagoblin/init/celery/__init__.py
@@ -17,8 +17,13 @@
import os
import sys
+from mediagoblin.media_types import get_media_types
+
MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media']
+MANDATORY_CELERY_IMPORTS = [i for i in get_media_types()]
+
+print(MANDATORY_CELERY_IMPORTS)
DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module'
diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py
new file mode 100644
index 00000000..67dab418
--- /dev/null
+++ b/mediagoblin/media_types/__init__.py
@@ -0,0 +1,70 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import os
+import sys
+
+class FileTypeNotSupported(Exception):
+ pass
+
+class InvalidFileType(Exception):
+ pass
+
+MEDIA_TYPES = [
+ 'mediagoblin.media_types.image',
+ 'mediagoblin.media_types.video']
+
+
+def get_media_types():
+ for media_type in MEDIA_TYPES:
+ yield media_type
+
+
+def get_media_managers():
+ for media_type in get_media_types():
+ '''
+ FIXME
+ __import__ returns the lowest-level module. If the plugin is located
+ outside the conventional plugin module tree, it will not be loaded
+ properly because of the [...]ugin.media_types.
+
+ We need this if we want to support a separate site-specific plugin
+ folder.
+ '''
+ try:
+ __import__(media_type)
+ except ImportError as e:
+ raise Exception('ERROR: Could not import {0}: {1}'.format(media_type, e))
+
+ yield media_type, sys.modules[media_type].MEDIA_MANAGER
+
+def get_media_manager(_media_type = None):
+ for media_type, manager in get_media_managers():
+ if media_type in _media_type:
+ return manager
+
+
+def get_media_type_and_manager(filename):
+ for media_type, manager in get_media_managers():
+ if filename.find('.') > 0:
+ ext = os.path.splitext(filename)[1].lower()
+ else:
+ raise InvalidFileType(
+ 'Could not find any file extension in "{0}"'.format(
+ filename))
+
+ if ext[1:] in manager['accepted_extensions']:
+ return media_type, manager
diff --git a/mediagoblin/media_types/image/__init__.py b/mediagoblin/media_types/image/__init__.py
new file mode 100644
index 00000000..0cd0383f
--- /dev/null
+++ b/mediagoblin/media_types/image/__init__.py
@@ -0,0 +1,28 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from mediagoblin.media_types.image.processing import process_media
+
+
+MEDIA_MANAGER = {
+ "human_readable": "Image",
+ "processor": process_media, # alternately a string,
+ # 'mediagoblin.media_types.image.processing'?
+ "display_template": "mediagoblin/media_displays/image.html",
+ "default_thumb": "images/media_thumbs/image.jpg",
+ "accepted_extensions": ["jpg", "jpeg", "png", "gif", "tiff"],
+ "accepted_mimetypes": [
+ "image/jpeg", "image/png", "image/gif", "image/tiff"]}
diff --git a/mediagoblin/media_types/image/processing.py b/mediagoblin/media_types/image/processing.py
new file mode 100644
index 00000000..2c4ad2b1
--- /dev/null
+++ b/mediagoblin/media_types/image/processing.py
@@ -0,0 +1,207 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import Image
+
+from celery.task import Task
+from celery import registry
+
+from mediagoblin.db.util import ObjectId
+from mediagoblin import mg_globals as mgg
+
+from mediagoblin.util import lazy_pass_to_ugettext as _
+
+THUMB_SIZE = 180, 180
+MEDIUM_SIZE = 640, 640
+
+
+def create_pub_filepath(entry, filename):
+ return mgg.public_store.get_unique_filepath(
+ ['media_entries',
+ unicode(entry['_id']),
+ filename])
+
+
+class BaseProcessingFail(Exception):
+ """
+ Base exception that all other processing failure messages should
+ subclass from.
+
+ You shouldn't call this itself; instead you should subclass it
+ and provid the exception_path and general_message applicable to
+ this error.
+ """
+ general_message = u''
+
+ @property
+ def exception_path(self):
+ return u"%s:%s" % (
+ self.__class__.__module__, self.__class__.__name__)
+
+ def __init__(self, **metadata):
+ self.metadata = metadata or {}
+
+
+class BadMediaFail(BaseProcessingFail):
+ """
+ Error that should be raised when an inappropriate file was given
+ for the media type specified.
+ """
+ general_message = _(u'Invalid file given for media type.')
+
+
+################################
+# Media processing initial steps
+################################
+
+class ProcessMedia(Task):
+ """
+ Pass this entry off for processing.
+ """
+ def run(self, media_id):
+ """
+ Pass the media entry off to the appropriate processing function
+ (for now just process_image...)
+ """
+ entry = mgg.database.MediaEntry.one(
+ {'_id': ObjectId(media_id)})
+
+ # Try to process, and handle expected errors.
+ try:
+ process_image(entry)
+ except BaseProcessingFail, exc:
+ mark_entry_failed(entry[u'_id'], exc)
+ return
+
+ entry['state'] = u'processed'
+ entry.save()
+
+ def on_failure(self, exc, task_id, args, kwargs, einfo):
+ """
+ If the processing failed we should mark that in the database.
+
+ Assuming that the exception raised is a subclass of BaseProcessingFail,
+ we can use that to get more information about the failure and store that
+ for conveying information to users about the failure, etc.
+ """
+ entry_id = args[0]
+ mark_entry_failed(entry_id, exc)
+
+
+process_media = registry.tasks[ProcessMedia.name]
+
+
+def mark_entry_failed(entry_id, exc):
+ """
+ Mark a media entry as having failed in its conversion.
+
+ Uses the exception that was raised to mark more information. If the
+ exception is a derivative of BaseProcessingFail then we can store extra
+ information that can be useful for users telling them why their media failed
+ to process.
+
+ Args:
+ - entry_id: The id of the media entry
+
+ """
+ # Was this a BaseProcessingFail? In other words, was this a
+ # type of error that we know how to handle?
+ if isinstance(exc, BaseProcessingFail):
+ # Looks like yes, so record information about that failure and any
+ # metadata the user might have supplied.
+ mgg.database['media_entries'].update(
+ {'_id': entry_id},
+ {'$set': {u'state': u'failed',
+ u'fail_error': exc.exception_path,
+ u'fail_metadata': exc.metadata}})
+ else:
+ # Looks like no, so just mark it as failed and don't record a
+ # failure_error (we'll assume it wasn't handled) and don't record
+ # metadata (in fact overwrite it if somehow it had previous info
+ # here)
+ mgg.database['media_entries'].update(
+ {'_id': entry_id},
+ {'$set': {u'state': u'failed',
+ u'fail_error': None,
+ u'fail_metadata': {}}})
+
+
+def process_image(entry):
+ """
+ Code to process an image
+ """
+ workbench = mgg.workbench_manager.create_workbench()
+
+ queued_filepath = entry['queued_media_file']
+ queued_filename = workbench.localized_file(
+ mgg.queue_store, queued_filepath,
+ 'source')
+
+ try:
+ thumb = Image.open(queued_filename)
+ except IOError:
+ raise BadMediaFail()
+
+ thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
+ # ensure color mode is compatible with jpg
+ if thumb.mode != "RGB":
+ thumb = thumb.convert("RGB")
+
+ thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg')
+ thumb_file = mgg.public_store.get_file(thumb_filepath, 'w')
+
+ with thumb_file:
+ thumb.save(thumb_file, "JPEG", quality=90)
+
+ # If the size of the original file exceeds the specified size of a `medium`
+ # file, a `medium.jpg` files is created and later associated with the media
+ # entry.
+ medium = Image.open(queued_filename)
+ medium_processed = False
+
+ if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]:
+ medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS)
+
+ if medium.mode != "RGB":
+ medium = medium.convert("RGB")
+
+ medium_filepath = create_pub_filepath(entry, 'medium.jpg')
+ medium_file = mgg.public_store.get_file(medium_filepath, 'w')
+
+ with medium_file:
+ medium.save(medium_file, "JPEG", quality=90)
+ medium_processed = True
+
+ # we have to re-read because unlike PIL, not everything reads
+ # things in string representation :)
+ queued_file = file(queued_filename, 'rb')
+
+ with queued_file:
+ original_filepath = create_pub_filepath(entry, queued_filepath[-1])
+
+ with mgg.public_store.get_file(original_filepath, 'wb') as original_file:
+ original_file.write(queued_file.read())
+
+ mgg.queue_store.delete_file(queued_filepath)
+ entry['queued_media_file'] = []
+ media_files_dict = entry.setdefault('media_files', {})
+ media_files_dict['thumb'] = thumb_filepath
+ media_files_dict['original'] = original_filepath
+ if medium_processed:
+ media_files_dict['medium'] = medium_filepath
+
+ # clean up workbench
+ workbench.destroy_self()
diff --git a/mediagoblin/media_types/video/__init__.py b/mediagoblin/media_types/video/__init__.py
new file mode 100644
index 00000000..2a36623e
--- /dev/null
+++ b/mediagoblin/media_types/video/__init__.py
@@ -0,0 +1,26 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from mediagoblin.media_types.video.processing import process_media
+
+
+MEDIA_MANAGER = {
+ "human_readable": "Video",
+ "processor": process_media, # alternately a string,
+ # 'mediagoblin.media_types.image.processing'?
+ "display_template": "mediagoblin/media_displays/video.html",
+ "default_thumb": "images/media_thumbs/video.jpg",
+ "accepted_extensions": ["mp4", "mov", "webm", "avi", "3gp", "3gpp"]}
diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py
new file mode 100644
index 00000000..94784836
--- /dev/null
+++ b/mediagoblin/media_types/video/processing.py
@@ -0,0 +1,260 @@
+# GNU MediaGoblin -- federated, autonomous media hosting
+# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+import Image
+import tempfile
+
+from celery.task import Task
+from celery import registry
+
+from mediagoblin.db.util import ObjectId
+from mediagoblin import mg_globals as mgg
+
+from mediagoblin.util import lazy_pass_to_ugettext as _
+
+import gobject
+
+import gst
+import arista
+
+from arista.transcoder import TranscoderOptions
+
+THUMB_SIZE = 180, 180
+MEDIUM_SIZE = 640, 640
+ARISTA_DEVICE_KEY = 'web'
+
+
+loop = None
+
+
+def process_video(entry):
+ """
+ Code to process a video
+ """
+ info = {}
+ workbench = mgg.workbench_manager.create_workbench()
+
+ queued_filepath = entry['queued_media_file']
+ queued_filename = workbench.localized_file(
+ mgg.queue_store, queued_filepath,
+ 'source')
+
+ arista.init()
+
+ devices = arista.presets.get()
+ device = devices[ARISTA_DEVICE_KEY]
+
+ queue = arista.queue.TranscodeQueue()
+
+ info['tmp_file'] = tmp_file = tempfile.NamedTemporaryFile()
+
+ info['medium_filepath'] = medium_filepath = create_pub_filepath(entry, 'video.webm')
+
+ output = tmp_file.name
+
+ uri = 'file://' + queued_filename
+
+ preset = device.presets[device.default]
+
+ opts = TranscoderOptions(uri, preset, output)
+
+ queue.append(opts)
+
+ info['entry'] = entry
+
+ queue.connect("entry-start", entry_start, info)
+# queue.connect("entry-pass-setup", entry_pass_setup, options)
+ queue.connect("entry-error", entry_error, info)
+ queue.connect("entry-complete", entry_complete, info)
+
+ info['loop'] = loop = gobject.MainLoop()
+
+ loop.run()
+
+ # we have to re-read because unlike PIL, not everything reads
+ # things in string representation :)
+ queued_file = file(queued_filename, 'rb')
+
+ with queued_file:
+ original_filepath = create_pub_filepath(entry, queued_filepath[-1])
+
+ with mgg.public_store.get_file(original_filepath, 'wb') as original_file:
+ original_file.write(queued_file.read())
+
+ mgg.queue_store.delete_file(queued_filepath)
+ entry['queued_media_file'] = []
+ media_files_dict = entry.setdefault('media_files', {})
+ media_files_dict['original'] = original_filepath
+
+ # clean up workbench
+ workbench.destroy_self()
+
+
+def create_pub_filepath(entry, filename):
+ return mgg.public_store.get_unique_filepath(
+ ['media_entries',
+ unicode(entry['_id']),
+ filename])
+
+
+class BaseProcessingFail(Exception):
+ """
+ Base exception that all other processing failure messages should
+ subclass from.
+
+ You shouldn't call this itself; instead you should subclass it
+ and provid the exception_path and general_message applicable to
+ this error.
+ """
+ general_message = u''
+
+ @property
+ def exception_path(self):
+ return u"%s:%s" % (
+ self.__class__.__module__, self.__class__.__name__)
+
+ def __init__(self, **metadata):
+ self.metadata = metadata or {}
+
+
+class BadMediaFail(BaseProcessingFail):
+ """
+ Error that should be raised when an inappropriate file was given
+ for the media type specified.
+ """
+ general_message = _(u'Invalid file given for media type.')
+
+
+################################
+# Media processing initial steps
+################################
+
+class ProcessMedia(Task):
+ """
+ Pass this entry off for processing.
+ """
+ def run(self, media_id):
+ """
+ Pass the media entry off to the appropriate processing function
+ (for now just process_image...)
+ """
+ entry = mgg.database.MediaEntry.one(
+ {'_id': ObjectId(media_id)})
+
+ # Try to process, and handle expected errors.
+ try:
+ process_video(entry)
+ except BaseProcessingFail, exc:
+ mark_entry_failed(entry[u'_id'], exc)
+ return
+
+ entry['state'] = u'processed'
+ entry.save()
+
+ def on_failure(self, exc, task_id, args, kwargs, einfo):
+ """
+ If the processing failed we should mark that in the database.
+
+ Assuming that the exception raised is a subclass of BaseProcessingFail,
+ we can use that to get more information about the failure and store that
+ for conveying information to users about the failure, etc.
+ """
+ entry_id = args[0]
+ mark_entry_failed(entry_id, exc)
+
+
+process_media = registry.tasks[ProcessMedia.name]
+
+
+def mark_entry_failed(entry_id, exc):
+ """
+ Mark a media entry as having failed in its conversion.
+
+ Uses the exception that was raised to mark more information. If the
+ exception is a derivative of BaseProcessingFail then we can store extra
+ information that can be useful for users telling them why their media failed
+ to process.
+
+ Args:
+ - entry_id: The id of the media entry
+
+ """
+ # Was this a BaseProcessingFail? In other words, was this a
+ # type of error that we know how to handle?
+ if isinstance(exc, BaseProcessingFail):
+ # Looks like yes, so record information about that failure and any
+ # metadata the user might have supplied.
+ mgg.database['media_entries'].update(
+ {'_id': entry_id},
+ {'$set': {u'state': u'failed',
+ u'fail_error': exc.exception_path,
+ u'fail_metadata': exc.metadata}})
+ else:
+ # Looks like no, so just mark it as failed and don't record a
+ # failure_error (we'll assume it wasn't handled) and don't record
+ # metadata (in fact overwrite it if somehow it had previous info
+ # here)
+ mgg.database['media_entries'].update(
+ {'_id': entry_id},
+ {'$set': {u'state': u'failed',
+ u'fail_error': None,
+ u'fail_metadata': {}}})
+
+
+def entry_start(queue, entry, options):
+ print(queue, entry, options)
+
+def entry_complete(queue, entry, info):
+ entry.transcoder.stop()
+ gobject.idle_add(info['loop'].quit)
+
+ with info['tmp_file'] as tmp_file:
+ mgg.public_store.get_file(info['medium_filepath'], 'wb').write(
+ tmp_file.read())
+ info['entry']['media_files']['medium'] = info['medium_filepath']
+
+ print('\n=== DONE! ===\n')
+
+ print(queue, entry, info)
+
+def entry_error(queue, entry, options):
+ print(queue, entry, options)
+
+def signal_handler(signum, frame):
+ """
+ Handle Ctr-C gracefully and shut down the transcoder.
+ """
+ global interrupted
+ print
+ print _("Interrupt caught. Cleaning up... (Ctrl-C to force exit)")
+ interrupted = True
+ signal.signal(signal.SIGINT, signal.SIG_DFL)
+
+def check_interrupted():
+ """
+ Check whether we have been interrupted by Ctrl-C and stop the
+ transcoder.
+ """
+ if interrupted:
+ try:
+ source = transcoder.pipe.get_by_name("source")
+ source.send_event(gst.event_new_eos())
+ except:
+ # Something pretty bad happened... just exit!
+ gobject.idle_add(loop.quit)
+
+ return False
+ return True
diff --git a/mediagoblin/storage/cloudfiles.py b/mediagoblin/storage/cloudfiles.py
index b1dd9450..85d52242 100644
--- a/mediagoblin/storage/cloudfiles.py
+++ b/mediagoblin/storage/cloudfiles.py
@@ -97,8 +97,14 @@ class CloudFilesStorage(StorageInterface):
def delete_file(self, filepath):
# TODO: Also delete unused directories if empty (safely, with
# checks to avoid race conditions).
- self.container.delete_object(
- self._resolve_filepath(filepath))
+ try:
+ self.container.delete_object(
+ self._resolve_filepath(filepath))
+ except cloudfiles.container.ResponseError:
+ pass
+ finally:
+ pass
+
def file_url(self, filepath):
return '/'.join([
diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py
index e24d78f3..78f52160 100644
--- a/mediagoblin/submit/views.py
+++ b/mediagoblin/submit/views.py
@@ -28,8 +28,9 @@ from mediagoblin.util import (
from mediagoblin.util import pass_to_ugettext as _
from mediagoblin.decorators import require_active_login
from mediagoblin.submit import forms as submit_forms, security
-from mediagoblin.process_media import process_media, mark_entry_failed
+from mediagoblin.process_media import mark_entry_failed
from mediagoblin.messages import add_message, SUCCESS
+from mediagoblin.media_types import get_media_type_and_manager
@require_active_login
@@ -45,15 +46,15 @@ def submit_start(request):
and request.POST['file'].file):
submit_form.file.errors.append(
_(u'You must provide a file.'))
- elif not security.check_filetype(request.POST['file']):
- submit_form.file.errors.append(
- _(u"The file doesn't seem to be an image!"))
else:
filename = request.POST['file'].filename
+ media_type, media_manager = get_media_type_and_manager(filename)
+
# create entry and save in database
entry = request.db.MediaEntry()
entry['_id'] = ObjectId()
+ entry['media_type'] = unicode(media_type)
entry['title'] = (
unicode(request.POST['title'])
or unicode(splitext(filename)[0]))
@@ -62,7 +63,6 @@ def submit_start(request):
entry['description_html'] = cleaned_markdown_conversion(
entry['description'])
- entry['media_type'] = u'image' # heh
entry['uploader'] = request.user['_id']
# Process the user's folksonomy "tags"
@@ -72,6 +72,7 @@ def submit_start(request):
# Generate a slug from the title
entry.generate_slug()
+
# Now store generate the queueing related filename
queue_filepath = request.app.queue_store.get_unique_filepath(
['media_entries',
@@ -103,7 +104,7 @@ def submit_start(request):
# (... don't change entry after this point to avoid race
# conditions with changes to the document via processing code)
try:
- process_media.apply_async(
+ media_manager['processor'].apply_async(
[unicode(entry['_id'])], {},
task_id=task_id)
except BaseException as exc:
diff --git a/mediagoblin/templates/mediagoblin/media_displays/image.html b/mediagoblin/templates/mediagoblin/media_displays/image.html
new file mode 100644
index 00000000..ad60fa94
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/media_displays/image.html
@@ -0,0 +1 @@
+{% extends 'mediagoblin/user_pages/media.html' %}
diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html
new file mode 100644
index 00000000..37586924
--- /dev/null
+++ b/mediagoblin/templates/mediagoblin/media_displays/video.html
@@ -0,0 +1,8 @@
+{% extends 'mediagoblin/user_pages/media.html' %}
+{% block mediagoblin_media %}
+
+{% endblock %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index 442bef6d..82a48e7c 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media.html
@@ -24,24 +24,26 @@
{% if media %}
+ {% if next %}
+
{% endif %}
--
cgit v1.2.3
From 1b36a8e80c09307a2c4ddf8cc8bfe786a9d86f7d Mon Sep 17 00:00:00 2001
From: Jef van Schendel
Date: Fri, 4 Nov 2011 02:20:26 +0100
Subject: On second thought, let's use this title for forgot_password.html
---
mediagoblin/templates/mediagoblin/auth/forgot_password.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/templates/mediagoblin/auth/forgot_password.html b/mediagoblin/templates/mediagoblin/auth/forgot_password.html
index c7f01678..9b821426 100644
--- a/mediagoblin/templates/mediagoblin/auth/forgot_password.html
+++ b/mediagoblin/templates/mediagoblin/auth/forgot_password.html
@@ -24,7 +24,7 @@
method="POST" enctype="multipart/form-data">
{{ csrf_token }}
-
{% trans %}Forgot your password?{% endtrans %}
+
{% trans %}Recover password{% endtrans %}
{{ wtforms_util.render_divs(fp_form) }}
--
cgit v1.2.3
From 80c9a7ee51590923a3b9f7a07419679af4a368d8 Mon Sep 17 00:00:00 2001
From: Jef van Schendel
Date: Fri, 4 Nov 2011 02:30:07 +0100
Subject: Small style changes to navigation buttons
---
mediagoblin/static/css/base.css | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index b026a819..23a7e6c5 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -290,11 +290,14 @@ img.media_icon{
/* navigation */
.navigation_button{
- width: 139px;
+ width: 135px;
display: block;
float: left;
text-align: center;
- background-color: #222;
+ background-color: #1d1d1d;
+ border: 1px solid;
+ border-color: #2c2c2c #232323 #1a1a1a;
+ border-radius: 3px;
text-decoration: none;
padding: 12px 0pt;
font-size: 2em;
@@ -306,7 +309,7 @@ p.navigation_button{
}
.navigation_left{
- margin-right: 2px;
+ margin-right: 6px;
}
/* messages */
--
cgit v1.2.3
From da76a8cbaa06ba63533f60051c66f08cd0e7baf4 Mon Sep 17 00:00:00 2001
From: Jef van Schendel
Date: Fri, 4 Nov 2011 02:34:00 +0100
Subject: Tiny padding change to vertically center navigation button arrows
---
mediagoblin/static/css/base.css | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index 23a7e6c5..afd10207 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -299,7 +299,7 @@ img.media_icon{
border-color: #2c2c2c #232323 #1a1a1a;
border-radius: 3px;
text-decoration: none;
- padding: 12px 0pt;
+ padding: 8px 0px 14px;
font-size: 2em;
margin: 0 0 20px
}
--
cgit v1.2.3
From d871f4e0d107268fab9dc33c648b1a6f7a99a652 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Fri, 4 Nov 2011 08:23:28 -0500
Subject: Updating translations
---
mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo | Bin 11089 -> 11119 bytes
mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po | 14 +-
mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo | Bin 11272 -> 11583 bytes
mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po | 92 +++--
mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo | Bin 11051 -> 11067 bytes
mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po | 8 +-
mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo | Bin 13895 -> 13899 bytes
mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po | 6 +-
mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo | Bin 0 -> 10812 bytes
mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po | 498 +++++++++++++++++++++++++
10 files changed, 568 insertions(+), 50 deletions(-)
create mode 100644 mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo
create mode 100644 mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po
diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo
index b65212eb..056e3eca 100644
Binary files a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.mo differ
diff --git a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po
index 5baab62e..5c4ef0d0 100644
--- a/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/de/LC_MESSAGES/mediagoblin.po
@@ -16,8 +16,8 @@ msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n"
"POT-Creation-Date: 2011-11-01 23:14-0500\n"
-"PO-Revision-Date: 2011-11-02 04:13+0000\n"
-"Last-Translator: cwebber \n"
+"PO-Revision-Date: 2011-11-02 15:18+0000\n"
+"Last-Translator: piratenpanda \n"
"Language-Team: German (http://www.transifex.net/projects/p/mediagoblin/team/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -259,7 +259,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/root.html:38
msgid "Excited to join us?"
-msgstr "Neugierig dich uns anzuschliessen?"
+msgstr "Neugierig dich uns anzuschließen?"
#: mediagoblin/templates/mediagoblin/root.html:39
#, python-format
@@ -292,8 +292,8 @@ msgstr "Dein Passwort wurde geändert. Versuche dich jetzt einzuloggen."
msgid ""
"Check your inbox. We sent an email with a URL for changing your password."
msgstr ""
-"Prüfe deinen Posteingang. Wir haben dir eine Email geschickt mit einer URL, "
-"um dein Passwort zu ändern."
+"Prüfe deinen Posteingang. Wir haben dir eine Email mit einem Link geschickt,"
+" mit dem du dein Passwort ändern kannst."
#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19
#, python-format
@@ -539,11 +539,11 @@ msgstr "Ja, wirklich löschen"
#: mediagoblin/user_pages/views.py:142
msgid "Empty comments are not allowed."
-msgstr ""
+msgstr "Leere Kommentare sind nicht erlaubt."
#: mediagoblin/user_pages/views.py:148
msgid "Comment posted!"
-msgstr ""
+msgstr "Kommentar hinzugefügt!"
#: mediagoblin/user_pages/views.py:181
msgid "You are about to delete another user's media. Proceed with caution."
diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo
index eaa18426..90e83303 100644
Binary files a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.mo differ
diff --git a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po
index 16939306..0a6a5a40 100644
--- a/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/fr/LC_MESSAGES/mediagoblin.po
@@ -3,6 +3,7 @@
# This file is distributed under the same license as the PROJECT project.
#
# Translators:
+# , 2011.
# , 2011.
# , 2011.
# , 2011.
@@ -13,8 +14,8 @@ msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n"
"POT-Creation-Date: 2011-11-01 23:14-0500\n"
-"PO-Revision-Date: 2011-11-02 04:13+0000\n"
-"Last-Translator: cwebber \n"
+"PO-Revision-Date: 2011-11-04 10:05+0000\n"
+"Last-Translator: chesuidayeur \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -42,7 +43,7 @@ msgstr "Confirmer le mot de passe"
#: mediagoblin/auth/forms.py:39
msgid "Type it again here to make sure there are no spelling mistakes."
msgstr ""
-"Tapez-le à nouveau ici pour vous assurer qu'il n'ya pas de fautes "
+"Tapez-le à nouveau ici pour vous assurer qu'il n'y a pas de fautes "
"d'orthographe."
#: mediagoblin/auth/forms.py:42
@@ -82,6 +83,8 @@ msgid ""
"Could not send password recovery email as your username is inactive or your "
"account's email address has not been verified."
msgstr ""
+"Impossible d'envoyer un email de récupération de mot de passe : votre compte"
+" est inactif ou bien l'email de votre compte n'a pas été vérifiée."
#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27
msgid "Title"
@@ -103,6 +106,8 @@ msgstr "La légende ne peut pas être laissée vide."
msgid ""
"The title part of this media's URL. You usually don't need to change this."
msgstr ""
+"Le nom de ce media dans l'URL. Vous n'avez normalement pas besoin de le "
+"changer"
#: mediagoblin/edit/forms.py:40
msgid "Bio"
@@ -130,7 +135,7 @@ msgstr ""
#: mediagoblin/process_media/errors.py:44
msgid "Invalid file given for media type."
-msgstr "Invalide fichier donné pour le type de média."
+msgstr "Le fichier envoyé ne correspond pas au type de média."
#: mediagoblin/submit/forms.py:25
msgid "File"
@@ -138,7 +143,7 @@ msgstr "Fichier"
#: mediagoblin/submit/forms.py:30
msgid "Description of this work"
-msgstr ""
+msgstr "Descriptif pour ce travail"
#: mediagoblin/submit/views.py:46
msgid "You must provide a file."
@@ -158,7 +163,7 @@ msgstr "Zut!"
#: mediagoblin/templates/mediagoblin/404.html:24
msgid "There doesn't seem to be a page at this address. Sorry!"
-msgstr "Il ne semble pas être une page à cette adresse. Désolé!"
+msgstr "Il ne semble pas y avoir de page à cette adresse. Désolé !"
#: mediagoblin/templates/mediagoblin/404.html:26
msgid ""
@@ -166,11 +171,11 @@ msgid ""
" been moved or deleted."
msgstr ""
"Si vous êtes sûr que l'adresse est correcte, peut-être la page que vous "
-"recherchez a été déplacé ou supprimé."
+"recherchez a été déplacée ou supprimée."
#: mediagoblin/templates/mediagoblin/404.html:32
msgid "Image of 404 goblin stressing out"
-msgstr "Image de 404 gobelin stresser"
+msgstr "Image de 404 gobelin angoissé"
#: mediagoblin/templates/mediagoblin/base.html:22
msgid "GNU MediaGoblin"
@@ -199,12 +204,12 @@ msgid ""
"Powered by MediaGoblin, a GNU project"
msgstr ""
-"Propulsé par MediaGoblin , un GNU de projet"
+"Propulsé par MediaGoblin , un projet "
+"GNU"
#: mediagoblin/templates/mediagoblin/root.html:24
msgid "Explore"
-msgstr ""
+msgstr "Explorer"
#: mediagoblin/templates/mediagoblin/root.html:27
msgid "Hi there, media lover! MediaGoblin is..."
@@ -219,15 +224,15 @@ msgid ""
"A place for people to collaborate and show off original and derived "
"creations!"
msgstr ""
-"Un lieu pour les personnes de collaborer et de montrer des créations "
-"originales et dérivées!"
+"Un espace de création collaboratif : montrez vos œuvres, originales ou "
+"dérivées !"
#: mediagoblin/templates/mediagoblin/root.html:31
msgid ""
"Free, as in freedom. (We’re a GNU project, "
"after all.)"
msgstr ""
-"Logiciel libre. (Nous sommes une GNU projet, "
+"Logiciel libre. (Nous sommes un projet GNU "
"après tout.)"
#: mediagoblin/templates/mediagoblin/root.html:32
@@ -235,8 +240,8 @@ msgid ""
"Aiming to make the world a better place through decentralization and "
"(eventually, coming soon!) federation!"
msgstr ""
-"Visant à rendre le monde meilleur grâce à la décentralisation et "
-"(éventuellement, venir bientôt!) fédération!"
+"Une tentative de rendre le monde meilleur grâce à la décentralisation et (à "
+"terme, et pour bientôt !) la fédération !"
#: mediagoblin/templates/mediagoblin/root.html:33
msgid ""
@@ -258,7 +263,7 @@ msgstr ""
#: mediagoblin/templates/mediagoblin/root.html:38
msgid "Excited to join us?"
-msgstr ""
+msgstr "Envi de vous joindre à nous ?"
#: mediagoblin/templates/mediagoblin/root.html:39
#, python-format
@@ -267,27 +272,33 @@ msgid ""
" or\n"
" Set up MediaGoblin on your own server"
msgstr ""
+"Créez gratuitement en compte\n"
+" ou\n"
+" Installez MediaGoblin sur votre propre serveur"
#: mediagoblin/templates/mediagoblin/root.html:53
msgid "Most recent media"
-msgstr ""
+msgstr "Tout derniers media"
#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29
msgid "Enter your new password"
-msgstr ""
+msgstr "Entrez un nouveau mot de passe"
#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29
msgid "Enter your username or email"
-msgstr ""
+msgstr "Entrez votre nom d'utilisateur ou votre email"
#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22
msgid "Your password has been changed. Try to log in now."
msgstr ""
+"Votre mot de passe a été changé. Essayez maintenant de vous identifier."
#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22
msgid ""
"Check your inbox. We sent an email with a URL for changing your password."
msgstr ""
+"Verifiez votre boîte de réception. Nous vous avons envoyé un email avec une "
+"URL vous permettant de changer votre mot de passe."
#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19
#, python-format
@@ -302,10 +313,19 @@ msgid ""
"If you think this is an error, just ignore this email and continue being\n"
"a happy goblin!"
msgstr ""
+"Bonjour %(username)s,\n"
+"\n"
+"Pour changer votre mot de passe GNU MediaGoblin, ouvrez l'URL suivante dans \n"
+"votre navigateur internet :\n"
+"\n"
+"%(verification_url)s\n"
+"\n"
+"Si vous pensez qu'il s'agit d'une erreur, ignorez simplement cet email et restez\n"
+"un goblin heureux !"
#: mediagoblin/templates/mediagoblin/auth/login.html:30
msgid "Logging in failed!"
-msgstr "Connexion a échoué!"
+msgstr "La connexion a échoué!"
#: mediagoblin/templates/mediagoblin/auth/login.html:43
msgid "Don't have an account yet?"
@@ -317,11 +337,11 @@ msgstr "Créez-en un ici!"
#: mediagoblin/templates/mediagoblin/auth/login.html:49
msgid "Forgot your password?"
-msgstr ""
+msgstr "Vous avez oublié votre mot de passe ?"
#: mediagoblin/templates/mediagoblin/auth/login.html:52
msgid "Change it!"
-msgstr ""
+msgstr "Changez-le !"
#: mediagoblin/templates/mediagoblin/auth/register.html:27
msgid "Create an account!"
@@ -396,7 +416,7 @@ msgstr "Voulez-vous vraiment supprimer %(title)s ?"
#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50
msgid "Delete Permanently"
-msgstr ""
+msgstr "Supprimer définitivement"
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22
msgid "Media processing panel"
@@ -419,7 +439,7 @@ msgstr "Aucun média en transformation"
#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50
msgid "These uploads failed to process:"
-msgstr "Ces ajouts n'etaient pas processé:"
+msgstr "Le traitement de ces ajouts a échoué :"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:39
#: mediagoblin/templates/mediagoblin/user_pages/user.html:59
@@ -428,7 +448,7 @@ msgstr "Vérification d'email nécessaire"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:42
msgid "Almost done! Your account still needs to be activated."
-msgstr "Presque fini! Votre compte a encore besoin d'être activé."
+msgstr "Presque fini ! Votre compte a encore besoin d'être activé."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:47
msgid ""
@@ -479,7 +499,7 @@ msgstr "Modifier le profil"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:96
msgid "This user hasn't filled in their profile (yet)."
-msgstr "Cet utilisateur n'a pas rempli leur profil (encore)."
+msgstr "Cet utilisateur n'a pas (encore) rempli son profil."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:122
#, python-format
@@ -491,8 +511,8 @@ msgid ""
"This is where your media will appear, but you don't seem to have added "
"anything yet."
msgstr ""
-"C'est là où vos médias apparaît, mais vous ne semblez pas avoir quoi que ce "
-"soit encore ajouté."
+"C'est là où vos médias apparaîssent, mais vous ne semblez pas avoir encore "
+"ajouté quoi que ce soit."
#: mediagoblin/templates/mediagoblin/user_pages/user.html:141
msgid "Add media"
@@ -500,11 +520,11 @@ msgstr "Ajouter des médias"
#: mediagoblin/templates/mediagoblin/user_pages/user.html:147
msgid "There doesn't seem to be any media here yet..."
-msgstr "Il ne semble pas être un média encore là ..."
+msgstr "Il ne semble pas y avoir de média là, pour l'instant ..."
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
msgid "feed icon"
-msgstr "icon de flux"
+msgstr "icone de flux"
#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23
msgid "Atom feed"
@@ -512,11 +532,11 @@ msgstr "flux Atom"
#: mediagoblin/templates/mediagoblin/utils/pagination.html:40
msgid "Newer"
-msgstr ""
+msgstr "Nouveaux"
#: mediagoblin/templates/mediagoblin/utils/pagination.html:46
msgid "Older"
-msgstr ""
+msgstr "Anciens"
#: mediagoblin/user_pages/forms.py:24
msgid "Comment"
@@ -524,15 +544,15 @@ msgstr "Commentaire"
#: mediagoblin/user_pages/forms.py:30
msgid "I am sure I want to delete this"
-msgstr ""
+msgstr "Je suis sûr de vouloir supprimer cela"
#: mediagoblin/user_pages/views.py:142
msgid "Empty comments are not allowed."
-msgstr ""
+msgstr "Les commentaires vides ne sont pas autorisés."
#: mediagoblin/user_pages/views.py:148
msgid "Comment posted!"
-msgstr ""
+msgstr "Votre commentaire a été posté !"
#: mediagoblin/user_pages/views.py:181
msgid "You are about to delete another user's media. Proceed with caution."
diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo
index 6e9c8897..2ab9cf8b 100644
Binary files a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.mo differ
diff --git a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po
index 2598f795..01fe5c48 100644
--- a/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ro/LC_MESSAGES/mediagoblin.po
@@ -9,8 +9,8 @@ msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n"
"POT-Creation-Date: 2011-11-01 23:14-0500\n"
-"PO-Revision-Date: 2011-11-02 04:13+0000\n"
-"Last-Translator: cwebber \n"
+"PO-Revision-Date: 2011-11-02 20:49+0000\n"
+"Last-Translator: gap \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -529,11 +529,11 @@ msgstr "Sunt sigur că doresc să șterg"
#: mediagoblin/user_pages/views.py:142
msgid "Empty comments are not allowed."
-msgstr ""
+msgstr "Comentariul trebuie să aibă un conținut."
#: mediagoblin/user_pages/views.py:148
msgid "Comment posted!"
-msgstr ""
+msgstr "Comentariul a fost transmis."
#: mediagoblin/user_pages/views.py:181
msgid "You are about to delete another user's media. Proceed with caution."
diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo
index 7cfc0b61..4b5481e0 100644
Binary files a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo and b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.mo differ
diff --git a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po
index aacd5ec8..f4bfbd67 100644
--- a/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po
+++ b/mediagoblin/i18n/ru/LC_MESSAGES/mediagoblin.po
@@ -9,8 +9,8 @@ msgstr ""
"Project-Id-Version: GNU MediaGoblin\n"
"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n"
"POT-Creation-Date: 2011-11-01 23:14-0500\n"
-"PO-Revision-Date: 2011-11-02 04:13+0000\n"
-"Last-Translator: cwebber \n"
+"PO-Revision-Date: 2011-11-04 11:13+0000\n"
+"Last-Translator: aleksejrs \n"
"Language-Team: LANGUAGE \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -515,7 +515,7 @@ msgstr "Я уверен, что хочу удалить это"
#: mediagoblin/user_pages/views.py:142
msgid "Empty comments are not allowed."
-msgstr ""
+msgstr "Empty comments are not allowed."
#: mediagoblin/user_pages/views.py:148
msgid "Comment posted!"
diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo
new file mode 100644
index 00000000..b0d8d3fc
Binary files /dev/null and b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.mo differ
diff --git a/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po
new file mode 100644
index 00000000..289bddb5
--- /dev/null
+++ b/mediagoblin/i18n/te/LC_MESSAGES/mediagoblin.po
@@ -0,0 +1,498 @@
+# Translations template for PROJECT.
+# Copyright (C) 2011 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+#
+# Translators:
+# వీవెన్ , 2011.
+msgid ""
+msgstr ""
+"Project-Id-Version: GNU MediaGoblin\n"
+"Report-Msgid-Bugs-To: http://bugs.foocorp.net/projects/mediagoblin/issues\n"
+"POT-Creation-Date: 2011-11-01 23:14-0500\n"
+"PO-Revision-Date: 2011-11-03 14:08+0000\n"
+"Last-Translator: veeven \n"
+"Language-Team: LANGUAGE \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+"Language: te\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+
+#: mediagoblin/auth/forms.py:25 mediagoblin/auth/forms.py:49
+msgid "Username"
+msgstr "వాడుకరి పేరు"
+
+#: mediagoblin/auth/forms.py:30 mediagoblin/auth/forms.py:53
+msgid "Password"
+msgstr "సంకేతపదం"
+
+#: mediagoblin/auth/forms.py:35
+msgid "Passwords must match."
+msgstr ""
+
+#: mediagoblin/auth/forms.py:37
+msgid "Confirm password"
+msgstr ""
+
+#: mediagoblin/auth/forms.py:39
+msgid "Type it again here to make sure there are no spelling mistakes."
+msgstr ""
+
+#: mediagoblin/auth/forms.py:42
+msgid "Email address"
+msgstr "ఈమెయిలు చిరునామా"
+
+#: mediagoblin/auth/views.py:55
+msgid "Sorry, registration is disabled on this instance."
+msgstr ""
+
+#: mediagoblin/auth/views.py:73
+msgid "Sorry, a user with that name already exists."
+msgstr ""
+
+#: mediagoblin/auth/views.py:77
+msgid "Sorry, that email address has already been taken."
+msgstr ""
+
+#: mediagoblin/auth/views.py:179
+msgid ""
+"Your email address has been verified. You may now login, edit your profile, "
+"and submit images!"
+msgstr ""
+
+#: mediagoblin/auth/views.py:185
+msgid "The verification key or user id is incorrect"
+msgstr ""
+
+#: mediagoblin/auth/views.py:207
+msgid "Resent your verification email."
+msgstr ""
+
+#: mediagoblin/auth/views.py:248
+msgid ""
+"Could not send password recovery email as your username is inactive or your "
+"account's email address has not been verified."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:24 mediagoblin/submit/forms.py:27
+msgid "Title"
+msgstr "శీర్షిక"
+
+#: mediagoblin/edit/forms.py:28 mediagoblin/submit/forms.py:32
+msgid "Tags"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:31
+msgid "Slug"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:32
+msgid "The slug can't be empty"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:33
+msgid ""
+"The title part of this media's URL. You usually don't need to change this."
+msgstr ""
+
+#: mediagoblin/edit/forms.py:40
+msgid "Bio"
+msgstr ""
+
+#: mediagoblin/edit/forms.py:43
+msgid "Website"
+msgstr ""
+
+#: mediagoblin/edit/views.py:64
+msgid "An entry with that slug already exists for this user."
+msgstr ""
+
+#: mediagoblin/edit/views.py:85
+msgid "You are editing another user's media. Proceed with caution."
+msgstr ""
+
+#: mediagoblin/edit/views.py:155
+msgid "You are editing a user's profile. Proceed with caution."
+msgstr ""
+
+#: mediagoblin/process_media/errors.py:44
+msgid "Invalid file given for media type."
+msgstr ""
+
+#: mediagoblin/submit/forms.py:25
+msgid "File"
+msgstr ""
+
+#: mediagoblin/submit/forms.py:30
+msgid "Description of this work"
+msgstr ""
+
+#: mediagoblin/submit/views.py:46
+msgid "You must provide a file."
+msgstr ""
+
+#: mediagoblin/submit/views.py:49
+msgid "The file doesn't seem to be an image!"
+msgstr ""
+
+#: mediagoblin/submit/views.py:121
+msgid "Woohoo! Submitted!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/404.html:21
+msgid "Oops!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/404.html:24
+msgid "There doesn't seem to be a page at this address. Sorry!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/404.html:26
+msgid ""
+"If you're sure the address is correct, maybe the page you're looking for has"
+" been moved or deleted."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/404.html:32
+msgid "Image of 404 goblin stressing out"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:22
+msgid "GNU MediaGoblin"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:47
+msgid "MediaGoblin logo"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:52
+msgid "Submit media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:63
+msgid "verify your email!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:73
+#: mediagoblin/templates/mediagoblin/auth/login.html:27
+#: mediagoblin/templates/mediagoblin/auth/login.html:35
+msgid "Log in"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/base.html:89
+msgid ""
+"Powered by MediaGoblin, a GNU project"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:24
+msgid "Explore"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:27
+msgid "Hi there, media lover! MediaGoblin is..."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:29
+msgid "The perfect place for your media!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:30
+msgid ""
+"A place for people to collaborate and show off original and derived "
+"creations!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:31
+msgid ""
+"Free, as in freedom. (We’re a GNU project, "
+"after all.)"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:32
+msgid ""
+"Aiming to make the world a better place through decentralization and "
+"(eventually, coming soon!) federation!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:33
+msgid ""
+"Built for extensibility. (Multiple media types coming soon to the software,"
+" including video support!)"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:34
+msgid ""
+"Powered by people like you. (You can help us improve this"
+" software!)"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:38
+msgid "Excited to join us?"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:39
+#, python-format
+msgid ""
+"Create a free account\n"
+" or\n"
+" Set up MediaGoblin on your own server"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/root.html:53
+msgid "Most recent media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/change_fp.html:29
+msgid "Enter your new password"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/forgot_password.html:29
+msgid "Enter your username or email"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/fp_changed_success.html:22
+msgid "Your password has been changed. Try to log in now."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/fp_email_sent.html:22
+msgid ""
+"Check your inbox. We sent an email with a URL for changing your password."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/fp_verification_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"\n"
+"to change your GNU MediaGoblin password, open the following URL in \n"
+"your web browser:\n"
+"\n"
+"%(verification_url)s\n"
+"\n"
+"If you think this is an error, just ignore this email and continue being\n"
+"a happy goblin!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:30
+msgid "Logging in failed!"
+msgstr "ప్రవేశం విఫలమయ్యింది!"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:43
+msgid "Don't have an account yet?"
+msgstr "మీకు ఇంకా ఖాతా లేదా?"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:46
+msgid "Create one here!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:49
+msgid "Forgot your password?"
+msgstr "మీ సంకేతపదాన్ని మర్చిపోయారా?"
+
+#: mediagoblin/templates/mediagoblin/auth/login.html:52
+msgid "Change it!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/register.html:27
+msgid "Create an account!"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/register.html:31
+msgid "Create"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/auth/verification_email.txt:19
+#, python-format
+msgid ""
+"Hi %(username)s,\n"
+"\n"
+"to activate your GNU MediaGoblin account, open the following URL in\n"
+"your web browser:\n"
+"\n"
+"%(verification_url)s"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit.html:29
+#, python-format
+msgid "Editing %(media_title)s"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/edit/edit.html:36
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:49
+msgid "Cancel"
+msgstr "రద్దుచేయి"
+
+#: mediagoblin/templates/mediagoblin/edit/edit.html:37
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:35
+msgid "Save changes"
+msgstr "మార్పులను భద్రపరచు"
+
+#: mediagoblin/templates/mediagoblin/edit/edit_profile.html:29
+#, python-format
+msgid "Editing %(username)s's profile"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/listings/tag.html:31
+msgid "Media tagged with:"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/submit/start.html:26
+msgid "Submit yer media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/submit/start.html:30
+msgid "Submit"
+msgstr "దాఖలు చెయ్యి"
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:32
+#, python-format
+msgid "%(username)s's media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/gallery.html:52
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:32
+msgid "Sorry, no such user found."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:30
+#, python-format
+msgid "Really delete %(title)s?"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html:50
+msgid "Delete Permanently"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:22
+msgid "Media processing panel"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:25
+msgid ""
+"You can track the state of media being processed for your gallery here."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:28
+msgid "Media in-processing"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:46
+msgid "No media in-processing"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/processing_panel.html:50
+msgid "These uploads failed to process:"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:39
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:59
+msgid "Email verification needed"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:42
+msgid "Almost done! Your account still needs to be activated."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:47
+msgid ""
+"An email should arrive in a few moments with instructions on how to do so."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:51
+msgid "In case it doesn't:"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:54
+msgid "Resend verification email"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:62
+msgid ""
+"Someone has registered an account with this username, but it still has to be"
+" activated."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:68
+#, python-format
+msgid ""
+"If you are that person but you've lost your verification email, you can log in and resend it."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:78
+#, python-format
+msgid "%(username)s's profile"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:85
+msgid "Here's a spot to tell others about yourself."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:90
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:108
+msgid "Edit profile"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:96
+msgid "This user hasn't filled in their profile (yet)."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:122
+#, python-format
+msgid "View all of %(username)s's media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:135
+msgid ""
+"This is where your media will appear, but you don't seem to have added "
+"anything yet."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:141
+msgid "Add media"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/user_pages/user.html:147
+msgid "There doesn't seem to be any media here yet..."
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/feed_link.html:21
+msgid "feed icon"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/feed_link.html:23
+msgid "Atom feed"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:40
+msgid "Newer"
+msgstr ""
+
+#: mediagoblin/templates/mediagoblin/utils/pagination.html:46
+msgid "Older"
+msgstr ""
+
+#: mediagoblin/user_pages/forms.py:24
+msgid "Comment"
+msgstr "వ్యాఖ్య"
+
+#: mediagoblin/user_pages/forms.py:30
+msgid "I am sure I want to delete this"
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:142
+msgid "Empty comments are not allowed."
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:148
+msgid "Comment posted!"
+msgstr ""
+
+#: mediagoblin/user_pages/views.py:181
+msgid "You are about to delete another user's media. Proceed with caution."
+msgstr ""
+
+
--
cgit v1.2.3
From 34b0874d9ad305f4c8d5e892a679bad2f33ed277 Mon Sep 17 00:00:00 2001
From: Elrond
Date: Sun, 30 Oct 2011 20:51:55 +0100
Subject: Some docs for the TestingMiddleware
To make the TestingMiddleware actually more useful in the
future, start to document it.
---
mediagoblin/middleware/testing.py | 25 +++++++++++++++++++++++++
mediagoblin/tests/tools.py | 2 ++
2 files changed, 27 insertions(+)
diff --git a/mediagoblin/middleware/testing.py b/mediagoblin/middleware/testing.py
index 06714769..99322661 100644
--- a/mediagoblin/middleware/testing.py
+++ b/mediagoblin/middleware/testing.py
@@ -15,6 +15,23 @@
# along with this program. If not, see .
class TestingMiddleware(object):
+ """
+ Middleware for the Unit tests
+
+ It might make sense to perform some tests on all
+ requests/responses. Or prepare them in a special
+ manner. For example all html responses could be tested
+ for being valid html *after* being rendered.
+
+ This module is getting inserted at the front of the
+ middleware list, which means: requests are handed here
+ first, responses last. So this wraps up the "normal"
+ app.
+
+ If you need to add a test, either add it directly to
+ the appropiate process_request or process_response, or
+ create a new method and call it from process_*.
+ """
def __init__(self, mg_app):
self.app = mg_app
@@ -23,12 +40,20 @@ class TestingMiddleware(object):
pass
def process_response(self, request, response):
+ # All following tests should be for html only!
if response.content_type != "text/html":
# Get out early
return
+
+ # If the template contains a reference to
+ # /mgoblin_static/ instead of using
+ # /request.staticdirect(), error out here.
+ # This could probably be implemented as a grep on
+ # the shipped templates easier...
if response.text.find("/mgoblin_static/") >= 0:
raise AssertionError(
"Response HTML contains reference to /mgoblin_static/ "
"instead of staticdirect. Request was for: "
+ request.full_path)
+
return
diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py
index e8558240..7f20f6e7 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -107,6 +107,8 @@ def get_test_app(dump_old_app=True):
# Insert the TestingMiddleware, which can do some
# sanity checks on every request/response.
+ # Doing it this way is probably not the cleanest way.
+ # We'll fix it, when we have plugins!
mg_globals.app.middleware.insert(0, TestingMiddleware(mg_globals.app))
app = TestApp(test_app)
--
cgit v1.2.3
From 33d11e995d183f339597715472e4f6ecc81ba557 Mon Sep 17 00:00:00 2001
From: Elrond
Date: Sat, 12 Nov 2011 13:21:41 +0100
Subject: Move TestingMiddleware to tests/tools.py
This middleware isn't needed outside of the tests, so let's
just put it there.
---
mediagoblin/middleware/testing.py | 59 ---------------------------------------
mediagoblin/tests/tools.py | 46 +++++++++++++++++++++++++++++-
2 files changed, 45 insertions(+), 60 deletions(-)
delete mode 100644 mediagoblin/middleware/testing.py
diff --git a/mediagoblin/middleware/testing.py b/mediagoblin/middleware/testing.py
deleted file mode 100644
index 99322661..00000000
--- a/mediagoblin/middleware/testing.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# GNU MediaGoblin -- federated, autonomous media hosting
-# Copyright (C) 2011 MediaGoblin contributors. See AUTHORS.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-class TestingMiddleware(object):
- """
- Middleware for the Unit tests
-
- It might make sense to perform some tests on all
- requests/responses. Or prepare them in a special
- manner. For example all html responses could be tested
- for being valid html *after* being rendered.
-
- This module is getting inserted at the front of the
- middleware list, which means: requests are handed here
- first, responses last. So this wraps up the "normal"
- app.
-
- If you need to add a test, either add it directly to
- the appropiate process_request or process_response, or
- create a new method and call it from process_*.
- """
-
- def __init__(self, mg_app):
- self.app = mg_app
-
- def process_request(self, request):
- pass
-
- def process_response(self, request, response):
- # All following tests should be for html only!
- if response.content_type != "text/html":
- # Get out early
- return
-
- # If the template contains a reference to
- # /mgoblin_static/ instead of using
- # /request.staticdirect(), error out here.
- # This could probably be implemented as a grep on
- # the shipped templates easier...
- if response.text.find("/mgoblin_static/") >= 0:
- raise AssertionError(
- "Response HTML contains reference to /mgoblin_static/ "
- "instead of staticdirect. Request was for: "
- + request.full_path)
-
- return
diff --git a/mediagoblin/tests/tools.py b/mediagoblin/tests/tools.py
index 7f20f6e7..420d9ba8 100644
--- a/mediagoblin/tests/tools.py
+++ b/mediagoblin/tests/tools.py
@@ -23,7 +23,6 @@ from webtest import TestApp
from mediagoblin import mg_globals
from mediagoblin.tools import testing
-from mediagoblin.middleware.testing import TestingMiddleware
from mediagoblin.init.config import read_mediagoblin_config
from mediagoblin.decorators import _make_safe
from mediagoblin.db.open import setup_connection_and_db_from_config
@@ -51,6 +50,51 @@ $ CELERY_CONFIG_MODULE=mediagoblin.init.celery.from_tests ./bin/nosetests"""
class BadCeleryEnviron(Exception): pass
+class TestingMiddleware(object):
+ """
+ Middleware for the Unit tests
+
+ It might make sense to perform some tests on all
+ requests/responses. Or prepare them in a special
+ manner. For example all html responses could be tested
+ for being valid html *after* being rendered.
+
+ This module is getting inserted at the front of the
+ middleware list, which means: requests are handed here
+ first, responses last. So this wraps up the "normal"
+ app.
+
+ If you need to add a test, either add it directly to
+ the appropiate process_request or process_response, or
+ create a new method and call it from process_*.
+ """
+
+ def __init__(self, mg_app):
+ self.app = mg_app
+
+ def process_request(self, request):
+ pass
+
+ def process_response(self, request, response):
+ # All following tests should be for html only!
+ if response.content_type != "text/html":
+ # Get out early
+ return
+
+ # If the template contains a reference to
+ # /mgoblin_static/ instead of using
+ # /request.staticdirect(), error out here.
+ # This could probably be implemented as a grep on
+ # the shipped templates easier...
+ if response.text.find("/mgoblin_static/") >= 0:
+ raise AssertionError(
+ "Response HTML contains reference to /mgoblin_static/ "
+ "instead of staticdirect. Request was for: "
+ + request.full_path)
+
+ return
+
+
def suicide_if_bad_celery_environ():
if not os.environ.get('CELERY_CONFIG_MODULE') == \
'mediagoblin.init.celery.from_tests':
--
cgit v1.2.3
From daed11b81263c3841ae23f45ed1bf33aa2e92992 Mon Sep 17 00:00:00 2001
From: Elrond
Date: Sat, 12 Nov 2011 14:26:35 +0100
Subject: 640: Configuration files should mention their _local versions
Thanks go to Aleksej Serdjukov for bringing this up and
providing the patch in the bug!
---
mediagoblin.ini | 3 +++
paste.ini | 3 +++
2 files changed, 6 insertions(+)
diff --git a/mediagoblin.ini b/mediagoblin.ini
index c22d12d7..728ab2f2 100644
--- a/mediagoblin.ini
+++ b/mediagoblin.ini
@@ -1,3 +1,6 @@
+# If you want to make changes to this file, first copy it to
+# mediagoblin_local.ini, then make the changes there.
+
[mediagoblin]
direct_remote_path = /mgoblin_static/
email_sender_address = "notice@mediagoblin.example.org"
diff --git a/paste.ini b/paste.ini
index 8866789c..c729e41d 100644
--- a/paste.ini
+++ b/paste.ini
@@ -1,3 +1,6 @@
+# If you want to make changes to this file, first copy it to
+# paste_local.ini, then make the changes there.
+
[DEFAULT]
# Set to true to enable web-based debugging messages and etc.
debug = false
--
cgit v1.2.3
From 8bb3eb185ab14e8e8f4fc7b3df9eac4e1438d030 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 12 Nov 2011 08:10:46 -0600
Subject: Probably should have MANIFEST.in checked in, for doing python sdists
---
MANIFEST.in | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 MANIFEST.in
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 00000000..b1f93dba
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,5 @@
+recursive-include mediagoblin/templates *.html
+recursive-include mediagoblin/static *.js *.css *.png *.svg
+recursive-include mediagoblin/tests *.ini
+recursive-include docs *.rst *.html
+
--
cgit v1.2.3
From 0cf5b8ad2499a93fdba5ff1202fdc554208ec85f Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 12 Nov 2011 13:35:41 -0600
Subject: Don't force-convert resized images to JPEG.
That's just not nice for those of us who like transparency!
---
mediagoblin/process_media/__init__.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py
index 2b9eed6e..85bdcbea 100644
--- a/mediagoblin/process_media/__init__.py
+++ b/mediagoblin/process_media/__init__.py
@@ -136,7 +136,7 @@ def process_image(entry):
thumb_file = mgg.public_store.get_file(thumb_filepath, 'w')
with thumb_file:
- thumb.save(thumb_file, "JPEG", quality=90)
+ thumb.save(thumb_file)
# If the size of the original file exceeds the specified size of a `medium`
# file, a `medium.jpg` files is created and later associated with the media
@@ -154,7 +154,7 @@ def process_image(entry):
medium_file = mgg.public_store.get_file(medium_filepath, 'w')
with medium_file:
- medium.save(medium_file, "JPEG", quality=90)
+ medium.save(medium_file)
medium_processed = True
# we have to re-read because unlike PIL, not everything reads
--
cgit v1.2.3
From d0504cfa875b0ac7340fb00a64fc8422faecdc9a Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 12 Nov 2011 15:12:39 -0600
Subject: Final step for non-force-conversion to jpeg
---
mediagoblin/process_media/__init__.py | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py
index 85bdcbea..f63fb2b0 100644
--- a/mediagoblin/process_media/__init__.py
+++ b/mediagoblin/process_media/__init__.py
@@ -14,8 +14,9 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-import Image
+import os
+import Image
from celery.task import Task
from celery import registry
@@ -122,17 +123,16 @@ def process_image(entry):
mgg.queue_store, queued_filepath,
'source')
+ extension = os.path.splitext(queued_filename)[1]
+
try:
thumb = Image.open(queued_filename)
except IOError:
raise BadMediaFail()
thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
- # ensure color mode is compatible with jpg
- if thumb.mode != "RGB":
- thumb = thumb.convert("RGB")
- thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg')
+ thumb_filepath = create_pub_filepath(entry, 'thumbnail' + extension)
thumb_file = mgg.public_store.get_file(thumb_filepath, 'w')
with thumb_file:
@@ -147,10 +147,7 @@ def process_image(entry):
if medium.size[0] > MEDIUM_SIZE[0] or medium.size[1] > MEDIUM_SIZE[1]:
medium.thumbnail(MEDIUM_SIZE, Image.ANTIALIAS)
- if medium.mode != "RGB":
- medium = medium.convert("RGB")
-
- medium_filepath = create_pub_filepath(entry, 'medium.jpg')
+ medium_filepath = create_pub_filepath(entry, 'medium' + extension)
medium_file = mgg.public_store.get_file(medium_filepath, 'w')
with medium_file:
--
cgit v1.2.3
From efd0a42ca1b81a2dd17aee1626060584a278020c Mon Sep 17 00:00:00 2001
From: Elrond
Date: Sun, 13 Nov 2011 19:51:11 +0100
Subject: Mark two strings for translation
---
mediagoblin/edit/views.py | 2 +-
mediagoblin/templates/mediagoblin/base.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py
index a6ddb553..17244831 100644
--- a/mediagoblin/edit/views.py
+++ b/mediagoblin/edit/views.py
@@ -170,7 +170,7 @@ def edit_profile(request):
messages.add_message(request,
messages.SUCCESS,
- 'Profile edited!')
+ _("Profile edited!"))
return redirect(request,
'mediagoblin.user_pages.user_home',
user=edit_username)
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html
index b4c4dcf3..925386e5 100644
--- a/mediagoblin/templates/mediagoblin/base.html
+++ b/mediagoblin/templates/mediagoblin/base.html
@@ -67,7 +67,7 @@
user= request.user['username']) }}">
{{ request.user['username'] }}
- (log out)
+ ({% trans %}log out{% endtrans %})
{% else %}
{% trans %}Log in{% endtrans %}
--
cgit v1.2.3
From b97ae0fd7da45c32897a4cb8437c04ddf04fdc95 Mon Sep 17 00:00:00 2001
From: Nathan Yergler
Date: Sun, 13 Nov 2011 11:41:43 -0800
Subject: Issue 653: Don't throw exception if response has no vary header.
---
mediagoblin/middleware/csrf.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py
index 7a5e352e..6c977f21 100644
--- a/mediagoblin/middleware/csrf.py
+++ b/mediagoblin/middleware/csrf.py
@@ -98,7 +98,7 @@ class CsrfMiddleware(object):
httponly=True)
# update the Vary header
- response.vary = (response.vary or []) + ['Cookie']
+ response.vary = getattr(response, 'vary', []) + ['Cookie']
def _make_token(self, request):
"""Generate a new token to use for CSRF protection."""
--
cgit v1.2.3
From ad3f1233df672688c09ab923d8bb216a351db8cb Mon Sep 17 00:00:00 2001
From: Nathan Yergler
Date: Sun, 13 Nov 2011 11:59:24 -0800
Subject: Issue 653: Handle the case where request.vary is None
---
mediagoblin/middleware/csrf.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py
index 6c977f21..d0601af8 100644
--- a/mediagoblin/middleware/csrf.py
+++ b/mediagoblin/middleware/csrf.py
@@ -98,7 +98,7 @@ class CsrfMiddleware(object):
httponly=True)
# update the Vary header
- response.vary = getattr(response, 'vary', []) + ['Cookie']
+ response.vary = (getattr(response, 'vary') or []) + ['Cookie']
def _make_token(self, request):
"""Generate a new token to use for CSRF protection."""
--
cgit v1.2.3
From d9ed3aeb402fc66de2a79d145b5a443c9e660c18 Mon Sep 17 00:00:00 2001
From: Nathan Yergler
Date: Sun, 13 Nov 2011 12:07:09 -0800
Subject: Issue 653: This time for sure!
---
mediagoblin/middleware/csrf.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/middleware/csrf.py b/mediagoblin/middleware/csrf.py
index d0601af8..8275c18e 100644
--- a/mediagoblin/middleware/csrf.py
+++ b/mediagoblin/middleware/csrf.py
@@ -98,7 +98,7 @@ class CsrfMiddleware(object):
httponly=True)
# update the Vary header
- response.vary = (getattr(response, 'vary') or []) + ['Cookie']
+ response.vary = (getattr(response, 'vary', None) or []) + ['Cookie']
def _make_token(self, request):
"""Generate a new token to use for CSRF protection."""
--
cgit v1.2.3
From 688f56c2dc579218b35263d0189e5d7c9ba9627f Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sun, 13 Nov 2011 14:34:22 -0600
Subject: Improved title block on media page
---
mediagoblin/templates/mediagoblin/user_pages/media.html | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index 17beffb2..2441ec1b 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media.html
@@ -20,6 +20,8 @@
{% import "/mediagoblin/utils/wtforms.html" as wtforms_util %}
{% from "mediagoblin/utils/pagination.html" import render_pagination %}
+{% block title %}{{ media.title }} — {{ super() }}{% endblock %}
+
{% block mediagoblin_content %}
{% if media %}
--
cgit v1.2.3
From 017d6ca3501b157277fc01fb37df2dbbd9ed17ef Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sun, 13 Nov 2011 14:38:40 -0600
Subject: Enhanced title for user profile page
---
mediagoblin/templates/mediagoblin/user_pages/user.html | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html
index c5beeaaa..d65da055 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/user.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/user.html
@@ -26,6 +26,17 @@
user=user.username) }}">
{% endblock mediagoblin_head %}
+{% block title %}
+ {%- if user -%}
+ {%- trans username=user.username -%}
+ {{ username }}'s profile
+ {%- endtrans %} — {{ super() }}
+ {%- else -%}
+ {{ super() }}
+ {%- endif -%}
+{% endblock %}
+
+
{% block mediagoblin_content -%}
{# If no user... #}
{% if not user %}
--
cgit v1.2.3
From 7fc25d27208ef9926e94eeba953160ffbe676942 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sun, 13 Nov 2011 14:40:11 -0600
Subject: If the gallery view makes sure we have a user anyway, do we need this
check?
Seems like the classic annoying "SHOULD NEVER HAPPEN" else: statement :)
---
.../templates/mediagoblin/user_pages/gallery.html | 39 ++++++++++------------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/mediagoblin/templates/mediagoblin/user_pages/gallery.html b/mediagoblin/templates/mediagoblin/user_pages/gallery.html
index df931d9c..86105493 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/gallery.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/gallery.html
@@ -27,28 +27,23 @@
{% endblock mediagoblin_head %}
{% block mediagoblin_content -%}
- {% if user %}
-
--
cgit v1.2.3
From 2b7aa99d3c221e713a95b664491f35612f9023cc Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sun, 13 Nov 2011 20:39:42 -0600
Subject: Only show "post a comment" link if comments already exist
The purpose of the link is to help you jump past comments to the
comment box, and so...
Even with this new conditional, I'm not entirely sure I like that link ;)
---
mediagoblin/templates/mediagoblin/user_pages/media.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index 2441ec1b..1e495b98 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media.html
@@ -62,7 +62,7 @@
{%- endtrans %}
- {% if request.user %}
+ {% if request.user and comments.count() %}
{% endif %}
--
cgit v1.2.3
From 0b3cdd6a25f8aaa74beecb7fed32a20cc13587a8 Mon Sep 17 00:00:00 2001
From: Jef van Schendel
Date: Sun, 20 Nov 2011 17:01:23 +0100
Subject: Navigation buttons edits. Removed images as they are no longer
needed. Related: bug #504
---
mediagoblin/static/css/base.css | 8 ++------
mediagoblin/static/images/navigation_end.png | Bin 718 -> 0 bytes
mediagoblin/static/images/navigation_left.png | Bin 406 -> 0 bytes
mediagoblin/static/images/navigation_right.png | Bin 383 -> 0 bytes
mediagoblin/templates/mediagoblin/utils/prev_next.html | 8 ++++----
5 files changed, 6 insertions(+), 10 deletions(-)
delete mode 100644 mediagoblin/static/images/navigation_end.png
delete mode 100644 mediagoblin/static/images/navigation_left.png
delete mode 100644 mediagoblin/static/images/navigation_right.png
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index c26e11af..12d88ffa 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -300,15 +300,11 @@ img.media_icon{
border-color: #2c2c2c #232323 #1a1a1a;
border-radius: 4px;
text-decoration: none;
- padding: 8px 0px 14px;
- font-size: 2em;
+ padding: 12px 0 16px;
+ font-size: 1.4em;
margin: 0 0 20px
}
-p.navigation_button{
- color: #272727;
-}
-
.navigation_left{
margin-right: 6px;
}
diff --git a/mediagoblin/static/images/navigation_end.png b/mediagoblin/static/images/navigation_end.png
deleted file mode 100644
index b2f27296..00000000
Binary files a/mediagoblin/static/images/navigation_end.png and /dev/null differ
diff --git a/mediagoblin/static/images/navigation_left.png b/mediagoblin/static/images/navigation_left.png
deleted file mode 100644
index d1645120..00000000
Binary files a/mediagoblin/static/images/navigation_left.png and /dev/null differ
diff --git a/mediagoblin/static/images/navigation_right.png b/mediagoblin/static/images/navigation_right.png
deleted file mode 100644
index d4caa7b8..00000000
Binary files a/mediagoblin/static/images/navigation_right.png and /dev/null differ
diff --git a/mediagoblin/templates/mediagoblin/utils/prev_next.html b/mediagoblin/templates/mediagoblin/utils/prev_next.html
index 75903076..3363891b 100644
--- a/mediagoblin/templates/mediagoblin/utils/prev_next.html
+++ b/mediagoblin/templates/mediagoblin/utils/prev_next.html
@@ -25,23 +25,23 @@
{# There are no previous entries for the very first media entry #}
{% if prev_entry_url %}
-
+ ← newer
{% else %}
{# This is the first entry. display greyed-out 'previous' image #}
-
+ ← newer
{% endif %}
{# Likewise, this could be the very last media entry #}
{% if next_entry_url %}
-
+ older →
{% else %}
{# This is the last entry. display greyed-out 'next' image #}
-
+ older →
{% endif %}
--
cgit v1.2.3
From 5dbeda8a0f2953aed13521b6e87376327e8302e0 Mon Sep 17 00:00:00 2001
From: Elrond
Date: Sun, 20 Nov 2011 20:15:21 +0100
Subject: Fix redirect to logical path
redirects should in nearly all cases go to a logical path
like 'mediagoblin.auth.login' and not to an absolute path
like "/auth/login".
---
mediagoblin/auth/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/auth/views.py b/mediagoblin/auth/views.py
index b3a70d46..d01861d1 100644
--- a/mediagoblin/auth/views.py
+++ b/mediagoblin/auth/views.py
@@ -202,7 +202,7 @@ def resend_activation(request):
messages.ERROR,
_('You must be logged in so we know who to send the email to!'))
- return redirect(request, "/auth/login")
+ return redirect(request, 'mediagoblin.auth.login')
if request.user["email_verified"]:
messages.add_message(
--
cgit v1.2.3
From 9404a9fed23bfe27144da4f8e692df1f692a25b5 Mon Sep 17 00:00:00 2001
From: Jakob Kramer
Date: Sun, 20 Nov 2011 21:15:07 +0100
Subject: don't use 'and' anymore, if there is only one tag
---
mediagoblin/templates/mediagoblin/utils/tags.html | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html
index 19ca8d2a..20c50f6e 100644
--- a/mediagoblin/templates/mediagoblin/utils/tags.html
+++ b/mediagoblin/templates/mediagoblin/utils/tags.html
@@ -20,7 +20,10 @@
{% trans %}Tagged with{% endtrans %}
{% for tag in media.tags %}
{% if loop.last %}
- {% trans %}and{% endtrans %} {{ tag['name'] }}.
{% elif loop.revindex==2 %}
--
cgit v1.2.3
From a00f1c1e1cecb8f127b6a064e2cd90c8f613660d Mon Sep 17 00:00:00 2001
From: Jakob Kramer
Date: Sun, 20 Nov 2011 21:30:46 +0100
Subject: eyecandy for programmers
---
mediagoblin/templates/mediagoblin/utils/tags.html | 24 ++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html
index 20c50f6e..49bc3cee 100644
--- a/mediagoblin/templates/mediagoblin/utils/tags.html
+++ b/mediagoblin/templates/mediagoblin/utils/tags.html
@@ -20,19 +20,21 @@
{% trans %}Tagged with{% endtrans %}
{% for tag in media.tags %}
{% if loop.last %}
+ {# the 'and' should only appear if there is more than one tag #}
{% if media.tags|length > 1 %}
- {% trans %}and{% endtrans %}
+ {% trans %}and{% endtrans %}
{% endif %}
- {{ tag['name'] }}.
- {% elif loop.revindex==2 %}
- {{ tag['name'] }}
- {% else %}{{ tag['name'] }},
+
+ {{ tag['name'] }}.
+ {% elif loop.revindex==2 %}
+ {{ tag['name'] }}
+ {% else %}{{ tag['name'] }},
{% endif %}
{% endfor %}
--
cgit v1.2.3
From fe0a8f53e251aae93bee5f4dee79d462fad751e8 Mon Sep 17 00:00:00 2001
From: Jakob Kramer
Date: Sun, 20 Nov 2011 21:40:51 +0100
Subject: fixed identation
---
mediagoblin/templates/mediagoblin/utils/tags.html | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/mediagoblin/templates/mediagoblin/utils/tags.html b/mediagoblin/templates/mediagoblin/utils/tags.html
index 49bc3cee..c7dfc8eb 100644
--- a/mediagoblin/templates/mediagoblin/utils/tags.html
+++ b/mediagoblin/templates/mediagoblin/utils/tags.html
@@ -24,15 +24,15 @@
{% if media.tags|length > 1 %}
{% trans %}and{% endtrans %}
{% endif %}
-
{{ tag['name'] }}.
- {% elif loop.revindex==2 %}
+ {% elif loop.revindex == 2 %}
{{ tag['name'] }}
- {% else %}{{ tag['name'] }},
{% endif %}
--
cgit v1.2.3
From a63b640f12896a873ebf96f9fe0ef62d0794bfe7 Mon Sep 17 00:00:00 2001
From: Joar Wandborg
Date: Mon, 21 Nov 2011 00:06:59 +0100
Subject: Stashing changes
---
mediagoblin/init/celery/__init__.py | 3 --
mediagoblin/media_types/__init__.py | 26 ++++++------
mediagoblin/media_types/video/processing.py | 49 ++++------------------
mediagoblin/media_types/video/transcoders.py | 1 -
mediagoblin/process_media/__init__.py | 3 ++
mediagoblin/templates/mediagoblin/base.html | 7 ++++
.../mediagoblin/media_displays/video.html | 18 +++++---
setup.py | 1 -
8 files changed, 43 insertions(+), 65 deletions(-)
diff --git a/mediagoblin/init/celery/__init__.py b/mediagoblin/init/celery/__init__.py
index 05c54b05..c5d37420 100644
--- a/mediagoblin/init/celery/__init__.py
+++ b/mediagoblin/init/celery/__init__.py
@@ -17,11 +17,8 @@
import os
import sys
-from mediagoblin.media_types import get_media_types
-
MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media']
-MANDATORY_CELERY_IMPORTS = [i for i in get_media_types()]
print(MANDATORY_CELERY_IMPORTS)
diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py
index 49d3ab9d..2d13f5a6 100644
--- a/mediagoblin/media_types/__init__.py
+++ b/mediagoblin/media_types/__init__.py
@@ -26,31 +26,33 @@ class FileTypeNotSupported(Exception):
class InvalidFileType(Exception):
pass
+# This should be more dynamic in the future. Perhaps put it in the .ini?
+# -- Joar
MEDIA_TYPES = [
'mediagoblin.media_types.image',
'mediagoblin.media_types.video']
def get_media_types():
+ '''
+ Generator that returns the available media types
+ '''
for media_type in MEDIA_TYPES:
yield media_type
def get_media_managers():
+ '''
+ Generator that returns all available media managers
+ '''
for media_type in get_media_types():
- '''
- FIXME
- __import__ returns the lowest-level module. If the plugin is located
- outside the conventional plugin module tree, it will not be loaded
- properly because of the [...]ugin.media_types.
-
- We need this if we want to support a separate site-specific plugin
- folder.
- '''
try:
__import__(media_type)
except ImportError as e:
- raise Exception('ERROR: Could not import {0}: {1}'.format(media_type, e))
+ raise Exception(
+ _('ERROR: Could not import {media_type}: {exception}').format(
+ media_type=media_type,
+ exception=e))
yield media_type, sys.modules[media_type].MEDIA_MANAGER
@@ -67,8 +69,8 @@ def get_media_type_and_manager(filename):
ext = os.path.splitext(filename)[1].lower()
else:
raise InvalidFileType(
- 'Could not find any file extension in "{0}"'.format(
- filename))
+ _('Could not find any file extension in "{filename}"').format(
+ filename=filename))
if ext[1:] in manager['accepted_extensions']:
return media_type, manager
diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py
index 027f527b..4e05a71c 100644
--- a/mediagoblin/media_types/video/processing.py
+++ b/mediagoblin/media_types/video/processing.py
@@ -15,25 +15,21 @@
# along with this program. If not, see .
import tempfile
-import pkg_resources
-import os
import logging
+import os
from celery.task import Task
from celery import registry
from mediagoblin.db.util import ObjectId
from mediagoblin import mg_globals as mgg
-from mediagoblin.util import lazy_pass_to_ugettext as _
-from mediagoblin.process_media.errors import BaseProcessingFail, BadMediaFail
+from mediagoblin.process_media import BaseProcessingFail
from mediagoblin.process_media import mark_entry_failed
from . import transcoders
THUMB_SIZE = 180, 180
MEDIUM_SIZE = 640, 640
-loop = None # Is this even used?
-
logger = logging.getLogger(__name__)
logging.basicConfig()
logger.setLevel(logging.DEBUG)
@@ -59,7 +55,11 @@ def process_video(entry):
'source')
medium_filepath = create_pub_filepath(
- entry, '640p.webm')
+ entry,
+ '{original}-640p.webm'.format(
+ original=os.path.splitext(
+ queued_filepath[-1])[0] # Select the
+ ))
thumbnail_filepath = create_pub_filepath(
entry, 'thumbnail.jpg')
@@ -163,38 +163,3 @@ class ProcessMedia(Task):
process_media = registry.tasks[ProcessMedia.name]
-
-
-def mark_entry_failed(entry_id, exc):
- """
- Mark a media entry as having failed in its conversion.
-
- Uses the exception that was raised to mark more information. If the
- exception is a derivative of BaseProcessingFail then we can store extra
- information that can be useful for users telling them why their media failed
- to process.
-
- Args:
- - entry_id: The id of the media entry
-
- """
- # Was this a BaseProcessingFail? In other words, was this a
- # type of error that we know how to handle?
- if isinstance(exc, BaseProcessingFail):
- # Looks like yes, so record information about that failure and any
- # metadata the user might have supplied.
- mgg.database['media_entries'].update(
- {'_id': entry_id},
- {'$set': {u'state': u'failed',
- u'fail_error': exc.exception_path,
- u'fail_metadata': exc.metadata}})
- else:
- # Looks like no, so just mark it as failed and don't record a
- # failure_error (we'll assume it wasn't handled) and don't record
- # metadata (in fact overwrite it if somehow it had previous info
- # here)
- mgg.database['media_entries'].update(
- {'_id': entry_id},
- {'$set': {u'state': u'failed',
- u'fail_error': None,
- u'fail_metadata': {}}})
diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py
index f6a2eb21..8d80beda 100644
--- a/mediagoblin/media_types/video/transcoders.py
+++ b/mediagoblin/media_types/video/transcoders.py
@@ -56,7 +56,6 @@ try:
import pygst
pygst.require('0.10')
import gst
- from gst import pbutils
from gst.extend import discoverer
except:
raise Exception('gst/pygst 0.10 could not be found')
diff --git a/mediagoblin/process_media/__init__.py b/mediagoblin/process_media/__init__.py
index 2b9eed6e..96fe49fe 100644
--- a/mediagoblin/process_media/__init__.py
+++ b/mediagoblin/process_media/__init__.py
@@ -53,10 +53,13 @@ class ProcessMedia(Task):
# Try to process, and handle expected errors.
try:
+ __import__(entry['media_type'])
process_image(entry)
except BaseProcessingFail, exc:
mark_entry_failed(entry[u'_id'], exc)
return
+ except ImportError, exc:
+ mark_entry_failed(entry[u'_id'], exc)
entry['state'] = u'processed'
entry.save()
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html
index b4c4dcf3..bad22e7e 100644
--- a/mediagoblin/templates/mediagoblin/base.html
+++ b/mediagoblin/templates/mediagoblin/base.html
@@ -28,8 +28,15 @@
href="{{ request.staticdirect('/css/extlib/960_16_col.css') }}"/>
+
+
+
+
{% block mediagoblin_head %}
{% endblock mediagoblin_head %}
diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html
index bff9889a..5b8ec789 100644
--- a/mediagoblin/templates/mediagoblin/media_displays/video.html
+++ b/mediagoblin/templates/mediagoblin/media_displays/video.html
@@ -1,11 +1,17 @@
{% extends 'mediagoblin/user_pages/media.html' %}
{% block mediagoblin_media %}
-
-
-
+
{% trans %}Actions{% endtrans %}
@@ -151,7 +151,7 @@ {% endif %} {% if app_config['allow_attachments'] - and (media['uploader'] == request.user['_id'] + and (media['uploader'] == request.user._id or request.user['is_admin']) %}
{% trans %}Here's a spot to tell others about yourself.{% endtrans %} @@ -113,7 +113,7 @@ {% else %}
{% trans -%} diff --git a/mediagoblin/tests/test_auth.py b/mediagoblin/tests/test_auth.py index 40961eca..153c6e53 100644 --- a/mediagoblin/tests/test_auth.py +++ b/mediagoblin/tests/test_auth.py @@ -168,7 +168,7 @@ def test_register_views(test_app): ## Make sure user is logged in request = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html']['request'] - assert request.session['user_id'] == unicode(new_user['_id']) + assert request.session['user_id'] == unicode(new_user._id) ## Make sure we get email confirmation, and try verifying assert len(mail.EMAIL_TEST_INBOX) == 1 @@ -185,7 +185,7 @@ def test_register_views(test_app): ### user should have these same parameters assert parsed_get_params['userid'] == [ - unicode(new_user['_id'])] + unicode(new_user._id)] assert parsed_get_params['token'] == [ new_user['verification_key']] @@ -193,7 +193,7 @@ def test_register_views(test_app): template.clear_test_template_context() response = test_app.get( "/auth/verify_email/?userid=%s&token=total_bs" % unicode( - new_user['_id'])) + new_user._id)) response.follow() context = template.TEMPLATE_TEST_CONTEXT[ 'mediagoblin/user_pages/user.html'] @@ -269,7 +269,7 @@ def test_register_views(test_app): # user should have matching parameters new_user = mg_globals.database.User.find_one({'username': 'happygirl'}) - assert parsed_get_params['userid'] == [unicode(new_user['_id'])] + assert parsed_get_params['userid'] == [unicode(new_user._id)] assert parsed_get_params['token'] == [new_user['fp_verification_key']] ### The forgotten password token should be set to expire in ~ 10 days @@ -280,7 +280,7 @@ def test_register_views(test_app): template.clear_test_template_context() response = test_app.get( "/auth/forgot_password/verify/?userid=%s&token=total_bs" % unicode( - new_user['_id']), status=400) + new_user._id), status=400) assert response.status == '400 Bad Request' ## Try using an expired token to change password, shouldn't work @@ -412,7 +412,7 @@ def test_authentication_views(test_app): # Make sure user is in the session context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/root.html'] session = context['request'].session - assert session['user_id'] == unicode(test_user['_id']) + assert session['user_id'] == unicode(test_user._id) # Successful logout # ----------------- diff --git a/mediagoblin/tests/test_submission.py b/mediagoblin/tests/test_submission.py index 1c657e6c..dec7118b 100644 --- a/mediagoblin/tests/test_submission.py +++ b/mediagoblin/tests/test_submission.py @@ -177,7 +177,7 @@ class TestSubmission: request.urlgen('mediagoblin.user_pages.media_confirm_delete', # No work: user=media.uploader().username, user=self.test_user['username'], - media=media['_id']), + media=media._id), # no value means no confirm {}) @@ -197,7 +197,7 @@ class TestSubmission: request.urlgen('mediagoblin.user_pages.media_confirm_delete', # No work: user=media.uploader().username, user=self.test_user['username'], - media=media['_id']), + media=media._id), {'confirm': 'y'}) response.follow() @@ -208,7 +208,7 @@ class TestSubmission: # Does media entry still exist? assert_false( request.db.MediaEntry.find( - {'_id': media['_id']}).count()) + {'_id': media._id}).count()) def test_malicious_uploads(self): # Test non-suppoerted file with non-supported extension diff --git a/mediagoblin/tools/pagination.py b/mediagoblin/tools/pagination.py index bc20ec90..5ebc3c5a 100644 --- a/mediagoblin/tools/pagination.py +++ b/mediagoblin/tools/pagination.py @@ -53,7 +53,7 @@ class Pagination(object): cursor = copy.copy(self.cursor) for (doc, increment) in izip(cursor, count(0)): - if doc['_id'] == jump_to_id: + if doc._id == jump_to_id: self.page = 1 + int(floor(increment / self.per_page)) self.active_id = jump_to_id diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py index 2090d6fd..82865bb4 100644 --- a/mediagoblin/user_pages/views.py +++ b/mediagoblin/user_pages/views.py @@ -45,7 +45,7 @@ def user_home(request, page): {'user': user}) cursor = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'processed'}).sort('created', DESCENDING) pagination = Pagination(page, cursor) @@ -78,7 +78,7 @@ def user_gallery(request, page): return render_404(request) cursor = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'processed'}).sort('created', DESCENDING) pagination = Pagination(page, cursor) @@ -135,8 +135,8 @@ def media_post_comment(request, media): assert request.method == 'POST' comment = request.db.MediaComment() - comment['media_entry'] = media['_id'] - comment['author'] = request.user['_id'] + comment['media_entry'] = media._id + comment['author'] = request.user._id comment['content'] = unicode(request.POST['comment_content']) comment['content_html'] = cleaned_markdown_conversion(comment['content']) @@ -179,7 +179,7 @@ def media_confirm_delete(request, media): location=media.url_for_self(request.urlgen)) if ((request.user[u'is_admin'] and - request.user[u'_id'] != media.uploader()[u'_id'])): + request.user._id != media.uploader()._id)): messages.add_message( request, messages.WARNING, _("You are about to delete another user's media. " @@ -207,7 +207,7 @@ def atom_feed(request): return render_404(request) cursor = request.db.MediaEntry.find({ - 'uploader': user['_id'], + 'uploader': user._id, 'state': 'processed'}) \ .sort('created', DESCENDING) \ .limit(ATOM_DEFAULT_NR_OF_UPDATED_ITEMS) @@ -251,7 +251,7 @@ def processing_panel(request): # # Make sure we have permission to access this user's panel. Only # admins and this user herself should be able to do so. - if not (user[u'_id'] == request.user[u'_id'] + if not (user._id == request.user._id or request.user.is_admin): # No? Let's simply redirect to this user's homepage then. return redirect( @@ -260,12 +260,12 @@ def processing_panel(request): # Get media entries which are in-processing processing_entries = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'processing'}).sort('created', DESCENDING) # Get media entries which have failed to process failed_entries = request.db.MediaEntry.find( - {'uploader': user['_id'], + {'uploader': user._id, 'state': 'failed'}).sort('created', DESCENDING) # Render to response -- cgit v1.2.3 From 3618a9ac5112c657fd095a0f9cbd346921a4e800 Mon Sep 17 00:00:00 2001 From: Elrond
Date: Mon, 14 Nov 2011 17:11:37 +0100
Subject: Dot-Notation: x._id = ObjectId() doesn't seem to work properly
For whatever reason, this does not work as expected:
entry._id = ObjectId()
Need to go this way:
entry['_id'] = ObjectId()
---
mediagoblin/submit/views.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/submit/views.py b/mediagoblin/submit/views.py
index bd63bd18..139b1d1d 100644
--- a/mediagoblin/submit/views.py
+++ b/mediagoblin/submit/views.py
@@ -52,7 +52,7 @@ def submit_start(request):
# create entry and save in database
entry = request.db.MediaEntry()
- entry._id = ObjectId()
+ entry['_id'] = ObjectId()
entry['title'] = (
unicode(request.POST['title'])
or unicode(splitext(filename)[0]))
--
cgit v1.2.3
From 64fd0462bdd821d5777d9697e67d951838f87de0 Mon Sep 17 00:00:00 2001
From: Joar Wandborg
Date: Tue, 15 Nov 2011 22:43:05 +0100
Subject: Committing some futile attempts to make GStreamer transcode the audio
properly.
- Added CPU count detection
- Added videorate
- Added audiorate
---
mediagoblin/media_types/video/transcoders.py | 45 +++++++++++++++++++++++-----
1 file changed, 38 insertions(+), 7 deletions(-)
diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py
index 3a30aedf..de3701f6 100644
--- a/mediagoblin/media_types/video/transcoders.py
+++ b/mediagoblin/media_types/video/transcoders.py
@@ -29,6 +29,18 @@ _log = logging.getLogger(__name__)
logging.basicConfig()
_log.setLevel(logging.DEBUG)
+CPU_COUNT = 2
+try:
+ import multiprocessing
+ try:
+ CPU_COUNT = multiprocessing.cpu_count()
+ except NotImplementedError:
+ _log.warning('multiprocessing.cpu_count not implemented')
+ pass
+except ImportError:
+ _log.warning('Could not import multiprocessing, defaulting to 2 CPU cores')
+ pass
+
try:
import gtk
except:
@@ -627,10 +639,13 @@ class VideoTranscoder:
self.videoqueue = gst.element_factory_make('queue', 'videoqueue')
self.pipeline.add(self.videoqueue)
+ self.videorate = gst.element_factory_make('videorate', 'videorate')
+ self.pipeline.add(self.videorate)
+
self.ffmpegcolorspace = gst.element_factory_make(
'ffmpegcolorspace', 'ffmpegcolorspace')
self.pipeline.add(self.ffmpegcolorspace)
-
+
self.videoscale = gst.element_factory_make('ffvideoscale', 'videoscale')
#self.videoscale.set_property('method', 2) # I'm not sure this works
#self.videoscale.set_property('add-borders', 0)
@@ -648,11 +663,22 @@ class VideoTranscoder:
self.audioqueue = gst.element_factory_make('queue', 'audioqueue')
self.pipeline.add(self.audioqueue)
+ self.audiorate = gst.element_factory_make('audiorate', 'audiorate')
+ self.pipeline.add(self.audiorate)
+
self.audioconvert = gst.element_factory_make('audioconvert', 'audioconvert')
self.pipeline.add(self.audioconvert)
+ self.audiocapsfilter = gst.element_factory_make('capsfilter', 'audiocapsfilter')
+ audiocaps = ['audio/x-raw-float']
+ self.audiocapsfilter.set_property(
+ 'caps',
+ gst.caps_from_string(
+ ','.join(audiocaps)))
+ self.pipeline.add(self.audiocapsfilter)
+
self.vorbisenc = gst.element_factory_make('vorbisenc', 'vorbisenc')
- self.vorbisenc.set_property('quality', 0.7)
+ self.vorbisenc.set_property('quality', 1)
self.pipeline.add(self.vorbisenc)
# WebMmux & filesink
@@ -685,7 +711,8 @@ class VideoTranscoder:
self.filesrc.link(self.decoder)
# Link all the video elements in a link to webmux
- self.videoqueue.link(self.ffmpegcolorspace)
+ self.videoqueue.link(self.videorate)
+ self.videorate.link(self.ffmpegcolorspace)
self.ffmpegcolorspace.link(self.videoscale)
self.videoscale.link(self.capsfilter)
#self.capsfilter.link(self.xvimagesink)
@@ -695,8 +722,12 @@ class VideoTranscoder:
if self.data.is_audio:
# Link all the audio elements in a line to webmux
#self.audioconvert.link(self.alsasink)
- self.audioqueue.link(self.audioconvert)
- self.audioconvert.link(self.vorbisenc)
+ self.audioqueue.link(self.audiorate)
+ self.audiorate.link(self.audioconvert)
+ self.audioconvert.link(self.audiocapsfilter)
+ self.audiocapsfilter.link(self.vorbisenc)
+ #self.audiocapsfilter.link(self.level)
+ #self.level.link(self.vorbisenc)
self.vorbisenc.link(self.webmmux)
self.webmmux.link(self.progressreport)
@@ -729,7 +760,7 @@ class VideoTranscoder:
'''
Sets up the output format (width, height) for the video
'''
- caps = ['video/x-raw-yuv', 'pixel-aspect-ratio=1/1']
+ caps = ['video/x-raw-yuv', 'pixel-aspect-ratio=1/1', 'framerate=30/1']
if self.data.videoheight > self.data.videowidth:
# Whoa! We have ourselves a portrait video!
@@ -743,7 +774,7 @@ class VideoTranscoder:
self.capsfilter.set_property(
'caps',
gst.caps_from_string(
- ', '.join(caps)))
+ ','.join(caps)))
def _on_message(self, bus, message):
_log.debug((bus, message, message.type))
--
cgit v1.2.3
From 359781f075f22c6ea677e28756c8046b2f405e63 Mon Sep 17 00:00:00 2001
From: Joar Wandborg
Date: Wed, 16 Nov 2011 14:20:27 +0100
Subject: Fixed video transcoding
- Added audiorate with tolerance 80 million
- Removed deprecated thumbnailer
---
mediagoblin/media_types/video/transcoders.py | 213 +--------------------------
1 file changed, 1 insertion(+), 212 deletions(-)
diff --git a/mediagoblin/media_types/video/transcoders.py b/mediagoblin/media_types/video/transcoders.py
index de3701f6..f6a2eb21 100644
--- a/mediagoblin/media_types/video/transcoders.py
+++ b/mediagoblin/media_types/video/transcoders.py
@@ -340,218 +340,6 @@ class VideoThumbnailer:
self.loop.quit()
-class DeprecatedVideoThumbnailer:
- '''
- Creates a video thumbnail
-
- - Sets up discoverer & transcoding pipeline.
- Discoverer finds out information about the media file
- - Launches gobject.MainLoop, this triggers the discoverer to start running
- - Once the discoverer is done, it calls the __discovered callback function
- - The __discovered callback function launches the transcoding process
- - The _on_message callback is called from the transcoding process until it
- gets a message of type gst.MESSAGE_EOS, then it calls __stop which shuts
- down the gobject.MainLoop
- '''
-
- WADSWORTH_CONSTANT = 30 # percent
-
- def __init__(self, src, dst, **kwargs):
- _log.info('Initializing VideoThumbnailer...')
-
- self.loop = gobject.MainLoop()
-
- self.source_path = src
- self.destination_path = dst
-
- self.destination_dimensions = kwargs.get('dimensions') or (180, 180)
-
- if not type(self.destination_dimensions) == tuple:
- raise Exception('dimensions must be tuple: (width, height)')
-
- self._setup()
- self._run()
-
- def _setup(self):
- self._setup_pipeline()
- self._setup_discover()
-
- def _run(self):
- _log.info('Discovering...')
- self.discoverer.discover()
- _log.info('Done')
-
- _log.debug('Initializing MainLoop()')
- self.loop.run()
-
- def _setup_discover(self):
- self.discoverer = discoverer.Discoverer(self.source_path)
-
- # Connect self.__discovered to the 'discovered' event
- self.discoverer.connect('discovered', self.__discovered)
-
- def __discovered(self, data, is_media):
- '''
- Callback for media discoverer.
- '''
- if not is_media:
- self.__stop()
- raise Exception('Could not discover {0}'.format(self.source_path))
-
- _log.debug('__discovered, data: {0}'.format(data))
-
- self.data = data
-
- # Run any tasks that depend on the info from the discovery
- self._on_discovered()
-
- # Tell the transcoding pipeline to start running
- _log.info('Transcoding...')
-
- def _on_discovered(self):
- self.__setup_capsfilter()
-
- def _setup_pipeline(self):
- # Create a new pipeline
- self.pipeline = gst.Pipeline('VideoThumbnailerPipeline')
-
- # Create the elements in the pipeline
- self.filesrc = gst.element_factory_make('filesrc', 'filesrc')
- self.filesrc.set_property('location', self.source_path)
- self.pipeline.add(self.filesrc)
-
- self.decoder = gst.element_factory_make('decodebin2', 'decoder')
- self.decoder.connect('new-decoded-pad', self._on_dynamic_pad)
- self.pipeline.add(self.decoder)
-
- self.ffmpegcolorspace = gst.element_factory_make(
- 'ffmpegcolorspace', 'ffmpegcolorspace')
- self.pipeline.add(self.ffmpegcolorspace)
-
- self.videoscale = gst.element_factory_make('videoscale', 'videoscale')
- self.videoscale.set_property('method', 'bilinear')
- self.pipeline.add(self.videoscale)
-
- self.capsfilter = gst.element_factory_make('capsfilter', 'capsfilter')
- self.pipeline.add(self.capsfilter)
-
- self.jpegenc = gst.element_factory_make('jpegenc', 'jpegenc')
- self.pipeline.add(self.jpegenc)
-
- #self.filesink = gst.element_factory_make('filesink', 'filesink')
- #self.filesink.set_property('location', self.destination_path)
- #self.pipeline.add(self.filesink)
-
- self.appsink = gst.element_factory_make('appsink', 'appsink')
- self.appsink.set_property('emit-signals', True)
- self.appsink.connect('new-preroll', self.__on_sink_preroll)
- self.pipeline.add(self.appsink)
-
- self.progressreport = gst.element_factory_make(
- 'progressreport', 'progressreport')
- self.progressreport.set_property('update-freq', 1)
- self.pipeline.add(self.progressreport)
-
- self.identity = gst.element_factory_make('identity', 'id')
- self.pipeline.add(self.identity)
-
- # Link all the elements together
- self.filesrc.link(self.decoder)
- self.ffmpegcolorspace.link(self.videoscale)
- self.videoscale.link(self.capsfilter)
- self.capsfilter.link(self.jpegenc)
- self.jpegenc.link(self.progressreport)
- self.progressreport.link(self.identity)
- #self.identity.link(self.filesink)
- self.identity.link(self.appsink)
-
- self.pipeline.set_state(gst.STATE_PAUSED)
-
- self._setup_bus()
-
- def __on_sink_preroll(self, sink):
- _log.debug('SINK PREROLL!!!!')
-
- def _on_dynamic_pad(self, dbin, pad, islast):
- '''
- Callback called when ``decodebin2`` has a pad that we can connect to
- '''
- # Intersect the capabilities of the video sink and the pad src
- # Then check if they have no common capabilities.
- if not self.ffmpegcolorspace.get_pad_template('sink')\
- .get_caps().intersect(pad.get_caps()).is_empty():
- # It IS a video src pad.
- pad.link(self.ffmpegcolorspace.get_pad('sink'))
- gst.DEBUG_BIN_TO_DOT_FILE(
- self.pipeline,
- gst.DEBUG_GRAPH_SHOW_ALL,
- 'ss')
-
- def _setup_bus(self):
- self.bus = self.pipeline.get_bus()
- self.bus.add_signal_watch()
- self.bus.connect('message', self._on_message)
-
- def __setup_capsfilter(self):
- caps = ['video/x-raw-rgb', 'pixel-aspect-ratio=1/1']
-
- if self.data.videoheight > self.data.videowidth:
- # Whoa! We have ourselves a portrait video!
- caps.append('height={0}'.format(
- self.destination_dimensions[1]))
- else:
- # It's a landscape, phew, how normal.
- caps.append('width={0}'.format(
- self.destination_dimensions[0]))
-
- self.capsfilter.set_property(
- 'caps',
- gst.caps_from_string(
- ', '.join(caps)))
-
- def __find_wadsworth(self):
- if self.decoder.seek_simple(
- gst.FORMAT_PERCENT,
- gst.SEEK_FLAG_NONE,
- 0 * 10000):
- _log.info('Found wadsworth')
- #pdb.set_trace()
- #self.pipeline.set_state(gst.STATE_PLAYING)
- self.__get_buffer()
- self.__stop()
- else:
- pdb.set_trace()
-
- def __get_buffer(self):
- buffer = self.appsink.emit('pull-preroll')
- open(self.destination_path, 'wb').write(buffer)
-
- def _on_message(self, bus, message):
- t = message.type
-
- _log.debug((
- t == gst.MESSAGE_ASYNC_DONE,
- bus,
- message))
-
- if t == gst.MESSAGE_EOS:
- self.__stop()
- _log.info('Got EOS')
- elif t == gst.MESSAGE_ASYNC_DONE:
- #pdb.set_trace()
- self.__find_wadsworth()
- elif t == gst.MESSAGE_ERROR:
- _log.error((bus, message))
- self.__stop()
-
- def __stop(self):
- _log.debug(self.loop)
-
- self.pipeline.set_state(gst.STATE_NULL)
-
- gobject.idle_add(self.loop.quit)
-
-
class VideoTranscoder:
'''
Video transcoder
@@ -664,6 +452,7 @@ class VideoTranscoder:
self.pipeline.add(self.audioqueue)
self.audiorate = gst.element_factory_make('audiorate', 'audiorate')
+ self.audiorate.set_property('tolerance', 80000000)
self.pipeline.add(self.audiorate)
self.audioconvert = gst.element_factory_make('audioconvert', 'audioconvert')
--
cgit v1.2.3
From 76c6c806caec7af20a3fe11c04bb783baacc3934 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Wed, 16 Nov 2011 17:53:46 -0600
Subject: Accidentally had user['profile'] where it shoulda been user['bio']
---
mediagoblin/templates/mediagoblin/user_pages/user.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/templates/mediagoblin/user_pages/user.html b/mediagoblin/templates/mediagoblin/user_pages/user.html
index c5beeaaa..6d938262 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/user.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/user.html
@@ -78,7 +78,7 @@
{%- trans username=user.username %}{{ username }}'s profile{% endtrans -%}
- {% if not user['url'] and not user['profile'] %}
+ {% if not user['url'] and not user['bio'] %}
{% if request.user['_id'] == user['_id'] %}
-
+
{% if next %}
-
{% endif %}
diff --git a/mediagoblin/templates/mediagoblin/auth/register.html b/mediagoblin/templates/mediagoblin/auth/register.html
index 25b68058..a0d0a277 100644
--- a/mediagoblin/templates/mediagoblin/auth/register.html
+++ b/mediagoblin/templates/mediagoblin/auth/register.html
@@ -29,7 +29,7 @@
{{ csrf_token }}
+ class="button_form" />
-- cgit v1.2.3 From ccca0fbfc3667900d0a5ad3687c27f4fd72db061 Mon Sep 17 00:00:00 2001 From: Christopher Allan Webber
Date: Thu, 17 Nov 2011 08:28:23 -0600
Subject: Beginnings of sqlalchemy models
---
mediagoblin/db/sql.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 mediagoblin/db/sql.py
diff --git a/mediagoblin/db/sql.py b/mediagoblin/db/sql.py
new file mode 100644
index 00000000..31ebfbf4
--- /dev/null
+++ b/mediagoblin/db/sql.py
@@ -0,0 +1,95 @@
+import datetime
+
+from sqlalchemy.ext.declarative import declarative_base
+from sqlalchemy import (
+ Column, Integer, Unicode, UnicodeText, DateTime, Boolean, ForeignKey,
+ UniqueConstraint)
+
+
+Base = declarative_base()
+
+
+class User(Base):
+ __tablename__ = "users"
+
+ id = Column(Integer, primary_key=True)
+ username = Column(Unicode, nullable=False, unique=True)
+ email = Column(Unicode, nullable=False)
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ pw_hash = Column(Unicode, nullable=False)
+ email_verified = Column(Boolean)
+ status = Column(Unicode, default="needs_email_verification", nullable=False)
+ verification_key = Column(Unicode)
+ is_admin = Column(Boolean, default=False, nullable=False)
+ url = Column(Unicode)
+ bio = Column(UnicodeText) # ??
+ bio_html = Column(UnicodeText) # ??
+ fp_verification_key = Column(Unicode)
+ fp_verification_expire = Column(DateTime)
+
+ ## TODO
+ # plugin data would be in a separate model
+
+
+class MediaEntry(Base):
+ __tablename__ = "media_entries"
+
+ id = Column(Integer, primary_key=True)
+ uploader = Column(Integer, ForeignKey('users.id'), nullable=False)
+ slug = Column(Unicode, nullable=False)
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ description = Column(UnicodeText) # ??
+ description_html = Column(UnicodeText) # ??
+ media_type = Column(Unicode, nullable=False)
+
+ fail_error = Column(Unicode)
+ fail_metadata = Column(UnicodeText)
+
+ queued_media_file = Column(Unicode)
+
+ queued_task_id = Column(Unicode)
+
+ __table_args__ = (
+ UniqueConstraint('uploader', 'slug'),
+ {})
+
+ ## TODO
+ # media_files
+ # media_data
+ # attachment_files
+ # fail_error
+
+
+class Tag(Base):
+ __tablename__ = "tags"
+
+ id = Column(Integer, primary_key=True)
+ slug = Column(Unicode, nullable=False, unique=True)
+
+
+class MediaTag(Base):
+ __tablename__ = "media_tags"
+
+ id = Column(Integer, primary_key=True)
+ tag = Column(Integer, ForeignKey('tags.id'), nullable=False)
+ name = Column(Unicode)
+ media_entry = Column(
+ Integer, ForeignKey('media_entries.id'),
+ nullable=False)
+ # created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+
+ __table_args__ = (
+ UniqueConstraint('tag', 'media_entry'),
+ {})
+
+
+class MediaComment(Base):
+ __tablename__ = "media_comments"
+
+ id = Column(Integer, primary_key=True)
+ media_entry = Column(
+ Integer, ForeignKey('media_entries.id'), nullable=False)
+ author = Column(Integer, ForeignKey('users.id'), nullable=False)
+ created = Column(DateTime, nullable=False, default=datetime.datetime.now)
+ content = Column(UnicodeText, nullable=False)
+ content_html = Column(UnicodeText)
--
cgit v1.2.3
From 6950c6c77c2daf4a47810e05a7c3f64f8995059d Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 19 Nov 2011 08:31:37 -0600
Subject: Adding app_config and global_config to the template environment
---
mediagoblin/tools/template.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py
index 905a36df..a0eaabe7 100644
--- a/mediagoblin/tools/template.py
+++ b/mediagoblin/tools/template.py
@@ -55,6 +55,8 @@ def get_jinja_env(template_loader, locale):
template_env.globals['fetch_messages'] = messages.fetch_messages
template_env.globals['gridify_list'] = gridify_list
template_env.globals['gridify_cursor'] = gridify_cursor
+ template_env.globals['app_config'] = mg_globals.app_config
+ template_env.globals['global_config'] = mg_globals.global_config
if exists(locale):
SETUP_JINJA_ENVS[locale] = template_env
--
cgit v1.2.3
From 53bc39755bf22fe8eebf06b051018eba111a64e7 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 19 Nov 2011 08:33:29 -0600
Subject: Add app_config and global_config to the template environment
---
mediagoblin/tools/template.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/mediagoblin/tools/template.py b/mediagoblin/tools/template.py
index a0eaabe7..0986761b 100644
--- a/mediagoblin/tools/template.py
+++ b/mediagoblin/tools/template.py
@@ -52,6 +52,7 @@ def get_jinja_env(template_loader, locale):
# All templates will know how to ...
# ... fetch all waiting messages and remove them from the queue
# ... construct a grid of thumbnails or other media
+ # ... have access to the global and app config
template_env.globals['fetch_messages'] = messages.fetch_messages
template_env.globals['gridify_list'] = gridify_list
template_env.globals['gridify_cursor'] = gridify_cursor
--
cgit v1.2.3
From 3c0411f51f43ade8c7d47df4f3843fd79d4709b5 Mon Sep 17 00:00:00 2001
From: "Pablo J. Urbano Santos"
Date: Sat, 19 Nov 2011 17:07:41 +0100
Subject: Allow instance owners to customize html titles of page: Added
html_title config option. Made base.html template use html_title option
as page title.
---
mediagoblin/config_spec.ini | 3 +++
mediagoblin/templates/mediagoblin/base.html | 2 +-
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index 900957ce..b804358c 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -1,4 +1,7 @@
[mediagoblin]
+# HTML title of the pages
+html_title = string(default="GNU MediaGoblin")
+
# database stuff
db_host = string()
db_name = string(default="mediagoblin")
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html
index 925386e5..0d6b9e40 100644
--- a/mediagoblin/templates/mediagoblin/base.html
+++ b/mediagoblin/templates/mediagoblin/base.html
@@ -19,7 +19,7 @@
- {% block title %}{% trans %}GNU MediaGoblin{% endtrans %}{% endblock title %}
+ {{ app_config['html_title'] }}
Date: Sat, 19 Nov 2011 19:11:42 +0100
Subject: Added parameter ascending to MediaEntry::get_comments, if true,
comments will be ordered ascending, otherwise descending
---
mediagoblin/db/models.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/db/models.py b/mediagoblin/db/models.py
index 1c1bc2fd..f13a4457 100644
--- a/mediagoblin/db/models.py
+++ b/mediagoblin/db/models.py
@@ -217,9 +217,14 @@ class MediaEntry(Document):
'created': datetime.datetime.utcnow,
'state': u'unprocessed'}
- def get_comments(self):
+ def get_comments(self, ascending=False):
+ if ascending:
+ order = ASCENDING
+ else:
+ order = DESCENDING
+
return self.db.MediaComment.find({
- 'media_entry': self._id}).sort('created', DESCENDING)
+ 'media_entry': self._id}).sort('created', order)
def get_display_media(self, media_map,
fetch_order=common.DISPLAY_IMAGE_FETCHING_ORDER):
--
cgit v1.2.3
From 1a3138addd43d410b03cdd1816e0a62bd217de30 Mon Sep 17 00:00:00 2001
From: "Pablo J. Urbano Santos"
Date: Sat, 19 Nov 2011 19:15:41 +0100
Subject: media_home: order comments by ascending date.
---
mediagoblin/user_pages/views.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py
index 82865bb4..98a21bb4 100644
--- a/mediagoblin/user_pages/views.py
+++ b/mediagoblin/user_pages/views.py
@@ -106,11 +106,11 @@ def media_home(request, media, page, **kwargs):
"""
if ObjectId(request.matchdict.get('comment')):
pagination = Pagination(
- page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE,
+ page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE,
ObjectId(request.matchdict.get('comment')))
else:
pagination = Pagination(
- page, media.get_comments(), MEDIA_COMMENTS_PER_PAGE)
+ page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE)
comments = pagination()
--
cgit v1.2.3
From fc5695c538f2b6d230c0e431087e9c10e6deac6c Mon Sep 17 00:00:00 2001
From: Corey Farwell
Date: Sat, 19 Nov 2011 10:43:31 -0800
Subject: incorrect path in nginx config
---
docs/source/deploying.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/source/deploying.rst b/docs/source/deploying.rst
index c2ba0c47..b944a3d3 100644
--- a/docs/source/deploying.rst
+++ b/docs/source/deploying.rst
@@ -207,7 +207,7 @@ this ``nginx.conf`` file should be modeled on the following: ::
# Instance specific media:
location /mgoblin_media/ {
- alias /srv/mediagoblin.example.org/mediagoblin/mediagoblin/user_dev/media/public/;
+ alias /srv/mediagoblin.example.org/mediagoblin/user_dev/media/public/;
}
# Mounting MediaGoblin itself via fastcgi.
--
cgit v1.2.3
From b4b7b6a57a5ad9a5e52a5d3e05f9ad3d3e8b650a Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 19 Nov 2011 13:42:30 -0600
Subject: Added Corey Farwell to the list of contributors
---
AUTHORS | 1 +
1 file changed, 1 insertion(+)
diff --git a/AUTHORS b/AUTHORS
index c9fc5c8e..b0ef7154 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -13,6 +13,7 @@ Thank you!
* Alex Camelio
* Bernhard Keller
* Caleb Forbes Davis V
+* Corey Farwell
* Chris Moylan
* Christopher Allan Webber
* Daniel Neel
--
cgit v1.2.3
From 7c378f2cd5324a05e709cbada5eb5668ce3a3469 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 19 Nov 2011 14:01:38 -0600
Subject: Allow user to set whether comments are ascending or descending
---
mediagoblin/config_spec.ini | 3 +++
mediagoblin/user_pages/views.py | 8 ++++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/mediagoblin/config_spec.ini b/mediagoblin/config_spec.ini
index 900957ce..4d412346 100644
--- a/mediagoblin/config_spec.ini
+++ b/mediagoblin/config_spec.ini
@@ -27,6 +27,9 @@ allow_registration = boolean(default=True)
tags_delimiter = string(default=",")
tags_max_length = integer(default=50)
+# Whether comments are ascending or descending
+comments_ascending = boolean(default=True)
+
# By default not set, but you might want something like:
# "%(here)s/user_dev/templates/"
local_templates = string()
diff --git a/mediagoblin/user_pages/views.py b/mediagoblin/user_pages/views.py
index 98a21bb4..25fd2ebb 100644
--- a/mediagoblin/user_pages/views.py
+++ b/mediagoblin/user_pages/views.py
@@ -106,11 +106,15 @@ def media_home(request, media, page, **kwargs):
"""
if ObjectId(request.matchdict.get('comment')):
pagination = Pagination(
- page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE,
+ page, media.get_comments(
+ mg_globals.app_config['comments_ascending']),
+ MEDIA_COMMENTS_PER_PAGE,
ObjectId(request.matchdict.get('comment')))
else:
pagination = Pagination(
- page, media.get_comments(True), MEDIA_COMMENTS_PER_PAGE)
+ page, media.get_comments(
+ mg_globals.app_config['comments_ascending']),
+ MEDIA_COMMENTS_PER_PAGE)
comments = pagination()
--
cgit v1.2.3
From 1bc231c766c41f61aee6d91c631bd972426b277b Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 19 Nov 2011 14:03:01 -0600
Subject: Added Pablo Santos to the AUTHORS file
---
AUTHORS | 1 +
1 file changed, 1 insertion(+)
diff --git a/AUTHORS b/AUTHORS
index b0ef7154..76e16b86 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -28,6 +28,7 @@ Thank you!
* Nathan Yergler
* Odin Hørthe Omdal
* Osama Khalid
+* Pablo J. Urbano Santos
* Rasmus Larsson
* Sam Kleinman
* Sebastian Spaeth
--
cgit v1.2.3
From 7880168526032bc2ddce96257d8f62a01e562832 Mon Sep 17 00:00:00 2001
From: Christopher Allan Webber
Date: Sat, 19 Nov 2011 14:06:48 -0600
Subject: Added back the title block
---
mediagoblin/templates/mediagoblin/base.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mediagoblin/templates/mediagoblin/base.html b/mediagoblin/templates/mediagoblin/base.html
index 0d6b9e40..64fafb73 100644
--- a/mediagoblin/templates/mediagoblin/base.html
+++ b/mediagoblin/templates/mediagoblin/base.html
@@ -19,7 +19,7 @@
- {{ app_config['html_title'] }}
+ {% block title %}{{ app_config['html_title'] }}{% endblock %}
Date: Sat, 19 Nov 2011 23:46:42 +0100
Subject: Change form structure and add relevant CSS rules
---
mediagoblin/static/css/base.css | 6 +++++-
mediagoblin/templates/mediagoblin/utils/wtforms.html | 12 +++++-------
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/mediagoblin/static/css/base.css b/mediagoblin/static/css/base.css
index afd10207..a7b659c3 100644
--- a/mediagoblin/static/css/base.css
+++ b/mediagoblin/static/css/base.css
@@ -212,7 +212,11 @@ text-align: center;
width: 100%;
}
-.form_field_label,.form_field_input {
+.form_field_input {
+ margin-bottom: 10px;
+}
+
+.form_field_label {
margin-bottom: 4px;
}
diff --git a/mediagoblin/templates/mediagoblin/utils/wtforms.html b/mediagoblin/templates/mediagoblin/utils/wtforms.html
index 6a86fd24..39dca7cc 100644
--- a/mediagoblin/templates/mediagoblin/utils/wtforms.html
+++ b/mediagoblin/templates/mediagoblin/utils/wtforms.html
@@ -18,18 +18,16 @@
{# Generically render a field #}
{% macro render_field_div(field) %}
-
- {{ _(field.label.text) }}
- {{ field }}
+
+
+ {{ field }}
{%- if field.errors -%}
{% for error in field.errors %}
-
- {{ error }}
-
+ {{ _(field.description) }}
+
{%- endmacro %}
--
cgit v1.2.3
From 2d62e9efd210becd30982e65e06a6ef97029b391 Mon Sep 17 00:00:00 2001
From: lora
Date: Sat, 19 Nov 2011 17:00:25 -0600
Subject: issue 582: use media.slug instead of media.id
---
mediagoblin/decorators.py | 3 +--
mediagoblin/templates/mediagoblin/user_pages/media.html | 4 ++--
.../templates/mediagoblin/user_pages/media_confirm_delete.html | 2 +-
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/mediagoblin/decorators.py b/mediagoblin/decorators.py
index 19e22bca..38f52ced 100644
--- a/mediagoblin/decorators.py
+++ b/mediagoblin/decorators.py
@@ -58,7 +58,7 @@ def user_may_delete_media(controller):
"""
def wrapper(request, *args, **kwargs):
uploader = request.db.MediaEntry.find_one(
- {'_id': ObjectId(request.matchdict['media'])}).uploader()
+ {'slug': request.matchdict['media'] }).uploader()
if not (request.user['is_admin'] or
request.user['_id'] == uploader['_id']):
return exc.HTTPForbidden()
@@ -95,7 +95,6 @@ def get_user_media_entry(controller):
if not user:
return render_404(request)
-
media = request.db.MediaEntry.find_one(
{'slug': request.matchdict['media'],
'state': 'processed',
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media.html b/mediagoblin/templates/mediagoblin/user_pages/media.html
index 433f74dc..5e1b73de 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media.html
@@ -124,7 +124,7 @@
diff --git a/mediagoblin/templates/mediagoblin/auth/login.html b/mediagoblin/templates/mediagoblin/auth/login.html
index 756f67c0..c3807e5f 100644
--- a/mediagoblin/templates/mediagoblin/auth/login.html
+++ b/mediagoblin/templates/mediagoblin/auth/login.html
@@ -42,10 +42,10 @@
{% trans %}Forgot your password?{% endtrans %}
{{ error }}
{% endfor %} {%- endif %} {% if field.description -%} -{{ _(field.description) }}
{%- endif %}{% set edit_url = request.urlgen('mediagoblin.edit.edit_media', user= media.uploader().username, - media= media._id) %} + media= media.slug) %}
@@ -133,7 +133,7 @@
{% set delete_url = request.urlgen('mediagoblin.user_pages.media_confirm_delete', user= media.uploader().username, - media= media._id) %} + media= media.slug) %}
diff --git a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html
index dd6923a9..f62082bd 100644
--- a/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html
+++ b/mediagoblin/templates/mediagoblin/user_pages/media_confirm_delete.html
@@ -23,7 +23,7 @@
{% trans %}Don't have one yet? It's easy!{% endtrans %}
{% trans register_url=request.urlgen('mediagoblin.auth.register') -%} - Create an account at this site + Create an account at this site or - Set up MediaGoblin on your own server + Set up MediaGoblin on your own server {%- endtrans %} {% endif %}