Update of /cvsroot/freevo/freevo/src/mediadb
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv1831/mediadb

Added Files:
        .cvsignore __init__.py db.py debug.py item.py listing.py 
Log Message:
New mediadb as replacement for util.mediainfo and other parts of freevo
getting informations about media items. It is not integrated yet! The
goal is to create one module dealing with all parts of informations in
freevo and to make creating menu listings much faster.


--- NEW FILE: debug.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# mediainfo.py - 
# -----------------------------------------------------------------------------
# $Id: debug.py,v 1.1 2005/03/13 10:13:35 dischi Exp $
#
# -----------------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
#
# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
#
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------

import time
import sys
import os
import stat
import mmpython
import pickle
import cPickle
import re
import logging
import copy

from mmpython.disc.discinfo import cdrom_disc_id

import sysconfig
import config
import util.fxdparser
import util.vfs as vfs
import util.cache as cache
from util.callback import *

log = logging.getLogger('mediainfo')


def print_data(data, space='    '):
    for key, info in data.items():
        if isinstance(info, (list, tuple)):
            print '%s%s: [' % (space, key)
            for i in info:
                if isinstance(i, dict):
                    print_data(i, space + '  ')
                    print
                else:
                    print '%s  %s' % (space, i)
            print '%s  ]' % (space)

        elif not key in ( 'mminfo', 'fxd' ):
            print '%s%s: %s' % (space, key, info)
    if not data.has_key('mminfo'):
        return
    mminfo = cPickle.loads(data['mminfo'])
    print_data(mminfo, '      ')
    print


# XXX MEDIAINFO UPDATE XXX
t1 = time.time()
l = Listing(sys.argv[1])
t2 = time.time()
l.update()
t3 = time.time()
print 'time: %s %s' % (t2 - t1, t3 - t1)
print
print
print 'Listing for %s' % l.cache.dirname
for key in l.cache.data:
    if not key in ('overlay', 'items'):
        print '  %s: %s' % (key, l.cache.data[key])
print
for file, info in l.cache.items.items():
    print '  %s' % file
    print_data(info)
print
for file, info in l.cache.overlay.items():
    print '  %s' % file
    print_data(info)
print

--- NEW FILE: .cvsignore ---
*.pyc *.pyo

--- NEW FILE: item.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# item.py -
# -----------------------------------------------------------------------------
# $Id: item.py,v 1.1 2005/03/13 10:13:35 dischi Exp $
#
# -----------------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
#
# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
#
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------

__all__ = [ 'ItemInfo' ]

# python imports
import pickle
import cPickle
import logging

# freevo imports
from util.callback import *

# get logging object
log = logging.getLogger('mediainfo')

class ItemInfo:
    def __init__(self, basename, dirname, attr, cache=None):
        if not attr:
            attr = {}
        self.attr = attr
        self.basename = basename
        self.tmp = {}
        self.mminfo = None
        self.hidden_variables = {}
        self.dirname = dirname
        self.filename = self.dirname + '/' + self.basename
        self.cache = cache


    def __str__(self):
        return self.basename


    def __getitem__(self, key):
        if key in ('cover', 'audiocover'):
            if self.attr.has_key(key):
                return self.attr[key]
            elif self.cache:
                return self.cache.data[key]
            return ''

        if self.tmp.has_key(key):
            return self.tmp[key]
        if self.attr.has_key(key):
            return self.attr[key]
        if self.hidden_variables.has_key(key):
            return self.hidden_variables[key]
        if not self.attr.has_key('mminfo'):
            return None
        if self.mminfo == None:
            log.debug('unpickle %s' % self.basename)
            self.mminfo = cPickle.loads(self.attr['mminfo'])
        log.debug('mmget %s (%s)' % (self.basename, key))
        if self.mminfo.has_key(key):
            return self.mminfo[key]
        return None


    def __setitem__(self, key, value):
        if self.attr.has_key(key):
            self.attr[key] = value
            if self.cache:
                self.cache.changed = True
                call_later(self.cache.save)
        else:
            self.tmp[key] = value


    def has_key(self, key):
        if key in ('cover', 'audiocover'):
            return True
        if self.tmp.has_key(key):
            return True
        if self.attr.has_key(key):
            return True
        if self.hidden_variables.has_key(key):
            return True
        if not self.attr.has_key('mminfo'):
            return False
        if self.mminfo == None:
            log.debug('unpickle %s' % self.basename)
            self.mminfo = cPickle.loads(self.attr['mminfo'])
        log.debug('mmget %s (%s)' % (self.basename, key))
        if self.mminfo.has_key(key):
            return True
        return False


    def keys(self):
        ret = [ 'cover', 'audiocover' ]
        if self.mminfo == None:
            if self.attr.has_key('mminfo'):
                log.debug('unpickle %s' % self.basename)
                self.mminfo = cPickle.loads(self.attr['mminfo'])
            else:
                self.mminfo = {}
        for vardict in self.tmp, self.attr, self.hidden_variables, self.mminfo:
            for key in vardict:
                if not key in ret:
                    ret.append(key)
        return ret


    def store(self, key, value):
        self.attr[key] = value
        if self.cache:
            self.cache.changed = True
            call_later(self.cache.save)
        return True


    def store_with_mtime(self, key, value):
        self.attr[key] = value
        if self.cache:
            self.cache.changed = True
            call_later(self.cache.save)
        if not key in self.attr['mtime_dep']:
            self.attr['mtime_dep'].append(key)
        return True


    def get_variables(self):
        return self.tmp


    def set_variables(self, list):
        self.tmp = list


    def set_permanent_variables(self, variables):
        self.hidden_variables = variables

    def delete(self, key):
        pass

--- NEW FILE: db.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# db.py -
# -----------------------------------------------------------------------------
# $Id: db.py,v 1.1 2005/03/13 10:13:35 dischi Exp $
#
# -----------------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
#
# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
#
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------

__all__ = [ 'Cache', 'FileCache', 'save', 'get' ]

# python imports
import time
import os
import stat
import mmpython
import pickle
import cPickle
import re
import logging

# freevo imports
import config
import util.fxdparser
import util.vfs as vfs
import util.cache as cache
from util.callback import *

# get logging object
log = logging.getLogger('mediadb')

VERSION = 1.6

def _simplify(object):
    """
    mmpython has huge objects to cache, we don't need them.
    This function simplifies them to be only string, integer, dict or
    list of one of those above. This makes the caching much faster
    """
    ret = {}
    for k in object.keys:
        if not k in [ 'thumbnail', 'url' ] and getattr(object,k) != None:
            value = getattr(object,k)
            if isstring(value):
                value = Unicode(value.replace('\0', '').lstrip().rstrip())
            if value:
                ret[k] = value

    for k in  ( 'video', 'audio'):
        # if it's an AVCORE object, also simplify video and audio
        # lists to string and it
        if hasattr(object, k) and getattr(object, k):
            ret[k] = []
            for o in getattr(object, k):
                ret[k].append(_simplify(o))

    if hasattr(object, 'tracks') and object.tracks:
        # read track informations for dvd
        ret['tracks'] = []
        for o in object.tracks:
            track = _simplify(o)
            if not track.has_key('audio'):
                track['audio'] = []
            if not track.has_key('subtitles'):
                track['subtitles'] = []
            ret['tracks'].append(track)

    for k in ('subtitles', 'chapters', 'mime', 'id' ):
        if hasattr(object, k) and getattr(object, k):
            ret[k] = getattr(object, k)

    return ret

def _parse_fxd_node(node):
    children = []
    for c in node.children:
        children.append(_parse_fxd_node(c))
    return (node.name, node.attrs, children, node.textof(), node.first_cdata,
            node.following_cdata)


def _parse_fxd(filename):
    data = util.fxdparser.FXDtree(filename, False)
    if data.tree.name != 'freevo':
        return {}
    is_skin_fxd = False
    for node in data.tree.children:
        if node.name == 'skin':
            is_skin_fxd = True
            break
    tree = []
    for node in data.tree.children:
        tree.append(_parse_fxd_node(node))
    return is_skin_fxd, tree


def _cover_filter(x):
    """
    filter function to get valid cover names
    """
    return re.search(config.AUDIO_COVER_REGEXP, x, re.IGNORECASE)


def _add_info(filename, object):
    mminfo = None
    if not object['ext'] in [ 'xml', 'fxd' ]:
        mminfo = mmpython.parse(filename)
    title = _getname(filename)
    object['title:filename'] = title
    if mminfo:
        # store mmpython data as pickle for faster loading
        object['mminfo'] = cPickle.dumps(_simplify(mminfo),
                                         pickle.HIGHEST_PROTOCOL)
        if mminfo.title:
            object['title'] = mminfo.title
        else:
            object['title'] = title
    elif object.has_key('mminfo'):
        del object['mminfo']
        object['title'] = title
    else:
        object['title'] = title

    if filename.endswith('.fxd'):
        # store fxd tree as pickle for faster loading
        object['fxd'] = cPickle.dumps(_parse_fxd(filename),
                                      pickle.HIGHEST_PROTOCOL)

    if os.path.isdir(filename):
        object['isdir'] = True
        listing = vfs.listdir(filename, include_overlay=True)
        # get directory cover
        for l in listing:
            if l.endswith('/cover.png') or l.endswith('/cover.jpg') or \
                   l.endswith('/cover.gif'):
                object['cover'] = l
                break
        else:
            if object.has_key('cover'):
                del object['cover']
            if object.has_key('audiocover'):
                del object['audiocover']
            files = util.find_matches(listing, ('jpg', 'gif', 'png' ))
            if len(files) == 1:
                object['audiocover'] = files[0]
            elif len(files) > 1 and len(files) < 10:
                files = filter(_cover_filter, files)
                if files:
                    object['audiocover'] = files[0]

        # save directory overlay mtime
        overlay = vfs.getoverlay(filename)
        if os.path.isdir(overlay):
            mtime = os.stat(overlay)[stat.ST_MTIME]
            object['overlay_mtime'] = mtime
        else:
            object['overlay_mtime'] = 0
    else:
        if object.has_key('isdir'):
            del object['isdir']


_FILENAME_REGEXP = re.compile("^(.*?)_(.)(.*)$")

def _getname(file):
    """
    make a nicer display name from file
    """
    if len(file) < 2:
        return Unicode(file)

    # basename without ext
    if file.rfind('/') < file.rfind('.'):
        name = file[file.rfind('/')+1:file.rfind('.')]
    else:
        name = file[file.rfind('/')+1:]
    if not name:
        # Strange, it is a dot file, return the complete
        # filename, I don't know what to do here. This should
        # never happen
        return Unicode(file)

    name = name[0].upper() + name[1:]

    while file.find('_') > 0 and _FILENAME_REGEXP.match(name):
        m = _FILENAME_REGEXP.match(name)
        if m:
            name = m.group(1) + ' ' + m.group(2).upper() + m.group(3)
    if name.endswith('_'):
        name = name[:-1]
    return Unicode(name)



class CacheList:
    def __init__(self):
        self.caches = {}

    def get(self, dirname):
        if dirname in self.caches:
            cache = self.caches[dirname]
            mtime = os.stat(cache.file)[stat.ST_MTIME]
            if mtime == cache.mtime:
                return cache
        c = Cache(dirname)
        self.caches[dirname] = c
        return c

    def save(self):
        for cache in self.caches.values():
            cache.save()


# global object
_cache_list = CacheList()

class Cache:
    """
    A cache object for the mediainfo holding one directory.
    """
    def __init__(self, dirname):
        self.dirname = dirname
        self.overlay_file = vfs.getoverlay(dirname)
        self.file = self.overlay_file + '/freevo.db'
        self.data = None
        self.changed = False
        self.check_time = 0
        if os.path.isfile(self.file):
            # load cache file
            self.data = cache.load(self.file, VERSION)
            self.mtime = os.stat(self.file)[stat.ST_MTIME]
        elif not os.path.isdir(os.path.dirname(self.overlay_file)):
            # create vfs overlay dir; we will need it anyway for
            # storing the db file
            os.makedirs(os.path.dirname(self.overlay_file))
        if not self.data:
            # create a new cache data dict
            self.data  = {'items_mtime': 0,
                          'items': {},
                          'overlay_mtime': {},
                          'overlay': {},
                          'cover': '',
                          'audiocover': '',
                          }
            # save file to make sure the file itself exist in the future
            # process and to avoid directory changes just because the cache
            # is saved to a new file.
            self.changed = True
            self.save()
        # 'normal' files
        self.items   = self.data['items']
        # file sin the overlay dir
        self.overlay = self.data['overlay']
        # internal stuff about changes
        self.__added   = []
        self.__changed = []
        self.__check_global = False
        # a hidden list of files only to check when checking the cache
        self.reduce_files = []


    def reduce(self, files):
        """
        Reduce the files to be checked to the given list of basenames.
        """
        self.reduce_files = files


    def check(self, overlay = False):
        """
        Check the directory for changes.
        """
        if overlay:
            # handling the overlay dir
            dirname = self.overlay_file
            listing = self.overlay
            mtime   = 'overlay_mtime'
        else:
            # handling the 'normal' dir
            dirname = self.dirname
            listing = self.items
            mtime   = 'items_mtime'

        deleted = []
        # get mtime (may be 0 for devices)
        data_mtime = os.stat(dirname)[stat.ST_MTIME]
        if data_mtime != self.data[mtime] or not data_mtime:
            log.debug('check %s' % dirname)
            # mtime differs, check directory for added and deleted files
            if not self.reduce_files:
                # store new mtime
                self.data[mtime] = data_mtime
            # get a current filelisting
            files = os.listdir(dirname)
            for file, info in listing.items():
                if file in files:
                    # in cache already
                    files.remove(file)
                else:
                    # deleted
                    deleted.append(file)
            for d in deleted:
                log.debug('deleted: %s' % d)
                # FIXME: if this file is an image, search every item in
                # the list if it uses this file as cover image.
                del listing[d]

            for f in files:
                # check all files f not in the cache
                if self.reduce_files and not f in self.reduce_files:
                    # ignore the file for now
                    continue
                if f in ('CVS', 'lost+found') or f.startswith('.'):
                    # ignore such files
                    continue
                if overlay and (f == 'freevo.db' or f.find('.thumb.') > 0 or \
                                f.endswith('.raw') or f.endswith('.cache')):
                    # ignore such files in overlay
                    continue
                fullname = dirname + '/' + f
                if overlay and os.path.isdir(fullname):
                    # ignore directories in overlay
                    continue
                # add as added
                self.__added.append((f, fullname))

        for basename, info in listing.items():
            # check all files for changes (compare mtime)
            if self.reduce_files and not basename in self.reduce_files:
                continue
            filename = dirname + '/' + basename
            mtime = os.stat(filename)[stat.ST_MTIME]
            if mtime != info['mtime']:
                # changed
                info['mtime'] = mtime
                self.__changed.append((basename, filename, info))
            elif info.has_key('isdir'):
                # For directories also check the overlay directory. A change
                # in the overlay will change the directory, too
                overlay = vfs.getoverlay(filename)
                if os.path.isdir(overlay):
                    mtime = os.stat(overlay)[stat.ST_MTIME]
                    if mtime != info['overlay_mtime']:
                        info['overlay_mtime'] = mtime
                        self.__changed.append((basename, filename, info))

        if deleted and len(self.__added):
            self.__check_global = True
            self.changed = True
        if overlay:
            self.check_time = time.time()
            if self.changed:
                call_later(self.save)
            return
        self.check(True)


    def save(self):
        """
        Save the cache.
        """
        if not self.changed:
            return
        log.info('save %s' % self.file)
        cache.save(self.file, self.data, VERSION)
        self.mtime = os.stat(self.file)[stat.ST_MTIME]
        self.changed = False


    def parse(self, callback):
        """
        Parse added and changed files. If callback is not None, the callback
        will be called after each file.
        """
        if not self.__added and not self.__changed and \
               not self.__check_global:
            return

        self.changed = True

        for basename, filename in self.__added:
            # check new files
            log.debug('new: %s' % basename)
            ext = basename[basename.rfind('.')+1:].lower()
            if ext == basename:
                ext = ''
            info = { 'ext'      : ext,
                     'mtime'    : os.stat(filename)[stat.ST_MTIME],
                     'mtime_dep': []
                     }
            _add_info(filename, info)

            prefix = basename[:-len(ext)]
            if ext in ('png', 'jpg', 'gif'):
                # the new item is an image, search all items for a similar
                # name to add the file as cover
                for i_basename, i_info in self.items.items():
                    if i_basename[:-len(i_info['ext'])] == prefix:
                        i_info['cover'] = filename
            else:
                # search the items in the list for covers matching the
                # basename of the new item
                for ext in ('png', 'jpg', 'gif'):
                    if prefix + ext in self.items:
                        info['cover'] = self.dirname + '/' + prefix + ext
                    if prefix + ext in self.overlay:
                        info['cover'] = self.overlay_file + '/' + prefix + ext
            if vfs.isoverlay(filename):
                self.overlay[basename] = info
            else:
                self.items[basename] = info
            if callback:
                callback()

        for basename, filename, info in self.__changed:
            # check changed files
            log.debug('changed: %s' % filename)
            _add_info(filename, info)
            log.debug(info['mtime_dep'])
            for key in info['mtime_dep']:
                del info[key]
            if callback:
                callback()

        if self.__check_global:
            # check global data when files are added or deleted
            for cover in ('cover.png', 'cover.jpg', 'cover.gif'):
                if self.items.has_key(cover):
                    # directory cover image
                    self.data['cover'] = self.dirname + '/' + cover
                    self.data['audiocover'] = self.data['cover']
                    break
                if self.overlay.has_key(cover):
                    # cover in overlay
                    self.data['cover'] = self.overlay_file + '/' + cover
                    self.data['audiocover'] = self.data['cover']
                    break
            else:
                # no cover, try to find at least some image that can be used
                # as cover for audio items
                self.data['cover'] = ''
                self.data['audiocover'] = ''
                cover = []
                for f, i in self.items.items():
                    if i['ext'] in ('png', 'jpg', 'gif'):
                        cover.append(f)
                        if len(cover) > 10:
                            cover = []
                            break
                if len(cover) == 1:
                    self.data['audiocover'] = cover[0]
                else:
                    cover = filter(_cover_filter, cover)
                    if cover:
                        self.data['audiocover'] = cover[0]

            if callback:
                callback()

        self.save()
        self.__added   = []
        self.__changed = []
        self.__check_global = False
        self.reduce_files = []


    def list(self):
        """
        Return all items.
        """
        return self.items.items() + self.overlay.items()


    def num_changes(self):
        """
        Return the number of changes in the directory. If the number is
        greater than zero, parse _must_ be called.
        """
        if self.check_time + 2 < time.time():
            self.check()
        changes = len(self.__added) + len(self.__changed)
        if self.__check_global:
            return changes + 1
        if not changes:
            self.reduce_files = []
        return changes

class FileCache:
    """
    Cache for one file
    """
    def __init__(self, filename, db):
        self.file = db
        self.data = None
        if os.path.isfile(self.file):
            # load cache file
            self.data = cache.load(self.file, VERSION)
            self.mtime = os.stat(self.file)[stat.ST_MTIME]
        if not self.data:
            # create a new cache data dict
            self.data  = { 'ext': '',
                           'cover': '',
                           'audiocover': '',
                           'mtime'    : os.stat(filename)[stat.ST_MTIME],
                           'mtime_dep': []
                           }
            # save file to make sure the file itself exist in the future
            # process and to avoid directory changes just because the cache
            # is saved to a new file.
            self.changed = True
            _add_info(filename, self.data)
            self.save()


    def save(self):
        """
        Save the cache.
        """
        if not self.changed:
            return
        log.info('save %s' % self.file)
        cache.save(self.file, self.data, VERSION)
        self.mtime = os.stat(self.file)[stat.ST_MTIME]
        self.changed = False



def save():
    _cache_list.save()


def get(dirname):
    return _cache_list.get(dirname)


--- NEW FILE: listing.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# mediainfo.py - 
# -----------------------------------------------------------------------------
# $Id: listing.py,v 1.1 2005/03/13 10:13:35 dischi Exp $
#
# -----------------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
#
# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
#
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------

__all__ = [ 'Listing', 'FileListing' ]

# python imports
import logging

# mediadb imports
import db
from db import Cache, FileCache
from item import ItemInfo

log = logging.getLogger('mediadb')

class Listing:
    def __init__(self, dirname):
        try:
            self.cache = db.get(dirname)
        except:
            log.exception('Listing error for %s' % dirname)
            self.data = []
            self.visible = []
            self.num_changes = 0
            return
        self.num_changes = self.cache.num_changes()
        self.dirname = dirname
        self.data = []
        if self.num_changes > 0:
            self.visible = []
            return
        for basename, item in self.cache.list():
            self.data.append(ItemInfo(basename, dirname, item, self.cache))
        self.visible = self.data


    def update(self, callback=None):
        if self.num_changes == 0:
            return
        self.cache.parse(callback)
        dirname = self.dirname
        cache = self.cache
        for basename, item in self.cache.list():
            self.data.append(ItemInfo(basename, dirname, item, cache))
        self.num_changes = 0
        self.visible = self.data


    def get_dir(self):
        ret = filter(lambda x: x.attr.has_key('isdir'), self.visible)
        self.visible = filter(lambda x: not x.attr.has_key('isdir'),
                              self.visible)
        return ret


    def remove(self, item_or_name):
        if isinstance(item_or_name, ItemInfo):
            self.visible.remove(item_or_name)
            return
        for item in self.visible:
            if item.filename == item_or_name or \
                   item.basename == item_or_name:
                self.visible.remove(item)
                return


    def get_by_name(self, name):
        for item in self.visible:
            if item.basename == name:
                return item
        return None


    def match_suffix(self, suffix_list):
        visible = self.visible
        self.visible = []
        ret = []
        for v in visible:
            if v.attr['ext'] in suffix_list: ret.append(v)
            else: self.visible.append(v)
        return ret



class FileListing(Listing):
    def __init__(self, files):
        self.caches = {}
        for f in files:
            if f == '/':
                # root directory in the list, ignore it for now
                log.error('unable to parse root directory')
                continue
            if f.endswith('/'):
                dirname  = f[:f[:-1].rfind('/')]
                basename = f[f[:-1].rfind('/')+1:-1]
            else:
                dirname = f[:f.rfind('/')]
                basename = f[f[:-1].rfind('/')+1:]
            try:
                if not dirname in self.caches:
                    cache = db.get(dirname)
                    self.caches[dirname] = ( cache, [ basename ] )
                else:
                    self.caches[dirname][1].append(basename)
            except:
                log.exception('Listing error for %s' % dirname)

        self.num_changes = 0
        for cache, files in self.caches.values():
            cache.reduce(files)
            self.num_changes += cache.num_changes()

        self.data = []
        if self.num_changes > 0:
            self.visible = []
            return
            
        for dirname, ( cache, all_files ) in self.caches.items():
            for basename, item in cache.list():
                if basename in all_files:
                    self.data.append(ItemInfo(basename, dirname, item, cache))
        self.visible = self.data


    def update(self, callback=None):
        for dirname, ( cache, all_files ) in self.caches.items():
            cache.parse(callback)
            for basename, item in cache.list():
                if basename in all_files:
                    self.data.append(ItemInfo(basename, dirname, item, cache))
        self.num_changes = 0
        self.visible = self.data



--- NEW FILE: __init__.py ---
# -*- coding: iso-8859-1 -*-
# -----------------------------------------------------------------------------
# mediadb
# -----------------------------------------------------------------------------
# $Id: __init__.py,v 1.1 2005/03/13 10:13:35 dischi Exp $
#
# TODO: o remove old functions (see below)
#       o include extendedmeta
#       o add SQLListing
#       o maybe preload whole cache? Expire cache?
#       o add InfoItem for / and network url
#       o add InfoItem for subditems
#
# -----------------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002-2004 Krister Lagerstrom, Dirk Meyer, et al.
#
# First Edition: Dirk Meyer <[EMAIL PROTECTED]>
# Maintainer:    Dirk Meyer <[EMAIL PROTECTED]>
#
# Please see the file freevo/Docs/CREDITS for a complete list of authors.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 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 MER-
# CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
# Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -----------------------------------------------------------------------------

# python imports
import os
import logging

# mmpython
from mmpython.disc.discinfo import cdrom_disc_id

# freevo imports
import sysconfig

# mediadb imports
from db import Cache, FileCache, save
from item import ItemInfo
from listing import Listing, FileListing

# get logging object
log = logging.getLogger('mediadb')


def disc_info(media, force=False):
    """
    Return information for the media
    """
    type, id  = cdrom_disc_id(media.devicename)
    if not id:
        # bad disc, e.g. blank disc
        return ItemInfo(None, None, None)
    cachefile = os.path.join(sysconfig.VFS_DIR, 'disc/metadata/%s.db' % id)
    if force and os.path.isfile(cachefile):
        os.unlink(cachefile)
    cache = FileCache(media.devicename, cachefile)
    info = ItemInfo('', '', cache.data, cache)
    info.filename = info['mime'][6:] + '://'
    return info


#
# FIXME: the following functions will be removed in the future
# also missing the attribute mmdata used by videoitem.py
#

def get(filename):
    # used by directory.py, item.py, videoitem.py and extendedmeta.py
    log.warning('get simple info %s', filename)
    listing = FileListing( [ filename ] )
    if listing.num_changes:
        listing.update()
    return listing.get_by_name(os.path.basename(filename))


def del_cache():
    # used by cache.py
    log.error('del_cache not defined anymore')


def set(filename, key, value):
    # used by extendedmeta.py
    log.error('set not defined anymore')


def cache_recursive(dirlist, verbose=False):
    # used by cache.py
    log.error('cache_recursive not defined anymore')


def cache_dir(dirname, callback=None):
    # used by cache.py, extendedmeta.py
    log.error('cache_dir not defined anymore')



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_id=6595&alloc_id=14396&op=click
_______________________________________________
Freevo-cvslog mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/freevo-cvslog

Reply via email to