From df5763129e8f260f022cee7311abbb6aaed3291a Mon Sep 17 00:00:00 2001 From: John-Mark Gurney Date: Tue, 19 Feb 2008 01:06:56 -0800 Subject: [PATCH] add a module to parsing my pyvr xml data... This has the shows showing up, but now I need to figure out why it hangs when browse into the shows... looking good... [git-p4: depot-paths = "//depot/": change = 1113] --- pymediaserv | 8 +- pyvr.py | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 pyvr.py diff --git a/pymediaserv b/pymediaserv index d38d405..fbdbe11 100755 --- a/pymediaserv +++ b/pymediaserv @@ -27,7 +27,13 @@ def tryloadmodule(mod): # ZipStorage w/ tar support should be last as it will gobble up empty files. # These should be sorted by how much work they do, the least work the earlier. # mpegtsmod can be really expensive. -modules = [ 'shoutcast', 'dvd', 'ZipStorage', 'mpegtsmod' ] +modules = [ + 'shoutcast', + 'pyvr', + 'dvd', + 'ZipStorage', + 'mpegtsmod', + ] modmap = {} for i in modules: modmap[i] = tryloadmodule(i) diff --git a/pyvr.py b/pyvr.py new file mode 100644 index 0000000..9b330c5 --- /dev/null +++ b/pyvr.py @@ -0,0 +1,268 @@ +#!/usr/bin/env python +# Copyright 2008 John-Mark Gurney +'''PVR Interface''' + +__version__ = '$Change: 1109 $' +# $Id: //depot/python/pymeds/main/shoutcast.py#13 $ + +from DIDLLite import Container, Item, VideoItem, Resource +from FSStorage import registerklassfun + +import os.path +import time +import twisted.web +from twisted.internet import reactor +from twisted.python import log + +def getPage(url, contextFactory=None, *args, **kwargs): + """Download a web page as a string. + + Download a page. Return the HTTPClientFactory, which will + callback with a page (as a string) or errback with a + description of the error. + + See HTTPClientFactory to see what extra args can be passed. + """ + from twisted.web.client import _parse, HTTPClientFactory + + scheme, host, port, path = _parse(url) + factory = HTTPClientFactory(url, *args, **kwargs) + if scheme == 'https': + from twisted.internet import ssl + if contextFactory is None: + contextFactory = ssl.ClientContextFactory() + reactor.connectSSL(host, port, factory, contextFactory) + else: + reactor.connectTCP(host, port, factory) + return factory + +class PYVRShow(VideoItem): + def __init__(self, *args, **kwargs): + baseurl = kwargs['url'] + self.info = kwargs['info'] + del kwargs['info'], kwargs['url'] + + VideoItem.__init__(self, *args, **kwargs) + + url = self.info['link'] + sc = urlparse.urlparse(url) + if not sc: + # need to combine w/ base url + url = urlparse.urljoin(baseurl, url) + self.res = Resource(url, + 'http-get:*:%s:*' % self.info['mimetype']) + #self.res.size = self.chapter.size + + def doUpdate(self): + pass + +import xml.sax +import xml.sax.handler +from xml.sax.saxutils import unescape + +class RecordingXML(xml.sax.handler.ContentHandler): + def __init__(self): + self.shows = {} + self.data = None + + def characters(self, chars): + if self.data is not None: + self.data.append(chars) + + def startElement(self, name, attrs): + if name in ('title', 'subtitle', 'mimetype', 'link', 'delete'): + self.data = [] + self.curel = name + elif name == 'record': + self.currec = {} + + def endElement(self, name): + if name in ('title', 'subtitle', 'mimetype', 'link', 'delete'): + data = unescape(''.join(self.data)) + self.currec[self.curel] = data + elif name == 'record': + rec = self.currec + try: + self.shows[rec['title']].append(rec) + except KeyError: + self.shows[rec['title']] = [ rec ] + + self.data = None + +def recxmltoobj(page): + obj = RecordingXML() + xml.sax.parseString(page, obj) + + return obj.shows + +class PYVRShows(Container): + def __init__(self, *args, **kwargs): + self.pyvr = kwargs['pyvr'] + del kwargs['pyvr'] + self.show = kwargs['show'] + del kwargs['show'] + + Container.__init__(self, *args, **kwargs) + + self.pathObjmap = {} + self.shows = {} + self.lastmodified = None + + def checkUpdate(self): + self.pyvr.checkUpdate() + if self.pyvr.lastmodified != self.lastmodified: + self.doUpdate(self) + + @staticmethod + def getunique(eps, ep): + i = 1 + while True: + title = '%s Copy %d' % (ep['subtitle'], i) + if not ret.has_key(title): + return title + i += 1 + + @staticmethod + def eplisttodict(eps): + ret = {} + for i in eps: + title = i['subtitle'] + if ret.has_key(title): + print 'WARNING: dup:', `i`, `ret[title]` + title = self.getunique(ret, i) + ret[title] = i + + return ret + + 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)) + if doupdate: + Container.doUpdate(self) + +class PYVR(Container): + def __init__(self, *args, **kwargs): + self.url = kwargs['url'] + del kwargs['url'] + + Container.__init__(self, *args, **kwargs) + + self.pathObjmap = {} + self.isPend = False + self.lastmodified = None + self.newobjs = None + self.objs = {} + self.lastcheck = 0 + + def checkUpdate(self): + if self.isPend: + print 'already' + raise self.pend + + if time.time() - self.lastcheck < 5: + print 'escape' + return + + # Check to see if any changes have been made + self.isPend = True + self.lastcheck = time.time() + self.page = getPage(self.url, method='HEAD') + self.page.deferred.addCallback(self.doCheck) + self.pend = self.page.deferred + + print 'doing raise' + raise self.pend + + def doCheck(self, x): + print 'got check' + print `self.page.response_headers` + slm = self.page.response_headers['last-modified'] + if slm == self.lastmodified: + # Page the same, don't do anything + self.isPend = False + return + + self.page = getPage(self.url) + self.page.deferred.addCallback(self.parsePage) + self.pend = self.page.deferred + + return self.pend + + def parsePage(self, page): + print 'parsing' + slm = self.page.response_headers['last-modified'] + self.lastmodified = slm + self.isPend = False + del self.page + del self.pend + + self.newobjs = recxmltoobj(page) + self.doUpdate() + + def doUpdate(self): + if self.newobjs is None: + import traceback + traceback.print_stack(file=log.logfile) + return + + 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.newobjs = None + + # sort our children + self.sort(lambda x, y: cmp(x.title, y.title)) + if doupdate: + Container.doUpdate(self) + +def detectpyvrfile(path, fobj): + bn = os.path.basename(path) + if bn == 'PYVR': + print 'detected' + return PYVR, { 'url': fobj.readline().strip() } + return None, None + +registerklassfun(detectpyvrfile)