From 1f255101f54579760f2238d70dd3aa0b3cd4ba92 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Sat, 24 Sep 2011 02:21:46 +0200 Subject: [PATCH] Multimedia support - Refractored video processing. --- mediagoblin/media_types/__init__.py | 1 + .../video/presets/web-advanced.json | 505 +++++++++ .../media_types/video/presets/web-flv.png | Bin 0 -> 2234 bytes .../media_types/video/presets/web-webm.svg | 259 +++++ mediagoblin/media_types/video/presets/web.svg | 982 ++++++++++++++++++ mediagoblin/media_types/video/processing.py | 186 ++-- .../static/images/media_thumbs/video.jpg | Bin 0 -> 7278 bytes .../mediagoblin/media_displays/video.html | 8 + 8 files changed, 1875 insertions(+), 66 deletions(-) create mode 100644 mediagoblin/media_types/video/presets/web-advanced.json create mode 100644 mediagoblin/media_types/video/presets/web-flv.png create mode 100644 mediagoblin/media_types/video/presets/web-webm.svg create mode 100644 mediagoblin/media_types/video/presets/web.svg create mode 100644 mediagoblin/static/images/media_thumbs/video.jpg diff --git a/mediagoblin/media_types/__init__.py b/mediagoblin/media_types/__init__.py index 67dab418..6a368cda 100644 --- a/mediagoblin/media_types/__init__.py +++ b/mediagoblin/media_types/__init__.py @@ -51,6 +51,7 @@ def get_media_managers(): 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: diff --git a/mediagoblin/media_types/video/presets/web-advanced.json b/mediagoblin/media_types/video/presets/web-advanced.json new file mode 100644 index 00000000..ce1d22ff --- /dev/null +++ b/mediagoblin/media_types/video/presets/web-advanced.json @@ -0,0 +1,505 @@ +{ + "make": "Generic", + "model": "Web Browser (Advanced)", + "description": "Media for World Wide Web", + "version": "0.1", + "author": { + "name": "Dionisio E Alonso", + "email": "dealonso@gmail.com" + }, + "icon": "file://web.svg", + "default": "WebM 480p", + "presets": [ + { + "name": "H.264 720p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 720p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 720p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 960, 1280 + ], + "height": [ + 720, 720 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 576p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 576p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 576p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 768, 1024 + ], + "height": [ + 576, 576 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 480p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 480p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 480p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 640, 854 + ], + "height": [ + 480, 480 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + + { + "name": "H.264 360p", + "extension": "mp4", + "container": "qtmux", + "vcodec": { + "name": "x264enc", + "container": "qtmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "qtmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + }, + { + "name": "WebM 360p", + "extension": "webm", + "container": "webmmux", + "icon": "file://web-webm.svg", + "vcodec": { + "name": "vp8enc", + "container": "webmmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "quality=5.75 threads=%(threads)s speed=2" + ] + }, + "acodec": { + "name": "vorbisenc", + "container": "webmmux", + "width": [ + 8, 32 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "quality=0.3" + ] + } + }, + { + "name": "Flash Video 360p", + "extension": "flv", + "icon": "file://web-flv.png", + "container": "flvmux", + "vcodec": { + "name": "x264enc", + "container": "flvmux", + "width": [ + 480, 640 + ], + "height": [ + 360, 360 + ], + "rate": [ + 1, 30 + ], + "passes": [ + "pass=qual quantizer=23 subme=6 cabac=0 threads=0" + ] + }, + "acodec": { + "name": "faac", + "container": "flvmux", + "width": [ + 8, 24 + ], + "depth": [ + 8, 24 + ], + "rate": [ + 8000, 96000 + ], + "channels": [ + 1, 2 + ], + "passes": [ + "bitrate=131072 profile=LC" + ] + } + } + ] +} diff --git a/mediagoblin/media_types/video/presets/web-flv.png b/mediagoblin/media_types/video/presets/web-flv.png new file mode 100644 index 0000000000000000000000000000000000000000..b75699f494cc5aefbdfb6c80ec099e434fcfd4de GIT binary patch literal 2234 zcmV;r2u1gaP)|?_Tq&~sV3GZOKpw#papARLcoG3`VgTMQIvv; zAc&Q|Sn=92DpLC()wZ@&M4E<}5REbIRL5ZSWMsh1Hs@{|h$cc2Ip8CQfh$lu z0J4u{n>wJh6yxSzfYe!I$I$uu{2Hunq8N#80AI{Sq=rBaWTFir5K7zxgHr zHK3X67h?ehD3`55AviH0zBr>f*Ojup9g?}WEtoJKtPIKKI>0?rK3^{^V|T=Cp3M*& z#>$QtdI*8&0DP6DLTiYXh6mo?Eu8PS*qyEg(j2(5z{_>Q+gvIv;`q6njY_d2f|fkv zpsYo-v532u2q;y;;t@!5p&4{3?BtlBDvjcRoR&rn_+&C+G8#gy2KAU)t3{fmh)#WX z3cy!s-y>i^=p3HMRWcUhi119BYuEG}8Lk^8lL^Ua#08h_F8sbNC3V*(kY;-JWU^js=8NghX-|Dw!*XFJ*zQFS~WZSZLhu)7-X=YYyJa75nd` zbIHZo3@zwnLey-cMH5kWwd|=hh+ECCH9WYxjVI(`68*NTV_+I%J(8*IJyYHt48 zm)Z8#Ye@QiChO~&>?lIggj6&-7vj60w%AOP2wUMolIQz8SjyoNWDUm}ZY+4<`+c@v zdo_E%^DR0%b};UpD}*UU)TpCW1C+{BH>DI@C`ZtFYOf?9x%Sgs`(+0TuLY69H^o{a zO%iJJbG-Ax&(mGp!DM~I%BnRRprCi^FZ52HV%X~;QRD=@o6*Wvok}1%9EbGYoq@RIP?;H1hQ8`@5UL47r&W z(DtsnnXFUJ7RAQNXvCH`FLBj9cQfe^>{z|qVda_Uc>LoBIrqv6al3RULc*uGt<1u?a_7OUlT*Ua?8UVFMgWjprJaO=otgWt6pPR>2a95so ztZI~L4tSzAaiLVQR9Z=ZVzIr7q3*~SkJ++&7fW~DPSPJ_19?h*>i#eA*ONzR&?OxV zh+D0|zl#`h<0-7rQwbzUkw&Kxuo^4J1PG(ykfjgaLHFVXt9_*u!(NYt8?NI$Z`nhw z+2YKxV;ueAV?=Q+$TlwcfSfL;(n<@MHZ2pmfL&|oB%!@<5lbI=W4BqI~{KN z!~swdjc$iOJoXa~fAwsVa$QMGwZkHpEF7u1e9HQ206>Aiv z!%$+ zqtS7mx&##|qFQWIr>l%og22>>88M&{649j7i*O(|Yvc6|=5{Qy?}5(|#WBfn2td8v z;-%+*$De-vH1*aTMCLJx{943Y_*m%%v-^E^5R+LTp&Z2FB0ZjvP9`KWX8RSpx$7HW zW#OtTt?Qr^N-3WG=0o&1)@XDt@Faym&5)~e*PZOMMuh@r)`7~Vh50uwa^cQ5ap}$P z;Q9~m=XGybwBQA3&&_f8(Pds({uyzrQ=G4YB4{ajuIZ14#dBs5ZK7mu*~*+ZnFQBmvwl#)E>&eOP(GNGASNDCyJSU~azo~T|& zoWcZvQncshSUquqNA5kq*_9OLyh5X`PS6E5NPN|gy;8j>47p%3;ij{&$ zMZ|fEJp9w2vwY}&{{F`kG}~R$pkfrR-~)FHnM1Rb^{O(YpM{WM(~v-x%IcjCtu6DY zC}Oy_>i#=jm@h%gBE1=D%tts-DzAejn3Z&Advk9?08 zAAf?gr(fcgqsRE$@#Bn!eHzU+QB)^&j}lc1k!s77)|4zTBL<+FVF`j#Jo(VWq)Y%s z9My^Ib?WU-u7qNCsiKF#E1OuC3Nc8jxAa;?Y#o@@qIQc&S{7lNZ((1@h)bX>&(ouy zC!IN7cw3A!(x_~jg-UQNP${ac2cjs7*_c}-tM@Tg+FbqZHhZX-%}=B5aur;?KIcpm zz8tH5<_^eKWU$$%QOPUu%q--$f`EVgD6CLE*%lD0#=>)vKS%64@G1fnuNG&44#Au6 z_FkrgEPpQ^XbPVfd++aWes=P4{D*1OUtMK^sl;%9G%0|D*7M0YdsbyzhkyXJ>KEA6 z6hi-3!K?zjSeKgWa^~t}BzH{Zq+*~3br+;67x2_*kQ{*04Rm588}ng + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/mediagoblin/media_types/video/presets/web.svg b/mediagoblin/media_types/video/presets/web.svg new file mode 100644 index 00000000..c0c68244 --- /dev/null +++ b/mediagoblin/media_types/video/presets/web.svg @@ -0,0 +1,982 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Globe + + + Jakub Steiner + + + + + Tuomas Kuosmanen + + + + http://jimmac.musichall.cz + + + globe + international + web + www + internet + network + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mediagoblin/media_types/video/processing.py b/mediagoblin/media_types/video/processing.py index 94784836..4cae1fd8 100644 --- a/mediagoblin/media_types/video/processing.py +++ b/mediagoblin/media_types/video/processing.py @@ -16,6 +16,7 @@ import Image import tempfile +import pkg_resources from celery.task import Task from celery import registry @@ -25,10 +26,14 @@ from mediagoblin import mg_globals as mgg from mediagoblin.util import lazy_pass_to_ugettext as _ +import mediagoblin.media_types.video + import gobject +gobject.threads_init() import gst import arista +import logging from arista.transcoder import TranscoderOptions @@ -38,12 +43,17 @@ ARISTA_DEVICE_KEY = 'web' loop = None +logger = logging.getLogger(__name__) +logging.basicConfig() +logger.setLevel(logging.DEBUG) def process_video(entry): """ Code to process a video """ + global loop + loop = None info = {} workbench = mgg.workbench_manager.create_workbench() @@ -54,8 +64,11 @@ def process_video(entry): arista.init() - devices = arista.presets.get() - device = devices[ARISTA_DEVICE_KEY] + + web_advanced_preset = pkg_resources.resource_filename( + __name__, + 'presets/web-advanced.json') + device = arista.presets.load(web_advanced_preset) queue = arista.queue.TranscodeQueue() @@ -69,38 +82,127 @@ def process_video(entry): preset = device.presets[device.default] + logger.debug('preset: {0}'.format(preset)) + 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) + queue.connect("entry-start", _transcoding_start, info) + queue.connect("entry-pass-setup", _transcoding_pass_setup, info) + queue.connect("entry-error", _transcoding_error, info) + queue.connect("entry-complete", _transcoding_complete, info) info['loop'] = loop = gobject.MainLoop() + info['queued_filename'] = queued_filename + info['queued_filepath'] = queued_filepath + info['workbench'] = workbench + + logger.debug('info: {0}'.format(info)) loop.run() + + ''' + try: + #thumb = Image.open(mediagoblin.media_types.video.MEDIA_MANAGER['default_thumb']) + except IOError: + raise BadMediaFail() - # we have to re-read because unlike PIL, not everything reads - # things in string representation :) - queued_file = file(queued_filename, 'rb') + thumb.thumbnail(THUMB_SIZE, Image.ANTIALIAS) + # ensure color mode is compatible with jpg + if thumb.mode != "RGB": + thumb = thumb.convert("RGB") - with queued_file: - original_filepath = create_pub_filepath(entry, queued_filepath[-1]) + thumb_filepath = create_pub_filepath(entry, 'thumbnail.jpg') + thumb_file = mgg.public_store.get_file(thumb_filepath, 'w') - with mgg.public_store.get_file(original_filepath, 'wb') as original_file: - original_file.write(queued_file.read()) + with thumb_file: + thumb.save(thumb_file, "JPEG", quality=90) + ''' - mgg.queue_store.delete_file(queued_filepath) - entry['queued_media_file'] = [] - media_files_dict = entry.setdefault('media_files', {}) - media_files_dict['original'] = original_filepath +def __close_processing(queue, qentry, info, error=False): + ''' + Update MediaEntry, move files, handle errors + ''' + if not error: + qentry.transcoder.stop() + gobject.idle_add(info['loop'].quit) + info['loop'].quit() + + print('\n-> Saving video...\n') + + 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') + + # we have to re-read because unlike PIL, not everything reads + # things in string representation :) + queued_file = file(info['queued_filename'], 'rb') + + with queued_file: + original_filepath = create_pub_filepath(info['entry'], info['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(info['queued_filepath']) + info['entry']['queued_media_file'] = [] + media_files_dict = info['entry'].setdefault('media_files', {}) + media_files_dict['original'] = original_filepath + # media_files_dict['thumb'] = thumb_filepath + + info['entry']['state'] = u'processed' + info['entry'].save() + + else: + qentry.transcoder.stop() + gobject.idle_add(info['loop'].quit) + info['loop'].quit() + info['entry']['state'] = u'failed' + info['entry'].save() # clean up workbench - workbench.destroy_self() + info['workbench'].destroy_self() + + +def _transcoding_start(queue, qentry, info): + logger.info('-> Starting transcoding') + logger.debug(queue, qentry, info) + +def _transcoding_complete(*args): + __close_processing(*args) + print(args) + +def _transcoding_error(*args): + logger.info('-> Error') + __close_processing(*args, error=True) + logger.debug(*args) + +def _transcoding_pass_setup(queue, qentry, options): + logger.info('-> Pass setup') + logger.debug(queue, qentry, options) + + +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 def create_pub_filepath(entry, filename): @@ -161,9 +263,6 @@ class ProcessMedia(Task): 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. @@ -213,48 +312,3 @@ def mark_entry_failed(entry_id, exc): 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/static/images/media_thumbs/video.jpg b/mediagoblin/static/images/media_thumbs/video.jpg new file mode 100644 index 0000000000000000000000000000000000000000..841dc796fda777f8dcf72ed90ebe52c539c77f0a GIT binary patch literal 7278 zcmbVwcQ~BE*Y;x7h)xo{hgA|p@2jq|SgbCI5+w+N1VM-%!Ro!URt-^tNc6V4C3cBU z^xi`7%I|vL>;1kzzwdtLJTupvIrp4vW}frR%+2)80)R?O9ik4v!@~n;-adev8Gs6a z0RJEUy$NmsBm({e2@w$?5h)2787T=VDH%B>IoTbGJEWv{sqa!yQc+P;k&)BT(ooUf zmZ|=c;Qg~C0FvAqQr#iFb6flWh?_P5H3^^qP)C5r3BaeuBcR5+=>o6-0QdyA-roBA zKOiO~A^{TM$aliIT_@ZiP_n~%tasS|!ixKZXUHwlt|MFY1TdrH(6KViH z9sxcOpO~2NzZ?A1QFDk8(kL5vjL~w6BJyk6iNwIqgBSPd=($v2H#h(}!7U{<0X0Ao zaE)pQQUR3zPhmbvCglhEBqs7Xdg5e9-Y?nwkbO5Gp=D>Ev~h`+DdnF$WHn7cf3If{Dl0Zcn!^~Ffgx`%Z|img8z7hhF5F9X-ZGm zWi-n$OU)Kl>fO}E_}AoVocUYxhf)1TcyNraqfBVA)HzuYbU7%VOb| z6j1bJLS`X^r06-2N(t}(5^4eutAr$ddmPr!JzP9Qf|AhkVKnpevBgbPT#1 zrpxsx@3Zx-m+g%|r=;VL+}NdNf}QmHU{Gc1lLpykDB$dto6TiNUUNLs@T(4a85&dXH1f3cW(5%pCH+vqx>*TGcgXDoO*TeCI6F3G>!HAgAiaG)#eoT+1KG(ybG)M-V$7pNcFB5n@LmUEo?TV6jfQFc4CJP@rL zz}uJvKT1(f&PsR7j8sdXq0d%^o~2Ty#-cvp*FVUZzwXafSv02HMZK6YfAerRN!sg& zT+xz^?yvwe%^ELgifHrJF&CT^uppnU})dE5Ro8*J4b zxs;K;iv=$`=Nmmw6Tz|9BQM?mNJj2uOlAu=*c)NI!X^hJZj1NS2o2{Pzp+@sqHG8LwupT@u{$hquKV!CKQhKw> z)ElK^U9okY>I+HFFq(+;t?(J&WtPJ3ugOG0*__4doBL%I4=!&28{L7qsHEP#DD9lN zLRpA`{@I56x`kU&mcV_2$kkZ(`<<_$Si#YpphruLBZfx2fp+Bl%FhnS9tP&;>zD74niuyLi-%XfoSf7(n3ol$mtSG`)QWT8U6SL7 zNrlygw|-%-1k4f8 z;JRSrtL<=}DKA5qrDlORS}P+o{3w>M-sSg^aIvr4Kgt5nk4_F?Q@U5#J}U#Cb5kh; z0qU0G4SaNs4s-4L=jIyoW($gjqw1EJnS>_yDV}XV+A^PNtEZPL?{5G;W6Ozs&uIJ; zWIDACs=|M7z5=Y%7-32Yvb*A{s&(FySUSqfVdlSj!%F8SM!uoU4*vo zC<<%AbB^3sb3GD0P;TTm4^n=CE#UTfPpGS7yX4&=nGgh3!B<#L_+o)HShXsHJ7lKX zKLmMn#w7Mpa33=*K861b6`HJZvDh67y#d7h;b)cQpO2&A`t-GDmi;Qf0vmxucsv<1 zs+)0inq1~+G(3TVj0J)T9zL_yidFLWk z66Y8~=|}&A71)N)3lA2~x(D(48>*!}VL#K;Nun2`D#=^t7v?E)Je51Ed)ZPHk8Xm& z0(VEx6BqJyR0Pyc2#dGbH3b9q&wEP;GxP&|ElaBkv_<|U3)S=tUO2%GP*8tBKF-(t#(AVwEkTQxUvQ-ZQ<&Ub zR1|Mi6%@Zpq!j(5UMtt}(RvdR@Wfa}K2njuYyqyJ_>1YUBpAMn`K78)IiffG7@bAS zSJhp2y}>_!#4GPu(W-AT*|eHkQZfs})W4E@lbd7X*jN8}JUyW3E3StwnLLEOZC@y{ zw6Q4DF;^_v3!QA+_`=s2aK_Bio8Kj}eP!1?+Lq~@H`LBMir$vqAFR!>+r?c!ijud9 zGeFAPzzsx4g$;fWcSf3Y(T<*buq<=RZ!vHQ%VZ3di#kp8T@~6F)8%WFC{(BHBKQt> zxViKUoTqX=<6_5ogB;PFw)W46?X7zD6qeh%CHiy9aFhM5VojF3HX5M#xBI?1?36;w zgPvh8Vk}RZ?T@?aA&J7r6CF^eI;6b-j*YC1>3ajk&aB7R&PFRIx2gzDOok1iNjZ=5O-|mGJhQM0ZftIVN@Pth{I#ETbvza)% z&r=2lV~tZR@S=m#nQ<`?+!zbwJJIV1;#1%0wAIdiWbsm2adt?Epp#S)73;td?uhcS zTWoRkTM2?bjl=jK&zpfCcId_FqY;%;mliL12kl~W*;nCKHP0Z*zI3^LjMf8&P5 zu?EK{%fyX{2XcbZ0vFz%4c=xeiFGK?xu6H6iWdd*NKwt=_0{G9fZn&fLBX?Rl=hXX zLG{|CxP!4d^ziO zyopuL`{J&Z2rCyKRx^D9nTqwj0eYSvv*>t3NhwIf)yrzj>sihg;p6Uk%E{hd%Uu`2K`lJvzP8U>iq=oH*ev?j+}^j$DQE z^8>bvUMc9O(IWcc$VPbaFl@lw?iRps+EY8$>h;_;DM`!^V7>va^E~$x z0(#QheGL$>`c3jm0II?0kkT_=B4Ra8suE|If9Y&|Hbra~f=hxf&}g#0S8KZTHv!S? zPW*J!mWUWFNvRqm@VGBKaM4>?lPCUoLT6UoP8-tT(~2`wdnvt~%+lHWj(1cnLYHsP z$^3rPnL(;r4X{MHrbV^25qqy+@cdN|AC#C^3Cg4nFVpL}040YapI*;sd9)#cH3 zC@@kw?y``$0M9^wi8ibh+AY6y4HCcqUF0#d(mdP@GBI35=Tz0c9Z|di==Z)1QOT$%#?nttBRAzCUNa1h5@Q`*8Ka4_ z#{1VbLfe&I=$}FZl@X%r+GT8-{e-Wz-rpf;SAKXNV^S{?He%}Ck8 zJkVB!sZ2M&yZ5S^)@YPw$ybPW582ikK@jx=Xh@Um*OA|=jjbnFSPJH ztFNg1J|>lsIt-t9{|=&m*@<};`5_aLnB($Ao^PGe14 zZWG#)=>;!wGDMk{IaxWS%%=Oin9F``?`SY$7r4)yB(;0d=JjjO93ub=PbQ5nfAvjD zOxRzI_E(Gh5hr~kQR(0>Zwbete3TiiV8M1v>KnlU-{E0z*27@2XZeoaq#pHz9MAYc z#Oxp1dNInT(E)IKYD4K6QNe@dPlz}j)or*c0K~x$OmGMMre|}~MwFZAtyEy7uYVeu zd>i7CgLOJM{_a+052PiB&la20K|aoHzSZuB6uK6bZ%I|x(nu$~!JGds3N85M&4k@N zIkRA5X}R;lAZypDmP{Y9m@5j2;t5Wac?tIn{28C-^;Zo9IW!{}Rbj{#izj++SmIg* zpG4+cM8_BZ;a80VbHqX2cjs9*ha}bi^UchDCZwlI+T&gz89O~uTrXq(Bo)ISPL&)e z_|Cd1^hLHovQ=|2BTOPKMd9$wXW&inS_P%lD58JaJHT<=N?fq0IrR46LNgkJev?<@ zJ;f-8%;jpUKx{BNi}h6YmF4;mKXM?+)P7BR1f?v~@j0hUsN_3)3M-qjLk>$sMLFE} zmeus&AtO%X0)j!~cNzuiwOQZY0K7J{Q$UxFTqjV?V2GUufE zNFZg@RQs?D;#=?tw}y6%nQXM&zI9!ol@D9{Ndj5WHmfcJEdUBIp!*_-?-2H%@ zR#>S_>E>hA*-jA)JeF-=x8<@Dm9$EgyVR*MuwP5^e{tWv*y(EJ zz51v;*E`+mpX4>NG<^YFncBpo3*E5I35b7s+?(o|*A)B&B)&p?Qu872j~DOUbt58y z*T9+3FDv2WMZ5fu_^5)`BFn;&L&G7gmd8IY|Ac6)*_v2d54d2mU@Nnf1nso7+@+K~ zxf@iTIX%Yq-{>-oB_Aw3@C^);3g;56H*FTa7l1?XR_YAu z(F^j$1*FfxaAG+_AUUI;%g(^qx+_Go05+o~+Pm%*IXkaa{^)zH$o(!cUMI#^B?%-p zzneBNJ!WjcOfpileWiiPm9)3E?JQiJ^`|gVngRF#n8~&7H-H=LbW!vQL(b*7bnw?jxw{`yYayqA2Q$Mg?0+3R)Afr(WCaIcCy* ztOh1|&V>COhUrz9y0WdD%rx1QC~-jOQ5#l)6<;X-{&0aY>pcUx44O~EvqdeU6-fJr z_$2N(fXAFap~LGV75oEUT;*oGmX*%wVvua;gqSX>{w(H*MR`t+OETQ+`Lo>oiR=?dvc-aV`k63>^X62Bt!jyx)o`9cHry*`#6?% z%5bkCXQ<%qY(w-FE-wMT43VP9vGeR-qgejaJ1UM3cN!^lBf5^uQJ#iRW5IE`lk$|q zOm6wYpZ?k)y{0iQqkzK$iwloaXU;A4az#dai6h-Lf4UXl<(Vlw6bjRE9M*~nt+dHG z4(&I1VNb}TTT!ecN0)qeA(lOIL{jaQ!Es1kiU3+XgQ>i$SgA2AxE}=b2#bAoutff3 zw&4|8Ud@PqzKDDL^>n!}!9Lqz+M(YSQV%Vw-YS&r14TYxOPMyOlgWR3Ws9C_sB}4i z3o(@3{`b>&4E;6H63z1Srml!4K3au+oS%#I*S9tgl15zR)$Q5k%@FA~fG8v&D3LmS z>q6OSPzQu6X)NQX6bNe4<9B)`-)?6|5%ID|z>vUDC`8Q~r>hnkgyT+0g=zQ-CF89D zjWW1hMRw`~UH0?dUS|HdToNtbL6uhJg_mLe+{UH|Bz{n?NbCd5h5l96cG607&k~t3 z0ftTUROW-LjO2(A3*EpCK$#M{%=S~Go}q9mzF|$c485V>4(0`xJLKQJyW9m%Xbha4 zq!%oCs}+`DWCpcV5P%2TQXBalH5#8dE8PHAA6=-v>z+}8`|x6_iIOiOAAeApd!|+P z+%OU5Iy@-w@k_MDrs5GTn`2A4*UI(;OKPI#uW%l7y+1ZYHor^CH+{_DU7V{`VPkfxHRr)4|}T}A;|IK2Gz(04`1T+@Gw_b@zWx4 z2xJMtMp%;EEfS5qQ;#YS`SUJ{zn}E%_%E;^0+T-&+j5bfKFjyB>s=JkHNoP%KA;=gP-xOXG)$Zdg|8vA=!ST=kf>RqKB)C zXkW%bB&x>+4@DEbA0$BxS6R{mIzuJK$&w03NnT+Y?}$IPD7AJ=VVce79|<OW+XAK=1^i;tO!IO@fk(uBdK>Zqv zYTfMKR|SfG)zRq(e=Qa4G)~RwWh%E@3m6Axs;uF1x#JWB(OHpaPHq0^$e#I-jtI?; zCC!msY`G?FrL#{y-3~9x+&QP?2H=rYX-BYds9@0W+-ds;ke|fnfTo|J_*FJ!WN%qI zXe8@f#3P)r)<+5-UIObQ;)y)kRD>DF$k{_kp8Z?F|3uZ&rx<@b@eH&h-IPSWEx2o8 zccc}5K>D#9yHp7(9>jUmLF>D;2dN@7l&Z_B<GpYX~V=9zm^=p-#Q zKPXnOKMkL#Yef%6;P!s3+16*I5TwOKK*o=5UzWtTdpNk* zDtXH*>|jXhZu2OYhv=cok$J?5+~Ok8vr6h@$d!Ld;BbD2}Zo|G#pB{VzaZq*wp| literal 0 HcmV?d00001 diff --git a/mediagoblin/templates/mediagoblin/media_displays/video.html b/mediagoblin/templates/mediagoblin/media_displays/video.html index 37586924..22b19240 100644 --- a/mediagoblin/templates/mediagoblin/media_displays/video.html +++ b/mediagoblin/templates/mediagoblin/media_displays/video.html @@ -5,4 +5,12 @@ media['media_files']['medium']) }}" type='video/webm; codecs="vp8, vorbis"' /> + {% if 'original' in media.media_files %} + + {%- trans -%} + Original + {%- endtrans -%} + + {% endif %} {% endblock %}