Merge remote-tracking branch 'remotes/jwandborg/master'
This commit is contained in:
commit
99d2ac1d83
@ -50,6 +50,9 @@ allow_attachments = boolean(default=False)
|
||||
# Cookie stuff
|
||||
csrf_cookie_name = string(default='mediagoblin_csrftoken')
|
||||
|
||||
# Media types
|
||||
enable_video = boolean(default=False)
|
||||
|
||||
[storage:publicstore]
|
||||
storage_class = string(default="mediagoblin.storage.filestorage:BasicFileStorage")
|
||||
base_dir = string(default="%(here)s/user_dev/media/public")
|
||||
|
@ -100,3 +100,11 @@ def user_add_forgot_password_token_and_expires(database):
|
||||
"""
|
||||
add_table_field(database, 'users', 'fp_verification_key', None)
|
||||
add_table_field(database, 'users', 'fp_token_expire', None)
|
||||
|
||||
|
||||
@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)
|
||||
|
@ -211,10 +211,12 @@ def _export_media(db, args):
|
||||
_log.info(u'Exporting {0} - {1}'.format(
|
||||
entry['title'],
|
||||
name))
|
||||
|
||||
mc_file = media_cache.get_file(path, mode='wb')
|
||||
mc_file.write(
|
||||
mg_globals.public_store.get_file(path, mode='rb').read())
|
||||
try:
|
||||
mc_file = media_cache.get_file(path, mode='wb')
|
||||
mc_file.write(
|
||||
mg_globals.public_store.get_file(path, mode='rb').read())
|
||||
except e:
|
||||
_log.error('Failed: {0}'.format(e))
|
||||
|
||||
_log.info('...Media exported')
|
||||
|
||||
|
@ -18,7 +18,7 @@ import os
|
||||
import sys
|
||||
|
||||
|
||||
MANDATORY_CELERY_IMPORTS = ['mediagoblin.process_media']
|
||||
MANDATORY_CELERY_IMPORTS = ['mediagoblin.processing']
|
||||
|
||||
DEFAULT_SETTINGS_MODULE = 'mediagoblin.init.celery.dummy_settings_module'
|
||||
|
||||
|
73
mediagoblin/media_types/__init__.py
Normal file
73
mediagoblin/media_types/__init__.py
Normal file
@ -0,0 +1,73 @@
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
|
||||
|
||||
|
||||
class FileTypeNotSupported(Exception):
|
||||
pass
|
||||
|
||||
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']
|
||||
|
||||
if mg_globals.app_config['enable_video']:
|
||||
MEDIA_TYPES.append('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():
|
||||
__import__(media_type)
|
||||
|
||||
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 "{filename}"').format(
|
||||
filename=filename))
|
||||
|
||||
if ext[1:] in manager['accepted_extensions']:
|
||||
return media_type, manager
|
26
mediagoblin/media_types/image/__init__.py
Normal file
26
mediagoblin/media_types/image/__init__.py
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from mediagoblin.media_types.image.processing import process_image
|
||||
|
||||
|
||||
MEDIA_MANAGER = {
|
||||
"human_readable": "Image",
|
||||
"processor": process_image, # 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"]}
|
@ -14,104 +14,23 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import Image
|
||||
import os
|
||||
|
||||
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.process_media.errors import BaseProcessingFail, BadMediaFail
|
||||
|
||||
|
||||
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])
|
||||
|
||||
from mediagoblin.processing import BaseProcessingFail, \
|
||||
mark_entry_failed, BadMediaFail, create_pub_filepath, THUMB_SIZE, \
|
||||
MEDIUM_SIZE
|
||||
|
||||
################################
|
||||
# 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._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):
|
||||
"""
|
27
mediagoblin/media_types/video/__init__.py
Normal file
27
mediagoblin/media_types/video/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from mediagoblin.media_types.video.processing import process_video
|
||||
|
||||
|
||||
MEDIA_MANAGER = {
|
||||
"human_readable": "Video",
|
||||
"processor": process_video, # 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", "mkv", "ogv", "ogg"]}
|
505
mediagoblin/media_types/video/devices/web-advanced.json
Normal file
505
mediagoblin/media_types/video/devices/web-advanced.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
BIN
mediagoblin/media_types/video/devices/web-flv.png
Normal file
BIN
mediagoblin/media_types/video/devices/web-flv.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
259
mediagoblin/media_types/video/devices/web-webm.svg
Normal file
259
mediagoblin/media_types/video/devices/web-webm.svg
Normal file
@ -0,0 +1,259 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48px"
|
||||
height="48px"
|
||||
id="svg2816"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="web-webm.svg">
|
||||
<defs
|
||||
id="defs2818">
|
||||
<linearGradient
|
||||
id="linearGradient3656">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3658" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3660" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3632">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.54901963;"
|
||||
offset="0"
|
||||
id="stop3634" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop3636" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3622">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3624" />
|
||||
<stop
|
||||
style="stop-color:#d3d7cf;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3626" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3600">
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3602" />
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3604" />
|
||||
</linearGradient>
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 24 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="48 : 24 : 1"
|
||||
inkscape:persp3d-origin="24 : 16 : 1"
|
||||
id="perspective2824" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3600"
|
||||
id="linearGradient3606"
|
||||
x1="20.256382"
|
||||
y1="2.546674"
|
||||
x2="20.256382"
|
||||
y2="46.881901"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3622"
|
||||
id="linearGradient3628"
|
||||
x1="21.2349"
|
||||
y1="7.948472"
|
||||
x2="21.2349"
|
||||
y2="40.191879"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3632"
|
||||
id="linearGradient3638"
|
||||
x1="6.4826794"
|
||||
y1="4.543263"
|
||||
x2="25.363527"
|
||||
y2="35.227882"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(0,-0.35355339)" />
|
||||
<inkscape:perspective
|
||||
id="perspective3693"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3600-5"
|
||||
id="linearGradient3606-9"
|
||||
x1="20.256382"
|
||||
y1="2.546674"
|
||||
x2="20.256382"
|
||||
y2="46.881901"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient3600-5">
|
||||
<stop
|
||||
style="stop-color:#8ae234;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3602-7" />
|
||||
<stop
|
||||
style="stop-color:#4e9a06;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3604-2" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
id="filter3731">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.82730657"
|
||||
id="feGaussianBlur3733" />
|
||||
</filter>
|
||||
<inkscape:perspective
|
||||
id="perspective3749"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
<inkscape:perspective
|
||||
id="perspective3782"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="20.51741"
|
||||
inkscape:cy="22.534228"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1099"
|
||||
inkscape:window-height="834"
|
||||
inkscape:window-x="801"
|
||||
inkscape:window-y="106"
|
||||
inkscape:window-maximized="0">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3608" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2821">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#000000;fill-opacity:0.2869955;stroke:none;filter:url(#filter3731)"
|
||||
id="path3598-4"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="13.857143"
|
||||
sodipodi:cy="24.714287"
|
||||
sodipodi:r1="25.596954"
|
||||
sodipodi:r2="12.798477"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 39.454098,24.714287 20.256381,35.798093 1.0586662,46.8819 l 0,-22.167614 0,-22.1676119 19.1977168,11.0838069 19.197715,11.083806 z"
|
||||
transform="matrix(1.0537808,0,0,1.0537808,3.6163385,-1.9600717)" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:url(#linearGradient3606);fill-opacity:1;stroke:#366a04;stroke-width:1.05497880999999993;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-linejoin:round"
|
||||
id="path3598"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="13.857143"
|
||||
sodipodi:cy="24.714287"
|
||||
sodipodi:r1="25.596954"
|
||||
sodipodi:r2="12.798477"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="M 39.454098,24.714287 20.256381,35.798093 1.0586662,46.8819 l 0,-22.167614 0,-22.1676119 19.1977168,11.0838069 19.197715,11.083806 z"
|
||||
transform="matrix(0.94788634,0,0,0.94788634,5.0257749,0.56128794)" />
|
||||
<path
|
||||
style="fill:url(#linearGradient3628);stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1"
|
||||
d="m 6.5304575,9.646791 8.7347075,20.091724 4.674611,-18.160553 4.525987,2.612472 3.885316,12.559503 4.403755,-7.765833 1.744319,1.009296 -2.127799,9.211229 -6.155446,3.554753 -4.028978,-9.439016 -2.255629,13.086534 -5.852703,3.373025 -7.5584205,-9.989634 0.01028,-20.1435 z"
|
||||
id="path3620"
|
||||
sodipodi:nodetypes="cccccccccccccc" />
|
||||
<path
|
||||
style="fill:none;stroke:url(#linearGradient3638);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 6.9826793,42.785087 0,-38.0953773 32.9068657,18.9987873"
|
||||
id="path3630"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.15686275"
|
||||
d="M 6.6184028,8.6135689 15.026019,28.134068 19.45616,10.995613"
|
||||
id="path3739"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.15686275"
|
||||
d="m 25.081121,14.552251 3.345117,11.020499 3.93014,-6.825955"
|
||||
id="path3739-5"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.15686275"
|
||||
d="m 6.6291261,30.85266 7.0710679,9.280777"
|
||||
id="path3772"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.15686275"
|
||||
d="m 34.736621,20.290253 -2.032932,8.794642"
|
||||
id="path3772-6"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.15686275"
|
||||
d="m 20.594485,35.934991 1.811961,-10.650796 3.270369,7.778174"
|
||||
id="path3796"
|
||||
sodipodi:nodetypes="ccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 8.8 KiB |
982
mediagoblin/media_types/video/devices/web.svg
Normal file
982
mediagoblin/media_types/video/devices/web.svg
Normal file
@ -0,0 +1,982 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48px"
|
||||
height="48px"
|
||||
id="svg3440"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/apps"
|
||||
sodipodi:docname="internet-web-browser.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape">
|
||||
<defs
|
||||
id="defs3">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 24 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="48 : 24 : 1"
|
||||
inkscape:persp3d-origin="24 : 16 : 1"
|
||||
id="perspective156" />
|
||||
<linearGradient
|
||||
id="linearGradient4750">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4752" />
|
||||
<stop
|
||||
style="stop-color:#fefefe;stop-opacity:1.0000000;"
|
||||
offset="0.37931034"
|
||||
id="stop4758" />
|
||||
<stop
|
||||
style="stop-color:#1d1d1d;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop4754" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4350">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4352" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4354" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4126">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop4128" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0.16494845;"
|
||||
offset="1.0000000"
|
||||
id="stop4130" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient4114">
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop4116" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop4118" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3962">
|
||||
<stop
|
||||
style="stop-color:#d3e9ff;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop3964" />
|
||||
<stop
|
||||
style="stop-color:#d3e9ff;stop-opacity:1.0000000;"
|
||||
offset="0.15517241"
|
||||
id="stop4134" />
|
||||
<stop
|
||||
style="stop-color:#4074ae;stop-opacity:1.0000000;"
|
||||
offset="0.75000000"
|
||||
id="stop4346" />
|
||||
<stop
|
||||
style="stop-color:#36486c;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop3966" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3962"
|
||||
id="radialGradient3968"
|
||||
gradientTransform="scale(0.999989,1.000011)"
|
||||
cx="18.247644"
|
||||
cy="15.716079"
|
||||
fx="18.247644"
|
||||
fy="15.716079"
|
||||
r="29.993349"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4114"
|
||||
id="radialGradient4120"
|
||||
gradientTransform="scale(1.643990,0.608276)"
|
||||
cx="15.115514"
|
||||
cy="63.965388"
|
||||
fx="15.115514"
|
||||
fy="63.965388"
|
||||
r="12.289036"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4126"
|
||||
id="radialGradient4132"
|
||||
gradientTransform="scale(0.999989,1.000011)"
|
||||
cx="15.601279"
|
||||
cy="12.142302"
|
||||
fx="15.601279"
|
||||
fy="12.142302"
|
||||
r="43.526714"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4350"
|
||||
id="radialGradient4356"
|
||||
gradientTransform="scale(1.179536,0.847791)"
|
||||
cx="11.826907"
|
||||
cy="10.476453"
|
||||
fx="11.826907"
|
||||
fy="10.476453"
|
||||
r="32.664848"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4750"
|
||||
id="radialGradient4756"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
cx="18.633780"
|
||||
cy="17.486208"
|
||||
fx="18.934305"
|
||||
fy="17.810213"
|
||||
r="40.692665"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1460"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1462"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1466"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1468"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1470"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1474"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1476"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1478"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1482"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1484"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1486"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1490"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1492"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1494"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1498"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1500"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1502"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1506"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1508"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1510"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1514"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1516"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1518"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1522"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1524"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1526"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1528"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1530"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1532"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1534"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1536"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1538"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1540"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1542"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1544"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1546"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1550"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1552"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1554"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="40.692665"
|
||||
fy="17.810213"
|
||||
fx="18.934305"
|
||||
cy="17.486208"
|
||||
cx="18.633780"
|
||||
gradientTransform="scale(1.036822,0.964486)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient1558"
|
||||
xlink:href="#linearGradient4750"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="0.17254902"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="9.8994949"
|
||||
inkscape:cx="25.799661"
|
||||
inkscape:cy="24.622653"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="823"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="30"
|
||||
inkscape:showpageshadow="false" />
|
||||
<metadata
|
||||
id="metadata4">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Globe</dc:title>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Tuomas Kuosmanen</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
|
||||
<dc:source>http://jimmac.musichall.cz</dc:source>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>globe</rdf:li>
|
||||
<rdf:li>international</rdf:li>
|
||||
<rdf:li>web</rdf:li>
|
||||
<rdf:li>www</rdf:li>
|
||||
<rdf:li>internet</rdf:li>
|
||||
<rdf:li>network</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/publicdomain/">
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#Distribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:url(#radialGradient4120);fill-opacity:1.0000000;stroke:none;stroke-opacity:1.0000000"
|
||||
id="path4112"
|
||||
sodipodi:cx="24.849752"
|
||||
sodipodi:cy="38.908627"
|
||||
sodipodi:rx="20.203051"
|
||||
sodipodi:ry="7.4751287"
|
||||
d="M 45.052803 38.908627 A 20.203051 7.4751287 0 1 1 4.6467018,38.908627 A 20.203051 7.4751287 0 1 1 45.052803 38.908627 z"
|
||||
transform="matrix(1.000000,0.000000,0.000000,1.243244,0.000000,-10.27241)" />
|
||||
<path
|
||||
style="fill:url(#radialGradient3968);fill-opacity:1.0000000;fill-rule:nonzero;stroke:#39396c;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
|
||||
d="M 43.959853,23.485499 C 43.959853,34.195217 35.277750,42.877222 24.569505,42.877222 C 13.860279,42.877222 5.1786663,34.195119 5.1786663,23.485499 C 5.1786663,12.776272 13.860279,4.0951517 24.569505,4.0951517 C 35.277750,4.0951517 43.959853,12.776272 43.959853,23.485499 L 43.959853,23.485499 z "
|
||||
id="path3214" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:0.42159382;fill:url(#radialGradient4356);fill-opacity:1.0000000;stroke:none;stroke-opacity:1.0000000"
|
||||
id="path4348"
|
||||
sodipodi:cx="17.778685"
|
||||
sodipodi:cy="15.271057"
|
||||
sodipodi:rx="12.929953"
|
||||
sodipodi:ry="9.2934036"
|
||||
d="M 30.708637 15.271057 A 12.929953 9.2934036 0 1 1 4.8487320,15.271057 A 12.929953 9.2934036 0 1 1 30.708637 15.271057 z"
|
||||
transform="matrix(0.835938,0.000000,0.000000,1.000000,9.886868,0.000000)" />
|
||||
<g
|
||||
id="g4136"
|
||||
style="fill:#000000;fill-opacity:0.71345031;fill-rule:nonzero;stroke:none;stroke-miterlimit:4.0000000"
|
||||
transform="matrix(0.982371,0.000000,0.000000,0.982371,0.121079,0.232914)">
|
||||
<g
|
||||
id="g4138">
|
||||
<g
|
||||
id="g4142">
|
||||
<path
|
||||
d="M 44.071300,20.714400 C 44.071300,20.977100 44.071300,20.714400 44.071300,20.714400 L 43.526400,21.331600 C 43.192400,20.938000 42.817400,20.607000 42.436600,20.261300 L 41.600700,20.384300 L 40.837000,19.521000 L 40.837000,20.589400 L 41.491300,21.084500 L 41.926800,21.577700 L 42.508800,20.919500 C 42.655300,21.193900 42.799800,21.468300 42.945300,21.742700 L 42.945300,22.565000 L 42.290000,23.305200 L 41.090800,24.128400 L 40.182600,25.034700 L 39.600600,24.374500 L 39.891600,23.634300 L 39.310500,22.976100 L 38.329100,20.878400 L 37.493200,19.933100 L 37.274400,20.179200 L 37.602500,21.372600 L 38.219700,22.071800 C 38.572200,23.089400 38.920900,24.062000 39.383800,25.034700 C 40.101600,25.034700 40.778300,24.958500 41.491200,24.868700 L 41.491200,25.444900 L 40.619100,27.584100 L 39.819300,28.488400 L 39.165000,29.888800 C 39.165000,30.656400 39.165000,31.424000 39.165000,32.191500 L 39.383800,33.097800 L 39.020500,33.508000 L 38.219700,34.002100 L 37.383800,34.701300 L 38.075200,35.482600 L 37.129900,36.306800 L 37.311500,36.840000 L 35.893500,38.445500 L 34.949200,38.445500 L 34.149400,38.939600 L 33.639600,38.939600 L 33.639600,38.281400 L 33.422800,36.963000 C 33.141500,36.136800 32.848600,35.316500 32.550700,34.496200 C 32.550700,33.890700 32.586800,33.291100 32.623000,32.685700 L 32.987300,31.863400 L 32.477500,30.875100 L 32.514600,29.517700 L 31.823200,28.736400 L 32.168900,27.605500 L 31.606400,26.967300 L 30.624000,26.967300 L 30.296900,26.597200 L 29.315500,27.214900 L 28.916100,26.761300 L 28.006900,27.543000 C 27.389700,26.843300 26.771500,26.144100 26.153400,25.444900 L 25.426800,23.716400 L 26.081100,22.730100 L 25.717800,22.319000 L 26.516600,20.425400 C 27.172900,19.609000 27.858400,18.825800 28.551800,18.039700 L 29.788100,17.710600 L 31.169000,17.546500 L 32.114300,17.793600 L 33.459000,19.150000 L 33.931700,18.615800 L 34.585000,18.533800 L 35.821300,18.944900 L 36.766600,18.944900 L 37.420900,18.368700 L 37.711900,17.957600 L 37.056600,17.546500 L 35.965800,17.464500 C 35.663100,17.044600 35.381800,16.603200 35.022400,16.230100 L 34.658100,16.394200 L 34.512600,17.464500 L 33.858300,16.724300 L 33.713800,15.900100 L 32.987200,15.325900 L 32.695200,15.325900 L 33.422700,16.148200 L 33.131700,16.888400 L 32.550600,17.052500 L 32.913900,16.312300 L 32.258600,15.984200 L 31.678500,15.326000 L 30.586700,15.572100 L 30.442200,15.900200 L 29.787900,16.312300 L 29.424600,17.217600 L 28.516400,17.669700 L 28.116000,17.217600 L 27.680500,17.217600 L 27.680500,15.736200 L 28.625800,15.242100 L 29.352400,15.242100 L 29.205900,14.666900 L 28.625800,14.090700 L 29.606300,13.884600 L 30.151200,13.268400 L 30.586700,12.527200 L 31.387500,12.527200 L 31.168700,11.952000 L 31.678500,11.622900 L 31.678500,12.281100 L 32.768300,12.527200 L 33.858100,11.622900 L 33.931300,11.210800 L 34.875600,10.553100 C 34.533800,10.595600 34.192000,10.626800 33.858000,10.717700 L 33.858000,9.9766000 L 34.221300,9.1538000 L 33.858000,9.1538000 L 33.059600,9.8940000 L 32.840800,10.305600 L 33.059600,10.882300 L 32.695300,11.868600 L 32.114200,11.539500 L 31.606400,10.964300 L 30.805600,11.539500 L 30.514600,10.223600 L 31.895500,9.3188000 L 31.895500,8.8247000 L 32.768500,8.2490000 L 34.149400,7.9194000 L 35.094700,8.2490000 L 36.838800,8.5781000 L 36.403300,9.0713000 L 35.458000,9.0713000 L 36.403300,10.058600 L 37.129900,9.2363000 L 37.350600,8.8745000 C 37.350600,8.8745000 40.137700,11.372500 41.730500,14.105000 C 43.323300,16.838400 44.071300,20.060100 44.071300,20.714400 z "
|
||||
id="path4144" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4146">
|
||||
<g
|
||||
id="g4150">
|
||||
<path
|
||||
d="M 26.070300,9.2363000 L 25.997100,9.7295000 L 26.506900,10.058600 L 27.378000,9.4829000 L 26.942500,8.9892000 L 26.360500,9.3188000 L 26.070500,9.2363000"
|
||||
id="path4152" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4154">
|
||||
<g
|
||||
id="g4158">
|
||||
<path
|
||||
d="M 26.870100,5.8633000 L 24.979500,5.1226000 L 22.799800,5.3692000 L 20.109400,6.1094000 L 19.600600,6.6035000 L 21.272500,7.7549000 L 21.272500,8.4131000 L 20.618200,9.0713000 L 21.491200,10.800300 L 22.071300,10.470200 L 22.799800,9.3188000 C 23.922800,8.9716000 24.929700,8.5781000 25.997100,8.0844000 L 26.870100,5.8632000"
|
||||
id="path4160" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4162">
|
||||
<g
|
||||
id="g4166">
|
||||
<path
|
||||
d="M 28.833000,12.774900 L 28.542000,12.033700 L 28.032200,12.198700 L 28.178700,13.103000 L 28.833000,12.774900"
|
||||
id="path4168" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4170">
|
||||
<g
|
||||
id="g4174">
|
||||
<path
|
||||
d="M 29.123000,12.608900 L 28.977500,13.597200 L 29.777300,13.432200 L 30.358400,12.857000 L 29.849600,12.362900 C 29.678700,11.907800 29.482400,11.483000 29.268500,11.046500 L 28.833000,11.046500 L 28.833000,11.539700 L 29.123000,11.868800 L 29.123000,12.609000"
|
||||
id="path4176" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4178">
|
||||
<g
|
||||
id="g4182">
|
||||
<path
|
||||
d="M 18.365200,28.242200 L 17.783200,27.089900 L 16.692900,26.843300 L 16.111400,25.280800 L 14.657800,25.444900 L 13.422400,24.540600 L 12.113300,25.692000 L 12.113300,25.873600 C 11.717300,25.759300 11.230500,25.743700 10.877900,25.526900 L 10.586900,24.704600 L 10.586900,23.799300 L 9.7148000,23.881300 C 9.7876000,23.305100 9.8598000,22.729900 9.9331000,22.153800 L 9.4238000,22.153800 L 8.9155000,22.812000 L 8.4062000,23.058100 L 7.6791000,22.647900 L 7.6063000,21.742600 L 7.7518000,20.755300 L 8.8426000,19.933000 L 9.7147000,19.933000 L 9.8597000,19.438900 L 10.950000,19.685000 L 11.749800,20.673300 L 11.895300,19.026800 L 13.276600,17.875400 L 13.785400,16.641000 L 14.803000,16.229900 L 15.384500,15.407600 L 16.692600,15.159600 L 17.347400,14.173300 C 16.693100,14.173300 16.038800,14.173300 15.384500,14.173300 L 16.620300,13.597100 L 17.491900,13.597100 L 18.728200,13.185000 L 18.873700,12.692800 L 18.437200,12.280700 L 17.928400,12.115700 L 18.073900,11.622500 L 17.710600,10.882300 L 16.838000,11.210400 L 16.983500,10.552700 L 15.965900,9.9765000 L 15.166600,11.374400 L 15.238900,11.868500 L 14.439600,12.198600 L 13.930300,13.267900 L 13.712500,12.280600 L 12.331200,11.704400 L 12.112900,10.964200 L 13.930300,9.8939000 L 14.730100,9.1537000 L 14.802900,8.2489000 L 14.366900,8.0018000 L 13.785400,7.9193000 L 13.422100,8.8246000 C 13.422100,8.8246000 12.814200,8.9437000 12.657900,8.9823000 C 10.661800,10.821700 6.6286000,14.792400 5.6916000,22.288500 C 5.7287000,22.462300 6.3708000,23.470100 6.3708000,23.470100 L 7.8972000,24.374400 L 9.4236000,24.786500 L 10.078400,25.609700 L 11.095500,26.349900 L 11.677000,26.267900 L 12.113000,26.464200 L 12.113000,26.597000 L 11.531900,28.160000 L 11.095400,28.818200 L 11.240900,29.148300 L 10.877600,30.380700 L 12.186200,32.767400 L 13.494300,33.919700 L 14.076300,34.742000 L 14.003100,36.470500 L 14.439600,37.456800 L 14.003100,39.349400 C 14.003100,39.349400 13.968900,39.337700 14.024600,39.527100 C 14.080800,39.716600 16.353700,40.978300 16.498200,40.870900 C 16.642200,40.761500 16.765300,40.665800 16.765300,40.665800 L 16.620300,40.255600 L 17.201400,39.679400 L 17.419700,39.103200 L 18.365000,38.773100 L 19.091600,36.962600 L 18.873800,36.470400 L 19.381600,35.730200 L 20.472400,35.482200 L 21.054400,34.165800 L 20.908900,32.521300 L 21.781000,31.286900 L 21.926500,30.052500 C 20.733100,29.460700 19.549500,28.851300 18.365000,28.242000"
|
||||
id="path4184" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4186">
|
||||
<g
|
||||
id="g4190">
|
||||
<path
|
||||
d="M 16.765600,9.5649000 L 17.492200,10.058600 L 18.074200,10.058600 L 18.074200,9.4829000 L 17.347600,9.1538000 L 16.765600,9.5649000"
|
||||
id="path4192" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4194">
|
||||
<g
|
||||
id="g4198">
|
||||
<path
|
||||
d="M 14.876000,8.9072000 L 14.512200,9.8120000 L 15.239300,9.8120000 L 15.603100,8.9892000 C 15.916600,8.7675000 16.228600,8.5444000 16.547900,8.3310000 L 17.275000,8.5781000 C 17.759400,8.9072000 18.243800,9.2363000 18.728600,9.5649000 L 19.456100,8.9072000 L 18.655800,8.5781000 L 18.292000,7.8374000 L 16.911100,7.6728000 L 16.838300,7.2612000 L 16.184000,7.4262000 L 15.893600,8.0020000 L 15.529800,7.2613000 L 15.384800,7.5904000 L 15.457600,8.4132000 L 14.876000,8.9072000"
|
||||
id="path4200" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4202">
|
||||
<g
|
||||
style="opacity:0.75000000"
|
||||
id="g4204">
|
||||
<path
|
||||
id="path4206"
|
||||
d="" />
|
||||
</g>
|
||||
<g
|
||||
id="g4208">
|
||||
<path
|
||||
id="path4210"
|
||||
d="" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4212">
|
||||
<g
|
||||
style="opacity:0.75000000"
|
||||
id="g4214">
|
||||
<path
|
||||
id="path4216"
|
||||
d="" />
|
||||
</g>
|
||||
<g
|
||||
id="g4218">
|
||||
<path
|
||||
id="path4220"
|
||||
d="" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4222">
|
||||
<g
|
||||
id="g4226">
|
||||
<path
|
||||
d="M 17.492200,6.8496000 L 17.856000,6.5210000 L 18.583100,6.3564000 C 19.081100,6.1142000 19.581100,5.9511000 20.109500,5.7802000 L 19.819500,5.2865000 L 18.881000,5.4213000 L 18.437600,5.8632000 L 17.706600,5.9692000 L 17.056700,6.2744000 L 16.740800,6.4272000 L 16.547900,6.6855000 L 17.492200,6.8496000"
|
||||
id="path4228" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g4230">
|
||||
<g
|
||||
id="g4234">
|
||||
<path
|
||||
d="M 18.728500,14.666500 L 19.165000,14.008300 L 18.510200,13.515100 L 18.728500,14.666500"
|
||||
id="path4236" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3216"
|
||||
style="color:#000000;fill:url(#radialGradient1460);fill-opacity:1.0000000;fill-rule:nonzero;stroke:none;stroke-width:1.0179454;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible"
|
||||
transform="matrix(0.982371,0.000000,0.000000,0.982371,-8.095179e-2,3.088300e-2)">
|
||||
<g
|
||||
id="g3218"
|
||||
style="color:#000000;fill:url(#radialGradient1462);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3222"
|
||||
style="color:#000000;fill:url(#radialGradient1466);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 44.071300,20.714400 C 44.071300,20.977100 44.071300,20.714400 44.071300,20.714400 L 43.526400,21.331600 C 43.192400,20.938000 42.817400,20.607000 42.436600,20.261300 L 41.600700,20.384300 L 40.837000,19.521000 L 40.837000,20.589400 L 41.491300,21.084500 L 41.926800,21.577700 L 42.508800,20.919500 C 42.655300,21.193900 42.799800,21.468300 42.945300,21.742700 L 42.945300,22.565000 L 42.290000,23.305200 L 41.090800,24.128400 L 40.182600,25.034700 L 39.600600,24.374500 L 39.891600,23.634300 L 39.310500,22.976100 L 38.329100,20.878400 L 37.493200,19.933100 L 37.274400,20.179200 L 37.602500,21.372600 L 38.219700,22.071800 C 38.572200,23.089400 38.920900,24.062000 39.383800,25.034700 C 40.101600,25.034700 40.778300,24.958500 41.491200,24.868700 L 41.491200,25.444900 L 40.619100,27.584100 L 39.819300,28.488400 L 39.165000,29.888800 C 39.165000,30.656400 39.165000,31.424000 39.165000,32.191500 L 39.383800,33.097800 L 39.020500,33.508000 L 38.219700,34.002100 L 37.383800,34.701300 L 38.075200,35.482600 L 37.129900,36.306800 L 37.311500,36.840000 L 35.893500,38.445500 L 34.949200,38.445500 L 34.149400,38.939600 L 33.639600,38.939600 L 33.639600,38.281400 L 33.422800,36.963000 C 33.141500,36.136800 32.848600,35.316500 32.550700,34.496200 C 32.550700,33.890700 32.586800,33.291100 32.623000,32.685700 L 32.987300,31.863400 L 32.477500,30.875100 L 32.514600,29.517700 L 31.823200,28.736400 L 32.168900,27.605500 L 31.606400,26.967300 L 30.624000,26.967300 L 30.296900,26.597200 L 29.315500,27.214900 L 28.916100,26.761300 L 28.006900,27.543000 C 27.389700,26.843300 26.771500,26.144100 26.153400,25.444900 L 25.426800,23.716400 L 26.081100,22.730100 L 25.717800,22.319000 L 26.516600,20.425400 C 27.172900,19.609000 27.858400,18.825800 28.551800,18.039700 L 29.788100,17.710600 L 31.169000,17.546500 L 32.114300,17.793600 L 33.459000,19.150000 L 33.931700,18.615800 L 34.585000,18.533800 L 35.821300,18.944900 L 36.766600,18.944900 L 37.420900,18.368700 L 37.711900,17.957600 L 37.056600,17.546500 L 35.965800,17.464500 C 35.663100,17.044600 35.381800,16.603200 35.022400,16.230100 L 34.658100,16.394200 L 34.512600,17.464500 L 33.858300,16.724300 L 33.713800,15.900100 L 32.987200,15.325900 L 32.695200,15.325900 L 33.422700,16.148200 L 33.131700,16.888400 L 32.550600,17.052500 L 32.913900,16.312300 L 32.258600,15.984200 L 31.678500,15.326000 L 30.586700,15.572100 L 30.442200,15.900200 L 29.787900,16.312300 L 29.424600,17.217600 L 28.516400,17.669700 L 28.116000,17.217600 L 27.680500,17.217600 L 27.680500,15.736200 L 28.625800,15.242100 L 29.352400,15.242100 L 29.205900,14.666900 L 28.625800,14.090700 L 29.606300,13.884600 L 30.151200,13.268400 L 30.586700,12.527200 L 31.387500,12.527200 L 31.168700,11.952000 L 31.678500,11.622900 L 31.678500,12.281100 L 32.768300,12.527200 L 33.858100,11.622900 L 33.931300,11.210800 L 34.875600,10.553100 C 34.533800,10.595600 34.192000,10.626800 33.858000,10.717700 L 33.858000,9.9766000 L 34.221300,9.1538000 L 33.858000,9.1538000 L 33.059600,9.8940000 L 32.840800,10.305600 L 33.059600,10.882300 L 32.695300,11.868600 L 32.114200,11.539500 L 31.606400,10.964300 L 30.805600,11.539500 L 30.514600,10.223600 L 31.895500,9.3188000 L 31.895500,8.8247000 L 32.768500,8.2490000 L 34.149400,7.9194000 L 35.094700,8.2490000 L 36.838800,8.5781000 L 36.403300,9.0713000 L 35.458000,9.0713000 L 36.403300,10.058600 L 37.129900,9.2363000 L 37.350600,8.8745000 C 37.350600,8.8745000 40.137700,11.372500 41.730500,14.105000 C 43.323300,16.838400 44.071300,20.060100 44.071300,20.714400 z "
|
||||
id="path3224"
|
||||
style="color:#000000;fill:url(#radialGradient1468);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3226"
|
||||
style="color:#000000;fill:url(#radialGradient1470);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3230"
|
||||
style="color:#000000;fill:url(#radialGradient1474);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 26.070300,9.2363000 L 25.997100,9.7295000 L 26.506900,10.058600 L 27.378000,9.4829000 L 26.942500,8.9892000 L 26.360500,9.3188000 L 26.070500,9.2363000"
|
||||
id="path3232"
|
||||
style="color:#000000;fill:url(#radialGradient1476);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3234"
|
||||
style="color:#000000;fill:url(#radialGradient1478);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3238"
|
||||
style="color:#000000;fill:url(#radialGradient1482);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 26.870100,5.8633000 L 24.979500,5.1226000 L 22.799800,5.3692000 L 20.109400,6.1094000 L 19.600600,6.6035000 L 21.272500,7.7549000 L 21.272500,8.4131000 L 20.618200,9.0713000 L 21.491200,10.800300 L 22.071300,10.470200 L 22.799800,9.3188000 C 23.922800,8.9716000 24.929700,8.5781000 25.997100,8.0844000 L 26.870100,5.8632000"
|
||||
id="path3240"
|
||||
style="color:#000000;fill:url(#radialGradient1484);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3242"
|
||||
style="color:#000000;fill:url(#radialGradient1486);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3246"
|
||||
style="color:#000000;fill:url(#radialGradient1490);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 28.833000,12.774900 L 28.542000,12.033700 L 28.032200,12.198700 L 28.178700,13.103000 L 28.833000,12.774900"
|
||||
id="path3248"
|
||||
style="color:#000000;fill:url(#radialGradient1492);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3250"
|
||||
style="color:#000000;fill:url(#radialGradient1494);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3254"
|
||||
style="color:#000000;fill:url(#radialGradient1498);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 29.123000,12.608900 L 28.977500,13.597200 L 29.777300,13.432200 L 30.358400,12.857000 L 29.849600,12.362900 C 29.678700,11.907800 29.482400,11.483000 29.268500,11.046500 L 28.833000,11.046500 L 28.833000,11.539700 L 29.123000,11.868800 L 29.123000,12.609000"
|
||||
id="path3256"
|
||||
style="color:#000000;fill:url(#radialGradient1500);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3258"
|
||||
style="color:#000000;fill:url(#radialGradient1502);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3262"
|
||||
style="color:#000000;fill:url(#radialGradient1506);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 18.365200,28.242200 L 17.783200,27.089900 L 16.692900,26.843300 L 16.111400,25.280800 L 14.657800,25.444900 L 13.422400,24.540600 L 12.113300,25.692000 L 12.113300,25.873600 C 11.717300,25.759300 11.230500,25.743700 10.877900,25.526900 L 10.586900,24.704600 L 10.586900,23.799300 L 9.7148000,23.881300 C 9.7876000,23.305100 9.8598000,22.729900 9.9331000,22.153800 L 9.4238000,22.153800 L 8.9155000,22.812000 L 8.4062000,23.058100 L 7.6791000,22.647900 L 7.6063000,21.742600 L 7.7518000,20.755300 L 8.8426000,19.933000 L 9.7147000,19.933000 L 9.8597000,19.438900 L 10.950000,19.685000 L 11.749800,20.673300 L 11.895300,19.026800 L 13.276600,17.875400 L 13.785400,16.641000 L 14.803000,16.229900 L 15.384500,15.407600 L 16.692600,15.159600 L 17.347400,14.173300 C 16.693100,14.173300 16.038800,14.173300 15.384500,14.173300 L 16.620300,13.597100 L 17.491900,13.597100 L 18.728200,13.185000 L 18.873700,12.692800 L 18.437200,12.280700 L 17.928400,12.115700 L 18.073900,11.622500 L 17.710600,10.882300 L 16.838000,11.210400 L 16.983500,10.552700 L 15.965900,9.9765000 L 15.166600,11.374400 L 15.238900,11.868500 L 14.439600,12.198600 L 13.930300,13.267900 L 13.712500,12.280600 L 12.331200,11.704400 L 12.112900,10.964200 L 13.930300,9.8939000 L 14.730100,9.1537000 L 14.802900,8.2489000 L 14.366900,8.0018000 L 13.785400,7.9193000 L 13.422100,8.8246000 C 13.422100,8.8246000 12.814200,8.9437000 12.657900,8.9823000 C 10.661800,10.821700 6.6286000,14.792400 5.6916000,22.288500 C 5.7287000,22.462300 6.3708000,23.470100 6.3708000,23.470100 L 7.8972000,24.374400 L 9.4236000,24.786500 L 10.078400,25.609700 L 11.095500,26.349900 L 11.677000,26.267900 L 12.113000,26.464200 L 12.113000,26.597000 L 11.531900,28.160000 L 11.095400,28.818200 L 11.240900,29.148300 L 10.877600,30.380700 L 12.186200,32.767400 L 13.494300,33.919700 L 14.076300,34.742000 L 14.003100,36.470500 L 14.439600,37.456800 L 14.003100,39.349400 C 14.003100,39.349400 13.968900,39.337700 14.024600,39.527100 C 14.080800,39.716600 16.353700,40.978300 16.498200,40.870900 C 16.642200,40.761500 16.765300,40.665800 16.765300,40.665800 L 16.620300,40.255600 L 17.201400,39.679400 L 17.419700,39.103200 L 18.365000,38.773100 L 19.091600,36.962600 L 18.873800,36.470400 L 19.381600,35.730200 L 20.472400,35.482200 L 21.054400,34.165800 L 20.908900,32.521300 L 21.781000,31.286900 L 21.926500,30.052500 C 20.733100,29.460700 19.549500,28.851300 18.365000,28.242000"
|
||||
id="path3264"
|
||||
style="color:#000000;fill:url(#radialGradient1508);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3266"
|
||||
style="color:#000000;fill:url(#radialGradient1510);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3270"
|
||||
style="color:#000000;fill:url(#radialGradient1514);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 16.765600,9.5649000 L 17.492200,10.058600 L 18.074200,10.058600 L 18.074200,9.4829000 L 17.347600,9.1538000 L 16.765600,9.5649000"
|
||||
id="path3272"
|
||||
style="color:#000000;fill:url(#radialGradient1516);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3274"
|
||||
style="color:#000000;fill:url(#radialGradient1518);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3278"
|
||||
style="color:#000000;fill:url(#radialGradient1522);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 14.876000,8.9072000 L 14.512200,9.8120000 L 15.239300,9.8120000 L 15.603100,8.9892000 C 15.916600,8.7675000 16.228600,8.5444000 16.547900,8.3310000 L 17.275000,8.5781000 C 17.759400,8.9072000 18.243800,9.2363000 18.728600,9.5649000 L 19.456100,8.9072000 L 18.655800,8.5781000 L 18.292000,7.8374000 L 16.911100,7.6728000 L 16.838300,7.2612000 L 16.184000,7.4262000 L 15.893600,8.0020000 L 15.529800,7.2613000 L 15.384800,7.5904000 L 15.457600,8.4132000 L 14.876000,8.9072000"
|
||||
id="path3280"
|
||||
style="color:#000000;fill:url(#radialGradient1524);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3282"
|
||||
style="color:#000000;fill:url(#radialGradient1526);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
style="opacity:0.75000000;color:#000000;fill:url(#radialGradient1528);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="g3284">
|
||||
<path
|
||||
d=""
|
||||
style="color:#000000;fill:url(#radialGradient1530);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="path3286" />
|
||||
</g>
|
||||
<g
|
||||
id="g3288"
|
||||
style="color:#000000;fill:url(#radialGradient1532);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d=""
|
||||
id="path3290"
|
||||
style="color:#000000;fill:url(#radialGradient1534);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3292"
|
||||
style="color:#000000;fill:url(#radialGradient1536);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
style="opacity:0.75000000;color:#000000;fill:url(#radialGradient1538);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="g3294">
|
||||
<path
|
||||
d=""
|
||||
style="color:#000000;fill:url(#radialGradient1540);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible"
|
||||
id="path3296" />
|
||||
</g>
|
||||
<g
|
||||
id="g3298"
|
||||
style="color:#000000;fill:url(#radialGradient1542);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d=""
|
||||
id="path3300"
|
||||
style="color:#000000;fill:url(#radialGradient1544);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3302"
|
||||
style="color:#000000;fill:url(#radialGradient1546);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3306"
|
||||
style="color:#000000;fill:url(#radialGradient1550);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 17.492200,6.8496000 L 17.856000,6.5210000 L 18.583100,6.3564000 C 19.081100,6.1142000 19.581100,5.9511000 20.109500,5.7802000 L 19.819500,5.2865000 L 18.881000,5.4213000 L 18.437600,5.8632000 L 17.706600,5.9692000 L 17.056700,6.2744000 L 16.740800,6.4272000 L 16.547900,6.6855000 L 17.492200,6.8496000"
|
||||
id="path3308"
|
||||
style="color:#000000;fill:url(#radialGradient1552);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
id="g3310"
|
||||
style="color:#000000;fill:url(#radialGradient1554);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<g
|
||||
id="g3314"
|
||||
style="color:#000000;fill:url(#radialGradient1558);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible">
|
||||
<path
|
||||
d="M 18.728500,14.666500 L 19.165000,14.008300 L 18.510200,13.515100 L 18.728500,14.666500"
|
||||
id="path3316"
|
||||
style="color:#000000;fill:url(#radialGradient4756);stroke-dashoffset:0.0000000;marker:none;marker-start:none;marker-mid:none;marker-end:none;visibility:visible;display:inline;overflow:visible" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
style="fill:none;fill-opacity:1.0000000;fill-rule:nonzero;stroke:url(#radialGradient4132);stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
|
||||
d="M 42.975093,23.485534 C 42.975093,33.651354 34.733915,41.892440 24.569493,41.892440 C 14.404139,41.892440 6.1634261,33.651261 6.1634261,23.485534 C 6.1634261,13.320180 14.404139,5.0799340 24.569493,5.0799340 C 34.733915,5.0799340 42.975093,13.320180 42.975093,23.485534 L 42.975093,23.485534 z "
|
||||
id="path4122" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 50 KiB |
118
mediagoblin/media_types/video/processing.py
Normal file
118
mediagoblin/media_types/video/processing.py
Normal file
@ -0,0 +1,118 @@
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
import tempfile
|
||||
import logging
|
||||
import os
|
||||
|
||||
from mediagoblin import mg_globals as mgg
|
||||
from mediagoblin.processing import mark_entry_failed, \
|
||||
THUMB_SIZE, MEDIUM_SIZE, create_pub_filepath
|
||||
from . import transcoders
|
||||
|
||||
logging.basicConfig()
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
_log.setLevel(logging.DEBUG)
|
||||
|
||||
|
||||
def process_video(entry):
|
||||
"""
|
||||
Code to process a video
|
||||
|
||||
Much of this code is derived from the arista-transcoder script in
|
||||
the arista PyPI package and changed to match the needs of
|
||||
MediaGoblin
|
||||
|
||||
This function sets up the arista video encoder in some kind of new thread
|
||||
and attaches callbacks to that child process, hopefully, the
|
||||
entry-complete callback will be called when the video is done.
|
||||
"""
|
||||
workbench = mgg.workbench_manager.create_workbench()
|
||||
|
||||
queued_filepath = entry['queued_media_file']
|
||||
queued_filename = workbench.localized_file(
|
||||
mgg.queue_store, queued_filepath,
|
||||
'source')
|
||||
|
||||
medium_filepath = create_pub_filepath(
|
||||
entry,
|
||||
'{original}-640p.webm'.format(
|
||||
original=os.path.splitext(
|
||||
queued_filepath[-1])[0] # Select the
|
||||
))
|
||||
|
||||
thumbnail_filepath = create_pub_filepath(
|
||||
entry, 'thumbnail.jpg')
|
||||
|
||||
|
||||
# Create a temporary file for the video destination
|
||||
tmp_dst = tempfile.NamedTemporaryFile()
|
||||
|
||||
with tmp_dst:
|
||||
# Transcode queued file to a VP8/vorbis file that fits in a 640x640 square
|
||||
transcoder = transcoders.VideoTranscoder(queued_filename, tmp_dst.name)
|
||||
|
||||
# Push transcoded video to public storage
|
||||
_log.debug('Saving medium...')
|
||||
mgg.public_store.get_file(medium_filepath, 'wb').write(
|
||||
tmp_dst.read())
|
||||
_log.debug('Saved medium')
|
||||
|
||||
entry['media_files']['webm_640'] = medium_filepath
|
||||
|
||||
# Save the width and height of the transcoded video
|
||||
entry['media_data']['video'] = {
|
||||
u'width': transcoder.dst_data.videowidth,
|
||||
u'height': transcoder.dst_data.videoheight}
|
||||
|
||||
# Create a temporary file for the video thumbnail
|
||||
tmp_thumb = tempfile.NamedTemporaryFile()
|
||||
|
||||
with tmp_thumb:
|
||||
# Create a thumbnail.jpg that fits in a 180x180 square
|
||||
transcoders.VideoThumbnailer(queued_filename, tmp_thumb.name)
|
||||
|
||||
# Push the thumbnail to public storage
|
||||
_log.debug('Saving thumbnail...')
|
||||
mgg.public_store.get_file(thumbnail_filepath, 'wb').write(
|
||||
tmp_thumb.read())
|
||||
_log.debug('Saved thumbnail')
|
||||
|
||||
entry['media_files']['thumb'] = thumbnail_filepath
|
||||
|
||||
|
||||
# Push original file to public storage
|
||||
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:
|
||||
_log.debug('Saving original...')
|
||||
original_file.write(queued_file.read())
|
||||
_log.debug('Saved original')
|
||||
|
||||
entry['media_files']['original'] = original_filepath
|
||||
|
||||
mgg.queue_store.delete_file(queued_filepath)
|
||||
|
||||
|
||||
# Save the MediaEntry
|
||||
entry.save()
|
658
mediagoblin/media_types/video/transcoders.py
Normal file
658
mediagoblin/media_types/video/transcoders.py
Normal file
@ -0,0 +1,658 @@
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import division
|
||||
|
||||
import os
|
||||
os.putenv('GST_DEBUG_DUMP_DOT_DIR', '/tmp')
|
||||
|
||||
import sys
|
||||
import logging
|
||||
import pdb
|
||||
import urllib
|
||||
|
||||
_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:
|
||||
raise Exception('Could not find pygtk')
|
||||
|
||||
try:
|
||||
import gobject
|
||||
gobject.threads_init()
|
||||
except:
|
||||
raise Exception('gobject could not be found')
|
||||
|
||||
try:
|
||||
import pygst
|
||||
pygst.require('0.10')
|
||||
import gst
|
||||
from gst.extend import discoverer
|
||||
except:
|
||||
raise Exception('gst/pygst 0.10 could not be found')
|
||||
|
||||
|
||||
class VideoThumbnailer:
|
||||
# Declaration of thumbnailer states
|
||||
STATE_NULL = 0
|
||||
STATE_HALTING = 1
|
||||
STATE_PROCESSING = 2
|
||||
|
||||
# The current thumbnailer state
|
||||
state = STATE_NULL
|
||||
|
||||
# This will contain the thumbnailing pipeline
|
||||
thumbnail_pipeline = None
|
||||
|
||||
buffer_probes = {}
|
||||
|
||||
errors = []
|
||||
|
||||
def __init__(self, source_path, dest_path):
|
||||
'''
|
||||
Set up playbin pipeline in order to get video properties.
|
||||
|
||||
Initializes and runs the gobject.MainLoop()
|
||||
'''
|
||||
self.source_path = source_path
|
||||
self.dest_path = dest_path
|
||||
|
||||
self.loop = gobject.MainLoop()
|
||||
|
||||
# Set up the playbin. It will be used to discover certain
|
||||
# properties of the input file
|
||||
self.playbin = gst.element_factory_make('playbin')
|
||||
|
||||
self.videosink = gst.element_factory_make('fakesink', 'videosink')
|
||||
self.playbin.set_property('video-sink', self.videosink)
|
||||
|
||||
self.audiosink = gst.element_factory_make('fakesink', 'audiosink')
|
||||
self.playbin.set_property('audio-sink', self.audiosink)
|
||||
|
||||
self.bus = self.playbin.get_bus()
|
||||
self.bus.add_signal_watch()
|
||||
self.watch_id = self.bus.connect('message', self._on_bus_message)
|
||||
|
||||
self.playbin.set_property('uri', 'file:{0}'.format(
|
||||
urllib.pathname2url(self.source_path)))
|
||||
|
||||
self.playbin.set_state(gst.STATE_PAUSED)
|
||||
|
||||
self.run()
|
||||
|
||||
def run(self):
|
||||
self.loop.run()
|
||||
|
||||
def _on_bus_message(self, bus, message):
|
||||
_log.debug(' BUS MESSAGE: {0}'.format(message))
|
||||
|
||||
if message.type == gst.MESSAGE_ERROR:
|
||||
gobject.idle_add(self._on_bus_error)
|
||||
|
||||
elif message.type == gst.MESSAGE_STATE_CHANGED:
|
||||
# The pipeline state has changed
|
||||
# Parse state changing data
|
||||
_prev, state, _pending = message.parse_state_changed()
|
||||
|
||||
_log.debug('State changed: {0}'.format(state))
|
||||
|
||||
if state == gst.STATE_PAUSED:
|
||||
if message.src == self.playbin:
|
||||
gobject.idle_add(self._on_bus_paused)
|
||||
|
||||
def _on_bus_paused(self):
|
||||
'''
|
||||
Set up thumbnailing pipeline
|
||||
'''
|
||||
current_video = self.playbin.get_property('current-video')
|
||||
|
||||
if current_video == 0:
|
||||
_log.debug('Found current video from playbin')
|
||||
else:
|
||||
_log.error('Could not get any current video from playbin!')
|
||||
|
||||
self.duration = self._get_duration(self.playbin)
|
||||
_log.info('Video length: {0}'.format(self.duration / gst.SECOND))
|
||||
|
||||
_log.info('Setting up thumbnailing pipeline')
|
||||
self.thumbnail_pipeline = gst.parse_launch(
|
||||
'filesrc location="{0}" ! decodebin ! '
|
||||
'ffmpegcolorspace ! videoscale ! '
|
||||
'video/x-raw-rgb,depth=24,bpp=24,pixel-aspect-ratio=1/1,width=180 ! '
|
||||
'fakesink signal-handoffs=True'.format(self.source_path))
|
||||
|
||||
self.thumbnail_bus = self.thumbnail_pipeline.get_bus()
|
||||
self.thumbnail_bus.add_signal_watch()
|
||||
self.thumbnail_watch_id = self.thumbnail_bus.connect(
|
||||
'message', self._on_thumbnail_bus_message)
|
||||
|
||||
self.thumbnail_pipeline.set_state(gst.STATE_PAUSED)
|
||||
|
||||
#gobject.timeout_add(3000, self._on_timeout)
|
||||
|
||||
return False
|
||||
|
||||
def _on_thumbnail_bus_message(self, bus, message):
|
||||
_log.debug('Thumbnail bus called, message: {0}'.format(message))
|
||||
|
||||
if message.type == gst.MESSAGE_ERROR:
|
||||
_log.error(message)
|
||||
gobject.idle_add(self._on_bus_error)
|
||||
|
||||
if message.type == gst.MESSAGE_STATE_CHANGED:
|
||||
_prev, state, _pending = message.parse_state_changed()
|
||||
|
||||
if (state == gst.STATE_PAUSED and
|
||||
not self.state == self.STATE_PROCESSING and
|
||||
message.src == self.thumbnail_pipeline):
|
||||
_log.info('Pipeline paused, processing')
|
||||
self.state = self.STATE_PROCESSING
|
||||
|
||||
for sink in self.thumbnail_pipeline.sinks():
|
||||
name = sink.get_name()
|
||||
factoryname = sink.get_factory().get_name()
|
||||
|
||||
if factoryname == 'fakesink':
|
||||
sinkpad = sink.get_pad('sink')
|
||||
|
||||
self.buffer_probes[name] = sinkpad.add_buffer_probe(
|
||||
self.buffer_probe_handler, name)
|
||||
|
||||
_log.info('Added buffer probe')
|
||||
|
||||
break
|
||||
|
||||
# Apply the wadsworth constant, fallback to 1 second
|
||||
seek_amount = max(self.duration / 100 * 30, 1 * gst.SECOND)
|
||||
|
||||
_log.debug('seek amount: {0}'.format(seek_amount))
|
||||
|
||||
seek_result = self.thumbnail_pipeline.seek(
|
||||
1.0,
|
||||
gst.FORMAT_TIME,
|
||||
gst.SEEK_FLAG_FLUSH | gst.SEEK_FLAG_ACCURATE,
|
||||
gst.SEEK_TYPE_SET,
|
||||
seek_amount,
|
||||
gst.SEEK_TYPE_NONE,
|
||||
0)
|
||||
|
||||
if not seek_result:
|
||||
self.errors.append('COULD_NOT_SEEK')
|
||||
_log.error('Couldn\'t seek! result: {0}'.format(
|
||||
seek_result))
|
||||
_log.info(message)
|
||||
self.shutdown()
|
||||
else:
|
||||
pass
|
||||
#self.thumbnail_pipeline.set_state(gst.STATE_PAUSED)
|
||||
#pdb.set_trace()
|
||||
|
||||
def buffer_probe_handler_real(self, pad, buff, name):
|
||||
'''
|
||||
Capture buffers as gdk_pixbufs when told to.
|
||||
'''
|
||||
try:
|
||||
caps = buff.caps
|
||||
if caps is None:
|
||||
_log.error('No caps passed to buffer probe handler!')
|
||||
self.shutdown()
|
||||
return False
|
||||
|
||||
_log.debug('caps: {0}'.format(caps))
|
||||
|
||||
filters = caps[0]
|
||||
width = filters["width"]
|
||||
height = filters["height"]
|
||||
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_data(
|
||||
buff.data, gtk.gdk.COLORSPACE_RGB, False, 8,
|
||||
width, height, width * 3)
|
||||
|
||||
# NOTE: 200x136 is sort of arbitrary. it's larger than what
|
||||
# the ui uses at the time of this writing.
|
||||
# new_width, new_height = scaled_size((width, height), (200, 136))
|
||||
|
||||
#pixbuf = pixbuf.scale_simple(
|
||||
#new_width, new_height, gtk.gdk.INTERP_BILINEAR)
|
||||
|
||||
pixbuf.save(self.dest_path, 'jpeg')
|
||||
_log.info('Saved thumbnail')
|
||||
del pixbuf
|
||||
self.shutdown()
|
||||
except gst.QueryError:
|
||||
pass
|
||||
return False
|
||||
|
||||
def buffer_probe_handler(self, pad, buff, name):
|
||||
'''
|
||||
Proxy function for buffer_probe_handler_real
|
||||
'''
|
||||
gobject.idle_add(
|
||||
lambda: self.buffer_probe_handler_real(pad, buff, name))
|
||||
|
||||
return True
|
||||
|
||||
def _get_duration(self, pipeline, retries=0):
|
||||
'''
|
||||
Get the duration of a pipeline.
|
||||
|
||||
Retries 5 times.
|
||||
'''
|
||||
if retries == 5:
|
||||
return 0
|
||||
|
||||
try:
|
||||
return pipeline.query_duration(gst.FORMAT_TIME)[0]
|
||||
except gst.QueryError:
|
||||
return self._get_duration(pipeline, retries + 1)
|
||||
|
||||
def _on_timeout(self):
|
||||
_log.error('TIMEOUT! DROP EVERYTHING!')
|
||||
self.shutdown()
|
||||
|
||||
def _on_bus_error(self, *args):
|
||||
_log.error('AHAHAHA! Error! args: {0}'.format(args))
|
||||
|
||||
def shutdown(self):
|
||||
'''
|
||||
Tell gobject to call __halt when the mainloop is idle.
|
||||
'''
|
||||
_log.info('Shutting down')
|
||||
self.__halt()
|
||||
|
||||
def __halt(self):
|
||||
'''
|
||||
Halt all pipelines and shut down the main loop
|
||||
'''
|
||||
_log.info('Halting...')
|
||||
self.state = self.STATE_HALTING
|
||||
|
||||
self.__disconnect()
|
||||
|
||||
gobject.idle_add(self.__halt_final)
|
||||
|
||||
def __disconnect(self):
|
||||
_log.debug('Disconnecting...')
|
||||
if not self.playbin is None:
|
||||
self.playbin.set_state(gst.STATE_NULL)
|
||||
for sink in self.playbin.sinks():
|
||||
name = sink.get_name()
|
||||
factoryname = sink.get_factory().get_name()
|
||||
|
||||
_log.debug('Disconnecting {0}'.format(name))
|
||||
|
||||
if factoryname == "fakesink":
|
||||
pad = sink.get_pad("sink")
|
||||
pad.remove_buffer_probe(self.buffer_probes[name])
|
||||
del self.buffer_probes[name]
|
||||
|
||||
self.playbin = None
|
||||
|
||||
if self.bus is not None:
|
||||
self.bus.disconnect(self.watch_id)
|
||||
self.bus = None
|
||||
|
||||
|
||||
def __halt_final(self):
|
||||
_log.info('Done')
|
||||
if self.errors:
|
||||
_log.error(','.join(self.errors))
|
||||
|
||||
self.loop.quit()
|
||||
|
||||
|
||||
class VideoTranscoder:
|
||||
'''
|
||||
Video transcoder
|
||||
|
||||
Transcodes the SRC video file to a VP8 WebM video file at DST
|
||||
|
||||
- Does the same thing as VideoThumbnailer, but produces a WebM vp8
|
||||
and vorbis video file.
|
||||
- The VideoTranscoder exceeds the VideoThumbnailer in the way
|
||||
that it was refined afterwards and therefore is done more
|
||||
correctly.
|
||||
'''
|
||||
def __init__(self, src, dst, **kwargs):
|
||||
_log.info('Initializing VideoTranscoder...')
|
||||
|
||||
self.loop = gobject.MainLoop()
|
||||
self.source_path = src
|
||||
self.destination_path = dst
|
||||
|
||||
# Options
|
||||
self.destination_dimensions = kwargs.get('dimensions') or (640, 640)
|
||||
self._progress_callback = kwargs.get('progress_callback') or None
|
||||
|
||||
if not type(self.destination_dimensions) == tuple:
|
||||
raise Exception('dimensions must be tuple: (width, height)')
|
||||
|
||||
self._setup()
|
||||
self._run()
|
||||
|
||||
def _setup(self):
|
||||
self._setup_discover()
|
||||
self._setup_pipeline()
|
||||
|
||||
def _run(self):
|
||||
_log.info('Discovering...')
|
||||
self.discoverer.discover()
|
||||
_log.info('Done')
|
||||
|
||||
_log.debug('Initializing MainLoop()')
|
||||
self.loop.run()
|
||||
|
||||
def _setup_discover(self):
|
||||
_log.debug('Setting up discoverer')
|
||||
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.__dict__))
|
||||
|
||||
self.data = data
|
||||
|
||||
# Launch things that should be done after discovery
|
||||
self._link_elements()
|
||||
self.__setup_videoscale_capsfilter()
|
||||
|
||||
# Tell the transcoding pipeline to start running
|
||||
self.pipeline.set_state(gst.STATE_PLAYING)
|
||||
_log.info('Transcoding...')
|
||||
|
||||
def _setup_pipeline(self):
|
||||
_log.debug('Setting up transcoding pipeline')
|
||||
# Create the pipeline bin.
|
||||
self.pipeline = gst.Pipeline('VideoTranscoderPipeline')
|
||||
|
||||
# Create all GStreamer elements, starting with
|
||||
# filesrc & decoder
|
||||
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)
|
||||
|
||||
# Video elements
|
||||
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)
|
||||
self.pipeline.add(self.videoscale)
|
||||
|
||||
self.capsfilter = gst.element_factory_make('capsfilter', 'capsfilter')
|
||||
self.pipeline.add(self.capsfilter)
|
||||
|
||||
self.vp8enc = gst.element_factory_make('vp8enc', 'vp8enc')
|
||||
self.vp8enc.set_property('quality', 6)
|
||||
self.vp8enc.set_property('threads', 2)
|
||||
self.pipeline.add(self.vp8enc)
|
||||
|
||||
# Audio elements
|
||||
self.audioqueue = gst.element_factory_make('queue', 'audioqueue')
|
||||
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')
|
||||
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', 1)
|
||||
self.pipeline.add(self.vorbisenc)
|
||||
|
||||
# WebMmux & filesink
|
||||
self.webmmux = gst.element_factory_make('webmmux', 'webmmux')
|
||||
self.pipeline.add(self.webmmux)
|
||||
|
||||
self.filesink = gst.element_factory_make('filesink', 'filesink')
|
||||
self.filesink.set_property('location', self.destination_path)
|
||||
self.pipeline.add(self.filesink)
|
||||
|
||||
# Progressreport
|
||||
self.progressreport = gst.element_factory_make(
|
||||
'progressreport', 'progressreport')
|
||||
# Update every second
|
||||
self.progressreport.set_property('update-freq', 1)
|
||||
self.progressreport.set_property('silent', True)
|
||||
self.pipeline.add(self.progressreport)
|
||||
|
||||
def _link_elements(self):
|
||||
'''
|
||||
Link all the elements
|
||||
|
||||
This code depends on data from the discoverer and is called
|
||||
from __discovered
|
||||
'''
|
||||
_log.debug('linking elements')
|
||||
# Link the filesrc element to the decoder. The decoder then emits
|
||||
# 'new-decoded-pad' which links decoded src pads to either a video
|
||||
# or audio sink
|
||||
self.filesrc.link(self.decoder)
|
||||
|
||||
# Link all the video elements in a row to webmmux
|
||||
gst.element_link_many(
|
||||
self.videoqueue,
|
||||
self.videorate,
|
||||
self.ffmpegcolorspace,
|
||||
self.videoscale,
|
||||
self.capsfilter,
|
||||
self.vp8enc,
|
||||
self.webmmux)
|
||||
|
||||
if self.data.is_audio:
|
||||
# Link all the audio elements in a row to webmux
|
||||
gst.element_link_many(
|
||||
self.audioqueue,
|
||||
self.audiorate,
|
||||
self.audioconvert,
|
||||
self.audiocapsfilter,
|
||||
self.vorbisenc,
|
||||
self.webmmux)
|
||||
|
||||
gst.element_link_many(
|
||||
self.webmmux,
|
||||
self.progressreport,
|
||||
self.filesink)
|
||||
|
||||
# Setup the message bus and connect _on_message to the pipeline
|
||||
self._setup_bus()
|
||||
|
||||
|
||||
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 self.ffmpegcolorspace.get_pad_template('sink')\
|
||||
.get_caps().intersect(pad.get_caps()).is_empty():
|
||||
# It is NOT a video src pad.
|
||||
pad.link(self.audioqueue.get_pad('sink'))
|
||||
else:
|
||||
# It IS a video src pad.
|
||||
pad.link(self.videoqueue.get_pad('sink'))
|
||||
|
||||
def _setup_bus(self):
|
||||
self.bus = self.pipeline.get_bus()
|
||||
self.bus.add_signal_watch()
|
||||
self.bus.connect('message', self._on_message)
|
||||
|
||||
def __setup_videoscale_capsfilter(self):
|
||||
'''
|
||||
Sets up the output format (width, height) for the video
|
||||
'''
|
||||
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!
|
||||
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 _on_message(self, bus, message):
|
||||
_log.debug((bus, message, message.type))
|
||||
|
||||
t = message.type
|
||||
|
||||
if t == gst.MESSAGE_EOS:
|
||||
self._discover_dst_and_stop()
|
||||
_log.info('Done')
|
||||
|
||||
elif t == gst.MESSAGE_ELEMENT:
|
||||
if message.structure.get_name() == 'progress':
|
||||
data = dict(message.structure)
|
||||
|
||||
if self._progress_callback:
|
||||
self._progress_callback(data)
|
||||
|
||||
_log.info('{percent}% done...'.format(
|
||||
percent=data.get('percent')))
|
||||
_log.debug(data)
|
||||
|
||||
elif t == gst.MESSAGE_ERROR:
|
||||
_log.error((bus, message))
|
||||
self.__stop()
|
||||
|
||||
def _discover_dst_and_stop(self):
|
||||
self.dst_discoverer = discoverer.Discoverer(self.destination_path)
|
||||
|
||||
self.dst_discoverer.connect('discovered', self.__dst_discovered)
|
||||
|
||||
self.dst_discoverer.discover()
|
||||
|
||||
|
||||
def __dst_discovered(self, data, is_media):
|
||||
self.dst_data = data
|
||||
|
||||
self.__stop()
|
||||
|
||||
def __stop(self):
|
||||
_log.debug(self.loop)
|
||||
|
||||
# Stop executing the pipeline
|
||||
self.pipeline.set_state(gst.STATE_NULL)
|
||||
|
||||
# This kills the loop, mercifully
|
||||
gobject.idle_add(self.__stop_mainloop)
|
||||
|
||||
def __stop_mainloop(self):
|
||||
'''
|
||||
Wrapper for gobject.MainLoop.quit()
|
||||
|
||||
This wrapper makes us able to see if self.loop.quit has been called
|
||||
'''
|
||||
_log.info('Terminating MainLoop')
|
||||
|
||||
self.loop.quit()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
os.nice(19)
|
||||
from optparse import OptionParser
|
||||
|
||||
parser = OptionParser(
|
||||
usage='%prog [-v] -a [ video | thumbnail ] SRC DEST')
|
||||
|
||||
parser.add_option('-a', '--action',
|
||||
dest='action',
|
||||
help='One of "video" or "thumbnail"')
|
||||
|
||||
parser.add_option('-v',
|
||||
dest='verbose',
|
||||
action='store_true',
|
||||
help='Output debug information')
|
||||
|
||||
parser.add_option('-q',
|
||||
dest='quiet',
|
||||
action='store_true',
|
||||
help='Dear program, please be quiet unless *error*')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.verbose:
|
||||
_log.setLevel(logging.DEBUG)
|
||||
else:
|
||||
_log.setLevel(logging.INFO)
|
||||
|
||||
if options.quiet:
|
||||
_log.setLevel(logging.ERROR)
|
||||
|
||||
_log.debug(args)
|
||||
|
||||
if not len(args) == 2:
|
||||
parser.print_help()
|
||||
sys.exit()
|
||||
|
||||
if options.action == 'thumbnail':
|
||||
VideoThumbnailer(*args)
|
||||
elif options.action == 'video':
|
||||
def cb(data):
|
||||
print('I\'m a callback!')
|
||||
transcoder = VideoTranscoder(*args, progress_callback=cb)
|
@ -1,45 +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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
|
||||
|
||||
|
||||
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.')
|
143
mediagoblin/processing.py
Normal file
143
mediagoblin/processing.py
Normal file
@ -0,0 +1,143 @@
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
from celery.task import Task
|
||||
|
||||
from mediagoblin.db.util import ObjectId
|
||||
from mediagoblin import mg_globals as mgg
|
||||
|
||||
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
|
||||
|
||||
from mediagoblin.media_types import get_media_manager
|
||||
|
||||
|
||||
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])
|
||||
|
||||
|
||||
################################
|
||||
# Media processing initial steps
|
||||
################################
|
||||
|
||||
class ProcessMedia(Task):
|
||||
"""
|
||||
DEPRECATED -- This now resides in the individual media plugins
|
||||
|
||||
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:
|
||||
#__import__(entry['media_type'])
|
||||
manager = get_media_manager(entry['media_type'])
|
||||
manager['processor'](entry)
|
||||
except BaseProcessingFail, exc:
|
||||
mark_entry_failed(entry._id, exc)
|
||||
return
|
||||
except ImportError, exc:
|
||||
mark_entry_failed(entry[u'_id'], exc)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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': {}}})
|
||||
|
||||
|
||||
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.')
|
BIN
mediagoblin/static/images/media_thumbs/video.jpg
Normal file
BIN
mediagoblin/static/images/media_thumbs/video.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.1 KiB |
@ -98,8 +98,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([
|
||||
|
@ -19,6 +19,8 @@ import uuid
|
||||
from os.path import splitext
|
||||
from cgi import FieldStorage
|
||||
|
||||
from celery import registry
|
||||
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
from mediagoblin.db.util import ObjectId
|
||||
@ -27,8 +29,9 @@ from mediagoblin.tools.translate import pass_to_ugettext as _
|
||||
from mediagoblin.tools.response import render_to_response, redirect
|
||||
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.processing import mark_entry_failed, ProcessMedia
|
||||
from mediagoblin.messages import add_message, SUCCESS
|
||||
from mediagoblin.media_types import get_media_type_and_manager, InvalidFileType
|
||||
|
||||
|
||||
@require_active_login
|
||||
@ -44,86 +47,90 @@ 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
|
||||
|
||||
# create entry and save in database
|
||||
entry = request.db.MediaEntry()
|
||||
entry['_id'] = ObjectId()
|
||||
entry['title'] = (
|
||||
unicode(request.POST['title'])
|
||||
or unicode(splitext(filename)[0]))
|
||||
|
||||
entry['description'] = unicode(request.POST.get('description'))
|
||||
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"
|
||||
entry['tags'] = convert_to_tag_list_of_dicts(
|
||||
request.POST.get('tags'))
|
||||
|
||||
# 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',
|
||||
unicode(entry._id),
|
||||
secure_filename(filename)])
|
||||
|
||||
# queue appropriately
|
||||
queue_file = request.app.queue_store.get_file(
|
||||
queue_filepath, 'wb')
|
||||
|
||||
with queue_file:
|
||||
queue_file.write(request.POST['file'].file.read())
|
||||
|
||||
# Add queued filename to the entry
|
||||
entry['queued_media_file'] = queue_filepath
|
||||
|
||||
# We generate this ourselves so we know what the taks id is for
|
||||
# retrieval later.
|
||||
|
||||
# (If we got it off the task's auto-generation, there'd be
|
||||
# a risk of a race condition when we'd save after sending
|
||||
# off the task)
|
||||
task_id = unicode(uuid.uuid4())
|
||||
entry['queued_task_id'] = task_id
|
||||
|
||||
# Save now so we have this data before kicking off processing
|
||||
entry.save(validate=True)
|
||||
|
||||
# Pass off to processing
|
||||
#
|
||||
# (... don't change entry after this point to avoid race
|
||||
# conditions with changes to the document via processing code)
|
||||
try:
|
||||
process_media.apply_async(
|
||||
[unicode(entry._id)], {},
|
||||
task_id=task_id)
|
||||
except BaseException as exc:
|
||||
# The purpose of this section is because when running in "lazy"
|
||||
# or always-eager-with-exceptions-propagated celery mode that
|
||||
# the failure handling won't happen on Celery end. Since we
|
||||
# expect a lot of users to run things in this way we have to
|
||||
# capture stuff here.
|
||||
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]))
|
||||
|
||||
entry['description'] = unicode(request.POST.get('description'))
|
||||
entry['description_html'] = cleaned_markdown_conversion(
|
||||
entry['description'])
|
||||
|
||||
entry['uploader'] = request.user['_id']
|
||||
|
||||
# Process the user's folksonomy "tags"
|
||||
entry['tags'] = convert_to_tag_list_of_dicts(
|
||||
request.POST.get('tags'))
|
||||
|
||||
# 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',
|
||||
unicode(entry._id),
|
||||
secure_filename(filename)])
|
||||
|
||||
# queue appropriately
|
||||
queue_file = request.app.queue_store.get_file(
|
||||
queue_filepath, 'wb')
|
||||
|
||||
with queue_file:
|
||||
queue_file.write(request.POST['file'].file.read())
|
||||
|
||||
# Add queued filename to the entry
|
||||
entry['queued_media_file'] = queue_filepath
|
||||
|
||||
# We generate this ourselves so we know what the taks id is for
|
||||
# retrieval later.
|
||||
|
||||
# (If we got it off the task's auto-generation, there'd be
|
||||
# a risk of a race condition when we'd save after sending
|
||||
# off the task)
|
||||
task_id = unicode(uuid.uuid4())
|
||||
entry['queued_task_id'] = task_id
|
||||
|
||||
# Save now so we have this data before kicking off processing
|
||||
entry.save(validate=True)
|
||||
|
||||
# Pass off to processing
|
||||
#
|
||||
# ... not completely the diaper pattern because the
|
||||
# exception is re-raised :)
|
||||
mark_entry_failed(entry._id, exc)
|
||||
# re-raise the exception
|
||||
raise
|
||||
# (... don't change entry after this point to avoid race
|
||||
# conditions with changes to the document via processing code)
|
||||
process_media = registry.tasks[ProcessMedia.name]
|
||||
try:
|
||||
process_media.apply_async(
|
||||
[unicode(entry._id)], {},
|
||||
task_id=task_id)
|
||||
except BaseException as exc:
|
||||
# The purpose of this section is because when running in "lazy"
|
||||
# or always-eager-with-exceptions-propagated celery mode that
|
||||
# the failure handling won't happen on Celery end. Since we
|
||||
# expect a lot of users to run things in this way we have to
|
||||
# capture stuff here.
|
||||
#
|
||||
# ... not completely the diaper pattern because the
|
||||
# exception is re-raised :)
|
||||
mark_entry_failed(entry._id, exc)
|
||||
# re-raise the exception
|
||||
raise
|
||||
|
||||
add_message(request, SUCCESS, _('Woohoo! Submitted!'))
|
||||
add_message(request, SUCCESS, _('Woohoo! Submitted!'))
|
||||
|
||||
return redirect(request, "mediagoblin.user_pages.user_home",
|
||||
user=request.user['username'])
|
||||
return redirect(request, "mediagoblin.user_pages.user_home",
|
||||
user=request.user['username'])
|
||||
except InvalidFileType, exc:
|
||||
submit_form.file.errors.append(
|
||||
_(u'Invalid file type.'))
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
|
@ -28,8 +28,15 @@
|
||||
href="{{ request.staticdirect('/css/extlib/960_16_col.css') }}"/>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ request.staticdirect('/css/base.css') }}"/>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="{{ request.staticdirect('/css/video-js.css') }}"/>
|
||||
<link rel="shortcut icon"
|
||||
href="{{ request.staticdirect('/images/goblin.ico') }}" />
|
||||
<script type="text/javascript"
|
||||
src="{{ request.staticdirect('/js/lib/video.js') }}"></script>
|
||||
<script type="text/javascript"
|
||||
src="{{ request.staticdirect('/js/video.js') }}"></script>
|
||||
<script type="text/javascript" src="http://html5.kaltura.org/js" > </script>
|
||||
{% block mediagoblin_head %}
|
||||
{% endblock mediagoblin_head %}
|
||||
</head>
|
||||
|
@ -0,0 +1 @@
|
||||
{% extends 'mediagoblin/user_pages/media.html' %}
|
25
mediagoblin/templates/mediagoblin/media_displays/video.html
Normal file
25
mediagoblin/templates/mediagoblin/media_displays/video.html
Normal file
@ -0,0 +1,25 @@
|
||||
{% extends 'mediagoblin/user_pages/media.html' %}
|
||||
{% block mediagoblin_media %}
|
||||
<div class="video-player" style="position: relative;">
|
||||
<video class="video-js vjs-default-skin"
|
||||
width="{{ media.media_data.video.width }}"
|
||||
height="{{ media.media_data.video.height }}"
|
||||
controls="controls"
|
||||
preload="auto"
|
||||
data-setup="">
|
||||
<source src="{{ request.app.public_store.file_url(
|
||||
media['media_files']['webm_640']) }}"
|
||||
type="video/webm; codecs="vp8, vorbis"" />
|
||||
</video>
|
||||
</div>
|
||||
{% if 'original' in media.media_files %}
|
||||
<p>
|
||||
<a href="{{ request.app.public_store.file_url(
|
||||
media['media_files']['original']) }}">
|
||||
{%- trans -%}
|
||||
Original
|
||||
{%- endtrans -%}
|
||||
</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
@ -26,24 +26,26 @@
|
||||
{% if media %}
|
||||
<div class="grid_11 alpha">
|
||||
<div class="media_image_container">
|
||||
{% set display_media = request.app.public_store.file_url(
|
||||
media.get_display_media(media.media_files)) %}
|
||||
{% block mediagoblin_media %}
|
||||
{% set display_media = request.app.public_store.file_url(
|
||||
media.get_display_media(media.media_files)) %}
|
||||
|
||||
{# if there's a medium file size, that means the medium size
|
||||
# isn't the original... so link to the original!
|
||||
#}
|
||||
{% if media['media_files'].has_key('medium') %}
|
||||
<a href="{{ request.app.public_store.file_url(
|
||||
media['media_files']['original']) }}">
|
||||
{# if there's a medium file size, that means the medium size
|
||||
# isn't the original... so link to the original!
|
||||
#}
|
||||
{% if media['media_files'].has_key('medium') %}
|
||||
<a href="{{ request.app.public_store.file_url(
|
||||
media['media_files']['original']) }}">
|
||||
<img class="media_image"
|
||||
src="{{ display_media }}"
|
||||
alt="Image for {{ media.title }}" />
|
||||
</a>
|
||||
{% else %}
|
||||
<img class="media_image"
|
||||
src="{{ display_media }}"
|
||||
alt="Image for {{ media.title }}" />
|
||||
</a>
|
||||
{% else %}
|
||||
<img class="media_image"
|
||||
src="{{ display_media }}"
|
||||
alt="Image for {{ media.title }}" />
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
<h2 class="media_title">
|
||||
|
@ -50,7 +50,7 @@ def test_setup_celery_from_config():
|
||||
assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float)
|
||||
assert fake_celery_module.CELERY_RESULT_PERSISTENT is True
|
||||
assert fake_celery_module.CELERY_IMPORTS == [
|
||||
'foo.bar.baz', 'this.is.an.import', 'mediagoblin.process_media']
|
||||
'foo.bar.baz', 'this.is.an.import', 'mediagoblin.processing']
|
||||
assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == {
|
||||
'database': 'mediagoblin'}
|
||||
assert fake_celery_module.CELERY_RESULT_BACKEND == 'mongodb'
|
||||
@ -74,7 +74,7 @@ def test_setup_celery_from_config():
|
||||
assert isinstance(fake_celery_module.CELERYD_ETA_SCHEDULER_PRECISION, float)
|
||||
assert fake_celery_module.CELERY_RESULT_PERSISTENT is False
|
||||
assert fake_celery_module.CELERY_IMPORTS == [
|
||||
'baz.bar.foo', 'import.is.a.this', 'mediagoblin.process_media']
|
||||
'baz.bar.foo', 'import.is.a.this', 'mediagoblin.processing']
|
||||
assert fake_celery_module.CELERY_MONGODB_BACKEND_SETTINGS == {
|
||||
'database': 'captain_lollerskates',
|
||||
'host': 'mongodb.example.org',
|
||||
|
@ -222,7 +222,7 @@ class TestSubmission:
|
||||
|
||||
context = template.TEMPLATE_TEST_CONTEXT['mediagoblin/submit/start.html']
|
||||
form = context['submit_form']
|
||||
assert form.file.errors == ['The file doesn\'t seem to be an image!']
|
||||
assert form.file.errors == [u'Invalid file type.']
|
||||
|
||||
# NOTE: The following 2 tests will ultimately fail, but they
|
||||
# *will* pass the initial form submission step. Instead,
|
||||
@ -246,7 +246,7 @@ class TestSubmission:
|
||||
assert_equal(entry['state'], 'failed')
|
||||
assert_equal(
|
||||
entry['fail_error'],
|
||||
u'mediagoblin.process_media.errors:BadMediaFail')
|
||||
u'mediagoblin.processing:BadMediaFail')
|
||||
|
||||
# Test non-supported file with .png extension
|
||||
# -------------------------------------------
|
||||
@ -266,4 +266,4 @@ class TestSubmission:
|
||||
assert_equal(entry['state'], 'failed')
|
||||
assert_equal(
|
||||
entry['fail_error'],
|
||||
u'mediagoblin.process_media.errors:BadMediaFail')
|
||||
u'mediagoblin.processing:BadMediaFail')
|
||||
|
@ -30,6 +30,8 @@ from mediagoblin.decorators import (uses_pagination, get_user_media_entry,
|
||||
|
||||
from werkzeug.contrib.atom import AtomFeed
|
||||
|
||||
from mediagoblin.media_types import get_media_manager
|
||||
|
||||
|
||||
@uses_pagination
|
||||
def user_home(request, page):
|
||||
@ -120,9 +122,11 @@ def media_home(request, media, page, **kwargs):
|
||||
|
||||
comment_form = user_forms.MediaCommentForm(request.POST)
|
||||
|
||||
media_template_name = get_media_manager(media['media_type'])['display_template']
|
||||
|
||||
return render_to_response(
|
||||
request,
|
||||
'mediagoblin/user_pages/media.html',
|
||||
media_template_name,
|
||||
{'media': media,
|
||||
'comments': comments,
|
||||
'pagination': pagination,
|
||||
|
@ -14,11 +14,15 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
|
||||
from mediagoblin import mg_globals
|
||||
from mediagoblin.tools.pagination import Pagination
|
||||
from mediagoblin.tools.response import render_to_response
|
||||
from mediagoblin.db.util import DESCENDING
|
||||
from mediagoblin.decorators import uses_pagination
|
||||
from mediagoblin import media_types
|
||||
|
||||
|
||||
|
||||
@uses_pagination
|
||||
@ -28,12 +32,12 @@ def root_view(request, page):
|
||||
|
||||
pagination = Pagination(page, cursor)
|
||||
media_entries = pagination()
|
||||
|
||||
return render_to_response(
|
||||
request, 'mediagoblin/root.html',
|
||||
{'media_entries': media_entries,
|
||||
'allow_registration': mg_globals.app_config["allow_registration"],
|
||||
'pagination': pagination})
|
||||
'pagination': pagination,
|
||||
'sys': sys})
|
||||
|
||||
|
||||
def simple_template_render(request):
|
||||
|
@ -47,7 +47,10 @@ class Workbench(object):
|
||||
return str(self.dir)
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.dir)
|
||||
try:
|
||||
return str(self)
|
||||
except AttributeError:
|
||||
return 'None'
|
||||
|
||||
def joinpath(self, *args):
|
||||
return os.path.join(self.dir, *args)
|
||||
|
Loading…
x
Reference in New Issue
Block a user