can use it... we now dynamicly build new classes from the base DIDLLite classes as necessary... Add the startings of the ability to read zip files w/o expanding them... this still needs some glue to work w/ the new world order.. it'll be a bit of work before I have zip in a zip working.. :) [git-p4: depot-paths = "//depot/": change = 808]v0.3
| @@ -4,6 +4,7 @@ | |||||
| # $Id$ | # $Id$ | ||||
| # | # | ||||
| import FileDIDL | |||||
| import errno | import errno | ||||
| import itertools | import itertools | ||||
| import os | import os | ||||
| @@ -79,27 +80,7 @@ class FSItem(FSObject, Item): | |||||
| self.res.size = os.path.getsize(self.FSpath) | self.res.size = os.path.getsize(self.FSpath) | ||||
| Item.doUpdate(self) | 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 defFS(path): | |||||
| def defFS(path, fobj): | |||||
| if os.path.isdir(path): | if os.path.isdir(path): | ||||
| # new dir | # new dir | ||||
| return FSDirectory, { 'path': path } | return FSDirectory, { 'path': path } | ||||
| @@ -110,30 +91,24 @@ def defFS(path): | |||||
| log.msg('skipping (not dir or reg): %s' % path) | log.msg('skipping (not dir or reg): %s' % path) | ||||
| return None, None | return None, None | ||||
| fn, ext = os.path.splitext(path) | |||||
| ext = ext.lower() | |||||
| try: | |||||
| mt = mimedict[ext] | |||||
| except KeyError: | |||||
| log.msg('no mime-type for: %s' % path) | |||||
| return None, None | |||||
| 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 None, None | |||||
| klass, mt = FileDIDL.buildClassMT(FSItem, path) | |||||
| return klass, { 'path': path, 'mimetype': mt } | return klass, { 'path': path, 'mimetype': mt } | ||||
| def dofileadd(cd, parent, path, name): | def dofileadd(cd, parent, path, name): | ||||
| klass = None | klass = None | ||||
| try: | |||||
| fobj = open(path) | |||||
| except: | |||||
| fobj = None | |||||
| for i in itertools.chain(klassfuns, ( defFS, )): | for i in itertools.chain(klassfuns, ( defFS, )): | ||||
| try: | try: | ||||
| klass, kwargs = i(os.path.join(path, name)) | |||||
| try: | |||||
| fobj.seek(0) # incase the call expects a clean file | |||||
| except: | |||||
| pass | |||||
| klass, kwargs = i(os.path.join(path, name), fobj) | |||||
| if klass is not None: | if klass is not None: | ||||
| break | break | ||||
| except: | except: | ||||
| @@ -0,0 +1,71 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright 2006 John-Mark Gurney <gurney_j@resnet.uoregon.edu> | |||||
| # | |||||
| # $Id$ | |||||
| # | |||||
| # | |||||
| # Convert file information into a DIDL class. Dynamicly generate a new class | |||||
| # from a base class and the DIDL class to be determined. | |||||
| # | |||||
| __all__ = [ 'mimetoclass', 'buildClassMT', 'getClassMT', ] | |||||
| import os.path | |||||
| import weakref | |||||
| from DIDLLite import VideoItem, AudioItem, TextItem, ImageItem | |||||
| from twisted.python import log | |||||
| from twisted.web import static | |||||
| mimedict = static.loadMimeTypes() | |||||
| classdict = weakref.WeakValueDictionary() | |||||
| mimetoclass = { | |||||
| 'application/ogg': AudioItem, | |||||
| 'video': VideoItem, | |||||
| 'audio': AudioItem, | |||||
| 'text': TextItem, | |||||
| 'image': ImageItem, | |||||
| } | |||||
| def getClassMT(name, mimetype = None, fp = None): | |||||
| '''Return a tuple of the DIDLLite class and mimetype responsible for the named/mimetyped/fpd file.''' | |||||
| if mimetype is None: | |||||
| fn, ext = os.path.splitext(name) | |||||
| ext = ext.lower() | |||||
| try: | |||||
| mimetype = mimedict[ext] | |||||
| except KeyError: | |||||
| log.msg('no mime-type for: %s' % name) | |||||
| return None, None | |||||
| ty = mimetype.split('/')[0] | |||||
| if mimetoclass.has_key(mimetype): | |||||
| klass = mimetoclass[mimetype] | |||||
| elif mimetoclass.has_key(ty): | |||||
| klass = mimetoclass[ty] | |||||
| else: | |||||
| # XXX - We could fall file -i on it | |||||
| log.msg('no item for mimetype: %s' % mimetype) | |||||
| return None, None | |||||
| return klass, mimetype | |||||
| def buildClassMT(baseklass, name, *args, **kwargs): | |||||
| klass, mt = getClassMT(name, *args, **kwargs) | |||||
| if klass is None: | |||||
| return None, None | |||||
| try: | |||||
| return classdict[(baseklass, klass)], mt | |||||
| except KeyError: | |||||
| pass | |||||
| class ret(baseklass, klass): | |||||
| pass | |||||
| ret.__name__ = '+'.join(map(lambda x: '%s.%s' % (x.__module__, x.__name__), (baseklass, klass))) | |||||
| classdict[(baseklass, klass)] = ret | |||||
| return ret, mt | |||||
| @@ -0,0 +1,83 @@ | |||||
| #!/usr/bin/env python | |||||
| # Copyright 2006 John-Mark Gurney <gurney_j@resnet.uroegon.edu> | |||||
| # | |||||
| # $Id$ | |||||
| # | |||||
| import os.path | |||||
| import zipfile | |||||
| from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource | |||||
| from FSStorage import FSObject, registerklassfun | |||||
| def isatpath(f, p): | |||||
| if f[:len(p)] != p: | |||||
| # First part of path doesn't match, it's not | |||||
| return False | |||||
| slash = f[len(p):].find('/') | |||||
| if slash != -1 and slash != len(f) - len(p) + 1: | |||||
| # Another path component, skip it, as long as it's not the char | |||||
| return False | |||||
| # otherwise, it is at this level | |||||
| endtrim = len(f) | |||||
| if slash: | |||||
| endtrip -= 1 | |||||
| return f[len(p):endtrim] | |||||
| class ZipChildDir(StorageFolder): | |||||
| '''This is to represent a child dir of the zip file.''' | |||||
| class ZipFile(FSObject, StorageFolder): | |||||
| def __init__(self, *args, **kwargs): | |||||
| '''If a zip argument is passed it, use that as the zip archive.''' | |||||
| path = kwargs['path'] | |||||
| del kwargs['path'] | |||||
| StorageFolder.__init__(self, *args, **kwargs) | |||||
| FSObject.__init__(self, path) | |||||
| # mapping from path to objectID | |||||
| self.pathObjmap = {} | |||||
| def getdirents(path): | |||||
| '''Returns the list of entires for the path, '' is the root path.''' | |||||
| lst = self.zip.namelist() | |||||
| if path: | |||||
| path += '/' | |||||
| return filter(lambda x, p = path: isatpath(x, p), lst) | |||||
| def doUpdate(self): | |||||
| # open the zipfile as necessary. | |||||
| self.zip = zipfile.ZipFile(self.FSpath) | |||||
| allzipfiles = sets.Set(self.zip.namelist()) | |||||
| children = sets.Set(getdirents('')) | |||||
| 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: | |||||
| if i in self.pathObjmap: | |||||
| continue | |||||
| # new object | |||||
| if i not in allzipfiles: | |||||
| # must be a dir | |||||
| else: | |||||
| ZipChild(self, i) | |||||
| def detectzipfile(path, fobj): | |||||
| try: | |||||
| z = zipfile.ZipFile(fobj) | |||||
| except: | |||||
| return None, None | |||||
| return ZipFile, {} | |||||
| registerklassfun(detectzipfile) | |||||