#!/usr/bin/env python import errno import os import sets import stat from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource from twisted.web import static from twisted.python import log mimedict = static.loadMimeTypes() def statcmp(a, b, cmpattrs = [ 'st_ino', 'st_dev', 'st_size', 'st_mtime', ]): if a is None or b is None: return False for i in cmpattrs: if getattr(a, i) != getattr(b, i): return False return True class FSObject(object): def __init__(self, path): self.FSpath = path self.pstat = None def checkUpdate(self): # need to handle no such file or directory # push it up? but still need to handle disappearing try: nstat = os.stat(self.FSpath) if statcmp(self.pstat, nstat): return self self.pstat = nstat self.doUpdate() except OSError, x: log.msg('os.stat, OSError: %s' % x) if x.errno in (errno.ENOENT, errno.ENOTDIR, errno.EPERM, ): # We can't access it anymore, delete it self.cd.delItem(self.id) else: raise x return self def doUpdate(self): raise NotImplementedError class FSItem(FSObject, Item): def __init__(self, *args, **kwargs): FSObject.__init__(self, kwargs['path']) del kwargs['path'] urlbase = kwargs['urlbase'] del kwargs['urlbase'] mimetype = kwargs['mimetype'] del kwargs['mimetype'] Item.__init__(self, *args, **kwargs) self.url = '%s%s' % (urlbase, self.FSpath) self.mimetype = mimetype def doUpdate(self): self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype) self.res.size = os.path.getsize(self.FSpath) Item.doUpdate(self) class FSVideoItem(FSItem, VideoItem): pass class FSAudioItem(FSItem, AudioItem): pass class FSTextItem(FSItem, TextItem): pass class FSImageItem(FSItem, ImageItem): pass mimetoklass = { 'application/ogg': FSAudioItem, 'video': FSVideoItem, 'audio': FSAudioItem, 'text': FSTextItem, 'image': FSImageItem, } def dofileadd(cd, parent, urlbase, path, name): fn, ext = os.path.splitext(name) ext = ext.lower() try: mt = mimedict[ext] except KeyError: log.msg('no mime-type for: %s' % name) return ty = mt.split('/')[0] if mimetoklass.has_key(mt): klass = mimetoklass[mt] elif mimetoklass.has_key(ty): klass = mimetoklass[ty] else: log.msg('no item for mt: %s' % mt) return return cd.addItem(parent, klass, name, urlbase = urlbase, path = os.path.join(path, name), mimetype = mt) class FSDirectory(FSObject, StorageFolder): def __init__(self, *args, **kwargs): path = kwargs['path'] del kwargs['path'] urlbase = kwargs['urlbase'] del kwargs['urlbase'] StorageFolder.__init__(self, *args, **kwargs) FSObject.__init__(self, path) # mapping from path to objectID self.pathObjmap = {} self.urlbase = urlbase def doUpdate(self): # We need to rescan this dir, and see if our children has # changed any. children = sets.Set(os.listdir(self.FSpath)) for i in self.pathObjmap.keys(): if i not in children: # delete self.cd.delItem(self.pathObjmap[i]) del self.pathObjmap[i] for i in children: fname = os.path.join(self.FSpath, i) if i in self.pathObjmap: continue # new object if os.path.isdir(fname): # new dir nf = self.cd.addContainer(self.id, i, klass = FSDirectory, path = fname, urlbase = self.urlbase) elif os.path.isfile(fname): # new file nf = dofileadd(self.cd, self.id, self.urlbase, self.FSpath, i) else: nf = None log.msg('skipping: %s' % fname) if nf is not None: self.pathObjmap[i] = nf # sort our children self.sort(lambda x, y: cmp(x.title, y.title)) # Pass up to handle UpdateID StorageFolder.doUpdate(self)