Author: dmeyer
Date: Wed Dec  6 20:52:29 2006
New Revision: 2160

Modified:
   trunk/metadata/TODO
   trunk/metadata/bin/mminfo
   trunk/metadata/src/__init__.py
   trunk/metadata/src/audio/eyed3info.py
   trunk/metadata/src/audio/flacinfo.py
   trunk/metadata/src/audio/ogginfo.py
   trunk/metadata/src/audio/webradioinfo.py
   trunk/metadata/src/disc/discinfo.py
   trunk/metadata/src/disc/dvdinfo.py
   trunk/metadata/src/factory.py
   trunk/metadata/src/fourcc.py
   trunk/metadata/src/image/IPTC.py
   trunk/metadata/src/image/core.py
   trunk/metadata/src/image/jpginfo.py
   trunk/metadata/src/image/pnginfo.py
   trunk/metadata/src/image/tiffinfo.py
   trunk/metadata/src/mediainfo.py
   trunk/metadata/src/misc/dirinfo.py
   trunk/metadata/src/video/asfinfo.py
   trunk/metadata/src/video/mkvinfo.py
   trunk/metadata/src/video/movinfo.py
   trunk/metadata/src/video/mpeginfo.py
   trunk/metadata/src/video/ogminfo.py
   trunk/metadata/src/video/riffinfo.py

Log:
Major cleanup of the code, it was way to ugly. The __dict__ access is
now gone, all attributes are class member functions. Use the table code
when possible to avoid duplicate code. It is also possible now to
convert the MediaInfo to a dict and back.


Modified: trunk/metadata/TODO
==============================================================================
--- trunk/metadata/TODO (original)
+++ trunk/metadata/TODO Wed Dec  6 20:52:29 2006
@@ -21,13 +21,6 @@
 
 Check attributes. Some are very similar and could be merged
 
-Cleanup stuff about what is stored in the __dict__ and what is a
-memeber variable. OK, after some thinking: MediaInfo should inherit
-from dict. That is the only way we can support attributes with
-whitespaces, etc. No more self.length, it is self['length'] in that
-case. That means all parser have to be updated, maybe temp. in
-WIP/metadata until it is done. THIS NEEDS CLEANUP!
-
 If possible, attributes should match
 http://www.freedesktop.org/wiki/Standards_2fshared_2dfilemetadata_2dspec
 and mime type should match

Modified: trunk/metadata/bin/mminfo
==============================================================================
--- trunk/metadata/bin/mminfo   (original)
+++ trunk/metadata/bin/mminfo   Wed Dec  6 20:52:29 2006
@@ -92,7 +92,7 @@
     if len(file) > 70:
         print "filename : %s[...]%s" % (file[:30], file[len(file)-30:])
     else:
-        print "filename : %s" % file
+        print "    filename: %s" % file
     if medium:
         print medium
         print

Modified: trunk/metadata/src/__init__.py
==============================================================================
--- trunk/metadata/src/__init__.py      (original)
+++ trunk/metadata/src/__init__.py      Wed Dec  6 20:52:29 2006
@@ -39,6 +39,7 @@
 # import factory code for kaa.metadata access
 from factory import *
 from disc.discinfo import cdrom_disc_id as getid
+from mediainfo import MediaInfo
 
 # use network functions
 USE_NETWORK     = 1

Modified: trunk/metadata/src/audio/eyed3info.py
==============================================================================
--- trunk/metadata/src/audio/eyed3info.py       (original)
+++ trunk/metadata/src/audio/eyed3info.py       Wed Dec  6 20:52:29 2006
@@ -186,7 +186,7 @@
                   tab[f.header.id] = f
                else:
                   log.debug(f.__class__)
-            self.appendtable('id3v2', tab, 'en')
+            self._appendtable('id3v2', tab)
 
             if id3.tag.frames['TCON']:
                genre = None
@@ -204,10 +204,10 @@
                   except KeyError:
                      self.genre = str(genre)
             # and some tools store it as trackno/trackof in TRCK
-            if not self['trackof'] and self['trackno'] and \
-                   self['trackno'].find('/') > 0:
-               self['trackof'] = self['trackno'][self['trackno'].find('/')+1:]
-               self['trackno'] = self['trackno'][:self['trackno'].find('/')]
+            if not self.trackof and self.trackno and \
+                   self.trackno.find('/') > 0:
+               self.trackof = self.trackno[self.trackno.find('/')+1:]
+               self.trackno = self.trackno[:self.trackno.find('/')]
          if id3:
             self.length = id3.getPlayTime()
       except (KeyboardInterrupt, SystemExit):
@@ -297,8 +297,7 @@
       if self.bitrate is None or self.samplerate is None:
          return
 
-      self.mode = _modes[mode]
-      self.keys.append('mode')
+      self._set('mode', _modes[mode])
 
 
 factory.register( 'audio/mp3', ('mp3',), mediainfo.TYPE_MUSIC, eyeD3Info )

Modified: trunk/metadata/src/audio/flacinfo.py
==============================================================================
--- trunk/metadata/src/audio/flacinfo.py        (original)
+++ trunk/metadata/src/audio/flacinfo.py        Wed Dec  6 20:52:29 2006
@@ -101,7 +101,7 @@
                 if header.has_key('TRACKNUMBER'):
                     self.trackno = header['TRACKNUMBER']
 
-                self.appendtable('VORBISCOMMENT', header)
+                self._appendtable('VORBISCOMMENT', header)
             elif type == 5:
                 # CUESHEET
                 pass

Modified: trunk/metadata/src/audio/ogginfo.py
==============================================================================
--- trunk/metadata/src/audio/ogginfo.py (original)
+++ trunk/metadata/src/audio/ogginfo.py Wed Dec  6 20:52:29 2006
@@ -105,7 +105,7 @@
             self.type = 'OGG Vorbis'
             self.subtype = ''
             self.length = self._calculateTrackLength(file)
-            self.appendtable('VORBISCOMMENT',header)
+            self._appendtable('VORBISCOMMENT',header)
 
 
     def _extractHeaderString(self,f):

Modified: trunk/metadata/src/audio/webradioinfo.py
==============================================================================
--- trunk/metadata/src/audio/webradioinfo.py    (original)
+++ trunk/metadata/src/audio/webradioinfo.py    Wed Dec  6 20:52:29 2006
@@ -40,13 +40,16 @@
 
 # http://205.188.209.193:80/stream/1006
 
-ICY_tags = { 'title': 'icy-name',
-             'genre': 'icy-genre',
-             'bitrate': 'icy-br',
-             'caption': 'icy-url',
-           }
+ICY = { 'icy-name': 'title',
+        'icy-genre': 'genre',
+        'icy-br': 'bitrate',
+        'icy-url': 'caption'
+      }
 
 class WebRadioInfo(mediainfo.MusicInfo):
+
+    table_mapping = { 'ICY' : ICY }
+
     def __init__(self, url):
         mediainfo.MusicInfo.__init__(self)
         tup = urlparse.urlsplit(url)
@@ -88,13 +91,11 @@
                 tab[icyline[:cidx].strip()] = icyline[cidx+2:].strip()
         if fi:
             fi.close()
-        self.appendtable('ICY', tab)
-        self.tag_map = { ('ICY', 'en') : ICY_tags }
-        # Copy Metadata from tables into the main set of attributes
-        for k in self.tag_map.keys():
-            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),
-                                      self.tag_map[k][x]),
-                self.tag_map[k].keys())
+        self._appendtable('ICY', tab)
+
+
+    def _finalize(self):
+        mediainfo.MusicInfo._finalize(self)
         self.bitrate = string.atoi(self.bitrate)*1000
 
 

Modified: trunk/metadata/src/disc/discinfo.py
==============================================================================
--- trunk/metadata/src/disc/discinfo.py (original)
+++ trunk/metadata/src/disc/discinfo.py Wed Dec  6 20:52:29 2006
@@ -209,11 +209,13 @@
 
 
 class DiscInfo(mediainfo.CollectionInfo):
+
+    _keys = mediainfo.CollectionInfo._keys + [ 'mixed', 'label' ]
+
     def isDisc(self, device):
         (type, self.id) = cdrom_disc_id(device, handle_mix=1)
         if type != 2:
             if type == 4:
-                self.keys.append('mixed')
                 self.mixed = 1
                 type = 1
             return type
@@ -229,5 +231,4 @@
             else:
                 self.label = self.id[16:]
 
-        self.keys.append('label')
         return type

Modified: trunk/metadata/src/disc/dvdinfo.py
==============================================================================
--- trunk/metadata/src/disc/dvdinfo.py  (original)
+++ trunk/metadata/src/disc/dvdinfo.py  Wed Dec  6 20:52:29 2006
@@ -71,13 +71,13 @@
 
 
 class DVDTitle(mediainfo.AVInfo):
+
+    _keys = mediainfo.AVInfo._keys + [ 'chapters', 'subtitles', 'angles' ]
+
     def __init__(self, info):
         mediainfo.AVInfo.__init__(self)
         self.chapters = info[0]
         self.angles = info[1]
-        self.keys.append('chapters')
-        self.keys.append('subtitles')
-        self.keys.append('angles')
 
         self.mime = 'video/mpeg'
         self.video.append(DVDVideo(info[2:8]))
@@ -91,6 +91,9 @@
 
 
 class DVDInfo(DiscInfo):
+
+    _keys = DiscInfo._keys + [ 'length' ]
+
     def __init__(self, device):
         DiscInfo.__init__(self)
         self.context = 'video'
@@ -103,7 +106,6 @@
         else:
             self.parseDisc(device)
 
-        self.keys.append('length')
         self.length = 0
         first       = 0
 
@@ -129,7 +131,7 @@
             ti = DVDTitle(title)
             ti.trackno = pos + 1
             ti.trackof = len(info)
-            self.appendtrack(ti)
+            self.tracks.append(ti)
 
 
     def parseDVDdir(self, dirname):

Modified: trunk/metadata/src/factory.py
==============================================================================
--- trunk/metadata/src/factory.py       (original)
+++ trunk/metadata/src/factory.py       Wed Dec  6 20:52:29 2006
@@ -79,25 +79,15 @@
     return Factory().get(mimetype,extensions)
 
 
-if TIME_DEBUG:
-    import time
+def parse(filename, force=True):
+    """
+    parse a file
+    """
+    result = Factory().create(filename, force)
+    if result:
+        result._finalize()
+    return result
 
-    def parse(filename, force=True):
-        """
-        parse a file
-        """
-        t1 = time.time()
-        result = Factory().create(filename, force)
-        t2 = time.time()
-        log.info('%s took %s seconds' % (filename, (t2-t1)))
-        return result
-else:
-    def parse(filename, force=True):
-        """
-        parse a file
-        """
-        return Factory().create(filename, force)
-        
 
 class _Factory:
     """
@@ -194,7 +184,7 @@
         if not force:
             log.info('No Type found by Extension. Give up')
             return None
-        
+
         log.info('No Type found by Extension. Trying all')
 
         for e in self.types:
@@ -276,7 +266,6 @@
             f.close()
             if r:
                 r.url = 'file://%s' % os.path.abspath(filename)
-                r.correct_data()
                 return r
         return None
 

Modified: trunk/metadata/src/fourcc.py
==============================================================================
--- trunk/metadata/src/fourcc.py        (original)
+++ trunk/metadata/src/fourcc.py        Wed Dec  6 20:52:29 2006
@@ -6,8 +6,8 @@
     """
     if isinstance(code, (int, long)):
         if code in TWOCC:
-            return u'0x%x' % code, unicode(TWOCC[code])
-        return u'0x%x' % code, u'Unknown'
+            return u'0x%04x' % code, unicode(TWOCC[code])
+        return u'0x%04x' % code, u'Unknown'
     if code.upper() in FOURCC:
         return unicode(code.upper()), unicode(FOURCC[code.upper()])
     if code.upper().startswith('MS'):
@@ -16,8 +16,8 @@
         return unicode(code), u'Unknown'
     code = (ord(code[0]) << 8) + ord(code[1])
     if code in TWOCC:
-        return u'0x%x' % code, unicode(TWOCC[code])
-    return u'0x%x' % code, u'Unknown'
+        return u'0x%04x' % code, unicode(TWOCC[code])
+    return u'0x%04x' % code, u'Unknown'
 
 
 TWOCC = {

Modified: trunk/metadata/src/image/IPTC.py
==============================================================================
--- trunk/metadata/src/image/IPTC.py    (original)
+++ trunk/metadata/src/image/IPTC.py    Wed Dec  6 20:52:29 2006
@@ -36,6 +36,18 @@
 from struct import unpack
 from kaa.strutils import str_to_unicode
 
+mapping = {
+    'by-line title': 'title',
+    'headline': 'title',
+    'date created': 'date',
+    'keywords': 'keywords',
+    'writer/editor': 'artist',
+    'credit': 'artist',
+    'country/primary location name': 'country',
+    'caption/abstract': 'caption',
+    'city': 'city'
+}
+
 # These names match the codes defined in ITPC's IIM record 2.
 # copied from iptcinfo by Josh Carter, [EMAIL PROTECTED]
 c_datasets = {

Modified: trunk/metadata/src/image/core.py
==============================================================================
--- trunk/metadata/src/image/core.py    (original)
+++ trunk/metadata/src/image/core.py    Wed Dec  6 20:52:29 2006
@@ -45,28 +45,24 @@
 
 # attributes for image files
 ATTRIBUTES = ['description', 'people', 'location', 'event', 'width', 'height',
-              'thumbnail','software','hardware', 'dpi', 'city', 'rotation']
+              'thumbnail','software','hardware', 'dpi', 'city', 'rotation' ]
 
 
 class ImageInfo(mediainfo.MediaInfo):
     """
     Digital Images, Photos, Pictures.
     """
-    def __init__(self):
-        mediainfo.MediaInfo.__init__(self)
-        for k in ATTRIBUTES:
-            setattr(self,k,None)
-            self.keys.append(k)
 
+    _keys = ATTRIBUTES
 
-    def correct_data(self):
+    def _finalize(self):
         """
         Add additional information and correct data.
         FIXME: parse_external_files here is very wrong
         """
         if self.url and self.url.startswith('file://'):
             self.parse_external_files(self.url[7:])
-        mediainfo.MediaInfo.correct_data(self)
+        mediainfo.MediaInfo._finalize(self)
 
 
     def parse_external_files(self, filename):
@@ -94,10 +90,7 @@
             key = str(child.getattr('name'))
             if not key or not child.content:
                 continue
-            self[key] = child.content
-            if not key in ATTRIBUTES + mediainfo.MEDIACORE:
-                # if it's in desc it must be important
-                self.keys.append(key)
+            self._set(key, child.content)
 
 
     def parse_dot_comment(self, filename):

Modified: trunk/metadata/src/image/jpginfo.py
==============================================================================
--- trunk/metadata/src/image/jpginfo.py (original)
+++ trunk/metadata/src/image/jpginfo.py Wed Dec  6 20:52:29 2006
@@ -66,8 +66,17 @@
         0xCF : "Differential lossless, arithmetic coding",
 }
 
+EXIFMap = {
+    'Image DateTime': 'date',
+    'Image Artist': 'artist',
+    'Image Model': 'hardware',
+    'Image Software': 'software',
+}
+
 class JPGInfo(core.ImageInfo):
 
+    table_mapping = { 'EXIF': EXIFMap, 'IPTC': IPTC.mapping }
+
     def __init__(self,file):
         core.ImageInfo.__init__(self)
         self.mime = 'image/jpeg'
@@ -85,7 +94,7 @@
         file.seek(2)
         app = file.read(4)
         self.meta = {}
-        
+
         while (len(app) == 4):
             (ff,segtype,seglen) = struct.unpack(">BBH", app)
             if ff != 0xff: break
@@ -111,12 +120,10 @@
                     exif = EXIF.process_file(fakefile)
                     fakefile.close()
                     if exif:
-                        self.setitem( 'date', exif, 'Image DateTime', True)
-                        self.setitem( 'artist', exif, 'Image Artist', True)
-                        self.setitem( 'hardware', exif, 'Image Model', True)
-                        self.setitem( 'software', exif, 'Image Software', True)
-                        self.setitem( 'thumbnail', exif, 'JPEGThumbnail', True)
-                        self.appendtable( 'EXIF', exif )
+                        self.thumbnail = exif.get('JPEGThumbnail', None)
+                        if self.thumbnail:
+                            self.thumbnail = str(self.thumbnail)
+                        self._appendtable('EXIF', exif)
 
                         if 'Image Orientation' in exif:
                             orientation = str(exif['Image Orientation'])
@@ -136,16 +143,7 @@
             elif segtype == 0xed:
                 iptc = IPTC.parseiptc(file.read(seglen-2))
                 if iptc:
-                    self.setitem( 'title', iptc, 'by-line title')
-                    self.setitem( 'title', iptc, 'headline')
-                    self.setitem( 'date' , iptc, 'date created')
-                    self.setitem( 'keywords', iptc, 'keywords')
-                    self.setitem( 'artist', iptc, 'writer/editor')
-                    self.setitem( 'artist', iptc, 'credit')
-                    self.setitem( 'country', iptc, 'country/primary location 
name')
-                    self.setitem( 'caption', iptc, 'caption/abstract')
-                    self.setitem( 'city', iptc, 'city')
-                    self.appendtable( 'IPTC', iptc )
+                    self._appendtable('IPTC', iptc)
 
             elif segtype == 0xe7:
                 # information created by libs like epeg
@@ -172,12 +170,10 @@
             app = file.read(4)
 
         if len(self.meta.keys()):
-            self.appendtable( 'JPGMETA', self.meta )
+            self._appendtable( 'JPGMETA', self.meta )
 
         for key, value in self.meta.items():
             if key.startswith('Thumb:') or key == 'Software':
-                setattr(self, key, value)
-                if not key in self.keys:
-                    self.keys.append(key)
-    
+                self._set(key, value)
+
 factory.register( 'image/jpeg', ('jpg','jpeg'), mediainfo.TYPE_IMAGE, JPGInfo )

Modified: trunk/metadata/src/image/pnginfo.py
==============================================================================
--- trunk/metadata/src/image/pnginfo.py (original)
+++ trunk/metadata/src/image/pnginfo.py Wed Dec  6 20:52:29 2006
@@ -71,12 +71,10 @@
         while self._readChunk(file):
             pass
         if len(self.meta.keys()):
-            self.appendtable( 'PNGMETA', self.meta )
+            self._appendtable( 'PNGMETA', self.meta )
         for key, value in self.meta.items():
             if key.startswith('Thumb:') or key == 'Software':
-                setattr(self, key, value)
-                if not key in self.keys:
-                    self.keys.append(key)
+                self._set(key, value)
 
 
     def _readChunk(self,file):

Modified: trunk/metadata/src/image/tiffinfo.py
==============================================================================
--- trunk/metadata/src/image/tiffinfo.py        (original)
+++ trunk/metadata/src/image/tiffinfo.py        Wed Dec  6 20:52:29 2006
@@ -54,6 +54,8 @@
 
 class TIFFInfo(core.ImageInfo):
 
+    table_mapping = { 'IPTC': IPTC.mapping }
+
     def __init__(self,file):
         core.ImageInfo.__init__(self)
         self.iptc = None
@@ -112,16 +114,7 @@
             raise mediainfo.KaaMetadataParseError()
 
         if iptc:
-            self.setitem( 'title', iptc, 'by-line title')
-            self.setitem( 'title', iptc, 'headline')
-            self.setitem( 'date' , iptc, 'date created')
-            self.setitem( 'keywords', iptc, 'keywords')
-            self.setitem( 'artist', iptc, 'writer/editor')
-            self.setitem( 'artist', iptc, 'credit')
-            self.setitem( 'country', iptc, 'country/primary location name')
-            self.setitem( 'caption', iptc, 'caption/abstract')
-            self.setitem( 'city', iptc, 'city')
-            self.appendtable( 'IPTC', iptc )
+            self._appendtable('IPTC', iptc)
 
 
 factory.register( 'image/tiff', ('tif','tiff'), mediainfo.TYPE_IMAGE, TIFFInfo)

Modified: trunk/metadata/src/mediainfo.py
==============================================================================
--- trunk/metadata/src/mediainfo.py     (original)
+++ trunk/metadata/src/mediainfo.py     Wed Dec  6 20:52:29 2006
@@ -53,33 +53,20 @@
 TYPE_HYPERTEXT = 8
 TYPE_MISC      = 10
 
-MEDIACORE = ['title', 'caption', 'comment', 'artist', 'size', 'type',
-             'subtype', 'date', 'keywords', 'country', 'language', 'url']
+MEDIACORE = ['title', 'caption', 'comment', 'size', 'type', 'subtype', 'date',
+             'keywords', 'country', 'language', 'url', 'media', 'artist']
 
 AUDIOCORE = ['channels', 'samplerate', 'length', 'encoder', 'codec', 'format',
-             'samplebits', 'bitrate' ]
+             'samplebits', 'bitrate', 'fourcc' ]
 
 VIDEOCORE = ['length', 'encoder', 'bitrate', 'samplerate', 'codec', 'format',
-             'samplebits', 'width', 'height', 'fps', 'aspect', 'trackno' ]
+             'samplebits', 'width', 'height', 'fps', 'aspect', 'trackno', 
'fourcc' ]
 
-MUSICCORE = ['trackno', 'trackof', 'album', 'genre','discs', 'thumbnail' ]
-
-# AVCORE is such a funny list. Who created it? I don't see any parser
-# that could ever fill out stuff like 'production designer'. Making this
-# list smaller would make kaa.metadata faster.
+MUSICCORE = ['trackno', 'trackof', 'album', 'genre', 'discs', 'thumbnail' ]
 
 AVCORE    = ['length', 'encoder', 'trackno', 'trackof', 'copyright', 'product',
-             'genre', 'secondary genre', 'subject', 'writer', 'producer',
-             'cinematographer', 'production designer', 'edited by',
-             'costume designer', 'music by', 'studio', 'distributed by',
-             'rating', 'starring', 'ripped by', 'digitizing date',
-             'internet address', 'source form', 'medium', 'source',
-             'archival location', 'commisioned by', 'engineer', 'cropped',
-             'sharpness', 'dimensions', 'lightness', 'dots per inch',
-             'palette setting', 'default audio stream', 'logo url',
-             'watermark url', 'info url', 'banner image', 'banner url',
-             'infotext', 'delay', 'image' ]
-
+             'genre', 'writer', 'producer', 'studio', 'rating', 'starring',
+             'delay', 'image', 'video', 'audio', 'subtitles', 'chapters' ]
 
 EXTENSION_DEVICE    = 'device'
 EXTENSION_DIRECTORY = 'directory'
@@ -92,51 +79,67 @@
 class KaaMetadataParseError:
     pass
 
-class MediaInfo:
+
+class MediaInfo(object):
     """
     MediaInfo is the base class to all Media Metadata Containers. It defines
     the basic structures that handle metadata. MediaInfo and its derivates
     contain a common set of metadata attributes that is listed in keys.
     Specific derivates contain additional keys to the dublin core set that is
     defined in MediaInfo.
-    MediaInfo also contains tables of addional metadata. These tables are maps
-    of keys to values. The keys themselves should remain in the format that is
-    defined by the metadata (I.E. Hex-Numbers, FOURCC, ...) and will be
-    translated to more readable and i18nified values by an external entity.
     """
-    def __init__(self):
-        self.keys = []
+    _keys = MEDIACORE
+    table_mapping = {}
+
+    def __init__(self, hash=None):
+        if hash is not None:
+            # create mediainfo based on dict
+            for key, value in hash.items():
+                if isinstance(value, list) and value and isinstance(value[0], 
dict):
+                    value = [ MediaInfo(x) for x in value ]
+                self._set(key, value)
+            return
+        
+        self._keys = self._keys[:]
         self._tables = {}
-        for k in MEDIACORE:
-            setattr(self,k,None)
-            self.keys.append(k)
-        # get media type by parsing the __class__ information
-        media = str(self.__class__)
-        media = media[media.find('kaa.metadata.') + 13:]
-        self.media = media[:media.find('.')]
-        self.keys.append('media')
+        for key in self._keys:
+            setattr(self, key, None)
+
 
+    #
+    # unicode and string convertion for debugging
+    #
 
     def __unicode__(self):
-        keys = copy.copy(self.keys)
-        hidden = []
-        for k in UNPRINTABLE_KEYS:
-            if k in keys:
-                keys.remove(k)
-                hidden.append(k)
-
-        result = reduce( lambda a,b: self[b] and b != u'url' and \
-                         u'%s\n        %s: %s' % \
-                         (a, unicode(b), unicode(self[b])) or a, keys, u'' )
-        for h in hidden:
-            if self[h]:
-                result += u'\n        %s: <unprintable data>' % h
-        if log.level < 30:
+        result = u''
+
+        # print normal attributes
+        lists = []
+        for key in self._keys:
+            value = getattr(self, key, None)
+            if value == None or key == 'url':
+                continue
+            if isinstance(value, list):
+                if value:
+                    lists.append((key, value))
+                continue
+            if key in UNPRINTABLE_KEYS:
+                value = '<unprintable data>'
+            result += u'  %10s: %s\n' % (unicode(key), unicode(value))
+
+        # print lists
+        for key, l in lists:
+            result += u'\n  %5s list:' % key
+            for item in l:
+                result += '\n    ' + unicode(item).replace('\n', '\n    ') + 
u'\n'
+
+        # print tables
+        if log.level >= 10:
             for name, table in self._tables.items():
                 result += '\n\n    Table %s' % str(name)
                 for key, value in table.items():
                     try:
-                        value = unicode(value) 
+                        value = unicode(value)
                         if len(value) > 50:
                             value = '<unprintable data>'
                     except UnicodeDecodeError:
@@ -148,62 +151,84 @@
     def __str__(self):
         return unicode_to_str(unicode(self))
 
-    
-    def appendtable(self, name, hashmap, language='en'):
+
+    def __repr__(self):
+        return '<%s %s>' % (str(self.__class__)[8:-2], self.url)
+
+
+    #
+    # internal functions
+    #
+
+    def _appendtable(self, name, hashmap):
         """
         Appends a tables of additional metadata to the Object.
         If such a table already exists, the given tables items are
         added to the existing one.
         """
-        if not self._tables.has_key((name, language)):
-            self._tables[(name, language)] = hashmap
+        if not self._tables.has_key(name):
+            self._tables[name] = hashmap
         else:
             # Append to the already existing table
             for k in hashmap.keys():
-                self._tables[(name, language)][k] = hashmap[k]
+                self._tables[name][k] = hashmap[k]
 
 
-    def correct_data(self):
+    def _set(self, key, value):
+        """
+        Set key to value and add the key to the internal keys list if
+        missing.
+        """
+        if value is None and getattr(self, key, None) is None:
+            return
+        if isinstance(value, str):
+            value = str_to_unicode(value)
+        setattr(self, key, value)
+        if not key in self._keys:
+            self._keys.append(key)
+
+
+    def _finalize(self):
         """
         Correct same data based on specific rules
         """
         # make sure all strings are unicode
-        for key in self.keys:
+        for key in self._keys:
             if key in UNPRINTABLE_KEYS:
                 continue
             value = getattr(self, key)
+            if value is None:
+                continue
             if isinstance(value, str):
                 setattr(self, key, str_to_unicode(value))
             if isinstance(value, unicode):
                 setattr(self, key, value.strip().rstrip().replace(u'\0', u''))
-
-
-    def gettable(self, name, language='en'):
-        """
-        returns a table of the given name and language
-        """
-        return self._tables.get((name, language), {})
-
-
-    def setitem(self, item, dict, key, convert_to_unicode=False):
-        """
-        Set item to a specific value for the dict.
-        """
-        value = dict.get(key)
-        if not value:
-            return
-        if isinstance(value, str):
-            value = str_to_unicode(value)
-        elif convert_to_unicode and not isinstance(value, unicode):
-            value = str_to_unicode(str(value))
-        self.__dict__[item] = value
-
+            if isinstance(value, list) and value and isinstance(value[0], 
MediaInfo):
+                for submenu in value:
+                    submenu._finalize()
+
+        # copy needed tags from tables
+        for name, table in self._tables.items():
+            mapping = self.table_mapping.get(name, {})
+            for tag, attr in mapping.items():
+                value = table.get(tag, None)
+                if value is not None:
+                    if not isinstance(value, (str, unicode)):
+                        value = unicode(str(value))
+                    elif isinstance(value, str):
+                        value = str_to_unicode(value)
+                    value = value.strip().rstrip().replace(u'\0', u'')
+                    setattr(self, attr, value)
+
+    #
+    # data access
+    #
 
     def __contains__(self, key):
         """
         Test if key exists in the dict
         """
-        return key in self.__dict__
+        return hasattr(self, key)
 
 
     def get(self, key, default = None):
@@ -211,94 +236,79 @@
         Returns key in dict, otherwise defaults to 'default' if key doesn't
         exist.
         """
-        if key not in self:
-            return default
-        return self[key]
+        return getattr(self, key, default)
 
 
-    def __getitem__(self,key):
+    def __getitem__(self, key):
         """
         get the value of 'key'
         """
-        if self.__dict__.has_key(key):
-            return self.__dict__[key]
-        elif hasattr(self, key):
-            return getattr(self, key)
-        return None
+        return getattr(self, key, None)
 
 
-    def __setitem__(self, key, val):
+    def __setitem__(self, key, value):
         """
-        set the value of 'key' to 'val'
+        set the value of 'key' to 'value'
         """
-        self.__dict__[key] = val
+        setattr(self, key, value)
 
 
     def has_key(self, key):
         """
         check if the object has a key 'key'
         """
-        return self.__dict__.has_key(key) or hasattr(self, key)
+        return hasattr(self, key)
 
 
-    def __delitem__(self, key):
+    def convert(self):
         """
-        delete informations about 'key'
+        Convert mediainfo to dict.
         """
-        try:
-            del self.__dict__[key]
-        except (KeyboardInterrupt, SystemExit):
-            sys.exit(0)
-        except:
-            pass
-        if hasattr(self, key):
-            setattr(self, key, None)
+        result = {}
+        for k in self._keys:
+            value = getattr(self, k, None)
+            if isinstance(value, list) and value and isinstance(value[0], 
MediaInfo):
+                value = [ x.convert() for x in value ]
+            result[k] = value
+        return result
+
+
+    def keys(self):
+        """
+        Return all keys.
+        """
+        return self._keys
 
 
 class AudioInfo(MediaInfo):
     """
     Audio Tracks in a Multiplexed Container.
     """
-    def __init__(self):
-        MediaInfo.__init__(self)
-        for k in AUDIOCORE:
-            setattr(self,k,None)
-            self.keys.append(k)
+    _keys = MediaInfo._keys + AUDIOCORE
+    media = 'audio'
 
-    def __unicode__(self):
-        result = u''
-        for key in self.keys:
-            value = self[key]
-            if value == None:
-                continue
-            if key == 'codec':
-                f, value = fourcc.resolve(value)
-                result += u'\n        fourcc: %s' % f
-            result += u'\n        %s: %s' % (unicode(key), unicode(value))
-        return result
+    def _finalize(self):
+        if self.codec is not None:
+            self.fourcc, self.codec = fourcc.resolve(self.codec)
 
 
 class MusicInfo(AudioInfo):
     """
     Digital Music.
     """
-    def __init__(self):
-        MediaInfo.__init__(self)
-        for k in AUDIOCORE+MUSICCORE:
-            setattr(self,k,None)
-            self.keys.append(k)
+    _keys = AudioInfo._keys + AUDIOCORE
+    media = 'audio'
 
-
-    def correct_data(self):
+    def _finalize(self):
         """
-        correct trackof to be two digest
+        Correct same data based on specific rules
         """
-        AudioInfo.correct_data(self)
-        if self['trackof']:
+        AudioInfo._finalize(self)
+        if self.trackof:
             try:
                 # XXX Why is this needed anyway?
-                if int(self['trackno']) < 10:
-                    self['trackno'] = '0%s' % int(self['trackno'])
+                if int(self.trackno) < 10:
+                    self.trackno = '0%s' % int(self.trackno)
             except (KeyboardInterrupt, SystemExit):
                 sys.exit(0)
             except:
@@ -309,46 +319,33 @@
     """
     Video Tracks in a Multiplexed Container.
     """
-    def __init__(self):
-        MediaInfo.__init__(self)
-        for k in VIDEOCORE:
-            setattr(self,k,None)
-            self.keys.append(k)
+    _keys = MediaInfo._keys + VIDEOCORE
+    media = 'video'
 
+    def _finalize(self):
+        if self.codec is not None:
+            self.fourcc, self.codec = fourcc.resolve(self.codec)
 
-    def __unicode__(self):
-        result = u''
-        for key in self.keys:
-            value = self[key]
-            if value == None:
-                continue
-            if key == 'codec':
-                f, value = fourcc.resolve(value)
-                result += u'\n        fourcc: %s' % f
-            result += u'\n        %s: %s' % (unicode(key), unicode(value))
-        return result
 
 class ChapterInfo(MediaInfo):
     """
     Chapter in a Multiplexed Container.
     """
+    _keys = ['name', 'pos', 'enabled']
+
     def __init__(self, name="", pos=0):
         MediaInfo.__init__(self)
-        self.keys = ['name', 'pos', 'enabled']
-        setattr(self,'name', name)
-        setattr(self,'pos', pos)
-        setattr(self,'enabled', True)
+        self.name = name
+        self.pos = pos
+        self.enabled = True
 
 
 class SubtitleInfo(MediaInfo):
     """
     Subtitle Tracks in a Multiplexed Container.
     """
-    def __init__(self):
-        MediaInfo.__init__(self)
-        self.keys = ['language', 'trackno', 'title']
-        for k in self.keys:
-            setattr(self, k, None)
+    _keys = ['language', 'trackno', 'title']
+    media = 'subtitle'
 
 
 class AVInfo(MediaInfo):
@@ -356,92 +353,34 @@
     Container for Audio and Video streams. This is the Container Type for
     all media, that contain more than one stream.
     """
+    _keys = MediaInfo._keys + AVCORE
+
     def __init__(self):
         MediaInfo.__init__(self)
-        for k in AVCORE:
-            setattr(self,k,None)
-            self.keys.append(k)
         self.audio = []
         self.video = []
         self.subtitles = []
         self.chapters  = []
 
 
-    def correct_data(self):
+    def _finalize(self):
         """
-        correct length to be an int
+        Correct same data based on specific rules
         """
-        MediaInfo.correct_data(self)
-        if not self['length'] and len(self.video) and self.video[0]['length']:
-            self['length'] = self.video[0]['length']
+        MediaInfo._finalize(self)
+        if not self.length and len(self.video) and self.video[0].length:
+            self.length = self.video[0].length
         for container in [ self ] + self.video + self.audio:
-            if container['length']:
-                container['length'] = int(container['length'])
-        for subitem in self.video + self.audio:
-            subitem.correct_data()
-            
-
-    def find_subtitles(self, filename):
-        """
-        Search for subtitle files. Right now only VobSub is supported
-        """
-        base = os.path.splitext(filename)[0]
-        if os.path.isfile(base+'.idx') and \
-               (os.path.isfile(base+'.sub') or os.path.isfile(base+'.rar')):
-            file = open(base+'.idx')
-            if file.readline().find('VobSub index file') > 0:
-                for line in file.readlines():
-                    if line.find('id') == 0:
-                        sub = SubtitleInfo()
-                        sub.language = line[4:6]
-                        sub.trackno = base + '.idx'  # Maybe not?
-                        self.subtitles.append(sub)
-            file.close()
-
-
-    def __unicode__(self):
-        result = u'Attributes:'
-        result += MediaInfo.__unicode__(self)
-        if len(self.video) + len(self.audio) + len(self.subtitles) > 0:
-            result += "\n Stream list:"
-            if len(self.video):
-                result += reduce( lambda a,b: a + u'  \n   Video Stream:' + \
-                                  unicode(b), self.video, u'' )
-            if len(self.audio):
-                result += reduce( lambda a,b: a + u'  \n   Audio Stream:' + \
-                                  unicode(b), self.audio, u'' )
-            if len(self.subtitles):
-                result += reduce( lambda a,b: a + u'  \n   Subtitle Stream:' +\
-                                  unicode(b), self.subtitles, u'' )
-
-        if not isinstance(self.chapters, int) and len(self.chapters) > 0:
-            result += u'\n Chapter list:'
-            for i in range(len(self.chapters)):
-                pos = self.chapters[i]['pos']
-                result += u'\n   %2s: "%s" %02d:%02d:%02d.%03d' % \
-                          (i+1, unicode(self.chapters[i]['name']),
-                           int(pos)/60/60, int(pos/60) % 60, 
-                           int(pos)%60, (pos-int(pos))*1000)
-        return result
+            if container.length:
+                container.length = int(container.length)
 
 
 class CollectionInfo(MediaInfo):
     """
     Collection of Digial Media like CD, DVD, Directory, Playlist
     """
+    _keys = MediaInfo._keys + [ 'id', 'tracks' ]
+
     def __init__(self):
         MediaInfo.__init__(self)
         self.tracks = []
-        self.keys.append('id')
-        self.id = None
-
-    def __unicode__(self):
-        result = MediaInfo.__unicode__(self)
-        result += u'\nTrack list:'
-        for counter in range(0,len(self.tracks)):
-             result += u' \nTrack %d:\n%s' % \
-                       (counter+1, unicode(self.tracks[counter]))
-        return result
-
-    def appendtrack(self, track):
-        self.tracks.append(track)

Modified: trunk/metadata/src/misc/dirinfo.py
==============================================================================
--- trunk/metadata/src/misc/dirinfo.py  (original)
+++ trunk/metadata/src/misc/dirinfo.py  Wed Dec  6 20:52:29 2006
@@ -74,10 +74,10 @@
         f = open(info)
         for l in f.readlines():
             if l.startswith('Icon='):
-                self.image = l[5:].strip()
-                if not self.image.startswith('/'):
-                    self.image = os.path.join(directory, self.image[2:])
-                self.keys.append('image')
+                image = l[5:].strip()
+                if not image.startswith('/'):
+                    image = os.path.join(directory, image[2:])
+                self._set('image', image)
             if l.startswith('Name='):
                 self.title = l[5:].strip()
             if l.startswith('Comment='):
@@ -102,13 +102,9 @@
                 image = os.path.join(directory, unicode_to_str(child.content))
                 if not os.path.isfile(image):
                     continue
-                self.image = image
-                self.keys.append('image')
+                self._set('image', image)
                 continue
-            self[key] = child.content
-            if not key in MEDIACORE:
-                # if it's in desc it must be important
-                self.keys.append(key)
+            self._set(key, child.content)
 
 # register to kaa.metadata core
 register('directory', EXTENSION_DIRECTORY, TYPE_MISC, DirInfo)

Modified: trunk/metadata/src/video/asfinfo.py
==============================================================================
--- trunk/metadata/src/video/asfinfo.py (original)
+++ trunk/metadata/src/video/asfinfo.py Wed Dec  6 20:52:29 2006
@@ -265,9 +265,8 @@
                     flags = struct.unpack('>QIIH4x', s[56:78])
             strno = flags & 63
             encrypted = flags >> 15
-            if encrypted and not 'encrypted' in self.keys:
-                self.encrypted = True
-                self.keys.append('encrypted')
+            if encrypted:
+                self._set('encrypted', True)
             if streamtype == GUIDS['ASF_Video_Media']:
                 vi = mediainfo.VideoInfo()
                 vi.width, vi.height, depth, \
@@ -323,7 +322,7 @@
                 d = self._parsekv(s[pos:])
                 pos += d[0]
                 descriptor[d[1]] = d[2]
-            self.appendtable('ASFDESCRIPTOR', descriptor)
+            self._appendtable('ASFDESCRIPTOR', descriptor)
 
         elif guid == GUIDS['ASF_Metadata_Object']:
             (count,) = struct.unpack('<H', s[24:26])
@@ -336,7 +335,7 @@
                 descriptor[d[1]] = d[2]
             # TODO: Find the stream in self.audio and self.video and
             #       append it there instead of here
-            self.appendtable('ASFMETADATA%d'%d[3], descriptor)
+            self._appendtable('ASFMETADATA%d'%d[3], descriptor)
 
         elif guid == GUIDS['ASF_Language_List_Object']:
             count = struct.unpack('<H', s[24:26])[0]
@@ -369,8 +368,8 @@
         elif guid == GUIDS['ASF_Content_Encryption_Object'] or \
              guid == GUIDS['ASF_Extended_Content_Encryption_Object']:
             self.encrypted = True
-            if not 'encrypted' in self.keys:
-                self.keys.append('encrypted')
+            if encrypted:
+                self._set('encrypted', True)
         else:
             # Just print the type:
             for h in GUIDS.keys():

Modified: trunk/metadata/src/video/mkvinfo.py
==============================================================================
--- trunk/metadata/src/video/mkvinfo.py (original)
+++ trunk/metadata/src/video/mkvinfo.py Wed Dec  6 20:52:29 2006
@@ -121,7 +121,7 @@
     'A_PCM/FLOAT/IEEE': 0x003,
     'A_TTA1': 0x77a1
 }
-    
+
 class EbmlEntity:
     """
     This is class that is responsible to handle one Ebml entity as described in
@@ -386,9 +386,9 @@
                     track.aspect = 
float(vidtab[MATROSKA_DISPLAY_VID_WIDTH_ID].get_value()) / \
                                 
vidtab[MATROSKA_DISPLAY_VID_HEIGHT_ID].get_value()
                 if MATROSKA_VID_INTERLACED in vidtab:
-                    self.keys.append('interlaced')
-                    self.interlaced = 
int(vidtab[MATROSKA_VID_INTERLACED].get_value())
-                    
+                    value = int(vidtab[MATROSKA_VID_INTERLACED].get_value())
+                    self._set('interlaced', value)
+
             except Exception, e:
                 log.debug("No other info about video track !!!")
             self.media = 'video'
@@ -451,8 +451,8 @@
             if elem.get_id() == MATROSKA_CHAPTER_ATOM_ID:
                 self.process_chapter_atom(elem)
             indice += elem.get_total_len() + elem.get_crc_len()
- 
-        
+
+
     def process_chapter_atom(self, atom):
         tabelem = self.process_one_level(atom)
         chap = mediainfo.ChapterInfo()

Modified: trunk/metadata/src/video/movinfo.py
==============================================================================
--- trunk/metadata/src/video/movinfo.py (original)
+++ trunk/metadata/src/video/movinfo.py Wed Dec  6 20:52:29 2006
@@ -53,12 +53,20 @@
 #     chapter_5_section_2.html#//apple_ref/doc/uid/TP40000939-CH206-BBCBIICE
 # Note: May need to define custom log level to work like ATOM_DEBUG did here
 
+QTUDTA = {
+    'nam': 'title',
+    'aut': 'artist',
+    'cpy': 'copyright'
+}
 
 class MovInfo(mediainfo.AVInfo):
+
+    table_mapping = { 'QTUDTA': QTUDTA }
+
     def __init__(self,file):
         mediainfo.AVInfo.__init__(self)
         self.context = 'video'
-        self.references = []
+        self._references = []
 
         self.mime = 'video/quicktime'
         self.type = 'Quicktime Video'
@@ -81,13 +89,8 @@
         while self._readatom(file):
             pass
 
-        info = self.gettable('QTUDTA', 'en')
-        self.setitem('title', info, 'nam')
-        self.setitem('artist', info, 'aut')
-        self.setitem('copyright', info, 'cpy')
-
-        if self.references:
-            self.keys.append('references')
+        if self._references:
+            self._set('references', self._references)
 
 
     def _readatom(self, file):
@@ -129,12 +132,12 @@
                 pos += datasize
             if len(i18ntabl.keys()) > 0:
                 for k in i18ntabl.keys():
-                    if QTLANGUAGES.has_key(k):
-                        self.appendtable('QTUDTA', i18ntabl[k], QTLANGUAGES[k])
-                        self.appendtable('QTUDTA', tabl, QTLANGUAGES[k])
+                    if QTLANGUAGES.has_key(k) and QTLANGUAGES[k] == 'en':
+                        self._appendtable('QTUDTA', i18ntabl[k])
+                        self._appendtable('QTUDTA', tabl)
             else:
                 log.debug('NO i18')
-                self.appendtable('QTUDTA', tabl)
+                self._appendtable('QTUDTA', tabl)
 
         elif atomtype == 'trak':
             atomdata = file.read(atomsize-8)
@@ -210,8 +213,7 @@
                                     # jpeg is no video, remove it from the list
                                     self.video.remove(vi)
                                     info = None
-                                print codec
-                                
+
                         elif mdia[1] == 'dinf':
                             dref = unpack('>I4s', atomdata[pos+8:pos+8+8])
                             log.debug('  --> %s, %s' % mdia)
@@ -323,7 +325,7 @@
 
                 pos += datasize
             if url:
-                self.references.append((url, quality, datarate))
+                self._references.append((url, quality, datarate))
 
         else:
             if not atomtype in ('wide', 'free'):

Modified: trunk/metadata/src/video/mpeginfo.py
==============================================================================
--- trunk/metadata/src/video/mpeginfo.py        (original)
+++ trunk/metadata/src/video/mpeginfo.py        Wed Dec  6 20:52:29 2006
@@ -227,11 +227,9 @@
                 pass
             elif ext == 1:
                 if (ord(buffer[pos+5]) >> 3) & 1:
-                    self.keys.append('progressive')
-                    self.progressive = 1
+                    self._set('progressive', True)
                 else:
-                    self.keys.append('interlaced')
-                    self.interlaced = 1
+                    self._set('interlaced', True)
                 return True
             else:
                 log.debug('ext', ext)
@@ -373,8 +371,7 @@
                     break
             else:
                 self.audio.append(mediainfo.AudioInfo())
-                self.audio[-1].id = id
-                self.audio[-1].keys.append('id')
+                self.audio[-1]._set('id', id)
             return 0
 
         if 0xE0 <= id <= 0xEF:
@@ -384,8 +381,7 @@
                     break
             else:
                 self.video.append(mediainfo.VideoInfo())
-                self.video[-1].id = id
-                self.video[-1].keys.append('id')
+                self.video[-1]._set('id', id)
             return 0
 
         if id == SEQ_HEAD:
@@ -405,9 +401,8 @@
                         break
                 else:
                     self.audio.append(mediainfo.AudioInfo())
-                    self.audio[-1].id = id
+                    self.audio[-1]._set('id', id)
                     self.audio[-1].codec = 'AC3'
-                    self.audio[-1].keys.append('id')
             return 0
 
         if id == SYS_PKT:
@@ -520,8 +515,7 @@
                     break
             else:
                 self.audio.append(mediainfo.AudioInfo())
-                self.audio[-1].id = id
-                self.audio[-1].keys.append('id')
+                self.audio[-1]._set('id', id)
 
         elif ord(buffer[3]) & 0xF0 == 0xE0:
             id = id or ord(buffer[3]) & 0xF
@@ -530,8 +524,7 @@
                     break
             else:
                 self.video.append(mediainfo.VideoInfo())
-                self.video[-1].id = id
-                self.video[-1].keys.append('id')
+                self.video[-1]._set('id', id)
 
             # new mpeg starting
             if buffer[header_length+9:header_length+13] == \
@@ -549,9 +542,8 @@
                         break
                 else:
                     self.audio.append(mediainfo.AudioInfo())
-                    self.audio[-1].id = id
+                    self.audio[-1]._set('id', id)
                     self.audio[-1].codec = 'AC3'
-                    self.audio[-1].keys.append('id')
 
         else:
             # unknown content
@@ -724,9 +716,6 @@
         if not self.sequence_header_offset:
             return 0
 
-        if hasattr(self, 'start') and self.start:
-            self.keys.append('start')
-
         # fill in values for support functions:
         self.__seek_size__   = 10000000  # 10 MB
         self.__sample_size__ = 100000    # 100 k scanning

Modified: trunk/metadata/src/video/ogminfo.py
==============================================================================
--- trunk/metadata/src/video/ogminfo.py (original)
+++ trunk/metadata/src/video/ogminfo.py Wed Dec  6 20:52:29 2006
@@ -54,20 +54,23 @@
 STREAM_HEADER_VIDEO = '<4sIQQIIHII'
 STREAM_HEADER_AUDIO = '<4sIQQIIHHHI'
 
-VORBISCOMMENT_tags = { 'title': 'TITLE',
-                       'album': 'ALBUM',
-                       'artist': 'ARTIST',
-                       'comment': 'COMMENT',
-                       'date': 'DATE',
-                       'encoder': 'ENCODER',
-                       'trackno': 'TRACKNUMBER',
-                       'language': 'LANGUAGE',
-                       'genre': 'GENRE',
-                     }
+VORBISCOMMENT = { 'TITLE': 'title',
+                  'ALBUM': 'album',
+                  'ARTIST': 'artist',
+                  'COMMENT': 'comment',
+                  'DATE': 'date',
+                  'ENCODER': 'encoder',
+                  'TRACKNUMBER': 'trackno',
+                  'LANGUAGE': 'language',
+                  'GENRE': 'genre',
+                }
 
 MAXITERATIONS = 10
 
 class OgmInfo(mediainfo.AVInfo):
+
+    table_mapping = { 'VORBISCOMMENT' : VORBISCOMMENT }
+
     def __init__(self, file):
         mediainfo.AVInfo.__init__(self)
         self.samplerate  = 1
@@ -110,7 +113,7 @@
                 self.length = max(self.all_streams[i].length, self.length)
 
                 # get meta info
-                for key in self.all_streams[i].keys:
+                for key in self.all_streams[i].keys():
                     if self.all_header[i].has_key(key):
                         self.all_streams[i][key] = self.all_header[i][key]
                         del self.all_header[i][key]
@@ -162,13 +165,7 @@
 
         # Copy Metadata from tables into the main set of attributes
         for header in self.all_header:
-            self.appendtable('VORBISCOMMENT', header)
-
-        self.tag_map = { ('VORBISCOMMENT', 'en') : VORBISCOMMENT_tags }
-        for k in self.tag_map.keys():
-            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),
-                                      self.tag_map[k][x]),
-                self.tag_map[k].keys())
+            self._appendtable('VORBISCOMMENT', header)
 
 
     def _parseOGGS(self,file):
@@ -306,8 +303,8 @@
 
             elif htype[:4] == 'text':
                 subtitle = mediainfo.MediaInfo()
-                subtitle.keys.append('language')
-                subtitle.type   = 'subtitle'
+                subtitle._set('language', None)
+                subtitle.type = 'subtitle'
                 subtitle.length = 0
                 self.all_streams.append(subtitle)
 

Modified: trunk/metadata/src/video/riffinfo.py
==============================================================================
--- trunk/metadata/src/video/riffinfo.py        (original)
+++ trunk/metadata/src/video/riffinfo.py        Wed Dec  6 20:52:29 2006
@@ -31,6 +31,7 @@
 
 # python imports
 import re
+import os
 import struct
 import string
 import logging
@@ -49,23 +50,20 @@
 # http://www.divx-digest.com/software/avitags_dll.html
 # File Format: google for odmlff2.pdf
 
-AVIINFO_tags = { 'title': 'INAM',
-                 'artist': 'IART',
-                 'product': 'IPRD',
-                 'date': 'ICRD',
-                 'comment': 'ICMT',
-                 'language': 'ILNG',
-                 'keywords': 'IKEY',
-                 'trackno': 'IPRT',
-                 'trackof': 'IFRM',
-                 'producer': 'IPRO',
-                 'writer': 'IWRI',
-                 'genre': 'IGNR',
-                 'copyright': 'ICOP',
-                 'trackno': 'IPRT',
-                 'trackof': 'IFRM',
-                 'comment': 'ICMT',
-               }
+AVIINFO = { 'INAM': 'title',
+            'IART': 'artist',
+            'IPRD': 'product',
+            'ICRD': 'date',
+            'ICMT': 'comment',
+            'ILNG': 'language',
+            'IKEY': 'keywords',
+            'IPRT': 'trackno',
+            'IFRM': 'trackof',
+            'IPRO': 'producer',
+            'IWRI': 'writer',
+            'IGNR': 'genre',
+                 'ICOP': 'copyright'
+          }
 
 PIXEL_ASPECT = {  # Taken from libavcodec/mpeg4data.h (pixel_aspect struct)
     1: (1, 1),
@@ -77,6 +75,9 @@
 
 
 class RiffInfo(mediainfo.AVInfo):
+
+    table_mapping = { 'AVIINFO' : AVIINFO }
+
     def __init__(self,file):
         mediainfo.AVInfo.__init__(self)
         # read the header
@@ -90,7 +91,6 @@
         self.junkStart = None
         self.infoStart = None
         self.type = h[8:12]
-        self.tag_map = { ('AVIINFO', 'en') : AVIINFO_tags }
         if self.type == 'AVI ':
             self.mime = 'video/avi'
         elif self.type == 'WAVE':
@@ -101,23 +101,35 @@
         except IOError:
             log.exception('error in file, stop parsing')
 
-        self.find_subtitles(file.name)
+        self._find_subtitles(file.name)
 
-        # Copy Metadata from tables into the main set of attributes
-        for k in self.tag_map.keys():
-            map(lambda x:self.setitem(x,self.gettable(k[0],k[1]),
-                                      self.tag_map[k][x]),
-                self.tag_map[k].keys())
         if not self.has_idx:
             log.debug('WARNING: avi has no index')
-            self.corrupt = 1
-            self.keys.append('corrupt')
+            self._set('corrupt', True)
 
 
     def _extractHeaderString(self,h,offset,len):
         return h[offset:offset+len]
 
 
+    def _find_subtitles(self, filename):
+        """
+        Search for subtitle files. Right now only VobSub is supported
+        """
+        base = os.path.splitext(filename)[0]
+        if os.path.isfile(base+'.idx') and \
+               (os.path.isfile(base+'.sub') or os.path.isfile(base+'.rar')):
+            file = open(base+'.idx')
+            if file.readline().find('VobSub index file') > 0:
+                for line in file.readlines():
+                    if line.find('id') == 0:
+                        sub = mediainfo.SubtitleInfo()
+                        sub.language = line[4:6]
+                        sub.trackno = base + '.idx'  # Maybe not?
+                        self.subtitles.append(sub)
+            file.close()
+
+
     def parseAVIH(self,t):
         retval = {}
         v = struct.unpack('<IIIIIIIIIIIIII',t[0:56])
@@ -299,7 +311,7 @@
 
     def parseLISTmovi(self, size, file):
         """
-        Digs into movi list, looking for a Video Object Layer header in an 
+        Digs into movi list, looking for a Video Object Layer header in an
         mpeg4 stream in order to determine aspect ratio.
         """
         i = 0
@@ -317,7 +329,7 @@
 
             key, sz = struct.unpack('<4sI', data)
             if key[2:] != 'dc' or sz > 1024*500:
-                # This chunk is not video or is unusually big (> 500KB); 
+                # This chunk is not video or is unusually big (> 500KB);
                 # skip it.
                 file.seek(sz, 1)
                 i += 8 + sz
@@ -335,7 +347,7 @@
             # logic for this is taken from libavcodec, h263.c
             pos = 0
             startcode = 0xff
-            def bits(v, o, n): 
+            def bits(v, o, n):
                 # Returns n bits in v, offset o bits.
                 return (v & 2**n-1 << (64-n-o)) >> 64-n-o
 
@@ -385,7 +397,7 @@
         if i < size:
             # Seek past whatever might be remaining of the movi list.
             file.seek(size-i,1)
- 
+
 
 
     def parseLIST(self,t):
@@ -488,7 +500,7 @@
                self.video[-1].format in ('DIVX', 'XVID', 'FMP4'): # any others?
                 # If we don't have the aspect (i.e. it isn't in odml vprp
                 # header), but we do know the video's dimensions, and
-                # we're dealing with an mpeg4 stream, try to get the aspect 
+                # we're dealing with an mpeg4 stream, try to get the aspect
                 # from the VOL header in the mpeg4 stream.
                 self.parseLISTmovi(size-4, file)
                 return True
@@ -496,16 +508,16 @@
                 log.debug('RIFF LIST "%s" to long to parse: %s bytes' % (key, 
size))
                 t = file.seek(size-4,1)
                 return True
-                
+
             t = file.read(size-4)
             log.debug('parse RIFF LIST "%s": %d bytes' % (key, size))
             value = self.parseLIST(t)
             self.header[key] = value
             if key == 'INFO':
                 self.infoStart = pos
-                self.appendtable( 'AVIINFO', value )
+                self._appendtable( 'AVIINFO', value )
             elif key == 'MID ':
-                self.appendtable( 'AVIMID', value )
+                self._appendtable( 'AVIMID', value )
             elif key in ('hdrl', ):
                 # no need to add this info to a table
                 pass

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to