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) | |||