1
# Miro - an RSS based video player application
2
# Copyright (C) 2005-2010 Participatory Culture Foundation
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
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 General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
# In addition, as a special exception, the copyright holders give
19
# permission to link the code of portions of this program with the OpenSSL
22
# You must obey the GNU General Public License in all respects for all of
23
# the code used other than OpenSSL. If you modify file(s) with this
24
# exception, you may extend this exception to your version of the file(s),
25
# but you are not obligated to do so. If you do not wish to do so, delete
26
# this exception statement from your version. If you delete this exception
27
# statement from all source files in the program, then also delete it here.
29
"""``miro.filetypes`` - functions for determining things from the
30
filename, enclosure, content-type, and other things.
35
# NOTE: if you change VIDEO_EXTENSIONS or AUDIO_EXTENSIONS, consider writing a
36
# database update so that the file_type attribute of the item table gets fixed
38
VIDEO_EXTENSIONS = ['.mov', '.wmv', '.mp4', '.m4v', '.ogv', '.anx',
39
'.mpg', '.avi', '.flv', '.mpeg', '.divx', '.xvid',
40
'.rmvb', '.mkv', '.m2v', '.ogm']
41
AUDIO_EXTENSIONS = ['.mp3', '.m4a', '.wma', '.mka', '.flac', '.ogg']
42
FEED_EXTENSIONS = ['.xml', '.rss', '.atom']
43
OTHER_EXTENSIONS = ['.pdf', '.txt', '.html', '.doc', '.bmp', '.gif', '.jpg',
44
'.jpeg', '.png', '.psd', '.tif', '.tiff',]
45
SUBTITLES_EXTENSIONS = ['.srt', '.sub', '.ass', '.ssa', '.smil', '.cmml']
48
UNSUPPORTED_MIMETYPES = ("video/3gpp", "video/vnd.rn-realvideo",
52
'video/quicktime': ['.mov'],
53
'video/mpeg': ['.mpeg', '.mpg', '.m2v'],
54
'video/mp4': ['.mp4', '.m4v'],
55
'video/mpeg4': ['.mp4', '.m4v'],
56
'video/flv': ['.flv'],
57
'video/x-flv': ['.flv'],
58
'video/x-ms-wmv': ['.wmv'],
59
'video/x-msvideo': ['.avi'],
60
'video/x-matroska': ['.mkv'],
61
'application/ogg': ['.ogg'],
62
'video/ogg': ['.ogv'],
64
'audio/flac': ['.flac'],
65
'audio/mpeg': ['.mp3'],
66
'audio/mp4': ['.m4a'],
67
'audio/x-ms-wma': ['.wma'],
68
'audio/x-matroska': ['.mka'],
70
'application/x-bittorrent': ['.torrent']
73
EXT_MIMETYPES_MAP = {}
74
for (mimetype, exts) in MIMETYPES_EXT_MAP.iteritems():
76
if ext not in EXT_MIMETYPES_MAP:
77
EXT_MIMETYPES_MAP[ext] = list()
78
EXT_MIMETYPES_MAP[ext].append(mimetype)
80
def is_allowed_mimetype(mimetype):
82
Pass a mimetype to this method and it will return a boolean
83
saying if the mimetype is something Miro can handle.
85
return (mimetype in MIMETYPES_EXT_MAP.keys())
87
def is_allowed_filename(filename):
89
Pass a filename to this method and it will return a boolean
90
saying if the filename represents video, audio or torrent.
92
return (is_video_filename(filename)
93
or is_audio_filename(filename)
94
or is_torrent_filename(filename))
96
def is_playable_filename(filename):
98
Pass a filename to this method and it will return a boolean
99
saying if the filename represents video or audio.
101
return is_video_filename(filename) or is_audio_filename(filename)
103
def _check_filename(filename, extension_list):
106
filename = filename.lower()
107
for ext in extension_list:
108
if filename.endswith(ext):
112
def is_video_filename(filename):
114
Pass a filename to this method and it will return a boolean
115
saying if the filename represents a video file.
117
return _check_filename(filename, VIDEO_EXTENSIONS)
119
def is_audio_filename(filename):
121
Pass a filename to this method and it will return a boolean
122
saying if the filename represents an audio file.
124
return _check_filename(filename, AUDIO_EXTENSIONS)
126
def is_other_filename(filename):
128
Pass a filename to this method and it will return a boolean
129
saying if the filename represents a non-audio, non-video file.
131
return _check_filename(filename, OTHER_EXTENSIONS)
133
def is_media_filename(filename):
134
"""Check if a filename is a video or audio filename"""
135
return is_video_filename(filename) or is_audio_filename(filename)
137
def is_torrent_filename(filename):
139
Pass a filename to this method and it will return a boolean
140
saying if the filename represents a torrent file.
142
return _check_filename(filename, ['.torrent'])
144
def is_feed_filename(filename):
146
Pass a filename to this method and it will return a boolean saying if the
147
filename possibly represents an Atom or RSS feed URL.
149
return _check_filename(filename, FEED_EXTENSIONS)
151
def is_subtitle_filename(filename):
153
Pass a filename to this method and it will return a boolean saying if the
154
filename possibly represents a sidecar subtitle file.
156
return _check_filename(filename, SUBTITLES_EXTENSIONS)
158
def is_video_enclosure(enclosure):
160
Pass an enclosure dictionary to this method and it will return a boolean
161
saying if the enclosure is a video or not.
163
return (_has_video_type(enclosure)
164
or _has_video_extension(enclosure, 'url')
165
or _has_video_extension(enclosure, 'href'))
167
def _has_video_type(enclosure):
168
return ('type' in enclosure
169
and (enclosure['type'].startswith(u'video/')
170
or enclosure['type'].startswith(u'audio/')
171
or enclosure['type'] == u"application/ogg"
172
or enclosure['type'] == u"application/x-annodex"
173
or enclosure['type'] == u"application/x-bittorrent"
174
or enclosure['type'] == u"application/x-shockwave-flash")
175
and (enclosure['type'] not in UNSUPPORTED_MIMETYPES))
177
def _has_video_extension(enclosure, key):
178
from miro import download_utils
180
elems = download_utils.parse_url(enclosure[key], split_path=True)
181
return is_allowed_filename(elems[3])
184
def is_feed_content_type(content_type):
185
"""Is a content-type for a RSS feed?"""
187
feed_types = [u'application/rdf+xml', u'application/atom+xml',
188
u'application/rss+xml', u'application/podcast+xml',
189
u'text/xml', u'application/xml',
191
for type_ in feed_types:
192
if content_type.startswith(type_):
196
def is_maybe_feed_content_type(content_type):
197
"""Could the content type contain a feed?
199
return content_type.startswith(u"text/")
201
def is_maybe_rss(body):
202
"""Sniffs the body to determine whether it's a feed or not.
204
this is very loosely taken from Firefox nsFeedSniffer.cpp and ideas in
205
http://blogs.msdn.com/rssteam/articles/PublishersGuide.aspx
210
for mem in ("<rss", "<feed", "<rdf:RDF"):
211
if body.find(mem) != -1:
215
def is_maybe_rss_url(url):
216
return (url.startswith("http")
217
and (url.startswith("http://feeds.feedburner.com")
220
def guess_extension(mimetype):
222
Pass a mime type to this method and it will return a corresponding
223
file extension, or None if it doesn't know about the type.
225
possible_extensions = MIMETYPES_EXT_MAP.get(mimetype)
226
if possible_extensions is None:
228
return possible_extensions[0]
230
def guess_mime_type(filename):
232
Pass a filename to this method and it will return a corresponding
233
mime type, or 'video/unknown' if the filename has a known video
234
extension but no corresponding mime type, or None if it doesn't
235
know about the file extension.
237
root, ext = os.path.splitext(filename)
238
possible_types = EXT_MIMETYPES_MAP.get(ext)
239
if possible_types is None:
240
if is_video_filename(filename):
241
return 'video/unknown'
242
elif is_audio_filename(filename):
243
return 'audio/unknown'
246
return possible_types[0]