Browse Source

move all the container handling into DIDLLite so that I get

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
John-Mark Gurney 15 years ago
parent
commit
64bcea6c62
9 changed files with 303 additions and 343 deletions
  1. +88
    -2
      DIDLLite.py
  2. +16
    -58
      FSStorage.py
  3. +43
    -82
      ZipStorage.py
  4. +12
    -52
      dvd.py
  5. +69
    -0
      item.py
  6. +15
    -34
      mpegtsmod.py
  7. +4
    -0
      pymeds.py
  8. +21
    -58
      pyvr.py
  9. +35
    -57
      shoutcast.py

+ 88
- 2
DIDLLite.py View File

@@ -2,7 +2,7 @@
# http://opensource.org/licenses/mit-license.php # http://opensource.org/licenses/mit-license.php


# Copyright 2005, Tim Potter <tpot@samba.org> # 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$' __version__ = '$Change$'
# $Id$ # $Id$
@@ -319,13 +319,99 @@ class Container(Object, list):
Object.__init__(self, cd, id, parentID, title, restricted, Object.__init__(self, cd, id, parentID, title, restricted,
creator, **kwargs) creator, **kwargs)
list.__init__(self) 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): 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': if self.id == '0':
self.updateID = (self.updateID + 1) self.updateID = (self.updateID + 1)
else: else:
self.updateID = (self.updateID + 1) % (1l << 32) self.updateID = (self.updateID + 1) % (1l << 32)
Container.doUpdate(self.cd['0'])
Container.didUpdate(self.cd['0'])


def toElement(self): def toElement(self):




+ 16
- 58
FSStorage.py View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python #!/usr/bin/env python
# Copyright 2006-2008 John-Mark Gurney <jmg@funkthat.com>
# Copyright 2006-2009 John-Mark Gurney <jmg@funkthat.com>


__version__ = '$Change$' __version__ = '$Change$'
# $Id$ # $Id$
@@ -13,7 +13,7 @@ import os
import sets import sets
import stat 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.web import resource, server, static
from twisted.python import log from twisted.python import log
from twisted.internet import abstract, interfaces, process, protocol, reactor from twisted.internet import abstract, interfaces, process, protocol, reactor
@@ -21,8 +21,6 @@ from zope.interface import implements


__all__ = [ 'registerklassfun', 'registerfiletoignore', __all__ = [ 'registerklassfun', 'registerfiletoignore',
'FSObject', 'FSItem', 'FSDirectory', 'FSObject', 'FSItem', 'FSDirectory',
'FSVideoItem', 'FSAudioItem', 'FSTextItem', 'FSImageItem',
'mimetoklass',
] ]


mimedict = static.loadMimeTypes() mimedict = static.loadMimeTypes()
@@ -59,7 +57,7 @@ class FSObject(object):
self.FSpath = path self.FSpath = path
self.pstat = None self.pstat = None


def checkUpdate(self):
def checkUpdate(self, **kwargs):
# need to handle no such file or directory # need to handle no such file or directory
# push it up? but still need to handle disappearing # push it up? but still need to handle disappearing
try: try:
@@ -68,7 +66,7 @@ class FSObject(object):
return return


self.pstat = nstat self.pstat = nstat
self.doUpdate()
self.doUpdate(**kwargs)
except OSError, x: except OSError, x:
log.msg('os.stat, OSError: %s' % x) log.msg('os.stat, OSError: %s' % x)
if x.errno in (errno.ENOENT, errno.ENOTDIR, errno.EPERM, ): if x.errno in (errno.ENOENT, errno.ENOTDIR, errno.EPERM, ):
@@ -78,10 +76,6 @@ class FSObject(object):
else: else:
raise raise


def doUpdate(self):
raise NotImplementedError


def __repr__(self): def __repr__(self):
return '<%s.%s: path: %s, id: %s, parent: %s, title: %s>' % \ return '<%s.%s: path: %s, id: %s, parent: %s, title: %s>' % \
(self.__class__.__module__, self.__class__.__name__, (self.__class__.__module__, self.__class__.__name__,
@@ -189,10 +183,8 @@ class DynamicTrans(resource.Resource):


class FSItem(FSObject, Item): class FSItem(FSObject, Item):
def __init__(self, *args, **kwargs): 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, kwargs['content'] = DynamicTrans(self.FSpath,
static.File(self.FSpath, mimetype)) static.File(self.FSpath, mimetype))
Item.__init__(self, *args, **kwargs) Item.__init__(self, *args, **kwargs)
@@ -238,7 +230,7 @@ def defFS(path, fobj):


return klass, { 'path': path, 'mimetype': mt } return klass, { 'path': path, 'mimetype': mt }


def dofileadd(cd, parent, path, name):
def dofileadd(path, name):
klass = None klass = None
fsname = os.path.join(path, name) fsname = os.path.join(path, name)
try: try:
@@ -262,10 +254,10 @@ def dofileadd(cd, parent, path, name):
pass pass


if klass is None or klass is IgnoreFile: if klass is None or klass is IgnoreFile:
return
return None, None, None, None


#print 'matched:', os.path.join(path, name), `i`, `klass` #print 'matched:', os.path.join(path, name), `i`, `klass`
return cd.addItem(parent, klass, name, **kwargs)
return klass, name, (), kwargs


class FSDirectory(FSObject, StorageFolder): class FSDirectory(FSObject, StorageFolder):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -274,48 +266,14 @@ class FSDirectory(FSObject, StorageFolder):
StorageFolder.__init__(self, *args, **kwargs) StorageFolder.__init__(self, *args, **kwargs)
FSObject.__init__(self, path) 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): def __repr__(self):
return ('<%s.%s: path: %s, id: %s, parent: %s, title: %s, ' + \ return ('<%s.%s: path: %s, id: %s, parent: %s, title: %s, ' + \


+ 43
- 82
ZipStorage.py View File

@@ -158,6 +158,7 @@ class ZipItem:
del kwargs['name'] del kwargs['name']


def checkUpdate(self): def checkUpdate(self):
# XXX - is this the correct order?
self.doUpdate() self.doUpdate()
self.zo.checkUpdate() self.zo.checkUpdate()


@@ -174,9 +175,6 @@ class ZipFile(ZipItem, Item):
self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype) self.res = Resource(self.url, 'http-get:*:%s:*' % self.mimetype)
self.res.size = self.zi.file_size self.res.size = self.zi.file_size


def doUpdate(self):
pass

class ZipChildDir(ZipItem, StorageFolder): class ZipChildDir(ZipItem, StorageFolder):
'''This is to represent a child dir of the zip file.''' '''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'] del kwargs['zf'], kwargs['zo'], kwargs['name']
StorageFolder.__init__(self, *args, **kwargs) 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): def __repr__(self):
return '<ZipChildDir: len: %d>' % len(self.pathObjmap)
return '<ZipChildDir: len: %d>' % len(self)


def tryTar(path): def tryTar(path):
# Try to see if it's a tar file # Try to see if it's a tar file
@@ -270,19 +249,16 @@ class ZipObject(FSObject, StorageFolder):


def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
'''If a zip argument is passed it, use that as the zip archive.''' '''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) StorageFolder.__init__(self, *args, **kwargs)
FSObject.__init__(self, path) FSObject.__init__(self, path)


# mapping from path to objectID
self.pathObjmap = {}

def doUpdate(self):
def genChildren(self):
# open the zipfile as necessary. # open the zipfile as necessary.
self.zip = genZipFile(self.FSpath) self.zip = genZipFile(self.FSpath)
nl = self.zip.namelist() nl = self.zip.namelist()

cnt = 0 cnt = 0
cursep = None cursep = None
for i in self.seps: for i in self.seps:
@@ -291,41 +267,26 @@ class ZipObject(FSObject, StorageFolder):
cursep = i cursep = i
cnt = newsum cnt = newsum
self.sep = cursep self.sep = cursep

hier = buildNameHier(nl, self.zip.infolist(), 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): def detectzipfile(path, fobj):
try: try:


+ 12
- 52
dvd.py View File

@@ -30,14 +30,12 @@ from twisted.spread import pb
from twisted.web import resource, server from twisted.web import resource, server


def gennameindexes(pref, item): def gennameindexes(pref, item):
ret = []
d = {} d = {}
for i, title in enumerate(item): for i, title in enumerate(item):
t = '%s %d (%s)' % (pref, i + 1, title.time) t = '%s %d (%s)' % (pref, i + 1, title.time)
ret.append(t)
d[t] = i d[t] = i


return ret, d
return d


class IterTransfer(pb.Viewable): class IterTransfer(pb.Viewable):
def __init__(self, iterable, request): def __init__(self, iterable, request):
@@ -142,30 +140,12 @@ class DVDTitle(StorageFolder):
self.doUpdate() self.doUpdate()
#return self.dvddisc.checkUpdate() #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): class DVDDisc(FSObject, StorageFolder):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -175,34 +155,14 @@ class DVDDisc(FSObject, StorageFolder):
StorageFolder.__init__(self, *args, **kwargs) StorageFolder.__init__(self, *args, **kwargs)
FSObject.__init__(self, path) 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) 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): def detectdvd(path, fobj):
if os.path.isdir(path): if os.path.isdir(path):


+ 69
- 0
item.py View File

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

+ 15
- 34
mpegtsmod.py View File

@@ -48,15 +48,13 @@ class _LimitedFile(file):
return file.read(self, min(size, self.remain())) return file.read(self, min(size, self.remain()))


def _gennameindexes(chan): def _gennameindexes(chan):
ret = []
d = {} d = {}


for i in chan: for i in chan:
t = '%s %s.%s' % (i['name'], i['major'], i['minor']) t = '%s %s.%s' % (i['name'], i['major'], i['minor'])
ret.append(t)
d[t] = i d[t] = i


return ret, d
return d


class MPEGTSTransfer(pb.Viewable): class MPEGTSTransfer(pb.Viewable):
def __init__(self, iterable, request): def __init__(self, iterable, request):
@@ -307,42 +305,25 @@ class MultiMPEGTS(FSObject, StorageFolder):
StorageFolder.__init__(self, *args, **kwargs) StorageFolder.__init__(self, *args, **kwargs)
FSObject.__init__(self, path) FSObject.__init__(self, path)


# mapping from path to objectID
self.pathObjmap = {}

def doUpdate(self):
def genChildren(self):
f = mpegts.TSPStream(_LimitedFile(self.FSpath, f = mpegts.TSPStream(_LimitedFile(self.FSpath,
size= 2*1024*1024))
size=2*1024*1024))
self.tvct = mpegts.GetTVCT(f) 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): def findtsstream(fp, pktsz=188):
d = fp.read(200*pktsz) d = fp.read(200*pktsz)


+ 4
- 0
pymeds.py View File

@@ -30,6 +30,7 @@ def tryloadmodule(mod):
modules = [ modules = [
'shoutcast', 'shoutcast',
'pyvr', 'pyvr',
'item',
'dvd', 'dvd',
'ZipStorage', 'ZipStorage',
'mpegtsmod', 'mpegtsmod',
@@ -196,6 +197,9 @@ def makeService(config):
s.doStop() s.doStop()
service.MultiService.stopService(self) service.MultiService.stopService(self)


import pickle
pickle.dump(cds, open('test.pickle', 'wb'), -1)

serv = PyMedS() serv = PyMedS()


internet.TCPServer(listenPort, site).setServiceParent(serv) internet.TCPServer(listenPort, site).setServiceParent(serv)


+ 21
- 58
pyvr.py View File

@@ -109,7 +109,6 @@ class PYVRShows(Container):


Container.__init__(self, *args, **kwargs) Container.__init__(self, *args, **kwargs)


self.pathObjmap = {}
self.shows = {} self.shows = {}
self.lastmodified = None self.lastmodified = None


@@ -140,34 +139,18 @@ class PYVRShows(Container):


return ret 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): 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 self.lastmodified = self.pyvr.lastmodified


@@ -178,7 +161,6 @@ class PYVR(Container):


Container.__init__(self, *args, **kwargs) Container.__init__(self, *args, **kwargs)


self.pathObjmap = {}
#self.pend = None #self.pend = None
self.lastmodified = None self.lastmodified = None
self.newobjs = None self.newobjs = None
@@ -241,42 +223,23 @@ class PYVR(Container):
self.newobjs = recxmltoobj(page.read()) self.newobjs = recxmltoobj(page.read())
self.doUpdate() self.doUpdate()


def genChildren(self):
return self.newobjs.iterkeys()

def createObject(self, i):
return PYVRShows, i, (), { 'show': i, 'pyvr': self }

def doUpdate(self): def doUpdate(self):
if self.newobjs is None: if self.newobjs is None:
import traceback import traceback
traceback.print_stack(file=log.logfile) 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): def detectpyvrfile(path, fobj):
bn = os.path.basename(path) bn = os.path.basename(path)


+ 35
- 57
shoutcast.py View File

@@ -15,7 +15,7 @@ import ConfigParser
import cStringIO as StringIO import cStringIO as StringIO
import os.path import os.path
import random import random
import time
import traceback import traceback


from py_shoutcast import * from py_shoutcast import *
@@ -312,7 +312,6 @@ class ShoutGenre(MusicGenre):
#self.feeds = ShoutcastFeedAsync(self.genre) #self.feeds = ShoutcastFeedAsync(self.genre)
self.feeds = feeds.ShoutcastFeed(self.genre) self.feeds = feeds.ShoutcastFeed(self.genre)
self.sl = None self.sl = None
self.pathObjmap = {}


MusicGenre.__init__(self, *args, **kwargs) MusicGenre.__init__(self, *args, **kwargs)


@@ -335,43 +334,36 @@ class ShoutGenre(MusicGenre):
return ret return ret


def checkUpdate(self): 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: if stations == self.sl:
return 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 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): class ShoutCast(Container):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -380,38 +372,24 @@ class ShoutCast(Container):
#self.genres = GenreFeedAsync() #self.genres = GenreFeedAsync()
self.genres = feeds.GenreFeed() self.genres = feeds.GenreFeed()
self.genre_list = None self.genre_list = None
self.pathObjmap = {}


def checkUpdate(self): def checkUpdate(self):
self.doUpdate()

def doUpdate(self):
#traceback.print_stack(file=log.logfile)
nl = self.genres.parse_genres() nl = self.genres.parse_genres()
if nl == self.genre_list: if nl == self.genre_list:
return 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 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): def detectshoutcastfile(origpath, fobj):
path = os.path.basename(origpath) path = os.path.basename(origpath)


Loading…
Cancel
Save