A Python UPnP Media Server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
5.2 KiB

  1. #!/usr/bin/env python
  2. '''DVD Handling'''
  3. default_audio_lang = 'en'
  4. import os
  5. import sets
  6. import sys
  7. sys.path.append('/Users/jgurney/p4/bktrau/info')
  8. try:
  9. import mpegts
  10. audiofilter = lambda x, y: mpegts.DVDAudioFilter(x, y)
  11. except ImportError:
  12. print >>sys.stderr, 'module mpegts could not be loaded, not filtering audio'
  13. audiofilter = lambda x, y: x
  14. from pydvdread import *
  15. from DIDLLite import StorageFolder, Movie, VideoItem, Resource
  16. from FSStorage import FSObject, registerklassfun
  17. from twisted.python import log, threadable
  18. from twisted.spread import pb
  19. from twisted.web import resource, server
  20. def gennameindexes(pref, item):
  21. ret = []
  22. d = {}
  23. for i, title in enumerate(item):
  24. t = '%s %d (%s)' % (pref, i + 1, title.time)
  25. ret.append(t)
  26. d[t] = i
  27. return ret, d
  28. class DVDChapterTransfer(pb.Viewable):
  29. def __init__(self, iterable, request):
  30. self.iter = iter(iterable)
  31. self.request = request
  32. request.registerProducer(self, 0)
  33. def resumeProducing(self):
  34. if not self.request:
  35. return
  36. # get data and write to request.
  37. try:
  38. data = self.iter.next()
  39. if data:
  40. # this .write will spin the reactor, calling
  41. # .doWrite and then .resumeProducing again, so
  42. # be prepared for a re-entrant call
  43. self.request.write(data)
  44. except StopIteration:
  45. if self.request:
  46. self.request.unregisterProducer()
  47. self.request.finish()
  48. self.request = None
  49. def pauseProducing(self):
  50. pass
  51. def stopProducing(self):
  52. # close zipfile
  53. self.request = None
  54. # Remotely relay producer interface.
  55. def view_resumeProducing(self, issuer):
  56. self.resumeProducing()
  57. def view_pauseProducing(self, issuer):
  58. self.pauseProducing()
  59. def view_stopProducing(self, issuer):
  60. self.stopProducing()
  61. synchronized = ['resumeProducing', 'stopProducing']
  62. threadable.synchronize(DVDChapterTransfer)
  63. class DVDChapterResource(resource.Resource):
  64. isLeaf = True
  65. def __init__(self, chapter):
  66. resource.Resource.__init__(self)
  67. self.chapter = chapter
  68. def getFileSize(self):
  69. return self.chapter.size
  70. def render(self, request):
  71. request.setHeader('content-type', 'video/mpeg')
  72. #request.setHeader('content-length', str(self.getFileSize()))
  73. if request.method == 'HEAD':
  74. return ''
  75. # return data
  76. DVDChapterTransfer(self.chapter, request)
  77. # and make sure the connection doesn't get closed
  78. return server.NOT_DONE_YET
  79. class DVDChapter(VideoItem):
  80. def __init__(self, *args, **kwargs):
  81. self.dvdtitle = kwargs['dvdtitle']
  82. self.chapter = kwargs['chapter']
  83. del kwargs['dvdtitle'], kwargs['chapter']
  84. audio = self.dvdtitle.selectaudio(default_audio_lang)
  85. kwargs['content'] = DVDChapterResource(
  86. audiofilter(self.chapter, 0x80 + audio.pos))
  87. VideoItem.__init__(self, *args, **kwargs)
  88. self.url = '%s/%s' % (self.cd.urlbase, self.id)
  89. self.res = Resource(self.url, 'http-get:*:video/mpeg:*')
  90. #self.res.size = self.chapter.size
  91. def doUpdate(self):
  92. pass
  93. class DVDTitle(StorageFolder):
  94. def __init__(self, *args, **kwargs):
  95. self.dvdtitle = kwargs['dvdtitle']
  96. self.dvddisc = kwargs['dvddisc']
  97. del kwargs['dvdtitle'], kwargs['dvddisc']
  98. StorageFolder.__init__(self, *args, **kwargs)
  99. # mapping from path to objectID
  100. self.pathObjmap = {}
  101. def checkUpdate(self):
  102. self.doUpdate()
  103. #return self.dvddisc.checkUpdate()
  104. return self
  105. def doUpdate(self):
  106. doupdate = False
  107. origchildren, toindex = gennameindexes('Chapter', self.dvdtitle)
  108. children = sets.Set(origchildren)
  109. for i in self.pathObjmap.keys():
  110. if i not in children:
  111. doupdate = True
  112. # delete
  113. self.cd.delItem(self.pathObjmap[i])
  114. del self.pathObjmap[i]
  115. for i in origchildren:
  116. if i in self.pathObjmap:
  117. continue
  118. # new object
  119. self.pathObjmap[i] = self.cd.addItem(self.id,
  120. DVDChapter, i, dvdtitle = self.dvdtitle,
  121. chapter = self.dvdtitle[toindex[i]])
  122. doupdate = True
  123. if doupdate:
  124. StorageFolder.doUpdate(self)
  125. class DVDDisc(FSObject, StorageFolder):
  126. def __init__(self, *args, **kwargs):
  127. path = kwargs['path']
  128. del kwargs['path']
  129. StorageFolder.__init__(self, *args, **kwargs)
  130. FSObject.__init__(self, path)
  131. # mapping from path to objectID
  132. self.pathObjmap = {}
  133. def doUpdate(self):
  134. # open the DVD as necessary.
  135. self.dvd = DVD(self.FSpath)
  136. doupdate = False
  137. origchildren, toindex = gennameindexes('Title', self.dvd)
  138. children = sets.Set(origchildren)
  139. for i in self.pathObjmap.keys():
  140. if i not in children:
  141. doupdate = True
  142. # delete
  143. self.cd.delItem(self.pathObjmap[i])
  144. del self.pathObjmap[i]
  145. for i in origchildren:
  146. if i in self.pathObjmap:
  147. continue
  148. # new object
  149. self.pathObjmap[i] = self.cd.addItem(self.id, DVDTitle,
  150. i, dvdtitle = self.dvd[toindex[i]], dvddisc = self)
  151. doupdate = True
  152. if doupdate:
  153. StorageFolder.doUpdate(self)
  154. def detectdvd(path, fobj):
  155. if os.path.isdir(path):
  156. log.msg('dvd isdir')
  157. # Make sure we there is only a VIDEO_TS in there, even
  158. # if there is a VIDEO_TS w/ other files, we will open
  159. # the VIDEO_TS as a DVD (if it is one)
  160. ld = os.listdir(path)
  161. if ld == ['VIDEO_TS' ]:
  162. pass
  163. elif not filter(lambda x: x[:4] != 'VTS_' and
  164. x[:9] != 'VIDEO_TS.', ld):
  165. pass
  166. else:
  167. return None, None
  168. d = DVD(path)
  169. return DVDDisc, { 'path': path }
  170. registerklassfun(detectdvd)