5 Commits

Author SHA1 Message Date
  John-Mark Gurney fcfa5bdded convert README to markdown and minor updates.. 1 year ago
  John-Mark Gurney a4ed76d890 use local forks to fix modern Python issues.. 1 year ago
  John-Mark Gurney 7666721ed6 add a date to files using their mtime.. 1 year ago
  John-Mark Gurney a8e8337e96 a string player requires these changes.. 1 year ago
  John-Mark Gurney dda96e70f0 convert mostly to Python 3.. basic functions work... 1 year ago
31 changed files with 502 additions and 576 deletions
Unified View
  1. +5
    -0
      .gitignore
  2. +2
    -2
      Clip.py
  3. +7
    -7
      ConnectionManager.py
  4. +23
    -23
      ContentDirectory.py
  5. +26
    -22
      DIDLLite.py
  6. +18
    -15
      FSStorage.py
  7. +4
    -3
      FileDIDL.py
  8. +30
    -21
      README.md
  9. +24
    -27
      SSDP.py
  10. +0
    -14
      ZipStorage.py
  11. +12
    -12
      audio.py
  12. +13
    -13
      audioraw.py
  13. +5
    -5
      cdrtoc.py
  14. +3
    -3
      debug.py
  15. +0
    -1
      dvd.py
  16. +10
    -10
      et.py
  17. +1
    -1
      item.py
  18. +0
    -12
      iterrarfile.py
  19. +0
    -37
      itertarfile.py
  20. +0
    -25
      iterzipfile.py
  21. +2
    -2
      mpegts/atschuff.py
  22. +215
    -221
      mpegts/mpegts.py
  23. +0
    -1
      mpegts/tssel.py
  24. +12
    -13
      mpegtsmod.py
  25. +12
    -8
      pymediaserv
  26. +16
    -16
      pymeds.py
  27. +13
    -13
      pyvr.py
  28. +3
    -0
      requirements.txt
  29. +6
    -6
      root-device.xml
  30. +34
    -35
      slinkemod.py
  31. +6
    -8
      soap_lite.py

+ 5
- 0
.gitignore View File

@@ -0,0 +1,5 @@
.DS_Store
__pycache__

# my venv
p

+ 2
- 2
Clip.py View File

@@ -35,7 +35,7 @@ class ClipProxyFile:
fp = self.fp fp = self.fp
records = iter(self.p[p:]) records = iter(self.p[p:])
while s: while s:
rec = records.next()
rec = next(records)
diff = self.pos - rec[0] diff = self.pos - rec[0]
rlen = min(s, rec[1] - diff) rlen = min(s, rec[1] - diff)
fp.seek(rec[2] + diff) fp.seek(rec[2] + diff)
@@ -76,7 +76,7 @@ class ClipProxy(static.File):
self.origfile = i['file'] self.origfile = i['file']
self.date = eval(i['datetuple'], { '__builtins__': {} }) self.date = eval(i['datetuple'], { '__builtins__': {} })
# date is UTC # date is UTC
p = [ map(int, x.split()) for x in i.get_payload().split('\n') if x ]
p = [ list(map(int, x.split())) for x in i.get_payload().split('\n') if x ]
pos = 0 pos = 0
self.pos = par = [] self.pos = par = []
for j in p: for j in p:


+ 7
- 7
ConnectionManager.py View File

@@ -11,23 +11,23 @@ from upnp import UPnPPublisher


class ConnectionManagerControl(UPnPPublisher): class ConnectionManagerControl(UPnPPublisher):
def soap_GetProtocolInfo(self, *args, **kwargs): def soap_GetProtocolInfo(self, *args, **kwargs):
log.msg('GetProtocolInfo(%s, %s)' % (`args`, `kwargs`))
log.msg('GetProtocolInfo(%s, %s)' % (repr(args), repr(kwargs)))
return { 'Source': 'http-get:*:*:*', 'Sink': '' } return { 'Source': 'http-get:*:*:*', 'Sink': '' }


def soap_PrepareForConnection(self, *args, **kwargs): def soap_PrepareForConnection(self, *args, **kwargs):
log.msg('PrepareForConnection(%s, %s)' % (`args`, `kwargs`))
log.msg('PrepareForConnection(%s, %s)' % (repr(args), repr(kwargs)))


def soap_ConnectionComplete(self, *args, **kwargs): def soap_ConnectionComplete(self, *args, **kwargs):
log.msg('ConnectionComplete(%s, %s)' % (`args`, `kwargs`))
log.msg('ConnectionComplete(%s, %s)' % (repr(args), repr(kwargs)))


def soap_GetCurrentConnectionIDs(self, *args, **kwargs): def soap_GetCurrentConnectionIDs(self, *args, **kwargs):
log.msg('GetCurrentConnectionIDs(%s, %s)' % (`args`, `kwargs`))
log.msg('GetCurrentConnectionIDs(%s, %s)' % (repr(args), repr(kwargs)))


def soap_GetCurrentConnectionInfo(self, *args, **kwargs): def soap_GetCurrentConnectionInfo(self, *args, **kwargs):
log.msg('GetProtocolInfo(%s, %s)' % (`args`, `kwargs`))
log.msg('GetProtocolInfo(%s, %s)' % (repr(args), repr(kwargs)))


class ConnectionManagerServer(resource.Resource): class ConnectionManagerServer(resource.Resource):
def __init__(self): def __init__(self):
resource.Resource.__init__(self) resource.Resource.__init__(self)
self.putChild('scpd.xml', static.File('connection-manager-scpd.xml'))
self.putChild('control', ConnectionManagerControl())
self.putChild(b'scpd.xml', static.File('connection-manager-scpd.xml'))
self.putChild(b'control', ConnectionManagerControl())

+ 23
- 23
ContentDirectory.py View File

@@ -27,7 +27,7 @@ reqname = 'requests'
from twisted.python import log from twisted.python import log
from twisted.web import resource, static from twisted.web import resource, static


from elementtree.ElementTree import Element, SubElement, tostring
from xml.etree.ElementTree import Element, SubElement, tostring
from upnp import UPnPPublisher, errorCode from upnp import UPnPPublisher, errorCode
from DIDLLite import DIDLElement, Container, Movie, Resource, MusicTrack from DIDLLite import DIDLElement, Container, Movie, Resource, MusicTrack


@@ -36,7 +36,7 @@ from twisted.python import failure


import debug import debug
import traceback import traceback
from urllib import quote
from urllib.parse import quote


class doRecall(defer.Deferred): class doRecall(defer.Deferred):
'''A class that will upon any callback from the Deferred object passed '''A class that will upon any callback from the Deferred object passed
@@ -80,7 +80,7 @@ class doRecall(defer.Deferred):
def wrapper(fun, *args, **kwargs): def wrapper(fun, *args, **kwargs):
try: try:
return fun(*args, **kwargs) return fun(*args, **kwargs)
except defer.Deferred, x:
except defer.Deferred as x:
return doRecallgen(x, fun, *args, **kwargs) return doRecallgen(x, fun, *args, **kwargs)


def doRecallgen(defer, fun, *args, **kwargs): def doRecallgen(defer, fun, *args, **kwargs):
@@ -124,17 +124,17 @@ class ContentDirectoryControl(UPnPPublisher, dict):
return return


if hasattr(i, 'content'): if hasattr(i, 'content'):
self.webbase.putChild(nid, i.content)
self.webbase.putChild(bytes(nid, 'ascii'), i.content)
#log.msg('children:', `self.children[parent]`, `i`) #log.msg('children:', `self.children[parent]`, `i`)
self.children[parent].append(i) self.children[parent].append(i)
self[i.id] = i self[i.id] = i
return i.id return i.id


def has_key(self, key):
return dict.has_key(self, key)
def __in__(self, k):
return dict.__in__(self, k)


def delItem(self, id): def delItem(self, id):
if not self.has_key(id):
if id not in self:
log.msg('already removed:', id) log.msg('already removed:', id)
return return
#log.msg('removing:', id) #log.msg('removing:', id)
@@ -195,7 +195,7 @@ class ContentDirectoryControl(UPnPPublisher, dict):
def soap_Browse(self, *args): def soap_Browse(self, *args):
l = {} l = {}
debug.appendnamespace(reqname, l) debug.appendnamespace(reqname, l)
if self.has_key(args[0]):
if args[0] in self:
l['object'] = self[args[0]] l['object'] = self[args[0]]
l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \ l['query'] = 'Browse(ObjectID=%s, BrowseFlags=%s, Filter=%s, ' \
'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \ 'StartingIndex=%s RequestedCount=%s SortCriteria=%s)' % \
@@ -261,8 +261,8 @@ class ContentDirectoryControl(UPnPPublisher, dict):


log.msg('Search(ContainerID=%s, SearchCriteria=%s, Filter=%s, ' \ log.msg('Search(ContainerID=%s, SearchCriteria=%s, Filter=%s, ' \
'StartingIndex=%s, RequestedCount=%s, SortCriteria=%s)' % 'StartingIndex=%s, RequestedCount=%s, SortCriteria=%s)' %
(`ContainerID`, `SearchCriteria`, `Filter`,
`StartingIndex`, `RequestedCount`, `SortCriteria`))
(repr(ContainerID), repr(SearchCriteria), repr(Filter),
repr(StartingIndex), repr(RequestedCount), repr(SortCriteria)))


def soap_CreateObject(self, *args, **kwargs): def soap_CreateObject(self, *args, **kwargs):
"""Create a new object.""" """Create a new object."""
@@ -270,14 +270,14 @@ class ContentDirectoryControl(UPnPPublisher, dict):
(ContainerID, Elements) = args (ContainerID, Elements) = args


log.msg('CreateObject(ContainerID=%s, Elements=%s)' % log.msg('CreateObject(ContainerID=%s, Elements=%s)' %
(`ContainerID`, `Elements`))
(repr(ContainerID), repr(Elements)))


def soap_DestroyObject(self, *args, **kwargs): def soap_DestroyObject(self, *args, **kwargs):
"""Destroy the specified object.""" """Destroy the specified object."""


(ObjectID) = args (ObjectID) = args


log.msg('DestroyObject(ObjectID=%s)' % `ObjectID`)
log.msg('DestroyObject(ObjectID=%s)' % repr(ObjectID))


def soap_UpdateObject(self, *args, **kwargs): def soap_UpdateObject(self, *args, **kwargs):
"""Modify, delete or insert object metadata.""" """Modify, delete or insert object metadata."""
@@ -285,8 +285,8 @@ class ContentDirectoryControl(UPnPPublisher, dict):
(ObjectID, CurrentTagValue, NewTagValue) = args (ObjectID, CurrentTagValue, NewTagValue) = args


log.msg('UpdateObject(ObjectID=%s, CurrentTagValue=%s, ' \ log.msg('UpdateObject(ObjectID=%s, CurrentTagValue=%s, ' \
'NewTagValue=%s)' % (`ObjectID`, `CurrentTagValue`,
`NewTagValue`))
'NewTagValue=%s)' % (repr(ObjectID), repr(CurrentTagValue),
repr(NewTagValue)))


def soap_ImportResource(self, *args, **kwargs): def soap_ImportResource(self, *args, **kwargs):
"""Transfer a file from a remote source to a local """Transfer a file from a remote source to a local
@@ -295,7 +295,7 @@ class ContentDirectoryControl(UPnPPublisher, dict):
(SourceURI, DestinationURI) = args (SourceURI, DestinationURI) = args


log.msg('ImportResource(SourceURI=%s, DestinationURI=%s)' % log.msg('ImportResource(SourceURI=%s, DestinationURI=%s)' %
(`SourceURI`, `DestinationURI`))
(repr(SourceURI), repr(DestinationURI)))


def soap_ExportResource(self, *args, **kwargs): def soap_ExportResource(self, *args, **kwargs):
"""Transfer a file from a local source to a remote """Transfer a file from a local source to a remote
@@ -304,7 +304,7 @@ class ContentDirectoryControl(UPnPPublisher, dict):
(SourceURI, DestinationURI) = args (SourceURI, DestinationURI) = args


log.msg('ExportResource(SourceURI=%s, DestinationURI=%s)' % log.msg('ExportResource(SourceURI=%s, DestinationURI=%s)' %
(`SourceURI`, `DestinationURI`))
(repr(SourceURI), repr(DestinationURI)))


def soap_StopTransferResource(self, *args, **kwargs): def soap_StopTransferResource(self, *args, **kwargs):
"""Stop a file transfer initiated by ImportResource or """Stop a file transfer initiated by ImportResource or
@@ -322,15 +322,15 @@ class ContentDirectoryControl(UPnPPublisher, dict):


log.msg('GetTransferProgress(TransferID=%s, TransferStatus=%s, ' \ log.msg('GetTransferProgress(TransferID=%s, TransferStatus=%s, ' \
'TransferLength=%s, TransferTotal=%s)' % 'TransferLength=%s, TransferTotal=%s)' %
(`TransferId`, `TransferStatus`, `TransferLength`,
`TransferTotal`))
(repr(TransferId), repr(TransferStatus), repr(TransferLength),
repr(TransferTotal)))


def soap_DeleteResource(self, *args, **kwargs): def soap_DeleteResource(self, *args, **kwargs):
"""Delete a specified resource.""" """Delete a specified resource."""


(ResourceURI) = args (ResourceURI) = args


log.msg('DeleteResource(ResourceURI=%s)' % `ResourceURI`)
log.msg('DeleteResource(ResourceURI=%s)' % repr(ResourceURI))


def soap_CreateReference(self, *args, **kwargs): def soap_CreateReference(self, *args, **kwargs):
"""Create a reference to an existing object.""" """Create a reference to an existing object."""
@@ -338,14 +338,14 @@ class ContentDirectoryControl(UPnPPublisher, dict):
(ContainerID, ObjectID) = args (ContainerID, ObjectID) = args


log.msg('CreateReference(ContainerID=%s, ObjectID=%s)' % log.msg('CreateReference(ContainerID=%s, ObjectID=%s)' %
(`ContainerID`, `ObjectID`))
(repr(ContainerID), repr(ObjectID)))


def __repr__(self): def __repr__(self):
return '<ContentDirectoryControl: cnt: %d, urlbase: %s, nextID: %d>' % (len(self), `self.urlbase`, self.nextID)
return '<ContentDirectoryControl: cnt: %d, urlbase: %s, nextID: %d>' % (len(self), repr(self.urlbase), self.nextID)


class ContentDirectoryServer(resource.Resource): class ContentDirectoryServer(resource.Resource):
def __init__(self, title, *args, **kwargs): def __init__(self, title, *args, **kwargs):
resource.Resource.__init__(self) resource.Resource.__init__(self)
self.putChild('scpd.xml', static.File('content-directory-scpd.xml'))
self.putChild(b'scpd.xml', static.File('content-directory-scpd.xml'))
self.control = ContentDirectoryControl(title, *args, **kwargs) self.control = ContentDirectoryControl(title, *args, **kwargs)
self.putChild('control', self.control)
self.putChild(b'control', self.control)

+ 26
- 22
DIDLLite.py View File

@@ -7,11 +7,12 @@
__version__ = '$Change: 1665 $' __version__ = '$Change: 1665 $'
# $Id: //depot/python/pymeds/main/DIDLLite.py#32 $ # $Id: //depot/python/pymeds/main/DIDLLite.py#32 $


import functools
import itertools import itertools
import unittest import unittest


import et import et
for i in [ 'Element', 'SubElement', 'tostring', '_ElementInterface' ]:
for i in [ 'Element', 'SubElement', 'tostring', ]:
locals()[i] = getattr(et.ET, i) locals()[i] = getattr(et.ET, i)


class Resource(object): class Resource(object):
@@ -53,7 +54,7 @@ class Resource(object):
try: try:
return self.attrs[key.lower()] return self.attrs[key.lower()]
except KeyError: except KeyError:
raise AttributeError, key
raise AttributeError(key)


def __setattr__(self, key, value): def __setattr__(self, key, value):
key = key.lower() key = key.lower()
@@ -72,15 +73,15 @@ class Resource(object):
value = getattr(self, funname)(value) value = getattr(self, funname)(value)
else: else:
value = str(value) value = str(value)
assert isinstance(value, basestring), \
'value is not a string: %s' % `value`
assert isinstance(value, str), \
'value is not a string: %s' % repr(value)
root.attrib[attr] = value root.attrib[attr] = value


return root return root


@staticmethod @staticmethod
def format_duration(s): def format_duration(s):
if isinstance(s, basestring):
if isinstance(s, str):
return s return s


# assume it is a number # assume it is a number
@@ -104,7 +105,7 @@ class ResourceList(list):
def append(self, k): def append(self, k):
assert isinstance(k, Resource) assert isinstance(k, Resource)
mt = k.protocolInfo.split(':')[2] mt = k.protocolInfo.split(':')[2]
if self._mt.has_key(mt):
if mt in self._mt:
return return


list.append(self, k) list.append(self, k)
@@ -204,12 +205,12 @@ class Object(object):
else: else:
self.restricted = '0' self.restricted = '0'


if kwargs.has_key('content'):
if 'content' in kwargs:
self._content = kwargs.pop('content') self._content = kwargs.pop('content')


for i in kwargs: for i in kwargs:
if i not in self._optionattrs: if i not in self._optionattrs:
raise TypeError('invalid keyword arg: %s' % `i`)
raise TypeError('invalid keyword arg: %s' % repr(i))
setattr(self, i, kwargs[i]) setattr(self, i, kwargs[i])


def __cmp__(self, other): def __cmp__(self, other):
@@ -245,12 +246,12 @@ class Object(object):
if obj is None: if obj is None:
continue continue
SubElement(root, '%s:%s' % (self._optionattrs[i], SubElement(root, '%s:%s' % (self._optionattrs[i],
i)).text = unicode(getattr(self, i))
i)).text = str(getattr(self, i))


if self.res is not None: if self.res is not None:
try: try:
resiter = iter(self.res) resiter = iter(self.res)
except TypeError, x:
except TypeError as x:
resiter = [ self.res ] resiter = [ self.res ]
for res in resiter: for res in resiter:
root.append(res.toElement()) root.append(res.toElement())
@@ -374,8 +375,11 @@ class Container(Object, list):


raise NotImplementedError raise NotImplementedError


def sort(self, fun=lambda x, y: cmp(x.title, y.title)):
return list.sort(self, fun)
def sort(self, fun=None):
if fun is not None:
return list.sort(self, key=functools.cmp_to_key(fun))
else:
return list.sort(self, key=lambda x: x.title)


def doUpdate(self): def doUpdate(self):
if self.doingUpdate: if self.doingUpdate:
@@ -396,12 +400,12 @@ class Container(Object, list):
# Delete the old object that no longer exists. # Delete the old object that no longer exists.
# Make a mapping of current names to ids. # Make a mapping of current names to ids.
names = {} names = {}
print 'i:', `self`, `self.genCurrent`, `self.__class__`
print('i:', repr(self), repr(self.genCurrent), repr(self.__class__))
for id, i in tuple(self.genCurrent()): for id, i in tuple(self.genCurrent()):
if i not in children: if i not in children:
didupdate = True didupdate = True
# delete # delete
print 'del:', `id`, `i`
print('del:', repr(id), repr(i))
self.cd.delItem(id) self.cd.delItem(id)
self.needcontupdate = True self.needcontupdate = True
else: else:
@@ -413,7 +417,7 @@ class Container(Object, list):
for i in children: for i in children:
if i in names: if i in names:
if isdict: if isdict:
print 'oc:', `oldchildren[i]`, `children[i]`
print('oc:', repr(oldchildren[i]), repr(children[i]))
if oldchildren[i] == children[i]: if oldchildren[i] == children[i]:
continue continue


@@ -433,7 +437,7 @@ class Container(Object, list):
#print 'i:', `i`, `isdict`, `args`, `self` #print 'i:', `i`, `isdict`, `args`, `self`
pass pass
except UnicodeEncodeError: except UnicodeEncodeError:
print 'i decode error'
print('i decode error')


klass, name, args, kwargs = self.createObject(i, *args) klass, name, args, kwargs = self.createObject(i, *args)
if klass is not None: if klass is not None:
@@ -457,7 +461,7 @@ class Container(Object, list):
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) % (1 << 32)
Container.didUpdate(self.cd['0']) Container.didUpdate(self.cd['0'])


def _addSet(self, e, items): def _addSet(self, e, items):
@@ -502,7 +506,7 @@ class MockContainer(object):
self.itemiter = itertools.count(1) self.itemiter = itertools.count(1)


def addItem(self, *args, **kwargs): def addItem(self, *args, **kwargs):
return self.itemiter.next()
return next(self.itemiter)


def __getitem__(self, id): def __getitem__(self, id):
return Container(None, '0', None, None) return Container(None, '0', None, None)
@@ -570,10 +574,10 @@ class StorageFolder(Container):


storageUsed = -1 storageUsed = -1


class DIDLElement(_ElementInterface):
class DIDLElement(Element):
def __init__(self): def __init__(self):
_ElementInterface.__init__(self, 'DIDL-Lite', {})
self.attrib['xmlns'] = 'urn:schemas-upnp-org:metadata-1-0/DIDL-Lite'
super().__init__('DIDL-Lite', {})
self.attrib['xmlns'] = 'urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/'
self.attrib['xmlns:dc'] = 'http://purl.org/dc/elements/1.1/' self.attrib['xmlns:dc'] = 'http://purl.org/dc/elements/1.1/'
self.attrib['xmlns:upnp'] = 'urn:schemas-upnp-org:metadata-1-0/upnp' self.attrib['xmlns:upnp'] = 'urn:schemas-upnp-org:metadata-1-0/upnp'


@@ -594,4 +598,4 @@ if __name__ == '__main__':
root.addItem(Container(None, '0\Photo\\', '0\\', 'Photo')) root.addItem(Container(None, '0\Photo\\', '0\\', 'Photo'))
root.addItem(Container(None, '0\OnlineMedia\\', '0\\', 'OnlineMedia')) root.addItem(Container(None, '0\OnlineMedia\\', '0\\', 'OnlineMedia'))


print tostring(root)
print(tostring(root))

+ 18
- 15
FSStorage.py View File

@@ -9,18 +9,18 @@ ffmpeg_path = '/usr/local/bin/ffmpeg'
ffmpeg_path = '/a/home/jmg/src/ffmpeg.tmp/ffmpeg' ffmpeg_path = '/a/home/jmg/src/ffmpeg.tmp/ffmpeg'
ffmpeg_path = '/usr/local/bin/ffmpeg-devel' ffmpeg_path = '/usr/local/bin/ffmpeg-devel'


import datetime
import FileDIDL import FileDIDL
import errno import errno
import itertools import itertools
import os import os
import sets
import stat import stat


from DIDLLite import StorageFolder, Item, 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
from zope.interface import implements
from zope.interface import implementer


__all__ = [ 'registerklassfun', 'registerfiletoignore', __all__ = [ 'registerklassfun', 'registerfiletoignore',
'FSObject', 'FSItem', 'FSDirectory', 'FSObject', 'FSItem', 'FSDirectory',
@@ -71,7 +71,7 @@ class FSObject(object):


self.pstat = nstat self.pstat = nstat
self.doUpdate(**kwargs) self.doUpdate(**kwargs)
except OSError, x:
except OSError as 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, ):
# We can't access it anymore, delete it # We can't access it anymore, delete it
@@ -83,17 +83,17 @@ class FSObject(object):
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__,
`self.FSpath`, self.id, self.parentID, `self.title`)
class NullConsumer(file, abstract.FileDescriptor):
implements(interfaces.IConsumer)
def __init__(self):
file.__init__(self, '/dev/null', 'w')
abstract.FileDescriptor.__init__(self)
def write(self, data):
pass
repr(self.FSpath), self.id, self.parentID, repr(self.title))
#@implementer(interfaces.IConsumer)
#class NullConsumer(file, abstract.FileDescriptor):
#
# def __init__(self):
# file.__init__(self, '/dev/null', 'w')
# abstract.FileDescriptor.__init__(self)
#
# def write(self, data):
# pass


class DynamTransfer(protocol.ProcessProtocol): class DynamTransfer(protocol.ProcessProtocol):
def __init__(self, path, mods, request): def __init__(self, path, mods, request):
@@ -166,7 +166,7 @@ class DynamTransfer(protocol.ProcessProtocol):
#'-vb', '8000k', #'-vb', '8000k',
#'-sc_threshold', '500000', '-b_strategy', '1', '-max_b_frames', '6', #'-sc_threshold', '500000', '-b_strategy', '1', '-max_b_frames', '6',
] + optdict[vcodec] + [ '-', ] ] + optdict[vcodec] + [ '-', ]
log.msg(*[`i` for i in args])
log.msg(*[repr(i) for i in args])
self.proc = process.Process(reactor, ffmpeg_path, args, self.proc = process.Process(reactor, ffmpeg_path, args,
None, None, self) None, None, self)
self.proc.closeStdin() self.proc.closeStdin()
@@ -203,6 +203,9 @@ class FSItem(FSObject, Item):
mimetype = kwargs.pop('mimetype') mimetype = kwargs.pop('mimetype')
kwargs['content'] = DynamicTrans(self.FSpath, kwargs['content'] = DynamicTrans(self.FSpath,
static.File(self.FSpath, mimetype)) static.File(self.FSpath, mimetype))

kwargs['date'] = datetime.datetime.utcfromtimestamp(os.stat(self.FSpath).st_mtime).isoformat() + '+00:00'

Item.__init__(self, *args, **kwargs) Item.__init__(self, *args, **kwargs)
self.url = '%s/%s' % (self.cd.urlbase, self.id) self.url = '%s/%s' % (self.cd.urlbase, self.id)
self.mimetype = mimetype self.mimetype = mimetype


+ 4
- 3
FileDIDL.py View File

@@ -30,6 +30,7 @@ mimetoclass = {


def getClassMT(name, mimetype = None, fp = None): def getClassMT(name, mimetype = None, fp = None):
'''Return a tuple of the DIDLLite class and mimetype responsible for the named/mimetyped/fpd file.''' '''Return a tuple of the DIDLLite class and mimetype responsible for the named/mimetyped/fpd file.'''

if mimetype is None: if mimetype is None:
fn, ext = os.path.splitext(name) fn, ext = os.path.splitext(name)
ext = ext.lower() ext = ext.lower()
@@ -40,9 +41,9 @@ def getClassMT(name, mimetype = None, fp = None):
return None, None return None, None


ty = mimetype.split('/')[0] ty = mimetype.split('/')[0]
if mimetoclass.has_key(mimetype):
if mimetype in mimetoclass:
klass = mimetoclass[mimetype] klass = mimetoclass[mimetype]
elif mimetoclass.has_key(ty):
elif ty in mimetoclass:
klass = mimetoclass[ty] klass = mimetoclass[ty]
else: else:
# XXX - We could fall file -i on it # XXX - We could fall file -i on it
@@ -64,7 +65,7 @@ def buildClassMT(baseklass, name, *args, **kwargs):


class ret(baseklass, klass): class ret(baseklass, klass):
pass pass
ret.__name__ = '+'.join(map(lambda x: '%s.%s' % (x.__module__, x.__name__), (baseklass, klass)))
ret.__name__ = '+'.join(['%s.%s' % (x.__module__, x.__name__) for x in (baseklass, klass)])


classdict[(baseklass, klass)] = ret classdict[(baseklass, klass)] = ret




README → README.md View File

@@ -1,39 +1,39 @@
This code is based upon code by Tim Potter.

It is licensed under the MIT license at:
http://opensource.org/licenses/mit-license.php
PyMedS
======


I got a D-Link DSM-520 but I needed a UPnP Media Server to stream data
with. I tried one, but it had issues running under FreeBSD's Linux
emulation. Since I know Python, I went looking for a python server
and found this code. The code was a good framework, so I expanded upon
it.
This is a UPnP Media Server based upon a plugable architecture to allow
other media repositories than just a file system.


Tested basic functionality with the following devices and/or programs: Tested basic functionality with the following devices and/or programs:
Sony PlayStation 3
VLC
BubbleUPnP (Android)

Historically tested basic functionality with the following devices and/or programs:
Cidero UPnP A/V Controller Cidero UPnP A/V Controller
Intel's Media Control Point and Media Renderer Intel's Media Control Point and Media Renderer
D-Link DSM-520 D-Link DSM-520
Sony PlayStation 3 Sony PlayStation 3
Linksys DMC-250 Linksys DMC-250


The Intel tools are good for testing (though Windows only) but have been
moved. Not sure where they are located now.
Usage
-----


Either make a directory media and put the files there, or make a symlink Either make a directory media and put the files there, or make a symlink
named media to your media files. Either will work. Run it as: named media to your media files. Either will work. Run it as:
./pymediaserv <localip> [ <http server port> ]
```
./pymediaserv <localip> [ <http server port> ]
```


The following packages are required to run the media server: The following packages are required to run the media server:
* Twisted (tested w/ 8.2.0) - http://twistedmatrix.com/trac/
* ElementTree (only pre-Python 2.5) -
http://effbot.org/zone/element-index.htm
* SOAPpy - http://pywebsvcs.sourceforge.net/
* fpconst (required by SOAPpy) -
http://sourceforge.net/project/showfiles.php?group_id=71248
* Twisted (tested w/ 22.10.0) - https://twisted.org/
* SOAPpy-py3 - https://github.com/Synerty/SOAPpy-py3

The requirements are in `requirements.txt` and can be installed
via `pip intall -r requirements.txt`.


Optional software packages:
* rarfile - http://grue.l-t.ee/~marko/src/rarfile/
* CDDB-py - http://cddb-py.sourceforge.net/
Misc Issues
-----------


Thanks to Coherence for soap_lite that solved the issues w/ PS3 not seeing Thanks to Coherence for soap_lite that solved the issues w/ PS3 not seeing
the media server. The PS3 with the latest firmware (2.50 and later) now the media server. The PS3 with the latest firmware (2.50 and later) now
@@ -50,6 +50,15 @@ Good Luck!


John-Mark Gurney <jmg@funkthat.com> John-Mark Gurney <jmg@funkthat.com>


License Information
-------------------

This code is based upon code by Tim Potter.

It is licensed under the MIT license at:
http://opensource.org/licenses/mit-license.php


Ideas for future improvements: Ideas for future improvements:
I have received a few ECONNABORTED errors at times. The patch I have received a few ECONNABORTED errors at times. The patch
twisted.internet.tcp.py.patch catches this error, and handles twisted.internet.tcp.py.patch catches this error, and handles

+ 24
- 27
SSDP.py View File

@@ -52,27 +52,24 @@ class SSDPServer(DatagramProtocol):
def doStop(self): def doStop(self):
'''Make sure we send out the byebye notifications.''' '''Make sure we send out the byebye notifications.'''


for st in self.known.keys():
for st in list(self.known.keys()):
self.doByebye(st) self.doByebye(st)
del self.known[st] del self.known[st]


DatagramProtocol.doStop(self) DatagramProtocol.doStop(self)


def datagramReceived(self, data, (host, port)):
def datagramReceived(self, data, hostporttup):
"""Handle a received multicast datagram.""" """Handle a received multicast datagram."""

# Break up message in to command and headers
# TODO: use the email module after trimming off the request line..
# This gets us much better header support.

host, port = hostporttup
data = data.decode('ascii')
header, payload = data.split('\r\n\r\n') header, payload = data.split('\r\n\r\n')
lines = header.split('\r\n') lines = header.split('\r\n')
cmd = string.split(lines[0], ' ')
lines = map(lambda x: x.replace(': ', ':', 1), lines[1:])
lines = filter(lambda x: len(x) > 0, lines)
cmd = lines[0].split(' ')
lines = [x.replace(': ', ':', 1) for x in lines[1:]]
lines = [x for x in lines if len(x) > 0]


headers = [string.split(x, ':', 1) for x in lines]
headers = dict(map(lambda x: (x[0].lower(), x[1]), headers))
headers = [x.split(':', 1) for x in lines]
headers = dict([(x[0].lower(), x[1]) for x in headers])


if cmd[0] == 'M-SEARCH' and cmd[1] == '*': if cmd[0] == 'M-SEARCH' and cmd[1] == '*':
# SSDP discovery # SSDP discovery
@@ -83,20 +80,20 @@ class SSDPServer(DatagramProtocol):
else: else:
log.msg('Unknown SSDP command %s %s' % cmd) log.msg('Unknown SSDP command %s %s' % cmd)


def discoveryRequest(self, headers, (host, port)):
def discoveryRequest(self, headers, hostporttup):
"""Process a discovery request. The response must be sent to """Process a discovery request. The response must be sent to
the address specified by (host, port).""" the address specified by (host, port)."""
host, port = hostporttup
log.msg('Discovery request for %s' % headers['st']) log.msg('Discovery request for %s' % headers['st'])


# Do we know about this service? # Do we know about this service?
if headers['st'] == 'ssdp:all': if headers['st'] == 'ssdp:all':
for i in self.known: for i in self.known:
hcopy = dict(headers.iteritems())
hcopy = dict(headers.items())
hcopy['st'] = i hcopy['st'] = i
self.discoveryRequest(hcopy, (host, port)) self.discoveryRequest(hcopy, (host, port))
return return
if not self.known.has_key(headers['st']):
if headers['st'] not in self.known:
return return


#print 'responding' #print 'responding'
@@ -110,7 +107,7 @@ class SSDPServer(DatagramProtocol):
response.extend(('', '')) response.extend(('', ''))
delay = random.randint(0, int(headers['mx'])) delay = random.randint(0, int(headers['mx']))
reactor.callLater(delay, self.transport.write, reactor.callLater(delay, self.transport.write,
'\r\n'.join(response), (host, port))
b'\r\n'.join((bytes(x, 'ascii') for x in response)), (host, port))


def register(self, usn, st, location): def register(self, usn, st, location):
"""Register a service or device that this SSDP server will """Register a service or device that this SSDP server will
@@ -144,12 +141,12 @@ class SSDPServer(DatagramProtocol):
'Host: %s:%d' % (SSDP_ADDR, SSDP_PORT), 'Host: %s:%d' % (SSDP_ADDR, SSDP_PORT),
'NTS: ssdp:byebye', 'NTS: ssdp:byebye',
] ]
stcpy = dict(self.known[st].iteritems())
stcpy = dict(self.known[st].items())
stcpy['NT'] = stcpy['ST'] stcpy['NT'] = stcpy['ST']
del stcpy['ST'] del stcpy['ST']
resp.extend(map(lambda x: ': '.join(x), stcpy.iteritems()))
resp.extend([': '.join(x) for x in stcpy.items()])
resp.extend(('', '')) resp.extend(('', ''))
resp = '\r\n'.join(resp)
resp = b'\r\n'.join(bytes(x, 'ascii') for x in resp)
self.transport.write(resp, (SSDP_ADDR, SSDP_PORT)) self.transport.write(resp, (SSDP_ADDR, SSDP_PORT))
self.transport.write(resp, (SSDP_ADDR, SSDP_PORT)) self.transport.write(resp, (SSDP_ADDR, SSDP_PORT))


@@ -162,19 +159,19 @@ class SSDPServer(DatagramProtocol):
'Host: %s:%d' % (SSDP_ADDR, SSDP_PORT), 'Host: %s:%d' % (SSDP_ADDR, SSDP_PORT),
'NTS: ssdp:alive', 'NTS: ssdp:alive',
] ]
stcpy = dict(self.known[st].iteritems())
stcpy = dict(self.known[st].items())
stcpy['NT'] = stcpy['ST'] stcpy['NT'] = stcpy['ST']
del stcpy['ST'] del stcpy['ST']
resp.extend(map(lambda x: ': '.join(x), stcpy.iteritems()))
resp.extend([': '.join(x) for x in stcpy.items()])
resp.extend(('', '')) resp.extend(('', ''))
self.transport.write('\r\n'.join(resp), (SSDP_ADDR, SSDP_PORT))
self.transport.write(b'\r\n'.join(bytes(x, 'ascii') for x in resp), (SSDP_ADDR, SSDP_PORT))


def notifyReceived(self, headers, (host, port)):
def notifyReceived(self, headers, hostporttup):
"""Process a presence announcement. We just remember the """Process a presence announcement. We just remember the
details of the SSDP service announced.""" details of the SSDP service announced."""
host, port = hostporttup
if headers['nts'] == 'ssdp:alive': if headers['nts'] == 'ssdp:alive':
if not self.elements.has_key(headers['nt']):
if headers['nt'] not in self.elements:
# Register device/service # Register device/service
self.elements[headers['nt']] = {} self.elements[headers['nt']] = {}
self.elements[headers['nt']]['USN'] = headers['usn'] self.elements[headers['nt']]['USN'] = headers['usn']
@@ -182,7 +179,7 @@ class SSDPServer(DatagramProtocol):
log.msg('Detected presence of %s' % headers['nt']) log.msg('Detected presence of %s' % headers['nt'])
#log.msg('headers: %s' % `headers`) #log.msg('headers: %s' % `headers`)
elif headers['nts'] == 'ssdp:byebye': elif headers['nts'] == 'ssdp:byebye':
if self.elements.has_key(headers['nt']):
if headers['nt'] in self.elements:
# Unregister device/service # Unregister device/service
del(self.elements[headers['nt']]) del(self.elements[headers['nt']])
log.msg('Detected absence for %s' % headers['nt']) log.msg('Detected absence for %s' % headers['nt'])


+ 0
- 14
ZipStorage.py View File

@@ -6,21 +6,7 @@ __version__ = '$Change$'


import itertools import itertools
import os.path import os.path
import sets
import time import time
import iterzipfile
zipfile = iterzipfile
import itertarfile
tarfile = itertarfile
try:
import iterrarfile
rarfile = iterrarfile
except ImportError:
class rarfile:
pass

rarfile = rarfile()
rarfile.is_rarfile = lambda x: False


import FileDIDL import FileDIDL
from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource from DIDLLite import StorageFolder, Item, VideoItem, AudioItem, TextItem, ImageItem, Resource


+ 12
- 12
audio.py View File

@@ -28,7 +28,7 @@ def bytespersecmt(mt):
try: try:
r = mttobytes[tmp[0].lower()] r = mttobytes[tmp[0].lower()]
except KeyError: except KeyError:
raise ValueError('invalid audio type: %s' % `tmp[0]`)
raise ValueError('invalid audio type: %s' % repr(tmp[0]))


v = set(('rate', 'channels')) v = set(('rate', 'channels'))
for i in tmp[1:]: for i in tmp[1:]:
@@ -38,7 +38,7 @@ def bytespersecmt(mt):
r *= int(value) r *= int(value)
else: else:
raise ValueError('invalid audio parameter %s in %s' % raise ValueError('invalid audio parameter %s in %s' %
(`arg`, `mt`))
(repr(arg), repr(mt)))


return r return r


@@ -67,7 +67,7 @@ class AudioPlayer(FileDescriptor):
self._writeDisconnected = True self._writeDisconnected = True


def writeSomeData(self, data): def writeSomeData(self, data):
print 'wsd:', len(data)
print('wsd:', len(data))
return fdesc.writeToFD(self.fileno(), data) return fdesc.writeToFD(self.fileno(), data)


def doRead(self): def doRead(self):
@@ -76,7 +76,7 @@ class AudioPlayer(FileDescriptor):
def connectionLost(self, reason): def connectionLost(self, reason):
FileDescriptor.connectionLost(self, reason) FileDescriptor.connectionLost(self, reason)


print 'AP, connectionLost'
print('AP, connectionLost')
self.fileno = lambda: -1 self.fileno = lambda: -1
self.setparameters = None self.setparameters = None
if self._dev is not None: if self._dev is not None:
@@ -85,7 +85,7 @@ class AudioPlayer(FileDescriptor):
self.attached = None self.attached = None


def stopProducing(self): def stopProducing(self):
print 'AP, sp'
print('AP, sp')
self.writefun = lambda x: None self.writefun = lambda x: None
FileDescriptor.stopProducing(self) FileDescriptor.stopProducing(self)


@@ -137,13 +137,13 @@ class AudioResource(resource.Resource):
nchan = int(nchan) nchan = int(nchan)
rate = int(rate) rate = int(rate)
except AttributeError: except AttributeError:
raise ValueError('Invalid audio format: %s' % `origfmt`)
raise ValueError('Invalid audio format: %s' % repr(origfmt))


try: try:
mt = self.mtformat[fmt] mt = self.mtformat[fmt]
except KeyError: except KeyError:
raise KeyError('No mime-type for audio format: %s.' % raise KeyError('No mime-type for audio format: %s.' %
`origfmt`)
repr(origfmt))


return '%s;rate=%d;channels=%d' % (mt, rate, nchan) return '%s;rate=%d;channels=%d' % (mt, rate, nchan)


@@ -158,7 +158,7 @@ class AudioResource(resource.Resource):
try: try:
request.setHeader('content-type', request.setHeader('content-type',
self.getmimetype(fmt, nchan, rate)) self.getmimetype(fmt, nchan, rate))
except (ValueError, AttributeError, KeyError), x:
except (ValueError, AttributeError, KeyError) as x:
return error.ErrorPage(http.UNSUPPORTED_MEDIA_TYPE, return error.ErrorPage(http.UNSUPPORTED_MEDIA_TYPE,
'Unsupported Media Type', str(x)).render(request) 'Unsupported Media Type', str(x)).render(request)


@@ -188,7 +188,7 @@ class ossaudiodev_fmts:
pass pass


for i in (k for k in dir(ossaudiodev) if k[:5] == 'AFMT_' and \ for i in (k for k in dir(ossaudiodev) if k[:5] == 'AFMT_' and \
isinstance(getattr(ossaudiodev, k), (int, long))):
isinstance(getattr(ossaudiodev, k), int)):
setattr(ossaudiodev_fmts, i, getattr(ossaudiodev, i)) setattr(ossaudiodev_fmts, i, getattr(ossaudiodev, i))


class AudioSource(AudioItem): class AudioSource(AudioItem):
@@ -219,7 +219,7 @@ def getfmtstrings(f):
r.append(i) r.append(i)


while f: while f:
print f, f & -f
print(f, f & -f)
r.append(f & -f) r.append(f & -f)
f ^= f & -f f ^= f & -f


@@ -263,10 +263,10 @@ class FileConsumer:
if __name__ == '__main__': if __name__ == '__main__':
if False: if False:
i = ossaudiodev.open('/dev/dsp2', 'r') i = ossaudiodev.open('/dev/dsp2', 'r')
print getfmtstrings(i.getfmts())
print(getfmtstrings(i.getfmts()))
i.setparameters(ossaudiodev.AFMT_S16_BE, 2, 44100, True) i.setparameters(ossaudiodev.AFMT_S16_BE, 2, 44100, True)


print `i.read(16)`
print(repr(i.read(16)))
else: else:
aplr = AudioPlayer('/dev/dsp2', 'r', aplr = AudioPlayer('/dev/dsp2', 'r',
(ossaudiodev.AFMT_S16_BE, 2, 44100, True)) (ossaudiodev.AFMT_S16_BE, 2, 44100, True))


+ 13
- 13
audioraw.py View File

@@ -29,7 +29,7 @@ def makeaudiomt(bitsps, rate, nchan):
mt = mtformat[bitsps] mt = mtformat[bitsps]
except KeyError: except KeyError:
raise KeyError('No mime-type for audio format: %s.' % raise KeyError('No mime-type for audio format: %s.' %
`bitsps`)
repr(bitsps))


return '%s;rate=%d;channels=%d' % (mt, rate, nchan) return '%s;rate=%d;channels=%d' % (mt, rate, nchan)


@@ -53,7 +53,7 @@ class DecoderProducer:
self.resumeProducing() self.resumeProducing()


def __repr__(self): def __repr__(self):
return '<DecoderProducer: decoder: %s, bytes left: %d, skip: %d>' % (`self.decoder`, self.tbytes, self.skipbytes)
return '<DecoderProducer: decoder: %s, bytes left: %d, skip: %d>' % (repr(self.decoder), self.tbytes, self.skipbytes)


def pauseProducing(self): def pauseProducing(self):
# XXX - bug in Twisted 8.2.0 on pipelined requests this is # XXX - bug in Twisted 8.2.0 on pipelined requests this is
@@ -99,11 +99,11 @@ class AudioResource(resource.Resource):
self.cnt = cnt self.cnt = cnt


def __repr__(self): def __repr__(self):
return '<AudioResource file: %s, dec: %s, start:%d, cnt: %d>' % (`self.f`, self.dec, self.start, self.cnt)
return '<AudioResource file: %s, dec: %s, start:%d, cnt: %d>' % (repr(self.f), self.dec, self.start, self.cnt)
def calcrange(self, rng, l): def calcrange(self, rng, l):
rng = rng.strip() rng = rng.strip()
unit, rangeset = rng.split('=') unit, rangeset = rng.split('=')
assert unit == 'bytes', `unit`
assert unit == 'bytes', repr(unit)
start, end = rangeset.split('-') start, end = rangeset.split('-')
start = int(start) start = int(start)
if end: if end:
@@ -238,10 +238,10 @@ class AudioDisc(FSObject, MusicAlbum):
return track['offset'] + index['offset'] return track['offset'] + index['offset']


def createObject(self, i, arg=None): 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.'''
'''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.'''


oi = i oi = i
i = int(i) i = int(i)
@@ -273,7 +273,7 @@ class AudioDisc(FSObject, MusicAlbum):
if tt in tags: if tt in tags:
if len(tags[tt]) != 1: if len(tags[tt]) != 1:
# XXX - track this? # XXX - track this?
print 'hun? ttitle:', `tags[tt]`
print('hun? ttitle:', repr(tags[tt]))


ttitle = tags[tt][0] ttitle = tags[tt][0]
if ' / ' in ttitle: if ' / ' in ttitle:
@@ -338,8 +338,8 @@ class AudioRawBase(FSObject):
self.res.append(r) self.res.append(r)


def doUpdate(self): def doUpdate(self):
print 'dU:', `self`, self.baseObject.doUpdate
print self.__class__.__bases__
print('dU:', repr(self), self.baseObject.doUpdate)
print(self.__class__.__bases__)
#import traceback #import traceback
#traceback.print_stack() #traceback.print_stack()
self.baseObject.doUpdate(self) self.baseObject.doUpdate(self)
@@ -351,7 +351,7 @@ class AudioRawTrack(AudioRawBase, MusicTrack):
baseObject = MusicTrack baseObject = MusicTrack


def detectaudioraw(origpath, fobj): def detectaudioraw(origpath, fobj):
for i in decoders.itervalues():
for i in decoders.values():
try: try:
obj = i(origpath) obj = i(origpath)
# XXX - don't support down sampling yet # XXX - don't support down sampling yet
@@ -378,7 +378,7 @@ def detectaudioraw(origpath, fobj):
pass pass
except: except:
import traceback import traceback
print 'WARNING: failed to parse toc:'
print('WARNING: failed to parse toc:')
traceback.print_exc() traceback.print_exc()


args['cuesheet'] = obj.cuesheet args['cuesheet'] = obj.cuesheet


+ 5
- 5
cdrtoc.py View File

@@ -23,13 +23,13 @@ def decodestrend(i, pos):
r.append('"') r.append('"')
pos = bspos + 2 pos = bspos + 2
elif c in string.digits: elif c in string.digits:
r.append(unichr(int(i[bspos + 1:bspos + 4], 8)))
r.append(chr(int(i[bspos + 1:bspos + 4], 8)))
pos = bspos + 4 pos = bspos + 4
elif c == 'n': elif c == 'n':
r.append('\n') r.append('\n')
pos = bspos + 2 pos = bspos + 2
else: else:
raise ValueError('unknown escape char: %s' % `c`)
raise ValueError('unknown escape char: %s' % repr(c))
else: else:
r.append(i[pos:dqpos]) r.append(i[pos:dqpos])
break break
@@ -92,7 +92,7 @@ def parsetoc(toc):
elif key == '//': elif key == '//':
pass pass
else: else:
raise ValueError('unknown line: %s' % `i`)
raise ValueError('unknown line: %s' % repr(i))
elif state == 1: elif state == 1:
if key == 'LANGUAGE_MAP': if key == 'LANGUAGE_MAP':
state = 2 state = 2
@@ -135,5 +135,5 @@ if __name__ == '__main__':
import sys import sys


for i in sys.argv[1:]: for i in sys.argv[1:]:
print 'file:', `i`
print parsetoc(open(i).read())
print('file:', repr(i))
print(parsetoc(open(i).read()))

+ 3
- 3
debug.py View File

@@ -28,7 +28,7 @@ class RingBuffer:
self.cur=0 self.cur=0
self.__class__ = RingBufferFull self.__class__ = RingBufferFull
def get(self): def get(self):
""" return a list of elements from the oldest to the newest"""
""" return a list of elements from the oldest to the newest"""
return self.data return self.data


class RingBufferFull: class RingBufferFull:
@@ -47,7 +47,7 @@ def doDebugging(opt):
global insertnamespace, appendnamespace, insertringbuf global insertnamespace, appendnamespace, insertringbuf


def insertnamespace(k, v): def insertnamespace(k, v):
assert isinstance(k, basestring)
assert isinstance(k, str)
sf.namespace[k] = v sf.namespace[k] = v


def appendnamespace(k, v): def appendnamespace(k, v):
@@ -71,4 +71,4 @@ def doDebugging(opt):
try: try:
reactor.listenTCP(56283, sf) reactor.listenTCP(56283, sf)
except twisted.internet.error.CannotListenError: except twisted.internet.error.CannotListenError:
print 'WARNING: cannot bind to debugger port.'
print('WARNING: cannot bind to debugger port.')

+ 0
- 1
dvd.py View File

@@ -9,7 +9,6 @@ default_audio_lang = 'en'


import itertools import itertools
import os import os
import sets


import sys import sys
sys.path.append('mpegts') sys.path.append('mpegts')


+ 10
- 10
et.py View File

@@ -29,7 +29,7 @@ except ImportError:
from xml import etree as elementtree from xml import etree as elementtree
except ImportError: except ImportError:
#print "no ElementTree module found, critical error" #print "no ElementTree module found, critical error"
raise ImportError, "no ElementTree module found, critical error"
raise ImportError("no ElementTree module found, critical error")


utf8_escape = re.compile(eval(r'u"[&<>\"]+"')) utf8_escape = re.compile(eval(r'u"[&<>\"]+"'))
escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"')) escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"'))
@@ -60,12 +60,12 @@ def new_encode_entity(text, pattern=utf8_escape):
if t is None: if t is None:
t = "&#%d;" % ord(char) t = "&#%d;" % ord(char)
append(t) append(t)
if type(text) == unicode:
if isinstance(text, str):
return ''.join(out) return ''.join(out)
else: else:
return u''.encode('utf-8').join(out)
return ''.encode('utf-8').join(out)
try: try:
if type(text) == unicode:
if isinstance(text, str):
return elementtree.ElementTree._encode(escape.sub(escape_entities, text), 'ascii') return elementtree.ElementTree._encode(escape.sub(escape_entities, text), 'ascii')
else: else:
return elementtree.ElementTree._encode(utf8_escape.sub(escape_entities, text.decode('utf-8')), 'utf-8') return elementtree.ElementTree._encode(utf8_escape.sub(escape_entities, text.decode('utf-8')), 'utf-8')
@@ -95,7 +95,7 @@ def namespace_map_update(namespaces):


elementtree.ElementTree._namespace_map.update(namespaces) elementtree.ElementTree._namespace_map.update(namespaces)


class ElementInterface(elementtree.ElementTree._ElementInterface):
class ElementInterface(elementtree.ElementTree.Element):
""" helper class """ """ helper class """


def indent(elem, level=0): def indent(elem, level=0):
@@ -128,8 +128,8 @@ def parse_xml(data, encoding="utf-8"):
data = data.encode(encoding) data = data.encode(encoding)
except UnicodeDecodeError: except UnicodeDecodeError:
pass pass
except Exception, error:
print "parse_xml encode Exception", error
except Exception as error:
print("parse_xml encode Exception", error)
import traceback import traceback
traceback.print_exc() traceback.print_exc()


@@ -137,9 +137,9 @@ def parse_xml(data, encoding="utf-8"):
data = data.replace('\x00','') data = data.replace('\x00','')
try: try:
p.feed(data) p.feed(data)
except Exception, error:
print "parse_xml feed Exception", error
print error, repr(data)
except Exception as error:
print("parse_xml feed Exception", error)
print(error, repr(data))
return None return None
else: else:
return ET.ElementTree(p.close()) return ET.ElementTree(p.close())

+ 1
- 1
item.py View File

@@ -54,7 +54,7 @@ class ItemObject(FSObject, Item):
pt = getElementText(rtpel[0]) pt = getElementText(rtpel[0])
pi = 'rtsp-rtp-udp:*:%s:*' % pt pi = 'rtsp-rtp-udp:*:%s:*' % pt
else: else:
print 'missing mimetype or rtppayloadtype element, skipping...'
print('missing mimetype or rtppayloadtype element, skipping...')
continue continue


url = getElementText(i.getElementsByTagName('url')[0]) url = getElementText(i.getElementsByTagName('url')[0])


+ 0
- 12
iterrarfile.py View File

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

__version__ = '$Change$'
# $Id$

import rarfile
from rarfile import *

class RarFile(rarfile.RarFile):
def readiter(self, name, blksize=16384):
yield self.read(name)

+ 0
- 37
itertarfile.py View File

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

__version__ = '$Change$'
# $Id$

import tarfile
from tarfile import *

TAR_PLAIN = tarfile.TAR_PLAIN
TAR_GZIPPED = tarfile.TAR_GZIPPED
TAR_BZ2 = 'bz2'

__all__ = tarfile.__all__

class TarFileCompat(tarfile.TarFileCompat):
def __init__(self, file, mode="r", compression=TAR_PLAIN):
if compression != TAR_BZ2:
tarfile.TarFileCompat.__init__(self, file, mode, compression)
return

self.tarfile = TarFile.bz2open(file, mode)
if mode[0:1] == "r":
members = self.tarfile.getmembers()
for i in xrange(len(members)):
m = members[i]
m.filename = m.name
m.file_size = m.size
m.date_time = time.gmtime(m.mtime)[:6]

def readiter(self, name, blksize=16384):
f = self.tarfile.extractfile(self.tarfile.getmember(name))
while True:
data = f.read(blksize)
if data == '':
break
yield data

+ 0
- 25
iterzipfile.py View File

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

__version__ = '$Change$'
# $Id$

import binascii
import os
import twisted.python.zipstream
import zipfile
from zipfile import *

__all__ = zipfile.__all__

class ZipFile(twisted.python.zipstream.ChunkingZipFile):
def readiter(self, name, blksize=16384):
"""Return file bytes (as a string) for name."""

#print 'ri:', `self`, `name`
fp = self.readfile(name)
while True:
d = fp.read(blksize)
if not d:
break
yield d

+ 2
- 2
mpegts/atschuff.py View File

@@ -60,10 +60,10 @@ try:


except ImportError: except ImportError:
def foo(*args): def foo(*args):
raise NotImplementedError, 'Failed to import ctypes'
raise NotImplementedError('Failed to import ctypes')
decode_title = decode_description = foo decode_title = decode_description = foo


except OSError: except OSError:
def foo(*args): def foo(*args):
raise NotImplementedError, 'Failed to find library huffdecode'
raise NotImplementedError('Failed to find library huffdecode')
decode_title = decode_description = foo decode_title = decode_description = foo

+ 215
- 221
mpegts/mpegts.py View File

@@ -30,18 +30,18 @@
import atschuff import atschuff
import itertools import itertools
import os import os
import sets
import struct import struct
import time import time
import traceback import traceback
from functools import reduce


TSSYNC = '\x47' TSSYNC = '\x47'
TSPKTLEN = 188 TSPKTLEN = 188
READBLK = 1024 READBLK = 1024


def attribreprlist(obj, attrs): def attribreprlist(obj, attrs):
return map(lambda x, y = obj: '%s: %s' % (x, repr(getattr(y, x))),
itertools.ifilter(lambda x, y = obj: hasattr(y, x), attrs))
return list(map(lambda x, y = obj: '%s: %s' % (x, repr(getattr(y, x))),
list(filter(lambda x, y = obj: hasattr(y, x), attrs))))


class UnReadSTR: class UnReadSTR:
def __init__(self, s): def __init__(self, s):
@@ -51,7 +51,7 @@ class UnReadSTR:
self._buf = [] self._buf = []
self._buftot = 0 self._buftot = 0


def __nonzero__(self):
def __bool__(self):
return self._buftot or self.pos < len(self.s) return self._buftot or self.pos < len(self.s)


def tell(self): def tell(self):
@@ -122,7 +122,7 @@ def DVDAudioFilter(itr, subchan):
for i in itr: for i in itr:
j = Pack(UnReadSTR(i)) j = Pack(UnReadSTR(i))


if filter(checksubchan, j):
if list(filter(checksubchan, j)):
yield i yield i


def findcodes(buf): def findcodes(buf):
@@ -138,53 +138,54 @@ def findcodes(buf):
i = j + 4 i = j + 4
return ret return ret


class UnRead(file):
def __init__(self, *args, **kwargs):
super(UnRead, self).__init__(*args, **kwargs)
self._buf = []
self._buftot = 0

def unread(self, buf):
self._buf.append(buf)
self._buftot += len(buf)

def peek(self, size):
r = self.read(size)
self.unread(r)
return r

def read(self, size = None):
if size is None and self._buf:
ret = self._buf.pop()
self._buftot -= len(ret)
elif size is None:
ret = super(UnRead, self).read()
else:
ret = []
while size and self._buftot:
ret.append(self._buf[-1][:size])
l = len(ret[-1])
if size > l:
assert len(self._buf[-1]) == l
self._buf.pop()
else:
self._buf[-1] = self._buf[-1][size:]
self._buftot -= l
size -= l
if False:
class UnRead(file):
def __init__(self, *args, **kwargs):
super(UnRead, self).__init__(*args, **kwargs)
self._buf = []
self._buftot = 0

def unread(self, buf):
self._buf.append(buf)
self._buftot += len(buf)

def peek(self, size):
r = self.read(size)
self.unread(r)
return r

def read(self, size = None):
if size is None and self._buf:
ret = self._buf.pop()
self._buftot -= len(ret)
elif size is None:
ret = super(UnRead, self).read()
else:
ret = []
while size and self._buftot:
ret.append(self._buf[-1][:size])
l = len(ret[-1])
if size > l:
assert len(self._buf[-1]) == l
self._buf.pop()
else:
self._buf[-1] = self._buf[-1][size:]
self._buftot -= l
size -= l


if size:
ret.append(super(UnRead, self).read(size))
if size:
ret.append(super(UnRead, self).read(size))


ret = ''.join(ret)
ret = ''.join(ret)


return ret
return ret


def read_timestamp(buf): def read_timestamp(buf):
assert len(buf) == 5 assert len(buf) == 5
assert (ord(buf[0]) & 0x1) == 1 assert (ord(buf[0]) & 0x1) == 1
assert (ord(buf[2]) & 0x1) == 1 assert (ord(buf[2]) & 0x1) == 1
assert (ord(buf[4]) & 0x1) == 1 assert (ord(buf[4]) & 0x1) == 1
return (long(ord(buf[0]) & 0xe) << 29) | (ord(buf[1]) << 21) | \
return (int(ord(buf[0]) & 0xe) << 29) | (ord(buf[1]) << 21) | \
((ord(buf[2]) & 0xfe) << 14) | (ord(buf[3]) << 7) | \ ((ord(buf[2]) & 0xfe) << 14) | (ord(buf[3]) << 7) | \
((ord(buf[4]) & 0xfe) >> 1) ((ord(buf[4]) & 0xfe) >> 1)


@@ -193,7 +194,7 @@ def read_escr(buf):
assert (ord(buf[0]) & 0x4) == 0x4 and (ord(buf[2]) & 0x4) == 0x4 assert (ord(buf[0]) & 0x4) == 0x4 and (ord(buf[2]) & 0x4) == 0x4
assert (ord(buf[4]) & 0x4) == 0x4 and (ord(buf[5]) & 0x1) == 0x1 assert (ord(buf[4]) & 0x4) == 0x4 and (ord(buf[5]) & 0x1) == 0x1


base = (long(ord(buf[0]) & 0x38) << 27) | ((ord(buf[0]) & 0x3) << 28) |\
base = (int(ord(buf[0]) & 0x38) << 27) | ((ord(buf[0]) & 0x3) << 28) |\
(ord(buf[1]) << 20) | ((ord(buf[2]) & 0xf8) << 15) | \ (ord(buf[1]) << 20) | ((ord(buf[2]) & 0xf8) << 15) | \
((ord(buf[2]) & 0x3) << 13) | (ord(buf[3]) << 5) | \ ((ord(buf[2]) & 0x3) << 13) | (ord(buf[3]) << 5) | \
((ord(buf[4]) & 0xf8) >> 3) ((ord(buf[4]) & 0xf8) >> 3)
@@ -240,7 +241,7 @@ class PES:
else: else:
self.length += 6 self.length += 6
if len(buf) < self.length: if len(buf) < self.length:
raise IndexError, 'not enough data'
raise IndexError('not enough data')


if self.stream_id == self.PADDING_ID: if self.stream_id == self.PADDING_ID:
# Validate padding? # Validate padding?
@@ -280,8 +281,7 @@ class PES:
self.DTS = read_timestamp(buf[i:i + 5]) self.DTS = read_timestamp(buf[i:i + 5])
i += 5 i += 5
elif ptsdts_flag == 0x1: elif ptsdts_flag == 0x1:
raise ValueError, \
"ptsdts flag forbidden: %d" % ptsdts_flag
raise ValueError("ptsdts flag forbidden: %d" % ptsdts_flag)
if escr_flag: if escr_flag:
self.ESCR = read_escr(buf[i:i + 6]) self.ESCR = read_escr(buf[i:i + 6])
i += 6 i += 6
@@ -373,7 +373,7 @@ class Pack(list):
assert (ord(d[4]) & 0xc0) == 0x40 assert (ord(d[4]) & 0xc0) == 0x40
self.SCR = read_escr(d[4:10]) self.SCR = read_escr(d[4:10])
assert ord(d[12]) & 0x3 == 0x3 assert ord(d[12]) & 0x3 == 0x3
m = map(ord, d[10:13])
m = list(map(ord, d[10:13]))
self.muxr = (m[0] << 14) | (m[1] << 6) | (m[2] >> 2) self.muxr = (m[0] << 14) | (m[1] << 6) | (m[2] >> 2)
self.stuff_len = ord(d[13]) & 0x7 self.stuff_len = ord(d[13]) & 0x7
f.read(self.stuff_len) f.read(self.stuff_len)
@@ -384,7 +384,7 @@ class Pack(list):
f.read(6) f.read(6)
hlen = (ord(d[4]) << 8) | ord(d[5]) hlen = (ord(d[4]) << 8) | ord(d[5])
header = f.read(hlen) header = f.read(hlen)
oh = map(ord, header)
oh = list(map(ord, header))
assert (oh[0] & 0x80) == 0x80 and \ assert (oh[0] & 0x80) == 0x80 and \
(oh[2] & 0x1) == 0x1 (oh[2] & 0x1) == 0x1
self.rate_bound = ((oh[0] & 0x7f) << 15) | \ self.rate_bound = ((oh[0] & 0x7f) << 15) | \
@@ -401,7 +401,7 @@ class Pack(list):
d = f.peek(1) d = f.peek(1)
self.streams = {} self.streams = {}
while ord(d) & 0x80: while ord(d) & 0x80:
d = map(ord, f.read(3))
d = list(map(ord, f.read(3)))
assert (d[1] & 0xc0) == 0xc0 assert (d[1] & 0xc0) == 0xc0
scaleflag = bool(d[1] & 0x20) scaleflag = bool(d[1] & 0x20)
self.streams[d[0]] = (((d[1] & 0x1f) << self.streams[d[0]] = (((d[1] & 0x1f) <<
@@ -437,8 +437,8 @@ class Pack(list):
def __str__(self): def __str__(self):
buf = [] buf = []
buf.append('\x00\x00\x01\xba') buf.append('\x00\x00\x01\xba')
clock = (1l << 46) | (((self.SCR[0] >> 30) & 0x7) << 43) | \
(1l << 42) | (((self.SCR[0] >> 15) & 0x7ffff) << 27) | \
clock = (1 << 46) | (((self.SCR[0] >> 30) & 0x7) << 43) | \
(1 << 42) | (((self.SCR[0] >> 15) & 0x7ffff) << 27) | \
(1 << 26) | ((self.SCR[0] & 0x7fff) << 11) | (1 << 10) | \ (1 << 26) | ((self.SCR[0] & 0x7fff) << 11) | (1 << 10) | \
((self.SCR[1] << 1) & 0x3fe) | 0x1 ((self.SCR[1] << 1) & 0x3fe) | 0x1
for i in range(6): for i in range(6):
@@ -449,7 +449,7 @@ class Pack(list):
buf.append(chr(((muxr << 2) & 0xfc) | 0x3)) buf.append(chr(((muxr << 2) & 0xfc) | 0x3))
buf.append(chr(0xf8 | (self.stuff_len & 7))) buf.append(chr(0xf8 | (self.stuff_len & 7)))
buf.append('\xff' * self.stuff_len) buf.append('\xff' * self.stuff_len)
buf.extend(map(str, self))
buf.extend(list(map(str, self)))
return ''.join(buf) return ''.join(buf)


# These are strings due to the floating point numbers # These are strings due to the floating point numbers
@@ -491,7 +491,7 @@ class ISO639LangDescriptor(list):
assert len(b) % 4 == 0 assert len(b) % 4 == 0


for i in range(len(b) / 4): for i in range(len(b) / 4):
lang = unicode(b[i * 4:i * 4 + 3], 'iso8859-1')
lang = str(b[i * 4:i * 4 + 3], 'iso8859-1')
atype = self.atypedict[ord(b[i * 4 + 3])] atype = self.atypedict[ord(b[i * 4 + 3])]
self.append((lang, atype)) self.append((lang, atype))


@@ -601,9 +601,7 @@ class AC3Descriptor:
else: else:
assert NotImplementedError, \ assert NotImplementedError, \
'the following code is untested' 'the following code is untested'
self.text = ''.join(map(lambda x:
unichr(ord(x[0]) * 256 + ord(x[1])),
[txt[i:i+2] for i in range(0, len(txt), 2)]))
self.text = ''.join([chr(ord(x[0]) * 256 + ord(x[1])) for x in [txt[i:i+2] for i in range(0, len(txt), 2)]])
def __repr__(self): def __repr__(self):
v = ['sample_rate', 'bsid', 'br_exact', 'bitrate', v = ['sample_rate', 'bsid', 'br_exact', 'bitrate',
@@ -619,11 +617,11 @@ class ContentAdvisory(list):


cnt = ord(data[0]) & 0x3f cnt = ord(data[0]) & 0x3f
i = 1 i = 1
for j in xrange(cnt):
for j in range(cnt):
region, dim = struct.unpack('>BB', data[i: i + 2]) region, dim = struct.unpack('>BB', data[i: i + 2])
i += 2 i += 2
d = {} d = {}
for j in xrange(dim):
for j in range(dim):
d[ord(data[i])] = ord(data[i + 1]) & 0xf d[ord(data[i])] = ord(data[i + 1]) & 0xf
i += 2 i += 2
desclen = ord(data[i]) desclen = ord(data[i])
@@ -669,13 +667,13 @@ class MultiStringStruct(dict):
return data.decode('UTF-16-BE') return data.decode('UTF-16-BE')
elif mode == 0x3e: elif mode == 0x3e:
# http://www.unicode.org/reports/tr6/ # http://www.unicode.org/reports/tr6/
raise NotImplementedError, 'Unicode Technical Report #6, A Standard Compression Scheme for Unicode'
raise NotImplementedError('Unicode Technical Report #6, A Standard Compression Scheme for Unicode')


# There are additional limitations # There are additional limitations
assert mode < 0x34, 'Invalid mode: %#x' % mode assert mode < 0x34, 'Invalid mode: %#x' % mode


return ''.join(map(lambda x, y = mode * 256: return ''.join(map(lambda x, y = mode * 256:
unichr(ord(x) + y), data))
chr(ord(x) + y), data))


assert (comp == 1 or comp == 2) and mode == 0xff, \ assert (comp == 1 or comp == 2) and mode == 0xff, \
'Invalid comp: %#x, mode: %#x' % (comp, mode) 'Invalid comp: %#x, mode: %#x' % (comp, mode)
@@ -707,7 +705,7 @@ class ComponentNameDescriptor(MultiStringStruct):
MultiStringStruct.__repr__(self) MultiStringStruct.__repr__(self)


def FindMe(data): def FindMe(data):
raise RuntimeError, 'found me'
raise RuntimeError('found me')


Descriptors = { Descriptors = {
# 0-63 Are listed in ISO 13818-1 Table 2-40 # 0-63 Are listed in ISO 13818-1 Table 2-40
@@ -738,82 +736,82 @@ PIDs = {
} }


def psip_calc_crc32(data, verbose = False, table = ( def psip_calc_crc32(data, verbose = False, table = (
0x00000000l, 0x04c11db7l, 0x09823b6el, 0x0d4326d9l,
0x130476dcl, 0x17c56b6bl, 0x1a864db2l, 0x1e475005l,
0x2608edb8l, 0x22c9f00fl, 0x2f8ad6d6l, 0x2b4bcb61l,
0x350c9b64l, 0x31cd86d3l, 0x3c8ea00al, 0x384fbdbdl,
0x4c11db70l, 0x48d0c6c7l, 0x4593e01el, 0x4152fda9l,
0x5f15adacl, 0x5bd4b01bl, 0x569796c2l, 0x52568b75l,
0x6a1936c8l, 0x6ed82b7fl, 0x639b0da6l, 0x675a1011l,
0x791d4014l, 0x7ddc5da3l, 0x709f7b7al, 0x745e66cdl,
0x9823b6e0l, 0x9ce2ab57l, 0x91a18d8el, 0x95609039l,
0x8b27c03cl, 0x8fe6dd8bl, 0x82a5fb52l, 0x8664e6e5l,
0xbe2b5b58l, 0xbaea46efl, 0xb7a96036l, 0xb3687d81l,
0xad2f2d84l, 0xa9ee3033l, 0xa4ad16eal, 0xa06c0b5dl,
0xd4326d90l, 0xd0f37027l, 0xddb056fel, 0xd9714b49l,
0xc7361b4cl, 0xc3f706fbl, 0xceb42022l, 0xca753d95l,
0xf23a8028l, 0xf6fb9d9fl, 0xfbb8bb46l, 0xff79a6f1l,
0xe13ef6f4l, 0xe5ffeb43l, 0xe8bccd9al, 0xec7dd02dl,
0x34867077l, 0x30476dc0l, 0x3d044b19l, 0x39c556ael,
0x278206abl, 0x23431b1cl, 0x2e003dc5l, 0x2ac12072l,
0x128e9dcfl, 0x164f8078l, 0x1b0ca6a1l, 0x1fcdbb16l,
0x018aeb13l, 0x054bf6a4l, 0x0808d07dl, 0x0cc9cdcal,
0x7897ab07l, 0x7c56b6b0l, 0x71159069l, 0x75d48ddel,
0x6b93dddbl, 0x6f52c06cl, 0x6211e6b5l, 0x66d0fb02l,
0x5e9f46bfl, 0x5a5e5b08l, 0x571d7dd1l, 0x53dc6066l,
0x4d9b3063l, 0x495a2dd4l, 0x44190b0dl, 0x40d816bal,
0xaca5c697l, 0xa864db20l, 0xa527fdf9l, 0xa1e6e04el,
0xbfa1b04bl, 0xbb60adfcl, 0xb6238b25l, 0xb2e29692l,
0x8aad2b2fl, 0x8e6c3698l, 0x832f1041l, 0x87ee0df6l,
0x99a95df3l, 0x9d684044l, 0x902b669dl, 0x94ea7b2al,
0xe0b41de7l, 0xe4750050l, 0xe9362689l, 0xedf73b3el,
0xf3b06b3bl, 0xf771768cl, 0xfa325055l, 0xfef34de2l,
0xc6bcf05fl, 0xc27dede8l, 0xcf3ecb31l, 0xcbffd686l,
0xd5b88683l, 0xd1799b34l, 0xdc3abdedl, 0xd8fba05al,
0x690ce0eel, 0x6dcdfd59l, 0x608edb80l, 0x644fc637l,
0x7a089632l, 0x7ec98b85l, 0x738aad5cl, 0x774bb0ebl,
0x4f040d56l, 0x4bc510e1l, 0x46863638l, 0x42472b8fl,
0x5c007b8al, 0x58c1663dl, 0x558240e4l, 0x51435d53l,
0x251d3b9el, 0x21dc2629l, 0x2c9f00f0l, 0x285e1d47l,
0x36194d42l, 0x32d850f5l, 0x3f9b762cl, 0x3b5a6b9bl,
0x0315d626l, 0x07d4cb91l, 0x0a97ed48l, 0x0e56f0ffl,
0x1011a0fal, 0x14d0bd4dl, 0x19939b94l, 0x1d528623l,
0xf12f560el, 0xf5ee4bb9l, 0xf8ad6d60l, 0xfc6c70d7l,
0xe22b20d2l, 0xe6ea3d65l, 0xeba91bbcl, 0xef68060bl,
0xd727bbb6l, 0xd3e6a601l, 0xdea580d8l, 0xda649d6fl,
0xc423cd6al, 0xc0e2d0ddl, 0xcda1f604l, 0xc960ebb3l,
0xbd3e8d7el, 0xb9ff90c9l, 0xb4bcb610l, 0xb07daba7l,
0xae3afba2l, 0xaafbe615l, 0xa7b8c0ccl, 0xa379dd7bl,
0x9b3660c6l, 0x9ff77d71l, 0x92b45ba8l, 0x9675461fl,
0x8832161al, 0x8cf30badl, 0x81b02d74l, 0x857130c3l,
0x5d8a9099l, 0x594b8d2el, 0x5408abf7l, 0x50c9b640l,
0x4e8ee645l, 0x4a4ffbf2l, 0x470cdd2bl, 0x43cdc09cl,
0x7b827d21l, 0x7f436096l, 0x7200464fl, 0x76c15bf8l,
0x68860bfdl, 0x6c47164al, 0x61043093l, 0x65c52d24l,
0x119b4be9l, 0x155a565el, 0x18197087l, 0x1cd86d30l,
0x029f3d35l, 0x065e2082l, 0x0b1d065bl, 0x0fdc1becl,
0x3793a651l, 0x3352bbe6l, 0x3e119d3fl, 0x3ad08088l,
0x2497d08dl, 0x2056cd3al, 0x2d15ebe3l, 0x29d4f654l,
0xc5a92679l, 0xc1683bcel, 0xcc2b1d17l, 0xc8ea00a0l,
0xd6ad50a5l, 0xd26c4d12l, 0xdf2f6bcbl, 0xdbee767cl,
0xe3a1cbc1l, 0xe760d676l, 0xea23f0afl, 0xeee2ed18l,
0xf0a5bd1dl, 0xf464a0aal, 0xf9278673l, 0xfde69bc4l,
0x89b8fd09l, 0x8d79e0bel, 0x803ac667l, 0x84fbdbd0l,
0x9abc8bd5l, 0x9e7d9662l, 0x933eb0bbl, 0x97ffad0cl,
0xafb010b1l, 0xab710d06l, 0xa6322bdfl, 0xa2f33668l,
0xbcb4666dl, 0xb8757bdal, 0xb5365d03l, 0xb1f740b4l
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
)): )):
'''Validate a PSIP CRC. Include the CRC in the data. The return value will be the valid data, or an exception will be raised if invalid.''' '''Validate a PSIP CRC. Include the CRC in the data. The return value will be the valid data, or an exception will be raised if invalid.'''


if verbose: if verbose:
i_crc = 0xffffffffl
i_crc = 0xffffffff
for i in data: for i in data:
i_crc = ((i_crc << 8) & 0xffffffffl) ^ table[(i_crc >>
i_crc = ((i_crc << 8) & 0xffffffff) ^ table[(i_crc >>
24) ^ ord(i)] 24) ^ ord(i)]
print hex(i_crc)
print(hex(i_crc))
else: else:
i_crc = reduce(lambda x, y: ((x << 8) & 0xffffffffl) ^
table[(x >> 24) ^ ord(y)], data, 0xffffffffl)
i_crc = reduce(lambda x, y: ((x << 8) & 0xffffffff) ^
table[(x >> 24) ^ ord(y)], data, 0xffffffff)
return i_crc return i_crc


def psip_crc32(data): def psip_crc32(data):
@@ -824,7 +822,7 @@ def getdescriptors(tb):
i = 0 i = 0
while i < len(tb): while i < len(tb):
t = ord(tb[i]) t = ord(tb[i])
if d.has_key(t):
if t in d:
l = ord(tb[i + 1]) l = ord(tb[i + 1])
data = tb[i + 2: i + 2 + l] data = tb[i + 2: i + 2 + l]
#print repr(d[t]), t, repr(data) #print repr(d[t]), t, repr(data)
@@ -918,9 +916,8 @@ and the key is the table number.'''
# XXX I may need to include the skipped part # XXX I may need to include the skipped part
# above in the crc calculations. # above in the crc calculations.
if not psip_crc32(payload[:self.sect_len]): if not psip_crc32(payload[:self.sect_len]):
raise ValueError, \
'CRC check failed: %s' % \
`payload[:self.sect_len]`
raise ValueError('CRC check failed: %s' % \
repr(payload[:self.sect_len]))
self.extension = (ord(payload[3]) << 8) | \ self.extension = (ord(payload[3]) << 8) | \
ord(payload[4]) ord(payload[4])
self.version = (ord(payload[5]) & 0x3e) >> 1 self.version = (ord(payload[5]) & 0x3e) >> 1
@@ -1007,7 +1004,7 @@ class PAT(PSIPObject, dict):
self.clear() self.clear()


def has_pid(self, pid): def has_pid(self, pid):
return self.pid_dict.has_key(pid)
return pid in self.pid_dict


def get_prog(self, pid): def get_prog(self, pid):
return self.pid_dict[pid] return self.pid_dict[pid]
@@ -1036,8 +1033,8 @@ def getaudiovideopids(pmt, lang = None):
vpids.append(cpid) vpids.append(cpid)
elif i[0] == 129: elif i[0] == 129:
apids.append(cpid) apids.append(cpid)
elif j.has_key(5) and i[0] != 5:
assert 'AC-3' in map(lambda x: x[:4], j[5]), (i, j)
elif 5 in j and i[0] != 5:
assert 'AC-3' in [x[:4] for x in j[5]], (i, j)
if lang is None or lang == j[10][0][0]: if lang is None or lang == j[10][0][0]:
apids.append(cpid) apids.append(cpid)
else: else:
@@ -1067,7 +1064,7 @@ class PMT(PSIPObject, dict):
self.clear() self.clear()
del self.es[:] del self.es[:]


def __nonzero__(self):
def __bool__(self):
return len(self) or bool(self.es) return len(self) or bool(self.es)


def parse_table(self, psip): def parse_table(self, psip):
@@ -1092,7 +1089,7 @@ class PMT(PSIPObject, dict):


def repr_part(self): def repr_part(self):
return [ 'PCRpid: %d' % self.pcrpid, dict.__repr__(self), return [ 'PCRpid: %d' % self.pcrpid, dict.__repr__(self),
'ES: %s' % `self.es` ]
'ES: %s' % repr(self.es) ]


def channelmajorminorsort(x, y): def channelmajorminorsort(x, y):
if x['major'] != y['major']: if x['major'] != y['major']:
@@ -1131,7 +1128,7 @@ class STT(PSIPObject):
self.ds_hour = ds_hour self.ds_hour = ds_hour


def repr_part(self, v=('ds_status', 'ds_day_of_month', 'ds_hour', )): def repr_part(self, v=('ds_status', 'ds_day_of_month', 'ds_hour', )):
return [ `time.ctime(self.utc)`, ] + attribreprlist(self, v)
return [ repr(time.ctime(self.utc)), ] + attribreprlist(self, v)


class MGT(list): class MGT(list):
def __init__(self, pidtable): def __init__(self, pidtable):
@@ -1149,7 +1146,7 @@ class MGT(list):


ntables = struct.unpack('>H', psip.table[1:3])[0] ntables = struct.unpack('>H', psip.table[1:3])[0]
i = 3 i = 3
for foo in xrange(ntables):
for foo in range(ntables):
type, pid, version, nbytes, desclen = \ type, pid, version, nbytes, desclen = \
struct.unpack('>HHBIH', psip.table[i:i + 11]) struct.unpack('>HHBIH', psip.table[i:i + 11])
i += 11 i += 11
@@ -1162,7 +1159,7 @@ class MGT(list):


# start watch # start watch
if type >= 0x100 and type <= 0x17f: if type >= 0x100 and type <= 0x17f:
if self.pidtable.has_key(pid):
if pid in self.pidtable:
# XXX - check that it's in watch # XXX - check that it's in watch
pass pass
else: else:
@@ -1171,7 +1168,7 @@ class MGT(list):
self.pidtable[pid] = TSPSIPHandler({ self.pidtable[pid] = TSPSIPHandler({
0xcb: EIT() }) 0xcb: EIT() })
elif type >= 0x200 and type <= 0x27f: elif type >= 0x200 and type <= 0x27f:
if self.pidtable.has_key(pid):
if pid in self.pidtable:
# XXX - check that it's in watch # XXX - check that it's in watch
pass pass
else: else:
@@ -1189,7 +1186,7 @@ class MGT(list):
#print `self` #print `self`


def __repr__(self): def __repr__(self):
return '<MGT: descriptors: %s, loop: %s>' % (`self.desc`,
return '<MGT: descriptors: %s, loop: %s>' % (repr(self.desc),
list.__repr__(self)) list.__repr__(self))


class EIT(list): class EIT(list):
@@ -1206,7 +1203,7 @@ class EIT(list):


ntables = ord(psip.table[1]) ntables = ord(psip.table[1])
i = 2 i = 2
for foo in xrange(ntables):
for foo in range(ntables):
event_id, start_time, lochilen, lolength, titlelen = \ event_id, start_time, lochilen, lolength, titlelen = \
struct.unpack('>HIBHB', psip.table[i:i + 10]) struct.unpack('>HIBHB', psip.table[i:i + 10])
i += 10 i += 10
@@ -1249,9 +1246,9 @@ class TVCT(PSIPObject, dict):
chancnt = ord(tb[i]) chancnt = ord(tb[i])
i += 1 i += 1
for foo in range(chancnt): for foo in range(chancnt):
shrtnm = ''.join(map(lambda x: unichr((ord(x[0]) <<
8) | ord(x[1])), [tb[i + x * 2:i + (x + 1) * 2] for
x in range(7)])).rstrip(unichr(0))
shrtnm = ''.join([chr((ord(x[0]) <<
8) | ord(x[1])) for x in [tb[i + x * 2:i + (x + 1) * 2] for
x in range(7)]]).rstrip(chr(0))
i += 7 * 2 i += 7 * 2
major = (((ord(tb[i]) << 8) | ord(tb[i + 1])) >> 2) & \ major = (((ord(tb[i]) << 8) | ord(tb[i + 1])) >> 2) & \
0x3ff 0x3ff
@@ -1337,7 +1334,7 @@ class TSPESHandler:


payload = p.payload payload = p.payload
if payload[:3] != '\x00\x00\x01': if payload[:3] != '\x00\x00\x01':
raise ValueError, 'packet start code invalid'
raise ValueError('packet start code invalid')
self.stream_id = ord(payload[3]) self.stream_id = ord(payload[3])
self.pes_len = (ord(payload[4]) << 8) | ord(payload[5]) self.pes_len = (ord(payload[4]) << 8) | ord(payload[5])
if not self.is_video(): if not self.is_video():
@@ -1373,7 +1370,7 @@ class TSPESHandler:
def read_clock(buf): def read_clock(buf):
assert len(buf) == 6 assert len(buf) == 6


base = (long(ord(buf[0])) << 25) | (ord(buf[1]) << 17) | \
base = (int(ord(buf[0])) << 25) | (ord(buf[1]) << 17) | \
(ord(buf[2]) << 9) | (ord(buf[3]) << 1) | \ (ord(buf[2]) << 9) | (ord(buf[3]) << 1) | \
(ord(buf[4]) >> 7) (ord(buf[4]) >> 7)
extension = ((ord(buf[4]) & 0x1) << 8) | ord(buf[5]) extension = ((ord(buf[4]) & 0x1) << 8) | ord(buf[5])
@@ -1609,27 +1606,27 @@ import re
import sys import sys


def usage(): def usage():
print 'Usage: %s -lmty <mpegtsstream>' % sys.argv[0]
print ' %s -k <pid> <mpegtsstream>' % sys.argv[0]
print ' %s -b [ -p ] <mpegtsstream>' % sys.argv[0]
print ' %s -c <channel> -o <output> <mpegtsstream>' % sys.argv[0]
print ''
print ' -l list channels'
print ' -m print PAT and PMT'
print ' -t print TVCT'
print ''
print ' -b bandwidth'
print ' -p sort by percentage'
print ''
print ' -c channel to capture'
print ' -o file to output channel'
print ''
print ' -k print PCR of pid stream'
print ''
print 'Options for all:'
print ' -y file offset when done'
print ' -s <start> Starting pos'
print ' -e <end> Ending pos'
print('Usage: %s -lmty <mpegtsstream>' % sys.argv[0])
print(' %s -k <pid> <mpegtsstream>' % sys.argv[0])
print(' %s -b [ -p ] <mpegtsstream>' % sys.argv[0])
print(' %s -c <channel> -o <output> <mpegtsstream>' % sys.argv[0])
print('')
print(' -l list channels')
print(' -m print PAT and PMT')
print(' -t print TVCT')
print('')
print(' -b bandwidth')
print(' -p sort by percentage')
print('')
print(' -c channel to capture')
print(' -o file to output channel')
print('')
print(' -k print PCR of pid stream')
print('')
print('Options for all:')
print(' -y file offset when done')
print(' -s <start> Starting pos')
print(' -e <end> Ending pos')


def findchannel(tvct, chan): def findchannel(tvct, chan):
for i in tvct['channels']: for i in tvct['channels']:
@@ -1661,18 +1658,18 @@ def GetTVCT(tsstream):
} }


def getpmt(pid, pm = pmts, psp = psippids): def getpmt(pid, pm = pmts, psp = psippids):
if not pm.has_key(pid):
if pid not in pm:
pm[pid] = PMT() pm[pid] = PMT()
psp[pid] = TSPSIPHandler({ 0x02: pm[pid] }) psp[pid] = TSPSIPHandler({ 0x02: pm[pid] })


def needpmts(pm = pmts): def needpmts(pm = pmts):
for i in pm.itervalues():
for i in pm.values():
if not i: if not i:
return True return True


return False return False


for i in itertools.imap(TSPacket, tsstream):
for i in map(TSPacket, tsstream):
try: try:
psippids[i.pid](i) psippids[i.pid](i)
except ValueError: except ValueError:
@@ -1689,7 +1686,7 @@ def GetTVCT(tsstream):


if needpat and pat: if needpat and pat:
needpat = False needpat = False
for j in pat.itervalues():
for j in pat.values():
getpmt(j) getpmt(j)


if not (needtvct or needpat or needpmts()): if not (needtvct or needpat or needpmts()):
@@ -1700,11 +1697,10 @@ def GetTVCT(tsstream):
lst.sort(channelmajorminorsort) lst.sort(channelmajorminorsort)
except KeyError: except KeyError:
# unable to find TVCT # unable to find TVCT
lst = pat.items()
lst.sort()
lst = map(lambda x, y: { 'name': 'PAT%d' % x[1],
lst = sorted(list(pat.items()))
lst = list(map(lambda x, y: { 'name': 'PAT%d' % x[1],
'prog_num': x[1], 'major': '?', 'minor': y}, lst, 'prog_num': x[1], 'major': '?', 'minor': y}, lst,
range(1, len(pat) + 1))
list(range(1, len(pat) + 1))))
tvct = { 'channels': lst } tvct = { 'channels': lst }


for i in lst: for i in lst:
@@ -1817,12 +1813,12 @@ def main():
}) })


def getpmt(pid, pm = pmts, psp = psippids): def getpmt(pid, pm = pmts, psp = psippids):
if not pm.has_key(pid):
if pid not in pm:
pm[pid] = PMT() pm[pid] = PMT()
psp[pid] = TSPSIPHandler({ 0x02: pm[pid] }) psp[pid] = TSPSIPHandler({ 0x02: pm[pid] })


def needpmts(pm = pmts): def needpmts(pm = pmts):
for i in pm.itervalues():
for i in pm.values():
if not i: if not i:
return True return True


@@ -1831,7 +1827,7 @@ def main():
lastpcr = None lastpcr = None
lastpatpos = None lastpatpos = None


for i in itertools.imap(TSPacket, s):
for i in map(TSPacket, s):
#if hasattr(i, 'splice_countdown') or hasattr(i, 'DTS_next_AU'): #if hasattr(i, 'splice_countdown') or hasattr(i, 'DTS_next_AU'):
# print 'splice_countdown:', repr(i) # print 'splice_countdown:', repr(i)
#if hasattr(i, 'PCR'): #if hasattr(i, 'PCR'):
@@ -1847,15 +1843,15 @@ def main():
if lastpcr is not None: if lastpcr is not None:
# I've only seen 2703 as the largest # I've only seen 2703 as the largest
if i.PCR[0] - lastpcr[0] > 3000: if i.PCR[0] - lastpcr[0] > 3000:
print lastpatpos
print(lastpatpos)
lastpcr = i.PCR lastpcr = i.PCR


try: try:
psippids[i.pid](i) psippids[i.pid](i)
except ValueError, x:
except ValueError as x:
#import traceback #import traceback
#print traceback.print_exc() #print traceback.print_exc()
print >>sys.stderr, 'bad crc:', repr(i)
print('bad crc:', repr(i), file=sys.stderr)
continue continue
except KeyError: except KeyError:
pass pass
@@ -1888,7 +1884,7 @@ def main():


if needpat and pat: if needpat and pat:
needpat = False needpat = False
for pn, j in pat.iteritems():
for pn, j in pat.items():
if pn == 0: if pn == 0:
# XXX - NIT # XXX - NIT
continue continue
@@ -1896,8 +1892,8 @@ def main():
getpmt(j) getpmt(j)


if needallmaps and pat and pmts: if needallmaps and pat and pmts:
for i in pat.itervalues():
if not pmts.has_key(i):
for i in pat.values():
if i not in pmts:
break break
needallmaps = False needallmaps = False


@@ -1914,11 +1910,11 @@ def main():
output)) output))


if allmaps: if allmaps:
print repr(pat)
print repr(pmts)
print(repr(pat))
print(repr(pmts))


if printtvct: if printtvct:
print repr(tvct)
print(repr(tvct))


if listchan: if listchan:
#List channels #List channels
@@ -1935,16 +1931,15 @@ def main():
if i['prog_num'] != 0 and i['prog_num'] != 0xffff: if i['prog_num'] != 0 and i['prog_num'] != 0xffff:
#print repr(pmts[pat[i['prog_num']]]) #print repr(pmts[pat[i['prog_num']]])
av = getaudiovideopids(pmts[pat[i['prog_num']]]) av = getaudiovideopids(pmts[pat[i['prog_num']]])
prog_info = '\t'.join(map(lambda x:
','.join(map(str, x)), av))
prog_info = '\t'.join([','.join(map(str, x)) for x in av])
else: else:
prog_info = '' prog_info = ''
print ('%(major)d.%(minor)d\t%(name)s\t' % i) + \
prog_info
print(('%(major)d.%(minor)d\t%(name)s\t' % i) + \
prog_info)


if printbandwidth: if printbandwidth:
totpkts = sum(pidcnt.itervalues())
i = pidcnt.items()
totpkts = sum(pidcnt.values())
i = list(pidcnt.items())
if printbandwidthpercent: if printbandwidthpercent:
def secondfirst(x, y): def secondfirst(x, y):
if x[1] == y[1]: if x[1] == y[1]:
@@ -1954,11 +1949,11 @@ def main():
else: else:
i.sort() i.sort()
for pid, cnt in i: for pid, cnt in i:
print '%4d\t%d\t%5.2f' % (pid, cnt,
float(cnt) * 100 / totpkts)
print('%4d\t%d\t%5.2f' % (pid, cnt,
float(cnt) * 100 / totpkts))


if printbyteoffset: if printbyteoffset:
print inp.tell()
print(inp.tell())


def justprint(v, p): def justprint(v, p):
'''v is pid, p is the data''' '''v is pid, p is the data'''
@@ -1966,15 +1961,15 @@ def justprint(v, p):
return return
pes = PES(p) pes = PES(p)
if pes.data[3] != '\x00': if pes.data[3] != '\x00':
print `pes`
print(repr(pes))
return return
fc = findcodes(pes.data) fc = findcodes(pes.data)
print 'justprint', v, len(p), repr(pes), repr(pes.data[:20]), fc
for i in filter(lambda x: x[1] == '\x00', fc):
print `pes.data[i[0] + 3: i[0] + 7]`
print('justprint', v, len(p), repr(pes), repr(pes.data[:20]), fc)
for i in [x for x in fc if x[1] == '\x00']:
print(repr(pes.data[i[0] + 3: i[0] + 7]))
if ((ord(pes.data[i[0] + 5]) & 0x38) >> 3) in (2, 3): if ((ord(pes.data[i[0] + 5]) & 0x38) >> 3) in (2, 3):
print 'non I frame found: %d' % \
((ord(pes.data[i[0] + 5]) & 0x38) >> 3)
print('non I frame found: %d' % \
((ord(pes.data[i[0] + 5]) & 0x38) >> 3))


if __name__ == '__main__': if __name__ == '__main__':
if True: if True:
@@ -1984,7 +1979,7 @@ if __name__ == '__main__':
if False: if False:
ps = UnRead(sys.argv[1]) ps = UnRead(sys.argv[1])
while ps: while ps:
print `Pack(ps)`
print(repr(Pack(ps)))
sys.exit() sys.exit()


s = TSPStream(open(sys.argv[1])) s = TSPStream(open(sys.argv[1]))
@@ -2007,7 +2002,7 @@ if __name__ == '__main__':
0x1ffb: TSPSIPHandler({ 0xc8: tvct }), 0x1ffb: TSPSIPHandler({ 0xc8: tvct }),
} }
first = last = None first = last = None
for j in itertools.imap(TSPacket, s):
for j in map(TSPacket, s):
count += 1 count += 1
if j.pid == 8191 or (j.pid != 0 and j.pid != 48): if j.pid == 8191 or (j.pid != 0 and j.pid != 48):
skipped += 1 skipped += 1
@@ -2019,24 +2014,24 @@ if __name__ == '__main__':
pidhandlers[j.pid](j) pidhandlers[j.pid](j)
except KeyError: except KeyError:
pass pass
except ValueError, x:
print 'VE:', x
except ValueError as x:
print('VE:', x)
#if pidhandlers[0x1ffb][0xc8]: #if pidhandlers[0x1ffb][0xc8]:
# print repr(pidhandlers[0x1ffb][0xc8]) # print repr(pidhandlers[0x1ffb][0xc8])
# We should probably cache which ones we've added, and remove # We should probably cache which ones we've added, and remove
# Ones that aren't there. Or do a clean_up callback. # Ones that aren't there. Or do a clean_up callback.
for k in pidhandlers[0][0].itervalues():
if pmts.has_key(k):
for k in pidhandlers[0][0].values():
if k in pmts:
continue continue
pmts[k] = PMT() pmts[k] = PMT()
pidhandlers[k] = TSPSIPHandler({ 0x02: pmts[k] }) pidhandlers[k] = TSPSIPHandler({ 0x02: pmts[k] })


for k in itertools.ifilter(lambda x: x.es, pmts.itervalues()):
for k in filter(lambda x: x.es, iter(pmts.values())):
#print repr(k) #print repr(k)
for l in k.es: for l in k.es:
if pesstreams.has_key(l[1]):
if l[1] in pesstreams:
continue continue
print repr(l)
print(repr(l))
pesstreams[l[1]] = TSPESHandler(lambda x, y = pesstreams[l[1]] = TSPESHandler(lambda x, y =
l[1]: justprint(y, x)) l[1]: justprint(y, x))
pidhandlers[l[1]] = pesstreams[l[1]] pidhandlers[l[1]] = pesstreams[l[1]]
@@ -2053,8 +2048,7 @@ if __name__ == '__main__':
pids[j.pid] += 1 pids[j.pid] += 1
except KeyError: except KeyError:
pids[j.pid] = 1 pids[j.pid] = 1
p = pids.items()
p.sort()
print p
print 'skipped:', skipped
print 'total:', count
p = sorted(list(pids.items()))
print(p)
print('skipped:', skipped)
print('total:', count)

+ 0
- 1
mpegts/tssel.py View File

@@ -32,7 +32,6 @@ sys.path.append('/Users/jgurney/p4/bktrau/info')


import itertools import itertools
import mpegts import mpegts
import sets
import struct import struct
import sys import sys




+ 12
- 13
mpegtsmod.py View File

@@ -9,9 +9,9 @@ tsselpypath = 'mpegts/tssel.py'
default_audio_lang = 'eng' default_audio_lang = 'eng'


import array import array
import io
import itertools import itertools
import os import os
import sets
import struct import struct


import sys import sys
@@ -29,10 +29,9 @@ from twisted.spread import pb
from twisted.internet import abstract, process, protocol, reactor from twisted.internet import abstract, process, protocol, reactor
from twisted.web import error, http, resource, server from twisted.web import error, http, resource, server


class _LimitedFile(file):
class _LimitedFile(io.FileIO):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.__size = kwargs['size']
del kwargs['size']
self.__size = kwargs.pop('size')
file.__init__(self, *args, **kwargs) file.__init__(self, *args, **kwargs)


def remain(self): def remain(self):
@@ -67,7 +66,7 @@ class MPEGTSTransfer(pb.Viewable):
return return
# get data and write to request. # get data and write to request.
try: try:
data = self.iter.next()
data = next(self.iter)
if data: if data:
# this .write will spin the reactor, calling # this .write will spin the reactor, calling
# .doWrite and then .resumeProducing again, so # .doWrite and then .resumeProducing again, so
@@ -117,9 +116,9 @@ class DynamTSTransfer(pb.Viewable):
data = self.fp.read(min(abstract.FileDescriptor.bufferSize, data = self.fp.read(min(abstract.FileDescriptor.bufferSize,
self.size - self.written) // 188 * 188) self.size - self.written) // 188 * 188)
dataarray = array.array('B', data) dataarray = array.array('B', data)
for i in xrange(0, len(data), 188):
for i in range(0, len(data), 188):
if data[i] != 'G': if data[i] != 'G':
print 'bad sync'
print('bad sync')
continue continue
frst = dataarray[i + 1] frst = dataarray[i + 1]
pid = (frst & 0x1f) << 8 | dataarray[i + 2] pid = (frst & 0x1f) << 8 | dataarray[i + 2]
@@ -141,7 +140,7 @@ class DynamTSTransfer(pb.Viewable):
# Remaining fields before array # Remaining fields before array
startpmt += 5 startpmt += 5
arraysize -= 5 arraysize -= 5
for startpmt in xrange(startpmt,
for startpmt in range(startpmt,
min(i + 188 - 3, startpmt + arraysize), 4): min(i + 188 - 3, startpmt + arraysize), 4):
prognum, ppid = struct.unpack('>2H', prognum, ppid = struct.unpack('>2H',
data[startpmt:startpmt + 4]) data[startpmt:startpmt + 4])
@@ -149,7 +148,7 @@ class DynamTSTransfer(pb.Viewable):
if ppid == self.pmt: if ppid == self.pmt:
break break
else: else:
raise KeyError, 'unable to find pmt(%d) in pkt: %s' % (pmt, `data[i:i + 188]`)
raise KeyError('unable to find pmt(%d) in pkt: %s' % (pmt, repr(data[i:i + 188])))


self.pats = itertools.cycle(tssel.genpats( self.pats = itertools.cycle(tssel.genpats(
self.pmt, prognum)) self.pmt, prognum))
@@ -157,14 +156,14 @@ class DynamTSTransfer(pb.Viewable):


if pid == 0 and self.didpat: if pid == 0 and self.didpat:
assert data[i + 4] =='\x00' and \ assert data[i + 4] =='\x00' and \
data[i + 5] == '\x00', 'error: %s' % `data[i:i + 10]`
data[i + 5] == '\x00', 'error: %s' % repr(data[i:i + 10])
repcnt += 1 repcnt += 1
pn = self.pats.next()
pn = next(self.pats)
data = data[:i] + pn + data[i + data = data[:i] + pn + data[i +
188:] 188:]


if repcnt > 1: if repcnt > 1:
print 'repcnt:', repcnt, 'len(data):', len(data)
print('repcnt:', repcnt, 'len(data):', len(data))


if data: if data:
self.written += len(data) self.written += len(data)
@@ -195,7 +194,7 @@ class DynamTSTransfer(pb.Viewable):


try: try:
self.fp = open(path) self.fp = open(path)
except IOError, e:
except IOError as e:
import errno import errno
if e[0] == errno.EACCESS: if e[0] == errno.EACCESS:
return error.ForbiddenResource().render(request) return error.ForbiddenResource().render(request)


+ 12
- 8
pymediaserv View File

@@ -6,11 +6,15 @@
from twisted.internet import reactor from twisted.internet import reactor
from twisted.application import service from twisted.application import service
from twisted.python import log, usage from twisted.python import log, usage
import ConfigParser
import configparser
import pymeds import pymeds
import os.path import os.path
import sys import sys


#fix for wstools
import collections
collections.MutableMapping = collections.abc.MutableMapping

defconfigfile = 'pymeds.ini' defconfigfile = 'pymeds.ini'
class ConfigFile(pymeds.Options): class ConfigFile(pymeds.Options):
optParameters = [ [ 'config', 'c', defconfigfile, optParameters = [ [ 'config', 'c', defconfigfile,
@@ -21,10 +25,10 @@ if __name__ == '__main__':
try: try:
config.checkpath = False config.checkpath = False
config.parseOptions() config.parseOptions()
print `config`
print(repr(config))
if os.path.exists(config['config']): if os.path.exists(config['config']):
print 'foo'
scp = ConfigParser.SafeConfigParser()
print('foo')
scp = configparser.SafeConfigParser()
scp.read(config['config']) scp.read(config['config'])
config.update(scp.items('pymeds')) config.update(scp.items('pymeds'))


@@ -32,12 +36,12 @@ if __name__ == '__main__':
config.checkpath = True config.checkpath = True
config.postOptions() config.postOptions()
elif config['config'] != defconfigfile: elif config['config'] != defconfigfile:
print 'bar'
print('bar')
raise usage.UsageError( raise usage.UsageError(
'config file %s does not exist' % config['config']) 'config file %s does not exist' % config['config'])
except usage.UsageError, errortext:
print '%s: %s' % (sys.argv[0], errortext)
print '%s: Try --help for usage details.' % sys.argv[0]
except usage.UsageError as errortext:
print('%s: %s' % (sys.argv[0], errortext))
print('%s: Try --help for usage details.' % sys.argv[0])
sys.exit(1) sys.exit(1)


log.startLogging(sys.stdout) log.startLogging(sys.stdout)


+ 16
- 16
pymeds.py View File

@@ -13,15 +13,15 @@ __version__ = '$Change: 1740 $'
# stage, where we simulate a namespace to either be thrown away when the # stage, where we simulate a namespace to either be thrown away when the
# time comes, or merge into the correct one) # time comes, or merge into the correct one)
import debug # my debugging module import debug # my debugging module
debug.doDebugging(True) # open up debugging port
debug.doDebugging(False) # open up debugging port


# Modules to import, maybe config file or something? # Modules to import, maybe config file or something?
def tryloadmodule(mod): def tryloadmodule(mod):
try: try:
return __import__(mod) return __import__(mod)
except ImportError: except ImportError:
#import traceback
#traceback.print_exc()
import traceback
traceback.print_exc()
pass pass


# ZipStorage w/ tar support should be last as it will gobble up empty files. # ZipStorage w/ tar support should be last as it will gobble up empty files.
@@ -50,7 +50,7 @@ checkmodules = [ x for x in modmap if modmap[x] is None ]


if checkmodules: if checkmodules:
checkmodules.sort() checkmodules.sort()
print 'The following modules were not loaded:', ', '.join(checkmodules)
print('The following modules were not loaded:', ', '.join(checkmodules))


from FSStorage import FSDirectory from FSStorage import FSDirectory
import os import os
@@ -58,12 +58,12 @@ import os.path
import random import random
import socket import socket
import string import string
import urlparse
import urllib.parse
from twisted.application import internet, service from twisted.application import internet, service
from twisted.python import usage from twisted.python import usage


def generateuuid(): def generateuuid():
return ''.join([ 'uuid:'] + map(lambda x: random.choice(string.letters), xrange(20)))
return ''.join([ 'uuid:'] + [random.choice(string.ascii_letters) for x in range(20)])


class Options(usage.Options): class Options(usage.Options):
checkpath = True checkpath = True
@@ -75,14 +75,14 @@ class Options(usage.Options):
def postOptions(self): def postOptions(self):
p = self['path'] p = self['path']
if self.checkpath and not os.path.isdir(p): if self.checkpath and not os.path.isdir(p):
raise usage.UsageError, 'path %s does not exist' % `p`
raise usage.UsageError('path %s does not exist' % repr(p))


def parseArgs(self, *args): def parseArgs(self, *args):
# XXX - twisted doesn't let you provide a message on what # XXX - twisted doesn't let you provide a message on what
# arguments are required, so we will do our own work in here. # arguments are required, so we will do our own work in here.


if len(args) not in (1, 2): if len(args) not in (1, 2):
raise usage.UsageError, 'Arguments: addr [ port ]'
raise usage.UsageError('Arguments: addr [ port ]')


self['addr'] = args[0] self['addr'] = args[0]
if len(args) == 1: if len(args) == 1:
@@ -154,8 +154,8 @@ def makeService(config):
'uuid': uuid, 'uuid': uuid,
'urlbase': urlbase, 'urlbase': urlbase,
} }
d = file('root-device.xml').read() % r
static.Data.__init__(self, d, 'text/xml')
d = open('root-device.xml').read() % r
static.Data.__init__(self, bytes(d, 'ascii'), 'text/xml')


root = WebServer() root = WebServer()
debug.insertnamespace('root', root) debug.insertnamespace('root', root)
@@ -163,14 +163,14 @@ def makeService(config):
# This sets up the root to be the media dir so we don't have to # This sets up the root to be the media dir so we don't have to
# enumerate the directory. # enumerate the directory.
cds = ContentDirectoryServer(config['title'], klass=FSDirectory, cds = ContentDirectoryServer(config['title'], klass=FSDirectory,
path=config['path'], urlbase=urlparse.urljoin(urlbase, 'content'),
path=config['path'], urlbase=urllib.parse.urljoin(urlbase, 'content'),
webbase=content) webbase=content)
debug.insertnamespace('cds', cds) debug.insertnamespace('cds', cds)
root.putChild('ContentDirectory', cds)
root.putChild(b'ContentDirectory', cds)
cds = cds.control cds = cds.control
root.putChild('ConnectionManager', ConnectionManagerServer())
root.putChild('root-device.xml', RootDevice())
root.putChild('content', content)
root.putChild(b'ConnectionManager', ConnectionManagerServer())
root.putChild(b'root-device.xml', RootDevice())
root.putChild(b'content', content)


fixupmimetypes() fixupmimetypes()


@@ -186,7 +186,7 @@ def makeService(config):
def startService(self): def startService(self):
service.MultiService.startService(self) service.MultiService.startService(self)


rdxml = urlparse.urljoin(urlbase, 'root-device.xml')
rdxml = urllib.parse.urljoin(urlbase, 'root-device.xml')
s.register('%s::upnp:rootdevice' % uuid, s.register('%s::upnp:rootdevice' % uuid,
'upnp:rootdevice', rdxml) 'upnp:rootdevice', rdxml)




+ 13
- 13
pyvr.py View File

@@ -13,8 +13,8 @@ import time
from twisted.internet import reactor from twisted.internet import reactor
from twisted.python import log from twisted.python import log
import twisted.web import twisted.web
import urlparse
import urllib2
import urllib.parse
import urllib.request, urllib.error, urllib.parse


def getPage(url, contextFactory=None, *args, **kwargs): def getPage(url, contextFactory=None, *args, **kwargs):
"""Download a web page as a string. """Download a web page as a string.
@@ -47,10 +47,10 @@ class PYVRShow(VideoItem):
VideoItem.__init__(self, *args, **kwargs) VideoItem.__init__(self, *args, **kwargs)


url = self.info['link'] url = self.info['link']
sc = urlparse.urlparse(url)[0]
sc = urllib.parse.urlparse(url)[0]
if not sc: if not sc:
# need to combine w/ base url # need to combine w/ base url
url = urlparse.urljoin(baseurl, url)
url = urllib.parse.urljoin(baseurl, url)
self.res = Resource(url, self.res = Resource(url,
'http-get:*:%s:*' % self.info['mimetype']) 'http-get:*:%s:*' % self.info['mimetype'])
self.res.duration = self.info['duration'] self.res.duration = self.info['duration']
@@ -126,7 +126,7 @@ class PYVRShows(Container):
i = 1 i = 1
while True: while True:
title = '%s Copy %d' % (ep['subtitle'], i) title = '%s Copy %d' % (ep['subtitle'], i)
if not eps.has_key(title):
if title not in eps:
return title return title
i += 1 i += 1


@@ -135,8 +135,8 @@ class PYVRShows(Container):
ret = {} ret = {}
for pos, i in enumerate(eps): for pos, i in enumerate(eps):
title = i['subtitle'] title = i['subtitle']
if ret.has_key(title):
print 'WARNING: dup:', `i`, `ret[title]`
if title in ret:
print('WARNING: dup:', repr(i), repr(ret[title]))
title = PYVRShows.getunique(ret, i) title = PYVRShows.getunique(ret, i)
i['pos'] = pos i['pos'] = pos
ret[title] = i ret[title] = i
@@ -184,9 +184,9 @@ class PYVR(FSObject, Container):
def runCheck(self): def runCheck(self):
while True: while True:
try: try:
self.page = urllib2.urlopen(self.url)
self.page = urllib.request.urlopen(self.url)
break break
except urllib2.HTTPError:
except urllib.error.HTTPError:
time.sleep(.1) time.sleep(.1)
#self.page = getPage(self.url, method='HEAD') #self.page = getPage(self.url, method='HEAD')
#self.page.deferred.addErrback(self.errCheck).addCallback( #self.page.deferred.addErrback(self.errCheck).addCallback(
@@ -195,7 +195,7 @@ class PYVR(FSObject, Container):
return self.doCheck(self.page) return self.doCheck(self.page)


def errCheck(self, x): def errCheck(self, x):
print 'errCheck:', `x`
print('errCheck:', repr(x))
self.runCheck() self.runCheck()


def doCheck(self, x): def doCheck(self, x):
@@ -225,14 +225,14 @@ class PYVR(FSObject, Container):
#self.pend = None #self.pend = None


self.newobjs = recxmltoobj(page.read()) self.newobjs = recxmltoobj(page.read())
print 'pp:', `self.newobjs`
print('pp:', repr(self.newobjs))
self.doUpdate() self.doUpdate()


def genChildren(self): def genChildren(self):
return self.newobjs.keys()
return list(self.newobjs.keys())


def createObject(self, i, arg=None): def createObject(self, i, arg=None):
print 'co:', `i`, `arg`
print('co:', repr(i), repr(arg))
return PYVRShows, i, (), { 'show': i, 'pyvr': self } return PYVRShows, i, (), { 'show': i, 'pyvr': self }


def doUpdate(self): def doUpdate(self):


+ 3
- 0
requirements.txt View File

@@ -0,0 +1,3 @@
twisted
-e git+https://www.funkthat.com/gitea/jmg/SOAPpy@main#egg=SOAPpy-py3
-e git+https://www.funkthat.com/gitea/jmg/wstools-py3@main#egg=wstools-py3

+ 6
- 6
root-device.xml View File

@@ -21,16 +21,16 @@
<service> <service>
<serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType> <serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
<serviceId>urn:upnp-org:serviceId:urn:schemas-upnp-org:service:ConnectionManager</serviceId> <serviceId>urn:upnp-org:serviceId:urn:schemas-upnp-org:service:ConnectionManager</serviceId>
<SCPDURL>ConnectionManager/scpd.xml</SCPDURL>
<controlURL>ConnectionManager/control</controlURL>
<eventSubURL>ConnectionManager/event</eventSubURL>
<SCPDURL>/ConnectionManager/scpd.xml</SCPDURL>
<controlURL>/ConnectionManager/control</controlURL>
<eventSubURL>/ConnectionManager/event</eventSubURL>
</service> </service>
<service> <service>
<serviceType>urn:schemas-upnp-org:service:ContentDirectory:1</serviceType> <serviceType>urn:schemas-upnp-org:service:ContentDirectory:1</serviceType>
<serviceId>urn:upnp-org:serviceId:urn:schemas-upnp-org:service:ContenDirectory</serviceId> <serviceId>urn:upnp-org:serviceId:urn:schemas-upnp-org:service:ContenDirectory</serviceId>
<SCPDURL>ContentDirectory/scpd.xml</SCPDURL>
<controlURL>ContentDirectory/control</controlURL>
<eventSubURL>ContentDirectory/event</eventSubURL>
<SCPDURL>/ContentDirectory/scpd.xml</SCPDURL>
<controlURL>/ContentDirectory/control</controlURL>
<eventSubURL>/ContentDirectory/event</eventSubURL>
</service> </service>
</serviceList> </serviceList>
<deviceList/> <deviceList/>


+ 34
- 35
slinkemod.py View File

@@ -57,7 +57,7 @@ class LimitedAudioProducer(object):
return r return r


def shutdown(self): def shutdown(self):
print 'lap: shutdown', `self.consumer`
print('lap: shutdown', repr(self.consumer))
# XXX - I still get writes after I've asked my producer to stop # XXX - I still get writes after I've asked my producer to stop
self.write = lambda x: None self.write = lambda x: None
self.producer.stopProducing() self.producer.stopProducing()
@@ -74,19 +74,19 @@ class LimitedAudioProducer(object):
return self.producer.resumeProducing() return self.producer.resumeProducing()


def stopProducing(self): def stopProducing(self):
print 'lap: sp'
print('lap: sp')
self.shutdown() self.shutdown()


# IConsumer # IConsumer
def registerProducer(self, producer, streaming): def registerProducer(self, producer, streaming):
print 'lap: regp'
print('lap: regp')
self.producer = producer self.producer = producer
self.streamingProducer = streaming self.streamingProducer = streaming


self.consumer.registerProducer(self, streaming) self.consumer.registerProducer(self, streaming)


def unregisterProducer(): def unregisterProducer():
print 'lap: unregp'
print('lap: unregp')
self.shutdown() self.shutdown()


def write(self, data): def write(self, data):
@@ -122,7 +122,7 @@ class ChangerTrack(resource.Resource):
return self._res.getmimetype() return self._res.getmimetype()


def render(self, request): def render(self, request):
print 'CTrender:', `request.postpath`, `request.method`, `request`
print('CTrender:', repr(request.postpath), repr(request.method), repr(request))
self.setlength(request) self.setlength(request)


if request.method == 'HEAD': if request.method == 'HEAD':
@@ -156,7 +156,7 @@ class ChangerTrack(resource.Resource):
'content-length', [ str(r) ]) 'content-length', [ str(r) ])


def docleanup(self, nf, request): def docleanup(self, nf, request):
print 'docleanup'
print('docleanup')


nf.addBoth(self.dostop) nf.addBoth(self.dostop)
nf.addBoth(lambda x: self.dounlock(request)) nf.addBoth(lambda x: self.dounlock(request))
@@ -168,19 +168,19 @@ class ChangerTrack(resource.Resource):
return None return None


def dostop(self, arg): def dostop(self, arg):
print 'dostop'
print('dostop')
d = self._obj.stop() d = self._obj.stop()
# Make sure we have stopped before we continue # Make sure we have stopped before we continue
d.addBoth(lambda x: arg) d.addBoth(lambda x: arg)
return d return d


def logerr(self, exc, *args): def logerr(self, exc, *args):
print 'logerr:', `args`
print('logerr:', repr(args))
exc.printTraceback() exc.printTraceback()
#exc.printDetailedTraceback() #exc.printDetailedTraceback()


def failed(self, exc, request): def failed(self, exc, request):
print 'in this failed case', self._obj.haslock(request), `request`
print('in this failed case', self._obj.haslock(request), repr(request))
if self._obj.haslock(request): if self._obj.haslock(request):
self.dounlock(request) self.dounlock(request)
# XXX - look at queue and decide # XXX - look at queue and decide
@@ -192,7 +192,7 @@ class ChangerTrack(resource.Resource):
return exc return exc


def printarg(self, args): def printarg(self, args):
print 'pa:', `self`, `args`
print('pa:', repr(self), repr(args))


def unregisterProducer(self): def unregisterProducer(self):
resource.Resource.unregisterProducer(self) resource.Resource.unregisterProducer(self)
@@ -298,15 +298,15 @@ class SLinkEChangerDisc(MusicAlbum):


# ContentDirectory calls this # ContentDirectory calls this
def checkUpdate(self): def checkUpdate(self):
print 'cU'
print('cU')
curid = self.getID() curid = self.getID()
if self._lastid != curid: if self._lastid != curid:
print 'dU'
print('dU')
self.doUpdate() self.doUpdate()
self._lastid = curid self._lastid = curid


def genChildren(self): def genChildren(self):
return dict(('%02d' % i, i) for i in xrange(1, self.getID()[1] + 1))
return dict(('%02d' % i, i) for i in range(1, self.getID()[1] + 1))


def createObject(self, i, arg): def createObject(self, i, arg):
return SLinkEChangerDiscTrack, i, (), { 'discobj': self, 'track': arg } return SLinkEChangerDiscTrack, i, (), { 'discobj': self, 'track': arg }
@@ -335,7 +335,7 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
config['audiodefault']) config['audiodefault'])


def aftershutdown(self): def aftershutdown(self):
print 'in SLinkEChanger after shutdown'
print('in SLinkEChanger after shutdown')
self._s.close() self._s.close()
self._s = None self._s = None


@@ -350,7 +350,7 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
self._poweroff.cancel() self._poweroff.cancel()
self._poweroff = None self._poweroff = None
self._lock = obj self._lock = obj
print 'tl: locked:', `self._lock`
print('tl: locked:', repr(self._lock))
return defer.succeed(True) return defer.succeed(True)


d = defer.Deferred() d = defer.Deferred()
@@ -372,24 +372,24 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
return False return False


def unlock(self, obj): def unlock(self, obj):
print 'unlock:', `obj`
print('unlock:', repr(obj))
if self._lock is None: if self._lock is None:
print 'ul: not locked'
print('ul: not locked')
raise RuntimeError('unlocked when not locked') raise RuntimeError('unlocked when not locked')


if obj is not self._lock: if obj is not self._lock:
print 'ul: wrong obj'
raise ValueError('unlocking when not locked by: %s, was locked by: %s' % (`obj`, self._lock))
print('ul: wrong obj')
raise ValueError('unlocking when not locked by: %s, was locked by: %s' % (repr(obj), self._lock))


if not self._pendinglocks: if not self._pendinglocks:
print 'really unlocked'
print('really unlocked')
self._lock = None self._lock = None
self._poweroff = reactor.callLater(300, self.turnoff) self._poweroff = reactor.callLater(300, self.turnoff)
return return


pobj = self._pendinglocks.pop(0) pobj = self._pendinglocks.pop(0)
self._lock = pobj[1] self._lock = pobj[1]
print 'passing lock:', `self._lock`
print('passing lock:', repr(self._lock))
pobj[2].cancel() pobj[2].cancel()
pobj[0].callback(True) pobj[0].callback(True)


@@ -402,7 +402,7 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
a = defer.waitForDeferred(self.checkids()) a = defer.waitForDeferred(self.checkids())
yield a yield a
a.getResult() a.getResult()
print 'powering cd changer off'
print('powering cd changer off')


# checkids may have rescheduled us. If we don't cancel it, # checkids may have rescheduled us. If we don't cancel it,
# we'd wake up every five minutes just to turn off again. # we'd wake up every five minutes just to turn off again.
@@ -415,13 +415,12 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):


@defer.deferredGenerator @defer.deferredGenerator
def checkids(self): def checkids(self):
print 'starting checkids'
print('starting checkids')
a = defer.waitForDeferred(self.transport.poweron()) a = defer.waitForDeferred(self.transport.poweron())
yield a yield a
print 'power should be on:', `a.getResult()`
discs = list(self.transport.discs())
discs.sort()
print discs
print('power should be on:', repr(a.getResult()))
discs = sorted(self.transport.discs())
print(discs)
for i in self.transport: for i in self.transport:
discnum = i discnum = i
i = str(i) i = str(i)
@@ -433,7 +432,7 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
except KeyError: except KeyError:
pass pass


print 'missing:', `i`
print('missing:', repr(i))


# No ID, fetch it. # No ID, fetch it.
a = defer.waitForDeferred(self.trylock(5, self)) a = defer.waitForDeferred(self.trylock(5, self))
@@ -447,12 +446,12 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
a = defer.waitForDeferred(threads.deferToThread(CDDB.query, cddbid)) a = defer.waitForDeferred(threads.deferToThread(CDDB.query, cddbid))
yield a yield a
queryres = a.getResult() queryres = a.getResult()
print 'res:', `i`, `queryres`
print('res:', repr(i), repr(queryres))
self._s[i] = { 'query': queryres, self._s[i] = { 'query': queryres,
'cddbid': cddbid, } 'cddbid': cddbid, }
self._changed = True self._changed = True
except slinke.NoDisc: except slinke.NoDisc:
print 'Disc not present: %d' % discnum
print('Disc not present: %d' % discnum)
continue continue
finally: finally:
self.unlock(self) self.unlock(self)
@@ -488,7 +487,7 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
# 210 multiple matches # 210 multiple matches
return q[1][0] return q[1][0]
else: else:
raise ValueError('what to do? %s' % `self._s[disc]`)
raise ValueError('what to do? %s' % repr(self._s[disc]))
def getDiscTitle(self, disc, wait=False): def getDiscTitle(self, disc, wait=False):
m = self.getMatch(disc, wait) m = self.getMatch(disc, wait)
@@ -502,17 +501,17 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
t = t.decode('iso8859-1') t = t.decode('iso8859-1')


if t.count('/') > 1: if t.count('/') > 1:
print 'tcount:', `t`
print('tcount:', repr(t))
try: try:
return t.split('/', 1)[1] return t.split('/', 1)[1]
except IndexError: except IndexError:
print 'ie:', `t`
print('ie:', repr(t))
return t return t


# CDPlayerProtocol interface # CDPlayerProtocol interface
def connectionMade(self): def connectionMade(self):
super(SLinkEChanger, self).connectionMade() super(SLinkEChanger, self).connectionMade()
print 'attached to cdplayer'
print('attached to cdplayer')
self._changed = True self._changed = True


# Make sure we start out off, or if we are missing CDDB id's, # Make sure we start out off, or if we are missing CDDB id's,
@@ -520,7 +519,7 @@ class SLinkEChanger(StorageSystem, slinke.CDPlayerProtocol):
self.turnoff() self.turnoff()


def stateChange(self): def stateChange(self):
print 'sC'
print('sC')


# ContentDirectory calls this # ContentDirectory calls this
def checkUpdate(self): def checkUpdate(self):


+ 6
- 8
soap_lite.py View File

@@ -82,18 +82,16 @@ def build_soap_call(method, arguments, is_response=False,
# append the arguments # append the arguments
if isinstance(arguments,dict): if isinstance(arguments,dict):
type_map = {str: 'xsd:string', type_map = {str: 'xsd:string',
unicode: 'xsd:string',
bytes: 'xsd:string',
int: 'xsd:int', int: 'xsd:int',
long: 'xsd:int',
float: 'xsd:float', float: 'xsd:float',
bool: 'xsd:boolean'} bool: 'xsd:boolean'}


for arg_name, arg_val in arguments.iteritems():
for arg_name, arg_val in arguments.items():
arg_type = type_map[type(arg_val)] arg_type = type_map[type(arg_val)]
if arg_type == 'xsd:string' and type(arg_val) == unicode:
arg_val = arg_val.encode('utf-8')
if arg_type == 'xsd:int' or arg_type == 'xsd:float':
arg_val = str(arg_val)
if isinstance(arg_val, bytes):
arg_val = arg_val.decode('utf-8')
arg_val = str(arg_val)
if arg_type == 'xsd:boolean': if arg_type == 'xsd:boolean':
arg_val = arg_val.lower() arg_val = arg_val.lower()


@@ -109,4 +107,4 @@ def build_soap_call(method, arguments, is_response=False,




preamble = """<?xml version="1.0" encoding="utf-8"?>""" preamble = """<?xml version="1.0" encoding="utf-8"?>"""
return preamble + ET.tostring(envelope,'utf-8')
return bytes(preamble + ET.tostring(envelope, 'unicode'), 'ascii')

Loading…
Cancel
Save