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

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. #!/usr/bin/env python
  2. # coding=utf8
  3. #
  4. # This file is part of PlayStream - enigma2 plugin to play video streams from various sources
  5. # Copyright (c) 2016 ivars777 (ivars777@gmail.com)
  6. # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
  7. # Used fragments of code from enigma2-plugin-tv3play by Taapat (https://github.com/Taapat/enigma2-plugin-tv3play)
  8. #
  9. import os,time,sys,os,os.path
  10. import datetime,re
  11. import urllib2
  12. from Plugins.Plugin import PluginDescriptor
  13. from enigma import ePicLoad, eServiceReference, eTimer, getDesktop
  14. from Screens.Screen import Screen
  15. from Screens.InfoBarGenerics import InfoBarShowHide
  16. from Screens.InfoBar import MoviePlayer
  17. from Screens.MessageBox import MessageBox
  18. from Screens.LocationBox import LocationBox
  19. from Screens.ChoiceBox import ChoiceBox
  20. from Screens.VirtualKeyBoard import VirtualKeyBoard
  21. #from Screens.InputBox import InputBox
  22. from Components.AVSwitch import AVSwitch
  23. from Components.ActionMap import ActionMap, HelpableActionMap
  24. from Components.Label import Label
  25. from Components.Input import Input
  26. from Components.MenuList import MenuList
  27. from Components.Pixmap import Pixmap
  28. from Components.Sources.List import List
  29. from Components.Sources.StaticText import StaticText
  30. from Components.Button import Button
  31. from Components.Task import job_manager
  32. from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations, ConfigDirectory, ConfigSet, ConfigYesNo, ConfigSelection, getConfigListEntry, ConfigSelectionNumber, ConfigNumber
  33. from Components.ConfigList import ConfigListScreen
  34. from Tools import Notifications
  35. from Tools.BoundFunction import boundFunction
  36. from Tools.Directories import resolveFilename, SCOPE_PLUGINS
  37. from Tools.LoadPixmap import LoadPixmap
  38. from twisted.web.client import downloadPage,defer,reactor
  39. import ContentSources
  40. import util
  41. from VideoDownload import downloadJob, HLSDownloadJob,VideoDownloadList
  42. #import enigma2_api
  43. e2 = None
  44. ##########################################################################
  45. config.plugins.playstream = ConfigSubsection()
  46. config.plugins.playstream.locations = ConfigLocations(default=["/media/hdd/movie/"])
  47. config.plugins.playstream.download_dir = ConfigDirectory(default="/media/hdd/movie/")
  48. config.plugins.playstream.tmp_dir = ConfigDirectory(default="/tmp/playstream/")
  49. config.plugins.playstream.streamproxy_start = ConfigYesNo(default = True)
  50. config.plugins.playstream.overwrite_download = ConfigYesNo(default = False)
  51. #config.plugins.playstream.size = ConfigSelection({"400x240":"400x240","220x132":"220x132","100x60":"100x60"}, default="220x132")
  52. config.plugins.playstream.clear_tmp = ConfigYesNo(default = True)
  53. class ConfigScreen(ConfigListScreen,Screen):
  54. skin = """
  55. <screen position="center,center" size="560,400" title="PlayStream Configuration" >
  56. <ePixmap name="red" position="0,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
  57. <ePixmap name="green" position="140,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
  58. <ePixmap name="yellow" position="280,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
  59. <ePixmap name="blue" position="420,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
  60. <widget name="key_red" position="0,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  61. <widget name="key_green" position="140,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  62. <widget name="key_yellow" position="280,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  63. <widget name="key_blue" position="420,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  64. <widget name="config" position="10,40" size="540,340" scrollbarMode="showOnDemand" />
  65. </screen>"""
  66. def __init__(self, session, args = 0):
  67. self.session = session
  68. #self.setup_title = "Options"
  69. Screen.__init__(self, session)
  70. cfg = config.plugins.playstream
  71. self.list = [
  72. getConfigListEntry(_("Download folder"), cfg.download_dir),
  73. getConfigListEntry(_("Overwrite download video"), cfg.overwrite_download),
  74. getConfigListEntry(_("TMP folder"), cfg.tmp_dir),
  75. getConfigListEntry(_("Clear tmp folder on exit"), cfg.clear_tmp),
  76. getConfigListEntry(_("Start playstreamproxy"), cfg.streamproxy_start),
  77. ]
  78. ConfigListScreen.__init__(self, self.list, session = self.session)
  79. self["key_red"] = Button(_("Cancel"))
  80. self["key_green"] = Button(_("Save"))
  81. self["key_yellow"] = Button("")
  82. self["key_blue"] = Button("")
  83. self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
  84. {
  85. "red": self.cancel,
  86. "green": self.save,
  87. "save": self.save,
  88. "cancel": self.cancel,
  89. "ok": self.ok,
  90. }, -2)
  91. def getCurrentEntry(self):
  92. return self["config"].getCurrent()[0]
  93. def getCurrentValue(self):
  94. return str(self["config"].getCurrent()[1].getText())
  95. def ok(self):
  96. if self["config"].getCurrent()[1] == config.plugins.playstream.download_dir:
  97. folder = config.plugins.playstream.download_dir.value
  98. #self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select Folder")
  99. self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
  100. elif self["config"].getCurrent()[1] == config.plugins.playstream.tmp_dir:
  101. self.session.openWithCallback(self.select_tmp_dir, LocationBox,"Select tmp folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
  102. else:
  103. self.save()
  104. def cb_download_dir(self, folder, select=None):
  105. if not folder:
  106. return
  107. print "Folder selected - %s"%folder
  108. config.plugins.playstream.download_dir.setValue(folder)
  109. config.plugins.playstream.download_dir.save()
  110. config.plugins.playstream.locations.save()
  111. config.save()
  112. def select_tmp_dir(self, folder, select=None):
  113. if not folder:
  114. return
  115. print "Folder selected - %s"%folder
  116. config.plugins.playstream.tmp_dir.setValue(folder)
  117. config.plugins.playstream.tmp_dir.save()
  118. config.plugins.playstream.locations.save()
  119. config.save()
  120. def save(self):
  121. print "saving"
  122. self.saveAll()
  123. self.close(True,self.session)
  124. def cancel(self):
  125. #print "cancel"
  126. self.close(False,self.session)
  127. def make_service(stream):
  128. url = stream["url"]
  129. headers = []
  130. if stream.has_key("headers"):
  131. for h in stream["headers"]:
  132. headers.append("%s=%s"%(h,stream["headers"][h]))
  133. if headers:
  134. headers ="&".join(headers)
  135. url = url+"#"+headers
  136. print "stream_url with headers=",headers
  137. url = url.encode("utf8")
  138. if "|" in url:
  139. url = url.replace("|","#")
  140. service_type = 4097
  141. if re.search("\.ts$",url.split("?")[0],re.IGNORECASE):
  142. service_type = 1
  143. if "resolver" in stream and stream["resolver"] in ("hqq","viaplay","filmas"):
  144. url = util.streamproxy_encode(stream["url"], stream["headers"])
  145. #if os.path.exists("/usr/bin/exteplayer3"): # problem playing hqq streams with gstreamer, use exteplayer3
  146. #service_type = 5002
  147. print "service_type=",service_type
  148. print "stream_url=",url
  149. service = eServiceReference(service_type, 0, url)
  150. service.setName( stream["name"])
  151. return service
  152. #####################################################################################################################
  153. class PSSubs(Screen):
  154. def __init__(self, session):
  155. desktopWidth = getDesktop(0).size().width()
  156. desktopHeight = getDesktop(0).size().height()
  157. offset = 20
  158. screenWidth = desktopWidth - (2 * offset)
  159. widgetWidth = screenWidth / 2 - 5
  160. self.skin = """
  161. <screen position="%d,%d" size="%d,140" zPosition="2" backgroundColor="transparent" flags="wfNoBorder">
  162. <widget name="subtitle" position="0,0" size="%d,140" valign="center" halign="center" font="Regular;36" transparent="1" foregroundColor="white" shadowColor="#40101010" shadowOffset="2,2" />
  163. </screen>""" % (offset, desktopHeight-offset-140, screenWidth, screenWidth)
  164. self['subtitle'] = Label()
  165. Screen.__init__(self, session)
  166. #####################################################################################################################
  167. class PSPlayer(MoviePlayer):
  168. def __init__(self, session, streams):
  169. print "PSPlayer init: ",streams
  170. self.session = session
  171. self.streams = streams
  172. self.cur_stream = self.streams[0] # TODO
  173. self.selected = 0
  174. self.resume_pos = 0
  175. service = make_service(self.cur_stream)
  176. MoviePlayer.__init__(self, session, service)
  177. self.skinName = "MoviePlayer"
  178. self["actions"] = ActionMap(["MediaPlayerActions","MediaPlayerSeekActions","MoviePlayerActions","InfobarSeekActions","MovieSelectionActions","ColorActions"], {
  179. "stop":self.leavePlayer,
  180. "leavePlayer":self.leavePlayer,
  181. "audio":self.select_stream,
  182. "AudioSelection":self.select_stream,
  183. "green":self.select_stream,
  184. "subtitles":self.select_captions,
  185. "text":self.select_captions,
  186. "yellow_key":self.select_captions,
  187. "yellow":self.select_captions,
  188. "pauseServiceYellow":self.select_captions,
  189. "pause":self.select_captions,
  190. "showEventInfo":self.service_info,
  191. "info":self.service_info
  192. })
  193. self.stimer = eTimer()
  194. if "callback" in dir(self.stimer):
  195. self.stimer.callback.append(self.update_subtitles)
  196. elif "timeout":
  197. self.stimer_conn = self.stimer.timeout.connect(self.update_subtitles)
  198. else:
  199. self.stimer = None
  200. self.stimer_step = 500
  201. if self.cur_stream["subs"]:
  202. self.subs = self.cur_stream["subs"]
  203. self.cur_subs = 0 # TODO - no konfiguracijas
  204. self.svisible = True # TODO - no konfiguracija
  205. self.sind = 0
  206. self.get_subs_current()
  207. else:
  208. self.subs = []
  209. self.cur_subs = 0
  210. self.svisible = False
  211. self.subtitle_window = self.session.instantiateDialog (PSSubs)
  212. self.onLayoutFinish.append(self.start_subtitles_timer)
  213. def start_subtitles_timer(self):
  214. if self.stimer:
  215. self.subtitle_window.show()
  216. print "start_subtitles_timer"
  217. self.stimer.start(self.stimer_step)
  218. def get_sub_pts(self,pts):
  219. sc = self.get_sub_ind(self.sind) # current subbtitle
  220. while True:
  221. if not sc:
  222. return "Error - no subs find" # TODO
  223. if pts > sc["end"]:
  224. self.sind += 1
  225. sc = self.get_sub_ind(self.sind)
  226. continue
  227. else:
  228. if pts <sc["begin"]:
  229. return " "
  230. else:
  231. txt = sc["text"] if sc["text"] else " "
  232. return txt
  233. def get_sub_ind(self,ind):
  234. subs_object = self.get_subs_current() # current subs object
  235. if subs_object:
  236. return subs_object.subs[ind] if ind<len(subs_object.subs) else None
  237. else:
  238. return None
  239. def get_subs_current(self):
  240. "Return current sub_object"
  241. if not "subs" in self.subs[self.cur_subs]:
  242. print "===== Captions to download", self.subs[self.cur_subs]["url"]
  243. subs_object = util.Captions(self.subs[self.cur_subs]["url"])
  244. print len(subs_object.subs), "items"
  245. self.subs[self.cur_subs]["subs"] = subs_object
  246. if not subs_object:
  247. return None
  248. else:
  249. return subs_object
  250. else:
  251. return self.subs[self.cur_subs]["subs"]
  252. def update_subtitles(self):
  253. if not self.shown and self.svisible:
  254. seek = self.getSeek()
  255. pos = seek.getPlayPosition()
  256. pts = pos[1]/90
  257. txt0 = "%d:%02d (%i)" % (pts/60/1000, (pts/1000)%60, pts)
  258. #print "Update_subtitles", txt0
  259. if not self.subtitle_window.shown:
  260. self.subtitle_window.show()
  261. if not self.subs:
  262. return
  263. txt = self.get_sub_pts(pts)
  264. #print "Show subtitle",txt
  265. #txt = txt0+": "+ txt
  266. self.subtitle_window["subtitle"].setText(txt)
  267. elif self.shown and self.svisible:
  268. if self.subtitle_window.shown:
  269. self.subtitle_window.hide()
  270. elif not self.svisible:
  271. if self.subtitle_window.shown:
  272. self.subtitle_window.hide()
  273. # struct SubtitleTrack
  274. # int type;
  275. # int pid;
  276. # int page_number;
  277. # int magazine_number;
  278. # std::string language_code;
  279. #selectedSubtitle = ???
  280. #self.enableSubtitle(selectedSubtitle)
  281. def start_subtitles_timer(self):
  282. self.stimer.start(self.stimer_step)
  283. def play_service(self,service):
  284. self.movieSelected(service)
  285. #def doShow(self):
  286. #self.svisible = False
  287. #InfoBarShowHide.doShow(self)
  288. #def doHide(self):
  289. #self.svisible = True
  290. #InfoBarShowHide.doHide(self)
  291. def service_info(self):
  292. print "########[MoviePlayer] service_info"
  293. text = "%s\n%s %s\n%s"%(self.cur_stream["name"],self.cur_stream["lang"],self.cur_stream["quality"],self.cur_stream["desc"])
  294. text = text.encode("utf8")
  295. #print text
  296. mtype = MessageBox.TYPE_INFO
  297. Notifications.AddPopup(text = text, type=mtype, timeout = 10)
  298. #Notifications.MessageBox(self.session, text=text, type=MessageBox.TYPE_INFO, timeout=10,
  299. #close_on_any_key=True,
  300. #default=True,
  301. #enable_input=True,
  302. #msgBoxID=None,
  303. #picon=False,
  304. #simple=False,
  305. #wizard=False,
  306. #list=None,
  307. #skin_name=None,
  308. #timeout_default=None)
  309. #return True
  310. def select_stream(self):
  311. print "########[MoviePlayer] select_stream"
  312. lst = []
  313. title = "Select stream"
  314. for i,s in enumerate(self.streams):
  315. lst.append(("[%s,%s] %s"%(s["lang"],s["quality"],s["name"]),i))
  316. self.session.openWithCallback(self.cb_select_stream, ChoiceBox, title = title, list = lst,selection = self.selected)
  317. def cb_select_stream(self,answer):
  318. #print "item_menu_selected",answer
  319. if not answer:
  320. return
  321. self.selected = answer[1]
  322. service = make_service(self.streams[self.selected])
  323. self.resume_pos = self.getSeek().getPlayPosition()[1]
  324. self.play_service(service)
  325. def serviceStarted(self):
  326. print "serviceStarted"
  327. if not self.resume_pos:
  328. self.resume_pos = 0
  329. print "doSeek",self.resume_pos
  330. #self.doSeek(self.resume_pos)
  331. def select_captions(self):
  332. print "########[MoviePlayer] select_caption"
  333. lst = []
  334. title = "Select subtitles"
  335. for i,s in enumerate(self.subs):
  336. lst.append((("%s - %s"%(s["lang"],s["name"])).encode("utf8"),i))
  337. if self.svisible:
  338. selection = self.cur_subs
  339. else:
  340. selection = len(lst)
  341. lst.append(("No captions",-1))
  342. self.session.openWithCallback(self.cb_select_captions, ChoiceBox, title = title, list = lst,selection = selection)
  343. def cb_select_captions(self,answer):
  344. #print "item_menu_selected",answer
  345. if not answer:
  346. return
  347. if answer[1] == -1:
  348. self.svisible = False
  349. else:
  350. self.cur_subs = answer[1]
  351. self.svisible = True
  352. def leavePlayer(self):
  353. self.close()
  354. #self.session.openWithCallback(self.leavePlayerConfirmed, MessageBox, _("Stop playing?"))
  355. def leavePlayerConfirmed(self, answer):
  356. if answer:
  357. self.close()
  358. def doEofInternal(self, playing):
  359. self.close()
  360. #def getPluginList(self):
  361. #from Components.PluginComponent import plugins
  362. #list = []
  363. #for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
  364. #if p.name != _("TV Play"):
  365. #list.append(((boundFunction(self.getPluginName, p.name),
  366. #boundFunction(self.runPlugin, p), lambda: True), None))
  367. #return list
  368. #def showMovies(self):
  369. #pass
  370. #####################################################################################################################
  371. class MainScreen(Screen):
  372. skin = """
  373. <screen position="center,center" size="1015,570" title="Play Stream">
  374. <eLabel position="5,0" size="1000,2" backgroundColor="#aaaaaa" />
  375. <widget name="title" position="10,2" size="1000,38" font="Regular;30" />
  376. <widget source="list" render="Listbox" position="10,55" size="580,470" \
  377. scrollbarMode="showOnDemand" >
  378. <convert type="TemplatedMultiContent" >
  379. {
  380. "template": [MultiContentEntryText(pos=(10, 1), size=(560, 30), \
  381. font=0, flags=RT_HALIGN_LEFT, text=0)],
  382. "fonts": [gFont("Regular", 20)],
  383. "itemHeight": 30
  384. }
  385. </convert>
  386. </widget>
  387. <widget name="pic" position="646,55" size="327,250" alphatest="on" />
  388. <widget name="cur" position="610,300" size="400,250" halign="center" font="Regular;20"/>
  389. <ePixmap name="exit" position="10,540" zPosition="2" size="140,40" pixmap="skin_default/buttons/key_exit.png" transparent="1" alphatest="on" />
  390. <widget name="key_exit" position="10,535" size="140,40" valign="center" halign="center" zPosition="4" backgroundColor="blue" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  391. <ePixmap name="red" position="150,535" zPosition="2" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
  392. <widget name="key_red" position="150,535" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  393. <ePixmap name="green" position="290,535" zPosition="2" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
  394. <widget name="key_green" position="290,535" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  395. <ePixmap name="yellow" position="430,535" zPosition="2" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
  396. <widget name="key_yellow" position="430,535" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  397. <ePixmap name="blue" position="570,535" zPosition="2" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
  398. <widget name="key_blue" position="570,535" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  399. <ePixmap name="menu" position="750,540" zPosition="2" size="140,40" pixmap="skin_default/buttons/key_menu.png" transparent="1" alphatest="on" />
  400. <widget name="key_menu" position="750,535" size="140,40" valign="center" halign="center" zPosition="4" backgroundColor="blue" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  401. </screen>"""
  402. def __init__(self, session):
  403. Screen.__init__(self, session)
  404. #self.setTitle2("Home")
  405. self.session = session
  406. self.e2 = None
  407. self["key_red"] = Button(_("Exit"))
  408. self["key_green"] = Button(_("Select"))
  409. self["key_yellow"] = Button(_("Options"))
  410. self["key_blue"] = Button(_("Config"))
  411. self["key_menu"] = Button("Menu")
  412. self["key_exit"] = Button("Back")
  413. self["actions"] = ActionMap(["OkCancelActions", "ColorActions","MenuActions", "NumberActions"],
  414. {
  415. #"cancel": self.Cancel,
  416. "ok": self.Ok,
  417. "green": self.Ok,
  418. "red": self.Cancel,
  419. "yellow": self.options_screen,
  420. "blue": self.config_screen,
  421. "menu": self.item_menu,
  422. "cancel": self.Back,
  423. })
  424. self["list"] = List([])
  425. self["list"].onSelectionChanged.append(self.SelectionChanged)
  426. self["pic"] = Pixmap()
  427. self["cur"] = Label()
  428. self["title"] = Label()
  429. self.downloading = 0
  430. self.activeDownloads = 0
  431. if not os.path.exists(config.plugins.playstream.tmp_dir.value):
  432. os.mkdir(config.plugins.playstream.tmp_dir.value)
  433. self.onLayoutFinish.append(self.LayoutFinish)
  434. def LayoutFinish(self):
  435. self.cur_directory = os.path.dirname(os.path.realpath(__file__))
  436. self.defimage = LoadPixmap(os.path.join(self.cur_directory,"PlayStream.png"))
  437. #self.defimage = None
  438. #sc = AVSwitch().getFramebufferScale()
  439. #self.defimage0 = ePicLoad()
  440. #self.defimage0.PictureData.get().append(boundFunction(self.FinishDecodeDef, os.path.join(self.cur_directory,"PlayStream.png")))
  441. #self.defimage0.setPara((self["pic"].instance.size().width(),self["pic"].instance.size().height(),sc[0], sc[1], False, 0, "#00000000"))
  442. #self.defimage0.startDecode("default")
  443. self.activeDownloads = 0
  444. self.images = {}
  445. self.images_url = {}
  446. self.picloads = {}
  447. self.history = []
  448. reload(ContentSources)
  449. self.sources = ContentSources.ContentSources(os.path.join(self.cur_directory,"sources"))
  450. self.config = self.sources.plugins["config"]
  451. self.cur_menu = ("Home","config::home","","Sākums") #
  452. self.content = self.sources.get_content(self.cur_menu[1])
  453. #print self.content
  454. self["list"].setList(self.content)
  455. self["cur"].setText(self.content[0][3])
  456. self.setTitle2(self.cur_menu[0])
  457. self.ShowPic(self.content[0][2])
  458. def SelectionChanged(self):
  459. current = self["list"].getCurrent()
  460. print "[PlayStream] SelectionChanged: current=",current
  461. if not current: return
  462. self["cur"].setText(current[3]) if current[3] else self["cur"].setText("")
  463. if current[2]:
  464. self.ShowPic(current[2])
  465. else:
  466. self.ShowDefPic()
  467. def setTitle2(self,title):
  468. #print self.keys()
  469. self["title"].setText(title)
  470. def ShowDefPic(self):
  471. if self.defimage:
  472. self["pic"].instance.setPixmap(self.defimage)
  473. def ShowPic(self,image_url):
  474. if image_url == "default":
  475. self.ShowDefPic()
  476. return
  477. elif self.images.has_key(image_url):
  478. if self.images[image_url] in (-1,-2):
  479. return
  480. elif self.images[image_url] == -3:
  481. self.ShowDefPic()
  482. return
  483. else:
  484. self["pic"].instance.setPixmap(self.images[image_url])
  485. else:
  486. if image_url.startswith("http"):
  487. fname = image_url.replace(":","-").replace("/","_")
  488. image_path = os.path.join(config.plugins.playstream.tmp_dir.value, fname)
  489. self.download_image(image_path, image_url)
  490. else: # local file
  491. image_path = os.path.join(self.cur_directory,image_url)
  492. self.start_decode(image_path,image_url)
  493. def start_decode(self,image_path,image_url):
  494. self.images[image_url] = -2
  495. self.images_url[image_path] = image_url
  496. sc = AVSwitch().getFramebufferScale()
  497. if not self.picloads.has_key(image_path):
  498. self.picloads[image_path] = ePicLoad()
  499. self.picloads[image_path].PictureData.get().append(boundFunction(self.FinishDecode, image_path))
  500. self.picloads[image_path].setPara((self["pic"].instance.size().width(),
  501. self["pic"].instance.size().height(),
  502. sc[0], sc[1], True, 0, "#00000000"))
  503. #print image_path,image_url
  504. self.picloads[image_path].startDecode(image_path)
  505. def FinishDecode(self, image_path,picInfo = None):
  506. image_url = self.images_url[image_path]
  507. del self.images_url[image_path] #III
  508. self.images[image_url] = self.picloads[image_path].getData()
  509. self["pic"].instance.setPixmap(self.images[image_url])
  510. del self.picloads[image_path]
  511. if len(self.images)>30:
  512. del self.images[self.images.keys()[0]]
  513. # self.images.pop()
  514. #def FinishDecodeDef(self, image_path,picInfo = None):
  515. # self.defimage = self.defimage0.getData()
  516. # del self.defimage0
  517. # self["pic"].instance.setPixmap(self.defimage)
  518. def download_image(self,image_path,image_url):
  519. #print "Image download started",self.downloading,image_path,image_url
  520. self.downloading += 1
  521. self.images[image_url] = -1
  522. downloadPage(image_url, image_path).addCallback(boundFunction(self.downloadFinished, image_path,image_url)).addErrback(boundFunction(self.downloadFailed, image_path,image_url))
  523. def downloadFinished(self, image_path, image_url, result):
  524. self.downloading -= 1
  525. #print "[ Play] Image downloaded finished ",self.downloading,image_path, image_url,result
  526. self.start_decode(image_path,image_url)
  527. def downloadFailed(self, image_path, image_url,result):
  528. self.downloading -= 1
  529. print "[TV Play] Image downloaded failed ",self.downloading,image_path, image_url,result
  530. self.images[image_url] = -3
  531. def Ok(self):
  532. current = self["list"].getCurrent()
  533. self.current = current
  534. index = self["list"].getIndex()
  535. self.index = index
  536. print "[PlayStream] - menu selected ", current
  537. data = current[1].split("::")[1] if "::" in current[1] else current[1]
  538. if not data:
  539. return
  540. elif self.sources.is_video(current[1]):
  541. if self.sources.stream_type(current[1]):
  542. stream = util.item()
  543. stream["url"] = current[1]
  544. stream["name"] = current[0]
  545. streams = [stream]
  546. else:
  547. try:
  548. streams = self.sources.get_streams(current[1])
  549. except Exception,e:
  550. print str(e)
  551. self.session. open(MessageBox, "Error - %s"%str(e) , MessageBox.TYPE_INFO)
  552. return
  553. if streams:
  554. #print streams
  555. for s in streams:
  556. if not s["name"]: s["name"] = current[0]
  557. if not s["img"]: s["img"] = current[2]
  558. if not s["desc"]: s["desc"] = current[3]
  559. try:
  560. self.session.open(PSPlayer, streams)
  561. except Exception as e:
  562. self.msg("Error launching player - " + str(e))
  563. return
  564. else:
  565. self.msg("No stream found - %s"%(self.current[1]))
  566. return
  567. elif current[1] == "back":
  568. cur_menu_old = self.cur_menu
  569. self.cur_menu = self.history.pop()
  570. new_content = self.sources.get_content(self.cur_menu[1])
  571. try:
  572. index = zip(*new_content)[1].index(cur_menu_old[1])
  573. except:
  574. index = 0
  575. self.setTitle2(self.cur_menu[0])
  576. self.show_content(new_content,index)
  577. else:
  578. print "selected=",current
  579. if "{0}" in current[1]:
  580. self.session.openWithCallback(self.cb_input,VirtualKeyBoard, title="Enter value", text="")
  581. #a = raw_input("Enter value:")
  582. #a = "big bang"
  583. #current = (current[0],current[1].format(a),current[2],current[3])
  584. #self.get_content(current)
  585. else:
  586. self.get_content(current)
  587. def cb_input(self,value):
  588. if not value:
  589. return
  590. current = self.current
  591. current = (current[0],current[1].format(value),current[2],current[3])
  592. self.get_content(current)
  593. def get_content(self,current):
  594. self.history.append(self.cur_menu)
  595. self.cur_menu = current
  596. try:
  597. new_content = self.sources.get_content(self.cur_menu[1])
  598. except Exception,e:
  599. self.cur_menu = self.history.pop()
  600. self.session. open(MessageBox, "Error - %s"%str(e) , MessageBox.TYPE_INFO)
  601. return
  602. self.setTitle2(self.cur_menu[0])
  603. self.show_content(new_content)
  604. def Back(self):
  605. self["list"].setIndex(0)
  606. self.Ok()
  607. def show_content(self,content,index=0):
  608. self["list"].setList(content)
  609. self["list"].setIndex(index)
  610. self.SelectionChanged()
  611. def Cancel(self):
  612. print "Exiting PlayStream"
  613. if config.plugins.playstream.clear_tmp.value and os.path.exists(config.plugins.playstream.tmp_dir.value):
  614. for name in os.listdir(config.plugins.playstream.tmp_dir.value):
  615. #print "remove "+os.path.join(config.plugins.playstream.tmp_dir.value, name)
  616. os.remove(os.path.join(config.plugins.playstream.tmp_dir.value, name))
  617. #os.rmdir(config.plugins.playstream.tmp_dir.value)
  618. self.close()
  619. def item_menu(self):
  620. print "\n[PlayStream] options\n"
  621. self.current = self["list"].getCurrent()
  622. self.index = self["list"].getIndex()
  623. #self.session. open(MessageBox, "Item options - %s"%current[0] , MessageBox.TYPE_INFO)
  624. #args=[current,self.cur_menu]
  625. #self.session.open(ItemMenuScreen,current,index,self)
  626. lst = [
  627. ("Aditional information","info","Display additional information about item"),
  628. ("Add to bouquet","bouquet","Add current item to Enigma2 bouquet"),
  629. ("Add to favorites","favorites","Add current item to PlayStrem favorites"),
  630. ("Show active downloads","download_list","Show active downloads list"),
  631. ("Set download folder","download_folder","Set download folder")
  632. ]
  633. if self.sources.is_video(self.current[1]):
  634. lst.extend([
  635. ("Download video to default folder","download","Download video to default folder"),
  636. ("Download video, ask folder","download2","Download video, ask download folder"),
  637. ("Download video to subfolder, ask parent folder","download3","Download video to subfolder, ask download folder"),
  638. ])
  639. else:
  640. lst.extend([
  641. ("Download list to default folder","download","Download videos in list (if any)"),
  642. ("Download list, ask folder","download2","Download videos in list (if any), ask download folder"),
  643. ])
  644. if "config::" in self.cur_menu[1]:
  645. lst.extend([
  646. ("Rename item","rename","Rename list item"),
  647. ("Move item","move","Move list item"),
  648. ("Delete item","delete","Delete list item"),
  649. ("Add submenu","add_list","Add submenu before selected item"),
  650. ])
  651. title = self.current[0]
  652. self.session.openWithCallback(self.cb_item_menu, ChoiceBox, title = title, list = lst) #TODO
  653. def cb_item_menu(self,answer):
  654. #print "item_menu_selected",answer
  655. if not answer:
  656. return
  657. self.answer = answer[1]
  658. if answer[1] == "info":
  659. self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO)
  660. pass # TODO parada papildus info
  661. elif answer[1] == "bouquet":
  662. #if not e2:
  663. #e2 = enigma2_api.DBServices()
  664. #print "load_buuquets - ",e2._load_bouquets()
  665. self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO)
  666. elif answer[1] == "favorites":
  667. lists = self.config.get_lists()
  668. lists2 = [(self.config.get_title(l),l) for l in lists]
  669. print lists2
  670. self.session.openWithCallback(self.cb_favorites, ChoiceBox, title="Selected menu item will be added",list = lists2)
  671. elif answer[1] in ("download2","download3"): # ask download folder before
  672. self.session.openWithCallback(self.download_prepare, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
  673. elif answer[1] == 'download':
  674. self.download_prepare(config.plugins.playstream.download_dir.value)
  675. elif answer[1] == 'download_list':
  676. self.download_list()
  677. elif answer[1] == 'download_folder':
  678. #downloadDir = "/media/hdd/movie" #config.plugins.playstream.downloadDir.value TODO
  679. self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
  680. elif answer[1] == "delete":
  681. lst = self.cur_menu[1].replace("config::","")
  682. #print lst
  683. self.config.del_item(lst,self.index)
  684. self.config.write_streams()
  685. txt = "'%s' deleted from favourite stream list '%s'"%(self.current[0],lst)
  686. self.session.open(MessageBox, txt, MessageBox.TYPE_INFO,timeout=5)
  687. elif answer[1] == "rename":
  688. #name2 = "Renamed"
  689. self.session.openWithCallback(self.cb_rename,VirtualKeyBoard, title="Enter new item name", text=self.current[0])
  690. elif answer[1] == "add_list":
  691. self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO,timeout=5)
  692. pass #TODO
  693. return
  694. def download_prepare(self, download_dir=""):
  695. current = self.current
  696. if not download_dir:
  697. return
  698. #download_dir = config.plugins.playstream.download_dir.value
  699. title = re.sub("\[.+?\]","", util.make_fname(current[0])).strip()
  700. download_dir2 = os.path.join(download_dir, title)
  701. if not self.sources.is_video(current[1]):
  702. #self.msg("Can not download listst (yet) - %s"%(current[1]))
  703. n = 0
  704. for current2 in self.sources.get_content(current[1]):
  705. if self.sources.is_video(current2[1]):
  706. n += 1
  707. self.download_video(current2,download_dir2)
  708. if n>0:
  709. self.msg("%s videos download started to %s"%(n,download_dir2))
  710. else:
  711. self.msg("No videos to download")
  712. else:
  713. if self.answer == "download":
  714. download_dir2 = download_dir
  715. if self.download_video(current,download_dir2):
  716. self.msg("Video download started to %s"%download_dir2)
  717. def cb_download_dir(self, downloadDir, select=None):
  718. if not downloadDir:
  719. return
  720. print "Folder selected - %s"%downloadDir
  721. config.plugins.playstream.download_dir.setValue(downloadDir)
  722. config.plugins.playstream.download_dir.save()
  723. config.plugins.playstream.locations.save()
  724. config.save()
  725. def download_list(self):
  726. self.session.open(VideoDownloadList)
  727. def download_video(self,current, download_dir=""):
  728. if self.sources.stream_type(current[1]):
  729. stream = util.item()
  730. stream["url"] = current[1]
  731. stream["name"] = current[0]
  732. streams = [stream]
  733. else:
  734. try:
  735. streams = self.sources.get_streams(current[1])
  736. except Exception,e:
  737. print "Error - %s"%str(e)
  738. self.session. open(MessageBox, "Error - %s"%str(e) , MessageBox.TYPE_INFO)
  739. return
  740. if not streams:
  741. self.msg("No stream found to download - %s"%(self.current[1]))
  742. return
  743. for s in streams:
  744. if not s["name"]: s["name"] = current[0]
  745. if not s["img"]: s["img"] = current[2]
  746. if not s["desc"]: s["desc"] = current[3]
  747. if len(streams)>1:
  748. stream = streams[0] # TODO iespeja izvelēties strīmu, ja to ir vairāki
  749. else:
  750. stream = streams[0]
  751. stream = util.stream_change(stream)
  752. return self.download_stream(stream, download_dir)
  753. def download_stream(self,stream,download_dir=""):
  754. print "download stream",stream
  755. #self.msg("Start downloading..")
  756. self.stream = stream
  757. stream_type = self.stream["type"] #self.sources.stream_type(stream["url"])
  758. if not stream_type: #
  759. print "Not supported stream type found to download - %s"%(self.current[1])
  760. self.msg("Not supported stream type found to download - %s"%(self.current[1]))
  761. return
  762. title = self.stream["name"].strip()
  763. url = self.stream["url"]
  764. stream_type = self.stream["type"] #self.sources.stream_type(stream["url"])
  765. downloadDir = config.plugins.playstream.download_dir.value if not download_dir else download_dir
  766. if not os.path.exists(downloadDir):
  767. try:
  768. os.mkdir(downloadDir)
  769. except Exception as e:
  770. print 'Error creating download directory "%s"!\nPlease specify in the settings existing directory\n%s'%(downloadDir,str(e))
  771. self.msg('Error creating download directory "%s"!\nPlease specify in the settings existing directory\n%s'%(downloadDir,str(e)))
  772. return
  773. fname0 = util.make_fname(title)
  774. fname = fname0 +".mp4"
  775. outputfile = os.path.join(downloadDir, fname)
  776. #print "Trying to download - ", current
  777. if self.stream["img"]:
  778. try:
  779. thumb = urllib2.urlopen(stream["img"]).read()
  780. except:
  781. thumb = ""
  782. if thumb:
  783. imgext = ".jpg"
  784. m = re.search("(\.\w{3})$",stream["img"])
  785. if m:
  786. imgext = m.group(1)
  787. imgfile = os.path.join(downloadDir,fname0+imgext)
  788. with open(imgfile,"wb") as f:
  789. f.write(thumb)
  790. if self.stream["subs"]:
  791. suburl = self.stream["subs"][0]["url"]
  792. print "\n**Download subtitles %s - %s"%(title,suburl)
  793. subs = urllib2.urlopen(suburl).read()
  794. if subs:
  795. #fname0 = re.sub("[/\n\r\t,:]"," ",title)
  796. subext = ".srt"
  797. subfile = os.path.join(downloadDir,fname0+subext)
  798. if ".xml" in suburl:
  799. subs = util.ttaf2srt(subs)
  800. with open(subfile,"w") as f:
  801. f.write(subs)
  802. else:
  803. print "\n Error downloading subtitle %s"%suburl
  804. if "nfo" in self.stream and self.stream["nfo"]:
  805. nfofile = subfile = os.path.join(downloadDir,fname0+".nfo")
  806. with open(nfofile,"w") as f:
  807. nfo_type,nfo = next(self.stream["nfo"].iteritems())
  808. f.write("<%s>\n"%nfo_type.encode("utf8"))
  809. for k,v in nfo.iteritems():
  810. if isinstance(v,unicode): v = v.encode("utf8")
  811. f.write(" <%s>%s</%s>\n"%(k.encode("utf8"), v, k.encode("utf8")))
  812. f.write("</%s>\n"%nfo_type.encode("utf8"))
  813. overwrite = config.plugins.playstream.overwrite_download.value
  814. if not overwrite and os.path.exists(outputfile):
  815. self.msg( _('Sorry, this file already exists:\n%s') % outputfile)
  816. return False
  817. #os.remove(outputfile)
  818. if stream_type in ("http","https"):
  819. print "\n**Download %s - %s"%(title,url)
  820. #reload(downloadJob)
  821. job_manager.AddJob(downloadJob(url, outputfile, title[:20], self.video_download_stop))
  822. self.activeDownloads += 1
  823. #self.msg(_('Video download started!'))
  824. return True
  825. elif stream_type == "hls":
  826. #self.msg("HLS stream download not yet implemented!")
  827. print "\n**Download %s - %s"%(title,url)
  828. #reload(HLSDownloadJob)
  829. print "HLSDownload", url,outputfile
  830. job_manager.AddJob(HLSDownloadJob(url, outputfile, title[:20], self.video_download_stop))
  831. self.activeDownloads += 1
  832. #self.msg(_('Video download started!'))
  833. return True
  834. elif stream_type == "rstp":
  835. self.msg("RSTP stream download not yet implemented!")
  836. return False
  837. else:
  838. self.msg("Unkown stream type!")
  839. return False
  840. def cb_rename(self,value):
  841. if not value:
  842. return
  843. lst = self.cur_menu[1].replace("config::","")
  844. pos = self.index
  845. print value
  846. item2 = list(self.current)
  847. item2[0]=value
  848. item2 = tuple(item2)
  849. self.config.replace_item(lst,item2,pos)
  850. self.config.write_streams()
  851. txt = "'%s' renamed to '%s'"%(self.current[0],value)
  852. self.session.open(MessageBox, txt, MessageBox.TYPE_INFO,timeout=5)
  853. def cb_favorites(self,answer):
  854. print "cb_favorites",answer,self.current
  855. if not answer:
  856. return
  857. value = answer[1]
  858. self.config.add_item(value,self.current)
  859. self.config.write_streams()
  860. txt = "'%s' added to favourite stream list '%s'"%(self.current[0],value)
  861. self.session.open(MessageBox, txt, MessageBox.TYPE_INFO,timeout=3)
  862. #self.session.openWithCallback(self.callMyMsg, MessageBox, _("Do you want to exit the plugin?"), MessageBox.TYPE_INFO)
  863. def config_screen(self):
  864. self.session.open(ConfigScreen,self)
  865. def options_screen(self):
  866. source = self.cur_menu[1].split("::")[0]
  867. options = self.sources.options_read(source)
  868. print source
  869. if not options:
  870. self.session. open(MessageBox, "No options available for source %s (%s)"%(self.cur_menu[0],source) , MessageBox.TYPE_INFO)
  871. else:
  872. self.session.open(OptionsScreen,self)
  873. def video_download_stop(self,title):
  874. #self.activeDownloads -= 1
  875. #self.msg("Download '%s'finished!"%title)
  876. print "video_download_stop ", title
  877. def msg2(self,msg,timeout=10,mtype = None):
  878. mtype=mtype if mtype else MessageBox.TYPE_INFO
  879. Notifications.AddPopup(text = msg, type=mtype, timeout=timeout)
  880. def msg(self,msg,timeout=10):
  881. self.session.open(MessageBox, msg, MessageBox.TYPE_INFO, timeout)
  882. ##########################################################################
  883. from Components.config import config, ConfigSubsection, ConfigYesNo,\
  884. getConfigListEntry, ConfigSelection, ConfigNumber, ConfigDirectory,ConfigText, ConfigSubDict
  885. from Components.ConfigList import ConfigListScreen
  886. #from Screens.LocationBox import LocationBox
  887. #config.plugins.playstream = ConfigSubDict()
  888. class OptionsScreen(ConfigListScreen,Screen):
  889. skin = """
  890. <screen position="center,center" size="560,400" >
  891. <ePixmap name="red" position="0,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
  892. <widget name="key_red" position="0,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  893. <ePixmap name="green" position="140,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
  894. <widget name="key_green" position="140,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  895. <ePixmap name="yellow" position="280,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
  896. <widget name="key_yellow" position="280,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  897. <ePixmap name="blue" position="420,0" zPosition="2" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
  898. <widget name="key_blue" position="420,0" size="140,40" valign="center" halign="center" zPosition="4" foregroundColor="white" font="Regular;20" transparent="1" shadowColor="background" shadowOffset="-2,-2" />
  899. <widget name="config" position="10,40" size="540,340" scrollbarMode="showOnDemand" />
  900. </screen>"""
  901. def __init__(self, session,*args):
  902. self.session = session
  903. Screen.__init__(self, session)
  904. self.main = args[0]
  905. self.setTitle(self.main.cur_menu[0]+" options")
  906. self.source = self.main.cur_menu[1].split("::")[0]
  907. self.cfg = ConfigSubDict() #config.plugins.playstream
  908. self.list = []
  909. self.options = self.main.sources.options_read(self.source)
  910. if not self.options:
  911. #self.session. open(MessageBox, "No options available for source %s (%s)"%(self.main.cur_menu[0],self.source) , MessageBox.TYPE_INFO)
  912. self.close(False,self.session)
  913. for k in self.options:
  914. self.cfg[k]=ConfigText(default=self.options[k],fixed_size=False)
  915. self.list.append(getConfigListEntry(k, self.cfg[k]))
  916. ConfigListScreen.__init__(self, self.list, session = self.session)
  917. self["key_red"] = Button(_("Cancel"))
  918. self["key_green"] = Button("Save")
  919. self["key_yellow"] = Button("")
  920. self["key_blue"] = Button("")
  921. self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
  922. {
  923. "red": self.cancel,
  924. "green": self.save,
  925. "save": self.save,
  926. "cancel": self.cancel,
  927. "ok": self.ok,
  928. }, -2)
  929. def getCurrentEntry(self):
  930. return self["config"].getCurrent()[0]
  931. def getCurrentValue(self):
  932. return str(self["config"].getCurrent()[1].getText())
  933. def ok(self):
  934. self.save()
  935. #if self["config"].getCurrent()[1] == config.plugins.getpicons.folder:
  936. #folder = config.plugins.getpicons.folder.value
  937. #self.session.openWithCallback(self.change_dir, LocationBox,"Select Folder")
  938. #else:
  939. #def change_dir(self, folder, select=None):
  940. #if folder:
  941. ##print "change_dir to %s"%folder
  942. #config.plugins.getpicons.folder.value = folder
  943. def save(self):
  944. print "saving"
  945. #self.saveAll()
  946. for k in self.options.keys():
  947. self.options[k]=self.cfg[k].value
  948. print "%s=%s"%(k,self.cfg[k].value)
  949. self.main.sources.options_write(self.source,self.options)
  950. self.close(True,self.session)
  951. def cancel(self):
  952. print "cancel"
  953. self.close(False,self.session)