rid of a lot of cut and paste... add a new module that uses XML to create a custom object... One example is to support a simple mp3 streaming website: <?xml version="1.0"?> <Object> <mimetype>audio/mpeg</mimetype> <res> <url>http://streaming.uoregon.edu:8000/</url> </res> </Object> Should be expanded to support more, but this is a good first cut... [git-p4: depot-paths = "//depot/": change = 1345]main
| @@ -2,7 +2,7 @@ | |||
| # http://opensource.org/licenses/mit-license.php | |||
| # Copyright 2005, Tim Potter <tpot@samba.org> | |||
| # Copyright 2006-2008 John-Mark Gurney <jmg@funkthat.com> | |||
| # Copyright 2006-2009 John-Mark Gurney <jmg@funkthat.com> | |||
| __version__ = '$Change$' | |||
| # $Id$ | |||
| @@ -319,13 +319,99 @@ class Container(Object, list): | |||
| Object.__init__(self, cd, id, parentID, title, restricted, | |||
| creator, **kwargs) | |||
| list.__init__(self) | |||
| self.doingUpdate = False | |||
| self.oldchildren = {} | |||
| def genCurrent(self): | |||
| '''This function returns a tuple/list/generator that returns | |||
| tuples of (id, name). name must match what is returned by | |||
| genChildren. If name is used for the title directly, no | |||
| override is necessary.''' | |||
| return ((x.id, x.title) for x in self) | |||
| def genChildren(self): | |||
| '''This function returns a list or dict of names for new | |||
| children.''' | |||
| raise NotImplementedError | |||
| def createObject(self, i, arg=None): | |||
| '''This function returns the (class, name, *args, **kwargs) | |||
| that will be passed to the addItem method of the | |||
| ContentDirectory. arg will be passed the value of the dict | |||
| keyed by i if genChildren is a dict.''' | |||
| raise NotImplementedError | |||
| def sort(self, fun=None): | |||
| if fun is None: | |||
| return list.sort(self, lambda x, y: cmp(x.title, | |||
| y.title)) | |||
| return list.sort(self, fun) | |||
| def doUpdate(self): | |||
| if self.doingUpdate: | |||
| return | |||
| self.doingUpdate = True | |||
| didupdate = False | |||
| children = self.genChildren() | |||
| if isinstance(children, dict): | |||
| oldchildren = self.oldchildren | |||
| self.oldchildren = children | |||
| isdict = True | |||
| else: | |||
| children = set(children) | |||
| isdict = False | |||
| names = {} | |||
| #print 'i:', `self`, `self.genCurrent`, `self.__class__` | |||
| for id, i in tuple(self.genCurrent()): | |||
| if i not in children: | |||
| didupdate = True | |||
| # delete | |||
| self.cd.delItem(id) | |||
| else: | |||
| names[i] = id | |||
| for i in children: | |||
| if i in names: | |||
| if isdict: | |||
| if oldchildren[i] == children[i]: | |||
| continue | |||
| self.cd.delItem(names[i]) | |||
| else: | |||
| # XXX - some sort of comparision? | |||
| continue | |||
| # new object | |||
| if isdict: | |||
| args = (children[i], ) | |||
| else: | |||
| args = () | |||
| #print 'i:', `i`, `isdict`, `args`, `self` | |||
| klass, name, args, kwargs = self.createObject(i, *args) | |||
| if klass is not None: | |||
| self.cd.addItem(self.id, klass, name, *args, | |||
| **kwargs) | |||
| didupdate = True | |||
| # sort our children | |||
| self.sort() | |||
| if didupdate: | |||
| self.didUpdate() | |||
| self.doingUpdate = False | |||
| def didUpdate(self): | |||
| if self.id == '0': | |||
| self.updateID = (self.updateID + 1) | |||
| else: | |||
| self.updateID = (self.updateID + 1) % (1l << 32) | |||
| Container.doUpdate(self.cd['0']) | |||
| Container.didUpdate(self.cd['0']) | |||
| def toElement(self): | |||
| @@ -1,5 +1,5 @@ | |||
| #!/usr/bin/env python | |||
| # Copyright 2006-2008 John-Mark Gurney <jmg@funkthat.com> | |||
| # Copyright 2006-2009 John-Mark Gurney <jmg@funkthat.com> | |||
| __version__ = '$Change$' | |||
| # $Id$ | |||
| @@ -13,7 +13,7 @@ import os | |||
| import sets | |||
| import stat | |||
| from DIDLLite import Container, StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource, ResourceList | |||
| from DIDLLite import StorageFolder, Item, Resource, ResourceList | |||
| from twisted.web import resource, server, static | |||
| from twisted.python import log | |||
| from twisted.internet import abstract, interfaces, process, protocol, reactor | |||
| @@ -21,8 +21,6 @@ from zope.interface import implements | |||
| __all__ = [ 'registerklassfun', 'registerfiletoignore', | |||
| 'FSObject', 'FSItem', 'FSDirectory', | |||
| 'FSVideoItem', 'FSAudioItem', 'FSTextItem', 'FSImageItem', | |||
| 'mimetoklass', | |||
| ] | |||
| mimedict = static.loadMimeTypes() | |||
| @@ -59,7 +57,7 @@ class FSObject(object): | |||
| self.FSpath = path | |||
| self.pstat = None | |||
| def checkUpdate(self): | |||
| def checkUpdate(self, **kwargs): | |||
| # need to handle no such file or directory | |||
| # push it up? but still need to handle disappearing | |||
| try: | |||
| @@ -68,7 +66,7 @@ class FSObject(object): | |||
| return | |||
| self.pstat = nstat | |||
| self.doUpdate() | |||
| self.doUpdate(**kwargs) | |||
| except OSError, x: | |||
| log.msg('os.stat, OSError: %s' % x) | |||
| if x.errno in (errno.ENOENT, errno.ENOTDIR, errno.EPERM, ): | |||
| @@ -78,10 +76,6 @@ class FSObject(object): | |||
| else: | |||
| raise | |||
| def doUpdate(self): | |||
| raise NotImplementedError | |||
| def __repr__(self): | |||
| return '<%s.%s: path: %s, id: %s, parent: %s, title: %s>' % \ | |||
| (self.__class__.__module__, self.__class__.__name__, | |||
| @@ -189,10 +183,8 @@ class DynamicTrans(resource.Resource): | |||
| class FSItem(FSObject, Item): | |||
| def __init__(self, *args, **kwargs): | |||
| FSObject.__init__(self, kwargs['path']) | |||
| del kwargs['path'] | |||
| mimetype = kwargs['mimetype'] | |||
| del kwargs['mimetype'] | |||
| FSObject.__init__(self, kwargs.pop('path')) | |||
| mimetype = kwargs.pop('mimetype') | |||
| kwargs['content'] = DynamicTrans(self.FSpath, | |||
| static.File(self.FSpath, mimetype)) | |||
| Item.__init__(self, *args, **kwargs) | |||
| @@ -238,7 +230,7 @@ def defFS(path, fobj): | |||
| return klass, { 'path': path, 'mimetype': mt } | |||
| def dofileadd(cd, parent, path, name): | |||
| def dofileadd(path, name): | |||
| klass = None | |||
| fsname = os.path.join(path, name) | |||
| try: | |||
| @@ -262,10 +254,10 @@ def dofileadd(cd, parent, path, name): | |||
| pass | |||
| if klass is None or klass is IgnoreFile: | |||
| return | |||
| return None, None, None, None | |||
| #print 'matched:', os.path.join(path, name), `i`, `klass` | |||
| return cd.addItem(parent, klass, name, **kwargs) | |||
| return klass, name, (), kwargs | |||
| class FSDirectory(FSObject, StorageFolder): | |||
| def __init__(self, *args, **kwargs): | |||
| @@ -274,48 +266,14 @@ class FSDirectory(FSObject, StorageFolder): | |||
| StorageFolder.__init__(self, *args, **kwargs) | |||
| FSObject.__init__(self, path) | |||
| # mapping from path to objectID | |||
| self.pathObjmap = {} | |||
| self.indoUpdate = False | |||
| def genCurrent(self): | |||
| return ((x.id, os.path.basename(x.FSpath)) for x in self ) | |||
| def doUpdate(self): | |||
| # We need to rescan this dir, and see if our children has | |||
| # changed any. | |||
| if self.indoUpdate: | |||
| return | |||
| #import traceback | |||
| #traceback.print_stack() | |||
| self.indoUpdate = True | |||
| doupdate = False | |||
| children = sets.Set(os.listdir(self.FSpath)) | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in children: | |||
| doupdate = True | |||
| # delete | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in children: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| # new object | |||
| nf = dofileadd(self.cd, self.id, self.FSpath, i) | |||
| if nf is not None: | |||
| doupdate = True | |||
| self.pathObjmap[i] = nf | |||
| # sort our children | |||
| self.sort(lambda x, y: cmp(x.title, y.title)) | |||
| # Pass up to handle UpdateID | |||
| if doupdate: | |||
| # Calling StorageFolder.doUpdate results in calling | |||
| # ourselves. | |||
| Container.doUpdate(self) | |||
| self.indoUpdate = False | |||
| def genChildren(self): | |||
| return os.listdir(self.FSpath) | |||
| def createObject(self, i): | |||
| return dofileadd(self.FSpath, i) | |||
| def __repr__(self): | |||
| return ('<%s.%s: path: %s, id: %s, parent: %s, title: %s, ' + \ | |||
| @@ -158,6 +158,7 @@ class ZipItem: | |||
| del kwargs['name'] | |||
| def checkUpdate(self): | |||
| # XXX - is this the correct order? | |||
| self.doUpdate() | |||
| self.zo.checkUpdate() | |||
| @@ -174,9 +175,6 @@ class ZipFile(ZipItem, Item): | |||
| self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype) | |||
| self.res.size = self.zi.file_size | |||
| def doUpdate(self): | |||
| pass | |||
| class ZipChildDir(ZipItem, StorageFolder): | |||
| '''This is to represent a child dir of the zip file.''' | |||
| @@ -188,48 +186,29 @@ class ZipChildDir(ZipItem, StorageFolder): | |||
| del kwargs['zf'], kwargs['zo'], kwargs['name'] | |||
| StorageFolder.__init__(self, *args, **kwargs) | |||
| # mapping from path to objectID | |||
| self.pathObjmap = {} | |||
| def doUpdate(self): | |||
| doupdate = False | |||
| children = sets.Set(self.hier.keys()) | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in children: | |||
| # delete | |||
| doupdate = True | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| cursep = self.sep | |||
| for i in children: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| # new object | |||
| pathname = cursep.join((self.name, i)) | |||
| if isinstance(self.hier[i], dict): | |||
| # must be a dir | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| ZipChildDir, i, zf=self.zf, zo=self, | |||
| name=pathname, hier=self.hier[i], | |||
| sep=cursep) | |||
| else: | |||
| klass, mt = FileDIDL.buildClassMT(ZipFile, i) | |||
| if klass is None: | |||
| continue | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| klass, i, zf = self.zf, zo = self, | |||
| name = pathname, mimetype = mt) | |||
| doupdate = True | |||
| # sort our children | |||
| self.sort(lambda x, y: cmp(x.title, y.title)) | |||
| if doupdate: | |||
| StorageFolder.doUpdate(self) | |||
| def genChildren(self): | |||
| return self.hier | |||
| def genCurrent(self): | |||
| return ((x.id, x.name.rsplit(self.sep, 1)[1]) for x in self) | |||
| def createObject(self, i, arg): | |||
| pathname = self.sep.join((self.name, i)) | |||
| kwargs = { 'zf': self.zf, 'zo': self, 'name': pathname } | |||
| if isinstance(self.hier[i], dict): | |||
| # must be a dir | |||
| klass = ZipChildDir | |||
| kwargs['sep'] = self.sep | |||
| kwargs['hier'] = self.hier[i] | |||
| else: | |||
| klass, mt = FileDIDL.buildClassMT(ZipFile, i) | |||
| kwargs['name'] = pathname | |||
| kwargs['mimetype'] = mt | |||
| return klass, i, (), kwargs | |||
| def __repr__(self): | |||
| return '<ZipChildDir: len: %d>' % len(self.pathObjmap) | |||
| return '<ZipChildDir: len: %d>' % len(self) | |||
| def tryTar(path): | |||
| # Try to see if it's a tar file | |||
| @@ -270,19 +249,16 @@ class ZipObject(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'] | |||
| path = kwargs.pop('path') | |||
| StorageFolder.__init__(self, *args, **kwargs) | |||
| FSObject.__init__(self, path) | |||
| # mapping from path to objectID | |||
| self.pathObjmap = {} | |||
| def doUpdate(self): | |||
| def genChildren(self): | |||
| # open the zipfile as necessary. | |||
| self.zip = genZipFile(self.FSpath) | |||
| nl = self.zip.namelist() | |||
| cnt = 0 | |||
| cursep = None | |||
| for i in self.seps: | |||
| @@ -291,41 +267,26 @@ class ZipObject(FSObject, StorageFolder): | |||
| cursep = i | |||
| cnt = newsum | |||
| self.sep = cursep | |||
| hier = buildNameHier(nl, self.zip.infolist(), cursep) | |||
| doupdate = False | |||
| children = sets.Set(hier.keys()) | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in children: | |||
| doupdate = True | |||
| # delete | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in children: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| # new object | |||
| if isinstance(hier[i], dict): | |||
| # must be a dir | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| ZipChildDir, i, zf=self.zip, zo=self, | |||
| name=i, hier=hier[i], sep=cursep) | |||
| else: | |||
| klass, mt = FileDIDL.buildClassMT(ZipFile, i) | |||
| if klass is None: | |||
| continue | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| klass, i, zf = self.zip, zo = self, | |||
| name = i, mimetype = mt) | |||
| doupdate = True | |||
| # sort our children | |||
| self.sort(lambda x, y: cmp(x.title, y.title)) | |||
| if doupdate: | |||
| StorageFolder.doUpdate(self) | |||
| return hier | |||
| def genCurrent(self): | |||
| return ((x.id, x.name) for x in self) | |||
| def createObject(self, i, arg): | |||
| kwargs = { 'zf': self.zip, 'zo': self, 'name': i } | |||
| if isinstance(arg, dict): | |||
| # must be a dir | |||
| kwargs['hier'] = arg | |||
| kwargs['sep'] = self.sep | |||
| klass = ZipChildDir | |||
| else: | |||
| klass, mt = FileDIDL.buildClassMT(ZipFile, i) | |||
| kwargs['mimetype'] = mt | |||
| return klass, i, (), kwargs | |||
| def detectzipfile(path, fobj): | |||
| try: | |||
| @@ -30,14 +30,12 @@ from twisted.spread import pb | |||
| from twisted.web import resource, server | |||
| def gennameindexes(pref, item): | |||
| ret = [] | |||
| d = {} | |||
| for i, title in enumerate(item): | |||
| t = '%s %d (%s)' % (pref, i + 1, title.time) | |||
| ret.append(t) | |||
| d[t] = i | |||
| return ret, d | |||
| return d | |||
| class IterTransfer(pb.Viewable): | |||
| def __init__(self, iterable, request): | |||
| @@ -142,30 +140,12 @@ class DVDTitle(StorageFolder): | |||
| self.doUpdate() | |||
| #return self.dvddisc.checkUpdate() | |||
| def doUpdate(self): | |||
| doupdate = False | |||
| origchildren, toindex = gennameindexes('Chapter', self.dvdtitle) | |||
| children = sets.Set(origchildren) | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in children: | |||
| doupdate = True | |||
| # delete | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in origchildren: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| # new object | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| DVDChapter, i, dvdtitle = self.dvdtitle, | |||
| chapter = self.dvdtitle[toindex[i]]) | |||
| doupdate = True | |||
| if doupdate: | |||
| StorageFolder.doUpdate(self) | |||
| def genChildren(self): | |||
| return gennameindexes('Chapter', self.dvdtitle) | |||
| def createObject(self, i, arg): | |||
| return DVDChapter, i, (), { 'dvdtitle': self.dvdtitle, | |||
| 'chapter': self.dvdtitle[arg] } | |||
| class DVDDisc(FSObject, StorageFolder): | |||
| def __init__(self, *args, **kwargs): | |||
| @@ -175,34 +155,14 @@ class DVDDisc(FSObject, StorageFolder): | |||
| StorageFolder.__init__(self, *args, **kwargs) | |||
| FSObject.__init__(self, path) | |||
| # mapping from path to objectID | |||
| self.pathObjmap = {} | |||
| def doUpdate(self): | |||
| # open the DVD as necessary. | |||
| def genChildren(self): | |||
| self.dvd = DVD(self.FSpath) | |||
| doupdate = False | |||
| origchildren, toindex = gennameindexes('Title', self.dvd) | |||
| children = sets.Set(origchildren) | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in children: | |||
| doupdate = True | |||
| # delete | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in origchildren: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| # new object | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, DVDTitle, | |||
| i, dvdtitle = self.dvd[toindex[i]], dvddisc = self) | |||
| doupdate = True | |||
| if doupdate: | |||
| StorageFolder.doUpdate(self) | |||
| return gennameindexes('Title', self.dvd) | |||
| def createObject(self, i, arg): | |||
| return DVDTitle, i, (), { 'dvdtitle': self.dvd[arg], | |||
| 'dvddisc': self } | |||
| def detectdvd(path, fobj): | |||
| if os.path.isdir(path): | |||
| @@ -0,0 +1,69 @@ | |||
| #!/usr/bin/env python | |||
| # Copyright 2009 John-Mark Gurney <jmg@funkthat.com> | |||
| __version__ = '$Change$' | |||
| # $Id$ | |||
| import FileDIDL | |||
| import xml.dom.minidom | |||
| from DIDLLite import StorageFolder, Item, Resource, ResourceList | |||
| from FSStorage import FSObject, registerklassfun | |||
| def getElementText(elm, strip=True): | |||
| s = ''.join(x.nodeValue for x in elm.childNodes) | |||
| if strip: | |||
| s = s.strip() | |||
| return s | |||
| class ItemObject(FSObject, Item): | |||
| def __init__(self, *args, **kwargs): | |||
| path = kwargs.pop('path') | |||
| dom = kwargs.pop('dom') | |||
| FSObject.__init__(self, path) | |||
| Item.__init__(self, *args, **kwargs) | |||
| self.checkUpdate(dom=dom) | |||
| def doUpdate(self, dom=None): | |||
| if dom is None: | |||
| dom = xml.dom.minidom.parse(open(self.FSpath)) | |||
| obj = dom.getElementsByTagName('Object')[0] | |||
| mt = getElementText(obj.getElementsByTagName('mimetype')[0]) | |||
| self.res = ResourceList() | |||
| for i in obj.getElementsByTagName('res'): | |||
| r = Resource(getElementText(i.getElementsByTagName( | |||
| 'url')[0]), 'http-get:*:%s:*' % mt) | |||
| size = i.getElementsByTagName('size') | |||
| if size: | |||
| r.size = int(getElementText(size[0])) | |||
| self.res.append(r) | |||
| super(ItemObject, self).doUpdate() | |||
| def canHandle(fobj): | |||
| # XXX - create schema and validate | |||
| dom = xml.dom.minidom.parse(fobj) | |||
| #print 'ch:', `dom` | |||
| obj = dom.getElementsByTagName('Object')[0] | |||
| mt = getElementText(obj.getElementsByTagName('mimetype')[0]) | |||
| #print 'ch:', `obj`, `mt` | |||
| return dom, mt | |||
| def detectitem(path, fobj): | |||
| #print 'di:', `path`, `fobj` | |||
| try: | |||
| dom, mt = canHandle(fobj) | |||
| except: | |||
| #import traceback | |||
| #traceback.print_exc() | |||
| return None, None | |||
| klass, mt = FileDIDL.buildClassMT(ItemObject, path, mimetype=mt) | |||
| return klass, { 'path': path, 'dom': dom } | |||
| registerklassfun(detectitem) | |||
| @@ -48,15 +48,13 @@ class _LimitedFile(file): | |||
| return file.read(self, min(size, self.remain())) | |||
| def _gennameindexes(chan): | |||
| ret = [] | |||
| d = {} | |||
| for i in chan: | |||
| t = '%s %s.%s' % (i['name'], i['major'], i['minor']) | |||
| ret.append(t) | |||
| d[t] = i | |||
| return ret, d | |||
| return d | |||
| class MPEGTSTransfer(pb.Viewable): | |||
| def __init__(self, iterable, request): | |||
| @@ -307,42 +305,25 @@ class MultiMPEGTS(FSObject, StorageFolder): | |||
| StorageFolder.__init__(self, *args, **kwargs) | |||
| FSObject.__init__(self, path) | |||
| # mapping from path to objectID | |||
| self.pathObjmap = {} | |||
| def doUpdate(self): | |||
| def genChildren(self): | |||
| f = mpegts.TSPStream(_LimitedFile(self.FSpath, | |||
| size= 2*1024*1024)) | |||
| size=2*1024*1024)) | |||
| self.tvct = mpegts.GetTVCT(f) | |||
| #log.msg('MultiMPEGTS genChildren: tvct: %s' % self.tvct) | |||
| return _gennameindexes(self.tvct['channels']) | |||
| doupdate = False | |||
| origchildren, toindex = _gennameindexes(self.tvct['channels']) | |||
| #log.msg('MultiMPEGTS doUpdate: tvct: %s' % self.tvct) | |||
| children = sets.Set(origchildren) | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in children: | |||
| doupdate = True | |||
| # delete | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in origchildren: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| # new object | |||
| if toindex[i]['prog_num'] == 0: | |||
| log.msg('bogus:', toindex[i]) | |||
| continue | |||
| def createObject(self, i, arg): | |||
| if arg['prog_num'] == 0: | |||
| log.msg('bogus:', arg) | |||
| return None, None, (), {} | |||
| #log.msg('real tvct:', toindex[i], toindex.keys(), | |||
| # self.tvct) | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, MPEGTS, | |||
| i, path = self.FSpath, tvct = toindex[i]) | |||
| doupdate = True | |||
| #log.msg('real tvct:', arg, toindex.keys(), self.tvct) | |||
| return MPEGTS, i, (), { 'path': self.FSpath, 'tvct': arg } | |||
| if doupdate: | |||
| StorageFolder.doUpdate(self) | |||
| def sort(self): | |||
| return super(MultiMPEGTS, self).sort(lambda x, y: | |||
| cmp((x.tvct['major'], x.tvct['minor']), | |||
| (y.tvct['major'], y.tvct['minor']))) | |||
| def findtsstream(fp, pktsz=188): | |||
| d = fp.read(200*pktsz) | |||
| @@ -30,6 +30,7 @@ def tryloadmodule(mod): | |||
| modules = [ | |||
| 'shoutcast', | |||
| 'pyvr', | |||
| 'item', | |||
| 'dvd', | |||
| 'ZipStorage', | |||
| 'mpegtsmod', | |||
| @@ -196,6 +197,9 @@ def makeService(config): | |||
| s.doStop() | |||
| service.MultiService.stopService(self) | |||
| import pickle | |||
| pickle.dump(cds, open('test.pickle', 'wb'), -1) | |||
| serv = PyMedS() | |||
| internet.TCPServer(listenPort, site).setServiceParent(serv) | |||
| @@ -109,7 +109,6 @@ class PYVRShows(Container): | |||
| Container.__init__(self, *args, **kwargs) | |||
| self.pathObjmap = {} | |||
| self.shows = {} | |||
| self.lastmodified = None | |||
| @@ -140,34 +139,18 @@ class PYVRShows(Container): | |||
| return ret | |||
| def genChildren(self): | |||
| return self.eplisttodict(self.pyvr.shows[self.show]) | |||
| def createObject(self, i, arg): | |||
| return PYVRShow, i, (), { 'url': self.pyvr.url, 'info': arg } | |||
| def sort(self): | |||
| Container.sort(self, lambda x, y: cmp(x.info['pos'], | |||
| y.info['pos'])) | |||
| def doUpdate(self): | |||
| nl = self.eplisttodict(self.pyvr.shows[self.show]) | |||
| doupdate = False | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in nl: | |||
| # delete | |||
| doupdate = True | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in nl: | |||
| if i in self.pathObjmap and self.shows[i] == nl[i]: | |||
| continue | |||
| doupdate = True | |||
| if i in self.pathObjmap: | |||
| # changed | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| PYVRShow, i, url=self.pyvr.url, info=nl[i]) | |||
| self.shows = nl | |||
| # sort our children | |||
| #self.sort(lambda x, y: cmp(x.title, y.title)) | |||
| self.sort(lambda x, y: cmp(x.info['pos'], y.info['pos'])) | |||
| if doupdate: | |||
| Container.doUpdate(self) | |||
| Container.doUpdate(self) | |||
| self.lastmodified = self.pyvr.lastmodified | |||
| @@ -178,7 +161,6 @@ class PYVR(Container): | |||
| Container.__init__(self, *args, **kwargs) | |||
| self.pathObjmap = {} | |||
| #self.pend = None | |||
| self.lastmodified = None | |||
| self.newobjs = None | |||
| @@ -241,42 +223,23 @@ class PYVR(Container): | |||
| self.newobjs = recxmltoobj(page.read()) | |||
| self.doUpdate() | |||
| def genChildren(self): | |||
| return self.newobjs.iterkeys() | |||
| def createObject(self, i): | |||
| return PYVRShows, i, (), { 'show': i, 'pyvr': self } | |||
| def doUpdate(self): | |||
| if self.newobjs is None: | |||
| import traceback | |||
| traceback.print_stack(file=log.logfile) | |||
| return | |||
| raise ValueError('did not get shows') | |||
| nl = self.newobjs | |||
| doupdate = False | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in nl: | |||
| # delete | |||
| doupdate = True | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| # This data is referenced when adding new shows | |||
| self.shows = nl | |||
| for i in nl: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| doupdate = True | |||
| try: | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| PYVRShows, i, show=i, pyvr=self) | |||
| except: | |||
| import traceback | |||
| traceback.print_exc(file=log.logfile) | |||
| raise | |||
| self.shows = self.newobjs | |||
| self.newobjs = None | |||
| Container.doUpdate(self) | |||
| # sort our children | |||
| self.sort(lambda x, y: cmp(x.title, y.title)) | |||
| if doupdate: | |||
| Container.doUpdate(self) | |||
| self.newobjs = None | |||
| def detectpyvrfile(path, fobj): | |||
| bn = os.path.basename(path) | |||
| @@ -15,7 +15,7 @@ import ConfigParser | |||
| import cStringIO as StringIO | |||
| import os.path | |||
| import random | |||
| import time | |||
| import traceback | |||
| from py_shoutcast import * | |||
| @@ -312,7 +312,6 @@ class ShoutGenre(MusicGenre): | |||
| #self.feeds = ShoutcastFeedAsync(self.genre) | |||
| self.feeds = feeds.ShoutcastFeed(self.genre) | |||
| self.sl = None | |||
| self.pathObjmap = {} | |||
| MusicGenre.__init__(self, *args, **kwargs) | |||
| @@ -335,43 +334,36 @@ class ShoutGenre(MusicGenre): | |||
| return ret | |||
| def checkUpdate(self): | |||
| self.doUpdate() | |||
| # Sometimes the shoutcast server returns a 503 (busy) which | |||
| # isn't valid XML, try again. | |||
| while True: | |||
| try: | |||
| stations = self.feeds.parse_stations() | |||
| break | |||
| except: | |||
| traceback.print_exc() | |||
| time.sleep(1) | |||
| def doUpdate(self): | |||
| #traceback.print_stack(file=log.logfile) | |||
| stations = self.feeds.parse_stations() | |||
| if stations == self.sl: | |||
| return | |||
| nl = self.genStations(stations) | |||
| doupdate = False | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in nl: | |||
| # delete | |||
| doupdate = True | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for name, i in nl.iteritems(): | |||
| if name in self.pathObjmap: | |||
| if cmpStation(i, self.cd[self.pathObjmap[name]].station): | |||
| continue | |||
| # Didn't match, readd | |||
| self.cd.delItem(self.pathObjmap[name]) | |||
| del self.pathObjmap[name] | |||
| doupdate = True | |||
| self.pathObjmap[name] = self.cd.addItem(self.id, | |||
| ShoutStation, '%sk-%s' % (i['Bitrate'], name), | |||
| station = i) | |||
| self.sl = stations | |||
| # sort our children | |||
| self.sort(lambda *a: stationwbitratecmp(*a)) | |||
| if doupdate: | |||
| Container.doUpdate(self) | |||
| self.doUpdate() | |||
| def genChildren(self): | |||
| return self.genStations(self.sl) | |||
| def genCurrent(self): | |||
| return ((x.id, x.station) for x in self) | |||
| def createObject(self, name, arg): | |||
| return ShoutStation, '%sk-%s' % (arg['Bitrate'], name), (), \ | |||
| { 'station': arg } | |||
| def sort(self): | |||
| super(ShoutGenre, self).sort(lambda *a: stationwbitratecmp(*a)) | |||
| class ShoutCast(Container): | |||
| def __init__(self, *args, **kwargs): | |||
| @@ -380,38 +372,24 @@ class ShoutCast(Container): | |||
| #self.genres = GenreFeedAsync() | |||
| self.genres = feeds.GenreFeed() | |||
| self.genre_list = None | |||
| self.pathObjmap = {} | |||
| def checkUpdate(self): | |||
| self.doUpdate() | |||
| def doUpdate(self): | |||
| #traceback.print_stack(file=log.logfile) | |||
| nl = self.genres.parse_genres() | |||
| if nl == self.genre_list: | |||
| return | |||
| doupdate = False | |||
| for i in self.pathObjmap.keys(): | |||
| if i not in nl: | |||
| # delete | |||
| doupdate = True | |||
| self.cd.delItem(self.pathObjmap[i]) | |||
| del self.pathObjmap[i] | |||
| for i in nl: | |||
| if i in self.pathObjmap: | |||
| continue | |||
| doupdate = True | |||
| self.pathObjmap[i] = self.cd.addItem(self.id, | |||
| ShoutGenre, i, genre=i) | |||
| self.genre_list = nl | |||
| # sort our children | |||
| self.sort(lambda x, y: cmp(x.title, y.title)) | |||
| if doupdate: | |||
| Container.doUpdate(self) | |||
| super(ShoutCast, self).doUpdate() | |||
| def genChildren(self): | |||
| return self.genre_list | |||
| def genCurrent(self): | |||
| return ((x.id, x.genre) for x in self) | |||
| def createObject(self, i): | |||
| return ShoutGenre, i, (), { 'genre': i } | |||
| def detectshoutcastfile(origpath, fobj): | |||
| path = os.path.basename(origpath) | |||