First step towards a MediaManager class: Compat one.
[mediagoblin.git] / mediagoblin / media_types / __init__.py
1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
3 #
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
13 #
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17 import os
18 import sys
19 import logging
20 import tempfile
21
22 from mediagoblin import mg_globals
23 from mediagoblin.tools.common import import_component
24 from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
25
26 _log = logging.getLogger(__name__)
27
28 class FileTypeNotSupported(Exception):
29 pass
30
31 class InvalidFileType(Exception):
32 pass
33
34
35 class CompatMediaManager(object):
36 def __init__(self, mm_dict, entry=None):
37 self.mm_dict = mm_dict
38 self.entry = entry
39
40 def __call__(self, entry):
41 "So this object can look like a class too, somehow"
42 assert self.entry is None
43 return self.__class__(self.mm_dict, entry)
44
45 def __getitem__(self, i):
46 return self.mm_dict[i]
47
48 def __contains__(self, i):
49 return (i in self.mm_dict)
50
51 def get(self, *args, **kwargs):
52 return self.mm_dict.get(*args, **kwargs)
53
54 def __getattr__(self, i):
55 return self.mm_dict[i]
56
57
58 def sniff_media(media):
59 '''
60 Iterate through the enabled media types and find those suited
61 for a certain file.
62 '''
63
64 try:
65 return get_media_type_and_manager(media.filename)
66 except FileTypeNotSupported:
67 _log.info('No media handler found by file extension. Doing it the expensive way...')
68 # Create a temporary file for sniffers suchs as GStreamer-based
69 # Audio video
70 media_file = tempfile.NamedTemporaryFile()
71 media_file.write(media.stream.read())
72 media.stream.seek(0)
73
74 for media_type, manager in get_media_managers():
75 _log.info('Sniffing {0}'.format(media_type))
76 if 'sniff_handler' in manager and \
77 manager['sniff_handler'](media_file, media=media):
78 _log.info('{0} accepts the file'.format(media_type))
79 return media_type, manager
80 else:
81 _log.debug('{0} did not accept the file'.format(media_type))
82
83 raise FileTypeNotSupported(
84 # TODO: Provide information on which file types are supported
85 _(u'Sorry, I don\'t support that file type :('))
86
87
88 def get_media_types():
89 """
90 Generator, yields the available media types
91 """
92 for media_type in mg_globals.app_config['media_types']:
93 yield media_type
94
95
96 def get_media_managers():
97 '''
98 Generator, yields all enabled media managers
99 '''
100 for media_type in get_media_types():
101 mm = import_component(media_type + ":MEDIA_MANAGER")
102
103 if isinstance(mm, dict):
104 mm = CompatMediaManager(mm)
105
106 yield media_type, mm
107
108
109 def get_media_type_and_manager(filename):
110 '''
111 Try to find the media type based on the file name, extension
112 specifically. This is used as a speedup, the sniffing functionality
113 then falls back on more in-depth bitsniffing of the source file.
114 '''
115 if filename.find('.') > 0:
116 # Get the file extension
117 ext = os.path.splitext(filename)[1].lower()
118
119 for media_type, manager in get_media_managers():
120 # Omit the dot from the extension and match it against
121 # the media manager
122 if ext[1:] in manager['accepted_extensions']:
123 return media_type, manager
124 else:
125 _log.info('File {0} has no file extension, let\'s hope the sniffers get it.'.format(
126 filename))
127
128 raise FileTypeNotSupported(
129 _(u'Sorry, I don\'t support that file type :('))