|
|
@@ -0,0 +1,155 @@ |
|
|
|
#!/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.pstat = nstat |
|
|
|
self.doUpdate() |
|
|
|
except OSError, x: |
|
|
|
log.msg('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 |
|
|
|
except: |
|
|
|
import traceback |
|
|
|
print traceback.print_exc() |
|
|
|
|
|
|
|
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(fpath) |
|
|
|
|
|
|
|
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: |
|
|
|
raise KeyError, 'no item for mt: %s' % mt |
|
|
|
|
|
|
|
return cd.addItem(parent, klass, name, urlbase = urlbase, |
|
|
|
path = os.path.join(path, name), mimetype = mt) |
|
|
|
|
|
|
|
class FSDirectory(StorageFolder, FSObject): |
|
|
|
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. |
|
|
|
log.msg('doUpdate: %s, path: %s' % (self.title, self.FSpath)) |
|
|
|
children = sets.Set(os.listdir(self.FSpath)) |
|
|
|
for i in self.pathObjmap: |
|
|
|
if i not in children: |
|
|
|
# delete |
|
|
|
self.cd.delItem(self.pathObjmap[i]) |
|
|
|
|
|
|
|
log.msg('doUpdate: %s, children: %s' % (self.title, children)) |
|
|
|
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 |
|
|
|
log.msg('i: %s, nf: %s' % (i, nf)) |
|
|
|
self.cd[nf].checkUpdate() |
|
|
|
|
|
|
|
# sort our children |
|
|
|
log.msg('doUpdate: %s, sorting: %s' % (self.title, list.__str__(self))) |
|
|
|
self.sort(lambda x, y: cmp(x.title, y.title)) |
|
|
|
log.msg('sorted') |