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

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



+ 16
- 58
FSStorage.py View File

@@ -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, ' + \


+ 43
- 82
ZipStorage.py View File

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


+ 12
- 52
dvd.py View File

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


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

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)


+ 4
- 0
pymeds.py View File

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


+ 21
- 58
pyvr.py View File

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


+ 35
- 57
shoutcast.py View File

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


Loading…
Cancel
Save