source: trunk/src/testing/app/FileViewer/FileServer/misc/mmpython/mediainfo.py @ 4

Revision 4, 13.3 KB checked in by ajaworski, 13 years ago (diff)

Added modified SAGE sources

Line 
1#if 0
2# -----------------------------------------------------------------------
3# $Id: mediainfo.py,v 1.68.2.1 2005/05/07 11:37:08 dischi Exp $
4# -----------------------------------------------------------------------
5# $Log: mediainfo.py,v $
6# Revision 1.68.2.1  2005/05/07 11:37:08  dischi
7# make sure all strings are unicode
8#
9# Revision 1.68  2005/04/16 15:01:15  dischi
10# convert exif tags to str
11#
12# Revision 1.67  2005/02/04 12:44:26  dischi
13# fix unicode bug
14#
15# Revision 1.66  2004/09/14 20:13:59  dischi
16# detect rar vobsub files
17#
18# Revision 1.65  2004/09/14 14:38:11  outlyer
19# Fix the broken 'less than' comparison so it is at least consistent, but I'm
20# not sure why we need to add zeroes to numbers anyway. It looks ugly for
21# albums with less than 10 tracks, and it seems unecessary since the
22# sort functions in Freevo add the '0' as needed.
23#
24# Revision 1.64  2004/09/10 19:43:12  outlyer
25# Added discs to exported dict.
26#
27# Revision 1.63  2004/05/29 12:30:36  dischi
28# add function to correct data from the different mime modules
29#
30# Revision 1.62  2004/05/28 12:26:24  dischi
31# Replace __str__ with unicode to avoid bad transformations. Everything
32# inside mmpython should be handled as unicode object.
33#
34# Revision 1.61  2004/05/27 08:59:50  dischi
35# fix chapters printing
36#
37# Revision 1.60  2004/05/20 15:55:08  dischi
38# add xml file detection
39#
40# Revision 1.59  2004/05/18 21:54:49  dischi
41# add chapter support
42#
43# -----------------------------------------------------------------------
44# MMPython - Media Metadata for Python
45# Copyright (C) 2003 Thomas Schueppel, Dirk Meyer
46#
47# This program is free software; you can redistribute it and/or modify
48# it under the terms of the GNU General Public License as published by
49# the Free Software Foundation; either version 2 of the License, or
50# (at your option) any later version.
51#
52# This program is distributed in the hope that it will be useful, but
53# WITHOUT ANY WARRANTY; without even the implied warranty of MER-
54# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
55# Public License for more details.
56#
57# You should have received a copy of the GNU General Public License along
58# with this program; if not, write to the Free Software Foundation, Inc.,
59# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
60#
61# -----------------------------------------------------------------------
62#endif
63
64
65TYPE_NONE = 0
66TYPE_AUDIO = 1
67TYPE_VIDEO = 2
68TYPE_IMAGE = 4
69TYPE_AV = 5
70TYPE_MUSIC = 6
71TYPE_HYPERTEXT = 8
72TYPE_MISC = 10
73
74import string
75import types
76import table
77import traceback
78import locale
79
80import re
81import urllib
82import urlparse
83import os
84
85LOCAL_ENCODING = locale.getpreferredencoding();
86if not LOCAL_ENCODING or LOCAL_ENCODING == "ANSI_X3.4-1968":
87    LOCAL_ENCODING = 'latin1';
88
89MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type', 'subtype',
90             'date', 'keywords', 'country', 'language', 'url']
91
92AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'samplebits',
93             'bitrate', 'language']
94
95VIDEOCORE = ['length', 'encoder', 'bitrate', 'samplerate', 'codec', 'samplebits',
96             'width', 'height', 'fps', 'aspect']
97
98IMAGECORE = ['description', 'people', 'location', 'event',
99             'width','height','thumbnail','software','hardware', 'dpi']
100
101MUSICCORE = ['trackno', 'trackof', 'album', 'genre','discs']
102
103AVCORE    = ['length', 'encoder', 'trackno', 'trackof', 'copyright', 'product',
104             'genre', 'secondary genre', 'subject', 'writer', 'producer',
105             'cinematographer', 'production designer', 'edited by', 'costume designer',
106             'music by', 'studio', 'distributed by', 'rating', 'starring', 'ripped by',
107             'digitizing date', 'internet address', 'source form', 'medium', 'source',
108             'archival location', 'commisioned by', 'engineer', 'cropped', 'sharpness',
109             'dimensions', 'lightness', 'dots per inch', 'palette setting',
110             'default audio stream', 'logo url', 'watermark url', 'info url',
111             'banner image', 'banner url', 'infotext', 'delay']
112
113
114UNPRINTABLE_KEYS = [ 'thumbnail', ]
115
116import table
117import mmpython
118
119EXTENSION_DEVICE    = 'device'
120EXTENSION_DIRECTORY = 'directory'
121EXTENSION_STREAM    = 'stream'
122
123DEBUG = 0
124
125try:
126    DEBUG = int(os.environ['MMPYTHON_DEBUG'])
127except:
128    pass
129
130def _debug(text):
131    """
132    Function for debug prints of MediaItem implementations.
133    """
134    if DEBUG > 1:
135        try:
136            print text
137        except:
138            print text.encode('latin-1', 'replace')
139   
140
141class MediaInfo:
142    """
143    MediaInfo is the base class to all Media Metadata Containers. It defines the
144    basic structures that handle metadata. MediaInfo and its derivates contain
145    a common set of metadata attributes that is listed in keys. Specific derivates
146    contain additional keys to the dublin core set that is defined in MediaInfo.
147    MediaInfo also contains tables of addional metadata. These tables are maps
148    of keys to values. The keys themselves should remain in the format that is
149    defined by the metadata (I.E. Hex-Numbers, FOURCC, ...) and will be translated
150    to more readable and i18nified values by an external entity.
151    """
152    def __init__(self):
153        self.keys = []
154        self._tables = {}
155        for k in MEDIACORE:
156            setattr(self,k,None)
157            self.keys.append(k)
158
159
160    def __unicode__(self):
161        import copy
162        keys = copy.copy(self.keys)
163
164        for k in UNPRINTABLE_KEYS:
165            if k in keys:
166                keys.remove(k)
167
168        result = u''
169        result += reduce( lambda a,b: self[b] and b != u'url' and u'%s\n        %s: %s' % \
170                         (a, unicode(b), unicode(self[b])) or a, keys, u'' )
171        if DEBUG:
172            try:
173                for i in self._tables.keys():
174                    try:
175                        result += unicode(self._tables[i])
176                    except AttributeError:
177                        pass
178            except AttributeError:
179                pass
180        return result
181       
182
183    def appendtable(self, name, hashmap, language='en'):
184        """
185        Appends a tables of additional metadata to the Object.
186        If such a table already exists, the given tables items are
187        added to the existing one.
188        """
189        if not self._tables.has_key((name, language)):
190            self._tables[(name, language)] = table.Table(hashmap, name, language)
191        else:
192            # Append to the already existing table
193            for k in hashmap.keys():
194                self._tables[(name, language)][k] = hashmap[k]
195   
196
197    def correct_data(self):
198        """
199        Correct same data based on specific rules
200        """
201        # make sure all strings are unicode
202        for key in self.keys:
203            value = getattr(self, key)
204            if isinstance(value, str):
205                setattr(self, key, unicode(value, LOCAL_ENCODING, 'replace'))
206
207
208    def gettable(self, name, language='en'):
209        """
210        returns a table of the given name and language       
211        """
212        return self._tables.get((name, language), {})
213   
214
215    def setitem(self, item, dict, key, convert_to_str=False):
216        """
217        set item to a specific value for the dict
218        """
219        try:
220            if self.__dict__.has_key(item):
221                if isinstance(dict[key], str):
222                    self.__dict__[item] = unicode(dict[key])
223                elif convert_to_str:
224                    self.__dict__[item] = unicode(dict[key])
225                else:
226                    self.__dict__[item] = dict[key]
227            else:
228                _debug("Unknown key: %s" % item)
229        except:
230            pass
231
232
233    def __getitem__(self,key):
234        """
235        get the value of 'key'
236        """
237        if self.__dict__.has_key(key):
238            if isinstance(self.__dict__[key], str):
239                return self.__dict__[key].strip().rstrip().replace('\0', '')
240            return self.__dict__[key]
241        elif hasattr(self, key):
242            return getattr(self, key)
243        return None
244
245       
246    def __setitem__(self, key, val):
247        """
248        set the value of 'key' to 'val'
249        """
250        self.__dict__[key] = val
251
252
253    def has_key(self, key):
254        """
255        check if the object has a key 'key'
256        """
257        return self.__dict__.has_key(key) or hasattr(self, key)
258
259
260    def __delitem__(self, key):
261        """
262        delete informations about 'key'
263        """
264        try:
265            del self.__dict__[key]
266        except:
267            pass
268        if hasattr(self, key):
269            setattr(self, key, None)
270
271       
272class AudioInfo(MediaInfo):
273    """
274    Audio Tracks in a Multiplexed Container.
275    """
276    def __init__(self):
277        self.keys = []
278        for k in AUDIOCORE:
279            setattr(self,k,None)
280            self.keys.append(k)
281
282
283class MusicInfo(AudioInfo):
284    """
285    Digital Music.
286    """
287    def __init__(self):
288        MediaInfo.__init__(self)
289        for k in AUDIOCORE+MUSICCORE:
290            setattr(self,k,None)
291            self.keys.append(k)
292
293    def correct_data(self):
294        """
295        correct trackof to be two digest
296        """
297        AudioInfo.correct_data(self)
298        if self['trackof']:
299            try:
300                # XXX Why is this needed anyway?
301                if int(self['trackno']) < 10:
302                    self['trackno'] = '0%s' % int(self['trackno'])
303            except:
304                pass
305
306           
307class VideoInfo(MediaInfo):
308    """
309    Video Tracks in a Multiplexed Container.
310    """
311    def __init__(self):
312        self.keys = []
313        for k in VIDEOCORE:
314            setattr(self,k,None)
315            self.keys.append(k)
316           
317
318class ChapterInfo(MediaInfo):
319    """
320    Chapter in a Multiplexed Container.
321    """
322    def __init__(self, name, pos=0):
323        self.keys = ['name', 'pos']
324        setattr(self,'name', name)
325        setattr(self,'pos', pos)
326           
327
328class AVInfo(MediaInfo):
329    """
330    Container for Audio and Video streams. This is the Container Type for
331    all media, that contain more than one stream.
332    """
333    def __init__(self):
334        MediaInfo.__init__(self)
335        for k in AVCORE:
336            setattr(self,k,None)
337            self.keys.append(k)
338        self.audio = []
339        self.video = []
340        self.subtitles = []
341        self.chapters  = []
342
343
344    def correct_data(self):
345        """
346        correct length to be an int
347        """
348        MediaInfo.correct_data(self)
349        if not self['length'] and len(self.video) and self.video[0]['length']:
350            self['length'] = self.video[0]['length']
351        for container in [ self ] + self.video + self.audio:
352            if container['length']:
353                container['length'] = int(container['length'])
354           
355                                 
356    def find_subtitles(self, filename):
357        """
358        Search for subtitle files. Right now only VobSub is supported
359        """
360        base = os.path.splitext(filename)[0]
361        if os.path.isfile(base+'.idx') and \
362               (os.path.isfile(base+'.sub') or os.path.isfile(base+'.rar')):
363            file = open(base+'.idx')
364            if file.readline().find('VobSub index file') > 0:
365                line = file.readline()
366                while (line):
367                    if line.find('id') == 0:
368                        self.subtitles.append(line[4:6])
369                    line = file.readline()
370            file.close()
371
372           
373    def __unicode__(self):
374        result = u'Attributes:'
375        result += MediaInfo.__unicode__(self)
376        if len(self.video) + len(self.audio) + len(self.subtitles) > 0:
377            result += "\n Stream list:"
378            if len(self.video):
379                result += reduce( lambda a,b: a + u'  \n   Video Stream:' + unicode(b),
380                                  self.video, u'' )
381            if len(self.audio):
382                result += reduce( lambda a,b: a + u'  \n   Audio Stream:' + unicode(b),
383                                  self.audio, u'' )
384            if len(self.subtitles):
385                result += reduce( lambda a,b: a + u'  \n   Subtitle Stream:' + unicode(b),
386                                  self.subtitles, u'' )
387        if not isinstance(self.chapters, int) and len(self.chapters) > 0:
388            result += u'\n Chapter list:'
389            for i in range(len(self.chapters)):
390                result += u'\n   %2s: "%s" %s' % (i+1, unicode(self.chapters[i]['name']),
391                                                  self.chapters[i]['pos'])
392        return result
393
394       
395class ImageInfo(MediaInfo):
396    """
397    Digital Images, Photos, Pictures.
398    """
399    def __init__(self):
400        MediaInfo.__init__(self)       
401        for k in IMAGECORE:
402            setattr(self,k,None)
403            self.keys.append(k)
404
405
406class CollectionInfo(MediaInfo):
407    """
408    Collection of Digial Media like CD, DVD, Directory, Playlist
409    """
410    def __init__(self):
411        MediaInfo.__init__(self)
412        self.tracks = []
413        self.keys.append('id')
414        self.id = None
415
416    def __unicode__(self):
417        result = MediaInfo.__unicode__(self)
418        result += u'\nTrack list:'
419        for counter in range(0,len(self.tracks)):
420             result += u' \nTrack %d:\n%s' % (counter+1, unicode(self.tracks[counter]))
421        return result
422   
423    def appendtrack(self, track):
424        self.tracks.append(track)
425
426
427def get_singleton():
428    print "This function is deprecated. Please use 'mmpython.Factory' instead."
429    return mmpython.Factory()
430
431   
Note: See TracBrowser for help on using the repository browser.