Enigma2 plugin to to play various online streams (mostly Latvian).

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import os
  2. from enigma import eTimer, getDesktop
  3. from Components.ActionMap import ActionMap
  4. from Components.FileList import FileList
  5. from Components.Sources.List import List
  6. from Components.Sources.StaticText import StaticText
  7. from Components.Task import Task, Job, job_manager
  8. from Screens.Screen import Screen
  9. from Tools.Downloader import downloadWithProgress
  10. from Tools.Directories import fileExists
  11. from os import path
  12. class HLSDownloadJob(Job):
  13. def __init__(self, url, destfile, title,downloadStop):
  14. Job.__init__(self, title)
  15. AddHLSProcessTask(self, url, destfile, title, downloadStop)
  16. class AddHLSProcessTask(Task):
  17. def __init__(self, job, url, destfile, title,downloadStop):
  18. Task.__init__(self, job, title)
  19. self.job = job
  20. self.title = title
  21. cmdline = '/usr/bin/gst-launch-1.0 "%s" ! hlsdemux ! filesink location="%s"'%(url,destfile)
  22. self.setCmdline(cmdline)
  23. self.url = url
  24. self.destfile = destfile
  25. self.downloadStop = downloadStop
  26. self.job.currentbytes = 0
  27. self.job.totalbytes = 0
  28. #self.setProgress(100)
  29. self.ProgressTimer = eTimer()
  30. self.ProgressTimer.callback.append(self.ProgressUpdate)
  31. def ProgressUpdate(self):
  32. if not fileExists(self.destfile, 'r'):
  33. return
  34. self.job.currentbytes = path.getsize(self.destfile)
  35. progress = self.job.currentbytes/float(self.job.totalbytes) * 100 if self.job.totalbytes else 0
  36. self.setProgress(progress)
  37. #self.setProgress(int((path.getsize(self.destfile)/float(self.totalbytes))*100))
  38. self.ProgressTimer.start(5000, True)
  39. def prepare(self):
  40. self.job.totalbytes = -1 # TODO getsize(self.url)
  41. self.ProgressTimer.start(5000, True)
  42. def afterRun(self):
  43. #self.setProgress(100)
  44. self.ProgressTimer.stop()
  45. self.downloadStop(self.title)
  46. class downloadJob(Job):
  47. def __init__(self, url, outputfile, title, downloadStop):
  48. Job.__init__(self, title)
  49. downloadTask(self, url, outputfile, title, downloadStop)
  50. class downloadTask(Task):
  51. def __init__(self, job, url, outputfile, title, downloadStop):
  52. Task.__init__(self, job, _('Downloading'))
  53. self.job = job
  54. self.title = title
  55. self.url = url
  56. self.outputfile = outputfile
  57. self.downloadStop = downloadStop
  58. self.job.currentbytes = 0
  59. self.job.totalbytes = -1
  60. def run(self, callback):
  61. self.callback = callback
  62. self.download = downloadWithProgress(self.url, self.outputfile)
  63. self.download.addProgress(self.downloadProgress)
  64. self.download.start().addCallback(self.downloadFinished)\
  65. .addErrback(self.downloadFailed)
  66. def downloadProgress(self, currentbytes, totalbytes):
  67. self.job.currentbytes = currentbytes
  68. self.job.totalbytes = totalbytes
  69. progress = self.job.currentbytes/float(self.job.totalbytes) * 100
  70. self.setProgress(progress)
  71. def downloadFinished(self, result):
  72. Task.processFinished(self, 0)
  73. self.setProgress(self.end)
  74. self.downloadStop(self.title)
  75. def downloadFailed(self, failure_instance=None, error_message=''):
  76. print '[PlayStream] Video download failed'
  77. if error_message == '' and failure_instance is not None:
  78. error_message = failure_instance.getErrorMessage()
  79. print '[PlayStream]', str(error_message)
  80. Task.processFinished(self, 1)
  81. self.downloadStop("")
  82. class VideoDownloadList(Screen):
  83. screenWidth = getDesktop(0).size().width()
  84. if screenWidth and screenWidth == 1920:
  85. skin = """<screen position="center,center" size="945,555">
  86. <widget source="list" render="Listbox" position="center,45" size="900,405" \
  87. scrollbarMode="showOnDemand" >
  88. <convert type="TemplatedMultiContent" >
  89. {"template": [
  90. MultiContentEntryText(pos=(15,1), size=(465,33), \
  91. font=0, flags=RT_HALIGN_LEFT, text=1), # Title
  92. MultiContentEntryText(pos=(345,1), size=(225,33), \
  93. font=0, flags=RT_HALIGN_RIGHT, text=2), # State
  94. MultiContentEntryProgress(pos=(585,6), size=(150,33), \
  95. percent=-3), # Progress
  96. MultiContentEntryText(pos=(750,1), size=(120,33), \
  97. font=0, flags=RT_HALIGN_LEFT, text=4), # Percentage
  98. ],
  99. "fonts": [gFont("Regular",30)],
  100. "itemHeight": 45}
  101. </convert>
  102. </widget>
  103. <ePixmap position="center,484" size="210,60" pixmap="skin_default/buttons/red.png" \
  104. transparent="1" alphatest="on" />
  105. <widget source="key_red" render="Label" position="center,485" zPosition="2" \
  106. size="210,60" valign="center" halign="center" font="Regular;33" transparent="1" />
  107. </screen>"""
  108. else:
  109. skin = """<screen position="center,center" size="630,370">
  110. <widget source="list" render="Listbox" position="center,30" size="600,270" \
  111. scrollbarMode="showOnDemand" >
  112. <convert type="TemplatedMultiContent" >
  113. {"template": [
  114. MultiContentEntryText(pos=(10,1), size=(210,22), \
  115. font=0, flags=RT_HALIGN_LEFT, text=1), # Title
  116. MultiContentEntryText(pos=(230,1), size=(150,22), \
  117. font=0, flags=RT_HALIGN_RIGHT, text=2), # State
  118. MultiContentEntryProgress(pos=(390,4), size=(100,22), \
  119. percent=-3), # Progress
  120. MultiContentEntryText(pos=(500,1), size=(80,22), \
  121. font=0, flags=RT_HALIGN_LEFT, text=4), # Percentage
  122. ],
  123. "fonts": [gFont("Regular",20)],
  124. "itemHeight": 30}
  125. </convert>
  126. </widget>
  127. <ePixmap position="center,323" size="140,40" pixmap="skin_default/buttons/red.png" \
  128. transparent="1" alphatest="on" />
  129. <widget source="key_red" render="Label" position="center,328" zPosition="2" \
  130. size="140,30" valign="center" halign="center" font="Regular;22" transparent="1" />
  131. </screen>"""
  132. def __init__(self, session):
  133. Screen.__init__(self, session)
  134. self['key_red'] = StaticText(_('Exit'))
  135. self['list'] = List([])
  136. self['actions'] = ActionMap(['SetupActions', 'ColorActions'],
  137. {
  138. 'cancel': self.close,
  139. 'ok': self.ok,
  140. 'red': self.close,
  141. 'blue': self.abort
  142. }, -2)
  143. self.onLayoutFinish.append(self.layoutFinished)
  144. self.onClose.append(self.cleanVariables)
  145. self.progressTimer = eTimer()
  146. self.progressTimer.callback.append(self.updateDownloadList)
  147. def layoutFinished(self):
  148. self.setTitle(_('Active video downloads'))
  149. self.updateDownloadList()
  150. def cleanVariables(self):
  151. del self.progressTimer
  152. def updateDownloadList(self):
  153. self.progressTimer.stop()
  154. downloadList = []
  155. for job in job_manager.getPendingJobs():
  156. progress = job.progress / float(job.end) * 100
  157. currentbytes = job.currentbytes if "currentbytes" in dir(job) else 0
  158. downloadList.append((job, job.name, job.getStatustext(),
  159. int(progress), "%.1fM"%(currentbytes/1024.0/1024.0) ))
  160. self['list'].updateList(downloadList)
  161. if downloadList:
  162. self.progressTimer.startLongTimer(2)
  163. def ok(self):
  164. current = self['list'].getCurrent()
  165. if current:
  166. from Screens.TaskView import JobView
  167. self.session.open(JobView, current[0])
  168. def abort(self):
  169. current = self['list'].getCurrent()
  170. job = current[0]
  171. if job.status == job.NOT_STARTED:
  172. job_manager.active_jobs.remove(job)
  173. self.close(False)
  174. elif job.status == job.IN_PROGRESS:
  175. job.cancel()
  176. else:
  177. self.close(False)
  178. class VideoDirBrowser(Screen):
  179. def __init__(self, session, downloadDir):
  180. Screen.__init__(self, session)
  181. self.skinName = ['VideoDirBrowser', 'FileBrowser']
  182. self['key_red'] = StaticText(_('Cancel'))
  183. self['key_green'] = StaticText(_('Use'))
  184. if not os.path.exists(downloadDir):
  185. downloadDir = '/'
  186. self.filelist = FileList(downloadDir, showFiles = False)
  187. self['filelist'] = self.filelist
  188. self['FilelistActions'] = ActionMap(['SetupActions', 'ColorActions'],
  189. {
  190. 'cancel': self.cancel,
  191. 'red': self.cancel,
  192. 'ok': self.ok,
  193. 'green': self.use
  194. }, -2)
  195. self.onLayoutFinish.append(self.layoutFinished)
  196. def layoutFinished(self):
  197. self.setTitle(_('Please select the download directory'))
  198. def ok(self):
  199. if self.filelist.canDescent():
  200. self.filelist.descent()
  201. def use(self):
  202. currentDir = self['filelist'].getCurrentDirectory()
  203. dirName = self['filelist'].getFilename()
  204. if currentDir is None or \
  205. (self.filelist.canDescent() and dirName and len(dirName) > len(currentDir)):
  206. self.close(dirName)
  207. def cancel(self):
  208. self.close(False)