-
Notifications
You must be signed in to change notification settings - Fork 0
/
__init__.py
163 lines (134 loc) · 5.74 KB
/
__init__.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# GNU MediaGoblin -- federated, autonomous media hosting
# Copyright (C) 2011, 2012 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 logging
import shutil
import tempfile
from mediagoblin.tools.pluginapi import hook_handle
from mediagoblin.tools.translate import lazy_pass_to_ugettext as _
_log = logging.getLogger(__name__)
class FileTypeNotSupported(Exception):
pass
class TypeNotFound(FileTypeNotSupported):
'''Raised if no mediagoblin plugin supporting this file type was found'''
pass
class MissingComponents(FileTypeNotSupported):
'''Raised if plugin found, but it can't process the file for some reason'''
pass
class MediaManagerBase(object):
"Base class for all media managers"
# Please override in actual media managers
media_fetch_order = None
@staticmethod
def sniff_handler(*args, **kwargs):
return False
def __init__(self, entry):
self.entry = entry
def __getitem__(self, i):
return getattr(self, i)
def __contains__(self, i):
return hasattr(self, i)
def sniff_media_contents(media_file, filename):
'''
Check media contents using 'expensive' scanning. For example, for video it
is checking the contents using gstreamer
:param media_file: file-like object with 'name' attribute
:param filename: expected filename of the media
'''
media_type = hook_handle('sniff_handler', media_file, filename)
if media_type:
_log.info('{0} accepts the file'.format(media_type))
return media_type, hook_handle(('media_manager', media_type))
else:
_log.debug('{0} did not accept the file'.format(media_type))
raise FileTypeNotSupported(
# TODO: Provide information on which file types are supported
_(u'Sorry, I don\'t support that file type :('))
def get_media_type_and_manager(filename):
'''
Try to find the media type based on the file name, extension
specifically. This is used as a speedup, the sniffing functionality
then falls back on more in-depth bitsniffing of the source file.
This hook is deprecated, 'type_match_handler' should be used instead
'''
if os.path.basename(filename).find('.') > 0:
# Get the file extension
ext = os.path.splitext(filename)[1].lower()
# Omit the dot from the extension and match it against
# the media manager
if hook_handle('get_media_type_and_manager', ext[1:]):
return hook_handle('get_media_type_and_manager', ext[1:])
else:
_log.info('File {0} has no file extension, let\'s hope the sniffers get it.'.format(
filename))
raise TypeNotFound(
_(u'Sorry, I don\'t support that file type :('))
def type_match_handler(media_file, filename):
'''Check media file by name and then by content
Try to find the media type based on the file name, extension
specifically. After that, if media type is one of supported ones, check the
contents of the file
'''
if os.path.basename(filename).find('.') > 0:
# Get the file extension
ext = os.path.splitext(filename)[1].lower()
# Omit the dot from the extension and match it against
# the media manager
hook_result = hook_handle('type_match_handler', ext[1:])
if hook_result:
_log.info('Info about file found, checking further')
MEDIA_TYPE, Manager, sniffer = hook_result
if not sniffer:
_log.debug('sniffer is None, plugin trusts the extension')
return MEDIA_TYPE, Manager
_log.info('checking the contents with sniffer')
try:
sniffer(media_file)
_log.info('checked, found')
return MEDIA_TYPE, Manager
except Exception as e:
_log.info('sniffer says it will not accept the file')
_log.debug(e)
raise
else:
_log.info('No plugins handled extension {0}'.format(ext))
else:
_log.info('File {0} has no known file extension, let\'s hope '
'the sniffers get it.'.format(filename))
raise TypeNotFound(_(u'Sorry, I don\'t support that file type :('))
def sniff_media(media_file, filename):
'''
Iterate through the enabled media types and find those suited
for a certain file.
'''
# copy the contents to a .name-enabled temporary file for further checks
# TODO: there are cases when copying is not required
tmp_media_file = tempfile.NamedTemporaryFile()
shutil.copyfileobj(media_file, tmp_media_file)
media_file.seek(0)
tmp_media_file.seek(0)
try:
return type_match_handler(tmp_media_file, filename)
except TypeNotFound as e:
_log.info('No plugins using two-step checking found')
# keep trying, using old `get_media_type_and_manager`
try:
return get_media_type_and_manager(filename)
except TypeNotFound as e:
# again, no luck. Do it expensive way
_log.info('No media handler found by file extension')
_log.info('Doing it the expensive way...')
return sniff_media_contents(tmp_media_file, filename)