use skin of MoviePlayer
[enigma2-plugins.git] / podcast / src / plugin.py
1 ##
2 ## Podcast
3 ## by AliAbdul
4 ##
5 from Components.ActionMap import ActionMap
6 from Components.config import config, ConfigSelection, ConfigSubsection, ConfigText, ConfigYesNo, getConfigListEntry
7 from Components.ConfigList import ConfigListScreen\r
8 from Components.FileList import FileList
9 from Components.Label import Label
10 from Components.Language import language\r
11 from Components.MenuList import MenuList
12 from Components.PluginComponent import plugins
13 from Components.ProgressBar import ProgressBar\r
14 from enigma import eServiceReference, eTimer
15 from os import environ, remove
16 from Plugins.Plugin import PluginDescriptor
17 from Screens.InfoBar import MoviePlayer
18 from Screens.MessageBox import MessageBox
19 from Screens.Screen import Screen
20 from Tools.BoundFunction import boundFunction
21 from Tools.Directories import fileExists, resolveFilename, SCOPE_LANGUAGE, SCOPE_PLUGINS
22 from Tools.Downloader import downloadWithProgress
23 from twisted.web.client import getPage
24 from xml.etree.cElementTree import parse
25 import gettext, re
26
27 ###################################################
28
29 def localeInit():
30         lang = language.getLanguage()
31         environ["LANGUAGE"] = lang[:2]\r
32         gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))\r
33         gettext.textdomain("enigma2")
34         gettext.bindtextdomain("Podcast", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/Podcast/locale/"))
35
36 def _(txt):\r
37         t = gettext.dgettext("Podcast", txt)\r
38         if t == txt:\r
39                 t = gettext.gettext(txt)\r
40         return t
41
42 localeInit()\r
43 language.addCallback(localeInit)
44
45 ###################################################
46
47 class ChangedMoviePlayer(MoviePlayer):
48         def __init__(self, session, service):
49                 MoviePlayer.__init__(self, session, service)
50                 self.skinName = "MoviePlayer"
51
52         def leavePlayer(self):
53                 self.session.openWithCallback(self.leavePlayerConfirmed, MessageBox, _("Stop playing this movie?"))
54
55         def leavePlayerConfirmed(self, answer):
56                 if answer:
57                         self.close()
58
59         def doEofInternal(self, playing):
60                 pass
61
62         def getPluginList(self):
63                 list = []
64                 for p in plugins.getPlugins(where=PluginDescriptor.WHERE_EXTENSIONSMENU):
65                         if p.name != _("Podcast"):
66                                 list.append(((boundFunction(self.getPluginName, p.name), boundFunction(self.runPlugin, p), lambda: True), None))
67                 return list
68
69         def showMovies(self):
70                 pass
71
72 ###################################################
73
74 config.plugins.Podcast = ConfigSubsection()
75 config.plugins.Podcast.buffer = ConfigYesNo(default=True)
76 config.plugins.Podcast.bufferDevice = ConfigText(default="/media/hdd/", fixed_size=False)
77 config.plugins.Podcast.keepStored = ConfigSelection(choices={"delete": _("delete"), "keep": _("keep on device"), "ask": _("ask me")}, default="delete")
78
79 ###################################################
80
81 def encodeUrl(url):
82         url = url.replace("&", "&")
83         url = url.replace("&lt;", "<")
84         url = url.replace("&gt;", ">")
85         url = url.replace("&#39;", "'")
86         url = url.replace("&quot;", '"')
87         url = url.replace("&#42;", "*")
88         url = url.replace("&#124;", "|")
89         url = url.replace("&#039;", "'")
90         url = url.replace("&#187;", ">>")
91         return url
92
93 ###################################################
94
95 class BufferThread():
96         def __init__(self):
97                 self.progress = 0
98                 self.downloading = False
99                 self.error = ""
100                 self.download = None
101
102         def startDownloading(self, url, file):
103                 self.progress = 0
104                 self.downloading = True
105                 self.error = ""
106                 self.download = downloadWithProgress(url, file)
107                 self.download.addProgress(self.httpProgress)
108                 self.download.start().addCallback(self.httpFinished).addErrback(self.httpFailed)
109
110         def httpProgress(self, recvbytes, totalbytes):
111                 self.progress = int(100 * recvbytes / float(totalbytes))
112
113         def httpFinished(self, string=""):
114                 self.downloading = False
115                 if string is not None:
116                         self.error = str(string)
117                 else:
118                         self.error = ""
119
120         def httpFailed(self, failure_instance=None, error_message=""):
121                 self.downloading = False
122                 if error_message == "" and failure_instance is not None:
123                         error_message = failure_instance.getErrorMessage()
124                         self.error = str(error_message)
125
126         def stop(self):
127                 self.progress = 0
128                 self.downloading = False
129                 self.error = ""
130                 self.download.stop()
131
132 bufferThread = BufferThread()
133
134 ###################################################
135
136 class PodcastBuffer(Screen):
137         skin = """
138                 <screen position="center,center" size="520,80" title="%s" >\r
139                         <widget name="info" position="5,5" size="510,40" font="Regular;18" halign="center" valign="center" />
140                         <widget name="progress" position="100,50" size="320,14" pixmap="skin_default/progress_big.png" borderWidth="2" borderColor="#cccccc" />\r
141                 </screen>""" % _("Podcast")
142 \r
143         def __init__(self, session, url, file):
144                 self.session = session
145                 Screen.__init__(self, session)
146                 
147                 self.url = url
148                 self.file = file
149                 
150                 self.infoTimer = eTimer()
151                 self.infoTimer.timeout.get().append(self.updateInfo)
152                 
153                 self["info"] = Label(_("Downloading movie: %s") % self.file)
154                 self["progress"] = ProgressBar()
155                 
156                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.okClicked, "cancel": self.exit}, -1)
157                 
158                 self.onLayoutFinish.append(self.downloadMovie)
159
160         def downloadMovie(self):
161                 bufferThread.startDownloading(self.url, self.file)
162                 self.infoTimer.start(300, False)
163
164         def updateInfo(self):
165                 if bufferThread.error != "":
166                         self["info"].setText(bufferThread.error)
167                         self.infoTimer.stop()
168                 else:
169                         progress = int(bufferThread.progress)
170                         self["progress"].setValue(progress)
171                         if progress == 100:
172                                 self.infoTimer.stop()
173                                 self.close(True)
174
175         def okClicked(self):
176                 if int(bufferThread.progress) > 0:
177                         self.infoTimer.stop()
178                         self.close(True)
179
180         def exit(self):
181                 bufferThread.download.stop()
182                 self.close(None)
183
184 ###################################################
185
186 class PodcastMovies(Screen):
187         skin = """
188                 <screen position="center,center" size="420,360" title="%s" >\r
189                         <widget name="list" position="5,5" size="410,250" scrollbarMode="showOnDemand" />\r
190                         <eLabel position="5,260" size="420,2" backgroundColor="#ffffff" />\r
191                         <widget name="info" position="5,265" size="420,90" font="Regular;18" />\r
192                 </screen>""" % _("Podcast")
193 \r
194         def __init__(self, session, url):
195                 self.session = session
196                 Screen.__init__(self, session)
197                 
198                 self.url = url
199                 self.list = []
200                 self.movies = []
201                 self.working = True
202                 
203                 self["list"] = MenuList([])
204                 self["list"].onSelectionChanged.append(self.showInfo)
205                 self["info"] = Label()
206                 
207                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
208                 
209                 self.onLayoutFinish.append(self.downloadMovies)
210
211         def ok(self):
212                 if self.working == False:
213                         if len(self.list) > 0:\r
214                                 idx = self["list"].getSelectionIndex()\r
215                                 (url, length, type) = self.splitExtraInfo(self.movies[idx][2])
216                                 if config.plugins.Podcast.buffer.value:
217                                         file = url
218                                         while file.__contains__("/"):
219                                                 idx = file.index("/")
220                                                 file = file[idx+1:]
221                                         self.file = "%s%s" % (config.plugins.Podcast.bufferDevice.value, file)
222                                         self.session.openWithCallback(self.bufferCallback, PodcastBuffer, url, self.file)
223                                 else:
224                                         ref = eServiceReference(4097, 0, url)
225                                         self.session.open(ChangedMoviePlayer, ref)
226
227         def bufferCallback(self, callback):
228                 if callback is not None:
229                         ref = eServiceReference(4097, 0, self.file)
230                         self.session.openWithCallback(self.delete, ChangedMoviePlayer, ref)
231
232         def delete(self, callback=None):
233                 if bufferThread.downloading: #still downloading?
234                         bufferThread.stop()
235                 if config.plugins.Podcast.keepStored.value == "delete":
236                         remove(self.file)
237                 elif config.plugins.Podcast.keepStored.value == "ask":
238                         self.session.openWithCallback(self.deleteCallback, MessageBox, _("Delete this movie?"))
239
240         def deleteCallback(self, callback):
241                 if callback:
242                         remove(self.file)
243
244         def exit(self):
245                 if self.working == False:
246                         self.close()
247
248         def downloadMovies(self):
249                 getPage(self.url).addCallback(self.showMovies).addErrback(self.error)
250
251         def showMovies(self, page):
252                 reonecat = re.compile(r'<title>(.+?)</title>.+?<description>(.+?)</description>.+?<pubDate>(.+?)</pubDate>.+?<enclosure(.+?)/>.+?', re.DOTALL)\r
253                 for title, description, pubDate, extra in reonecat.findall(page):
254                         if title.startswith("<![CDATA["):
255                                 title = title[9:]
256                         if title.endswith("]]>"):
257                                 title = title[:-3]
258                         if description.__contains__("<![CDATA["):
259                                 idx = description.index("<![CDATA[")
260                                 description = description[idx+10:]
261                         if description.endswith("]]>"):
262                                 description = description[:-3]\r
263                         self.list.append(encodeUrl(title))\r
264                         self.movies.append([description, pubDate, extra])\r
265                 self["list"].setList(self.list)\r
266                 self.showInfo()
267                 self.working = False
268
269         def error(self, error=""):
270                 print "[Podcast] Error:", error
271                 self.instance.setTitle(_("Error getting movies"))
272                 self.working = False\r
273 \r
274         def showInfo(self):\r
275                 if len(self.list) > 0:\r
276                         idx = self["list"].getSelectionIndex()\r
277                         description = self.movies[idx][0]\r
278                         pubDate = self.movies[idx][1]\r
279                         (url, length, type) = self.splitExtraInfo(self.movies[idx][2])\r
280                         self["info"].setText("%s: %s\n%s: %s   %s: %s\n%s" % (_("Date"), pubDate, _("Length"), length, _("Type"), type, encodeUrl(description)))\r
281 \r
282         def splitExtraInfo(self, info):\r
283                 if info.__contains__('url="'):\r
284                         idx = info.index('url="')\r
285                         url = info[idx+5:]\r
286                         idx = url.index('"')\r
287                         url = url[:idx]\r
288                 else:\r
289                         url = "N/A"\r
290                 \r
291                 if info.__contains__('length="'):\r
292                         idx = info.index('length="')\r
293                         length = info[idx+8:]\r
294                         idx = length.index('"')\r
295                         length = length[:idx]\r
296                         length = str((int(length) / 1024) / 1024) + " MB"\r
297                 else:\r
298                         length = "N/A"\r
299                 \r
300                 if info.__contains__('type="'):\r
301                         idx = info.index('type="')\r
302                         type = info[idx+6:]\r
303                         idx = type.index('"')\r
304                         type = type[:idx]\r
305                 else:\r
306                         type = "N/A"\r
307                 \r
308                 return (url, length, type)
309
310 ###################################################
311
312 class PodcastPodcasts(Screen):
313         skin = """
314                 <screen position="center,center" size="420,360" title="%s" >\r
315                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
316                 </screen>""" % _("Podcast")
317 \r
318         def __init__(self, session, provider):
319                 self.session = session
320                 Screen.__init__(self, session)
321                 
322                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.close}, -1)
323                 
324                 self.urls = []
325                 list = []
326                 for podcast in provider.findall("podcast"):
327                         name = podcast.get("name") or None
328                         name = name.encode("UTF-8") or name
329                         url = podcast.get("url") or None
330                         if name and url:
331                                 list.append(name)
332                                 self.urls.append(url)
333                 self["list"] = MenuList(list)
334
335         def ok(self):
336                 if len(self.urls) > 0:
337                         cur = self.urls[self["list"].getSelectedIndex()]
338                         self.session.open(PodcastMovies, cur)
339
340 ###################################################
341
342 class PodcastProvider(Screen):
343         skin = """
344                 <screen position="center,center" size="420,360" title="%s" >
345                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
346                 </screen>""" % _("Podcast")
347 \r
348         def __init__(self, session, language):
349                 self.session = session
350                 Screen.__init__(self, session)
351                 
352                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.close}, -1)
353                 
354                 self.providers = []
355                 list = []
356                 for provider in language.findall("provider"):
357                         name = provider.get("name") or None
358                         name = name.encode("UTF-8") or name
359                         if name:
360                                 list.append(name)
361                                 self.providers.append(provider)
362                 self["list"] = MenuList(list)
363
364         def ok(self):
365                 if len(self.providers) > 0:
366                         cur = self.providers[self["list"].getSelectedIndex()]
367                         self.session.open(PodcastPodcasts, cur)
368
369 ###################################################
370
371 class PodcastXML(Screen):
372         skin = """
373                 <screen position="center,center" size="420,360" title="%s" >\r
374                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
375                 </screen>""" % _("Podcast")
376 \r
377         def __init__(self, session):
378                 self.session = session
379                 Screen.__init__(self, session)
380                 
381                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.close}, -1)
382                 
383                 self.languages = []
384                 list = []
385                 file = "/etc/podcast/podcasts.xml"
386                 if fileExists(file):
387                         xml = parse(file).getroot()
388                         for language in xml.findall("language"):
389                                 name = language.get("name") or None
390                                 name = name.encode("UTF-8") or name
391                                 if name:
392                                         list.append(name)
393                                         self.languages.append(language)
394                 self["list"] = MenuList(list)
395
396         def ok(self):
397                 if len(self.languages) > 0:
398                         cur = self.languages[self["list"].getSelectedIndex()]
399                         self.session.open(PodcastProvider, cur)
400
401 ###################################################
402
403 class PodcastComGenre2(Screen):
404         skin = """
405                 <screen position="center,center" size="420,360" title="%s" >\r
406                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
407                 </screen>""" % _("Podcast")
408 \r
409         def __init__(self, session, url):
410                 self.session = session
411                 Screen.__init__(self, session)
412                 
413                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
414                 
415                 self.url = url
416                 self.urls = []
417                 self.working = True
418                 self["list"] = MenuList([])
419                 
420                 self.onLayoutFinish.append(self.downloadGenres)
421
422         def ok(self):
423                 if self.working == False:
424                         if len(self.urls) > 0:
425                                 self.working = True
426                                 cur = self.urls[self["list"].getSelectedIndex()]
427                                 getPage(cur).addCallback(self.getRssUrl).addErrback(self.error2)
428
429         def getRssUrl(self, page):
430                 idx = page.index('">rss feed</a><br>')
431                 page = page[:idx]
432                 while page.__contains__("http://"):
433                         idx = page.index("http://")
434                         page = page[idx+1:]
435                 self.working = False
436                 self.session.open(PodcastMovies, "h%s"%page)
437
438         def exit(self):
439                 if self.working == False:
440                         self.close()
441
442         def downloadGenres(self):
443                 getPage(self.url).addCallback(self.getGenres).addErrback(self.error)
444
445         def getGenres(self, page):
446                 list = []
447                 reonecat = re.compile(r'height="19"><a href="(.+?)">(.+?)</a>', re.DOTALL)\r
448                 for url, title in reonecat.findall(page):\r
449                         list.append(encodeUrl(title))\r
450                         self.urls.append(url)\r
451                 self["list"].setList(list)
452                 self.working = False
453
454         def error(self, error=""):
455                 print "[Podcast] Error:", error
456                 self.instance.setTitle(_("Error getting genres"))
457                 self.working = False
458
459         def error2(self, error=""):
460                 print "[Podcast] Error:", error
461                 self.instance.setTitle(_("Error getting rss feed"))
462                 self.working = False
463
464 ###################################################
465
466 class PodcastComGenre(Screen):
467         skin = """
468                 <screen position="center,center" size="420,360" title="%s" >
469                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
470                 </screen>""" % _("Podcast")
471 \r
472         def __init__(self, session, url):
473                 self.session = session
474                 Screen.__init__(self, session)
475                 
476                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
477                 
478                 self.url = url
479                 self.urls = []
480                 self.working = True
481                 self["list"] = MenuList([])
482                 
483                 self.onLayoutFinish.append(self.downloadSite)
484
485         def ok(self):
486                 if self.working == False:
487                         if len(self.urls) > 0:
488                                 cur = self.urls[self["list"].getSelectedIndex()]
489                                 self.session.open(PodcastComGenre2, cur)
490
491         def exit(self):
492                 if self.working == False:
493                         self.close()
494
495         def downloadSite(self):
496                 getPage(self.url).addCallback(self.getUrl).addErrback(self.error)
497
498         def getUrl(self, page):
499                 reonecat = re.compile(r'Get this podcast channel on your mobile phone:</strong><br><a href="(.+?)"', re.DOTALL)
500                 list = reonecat.findall(page)
501                 if len(list) > 0:
502                         getPage(list[0]).addCallback(self.getGenres).addErrback(self.error)
503                 else:
504                         self.error("Error getting movies-url")
505
506         def getGenres(self, page):
507                 list = []
508                 reonecat = re.compile(r'height="17"><a title="(.+?)" href="(.+?)">(.+?)</a>', re.DOTALL)\r
509                 for title2, url, title in reonecat.findall(page):\r
510                         list.append(encodeUrl(title))\r
511                         self.urls.append(url)\r
512                 self["list"].setList(list)
513                 self.working = False
514
515         def error(self, error=""):
516                 print "[Podcast] Error:", error
517                 self.instance.setTitle(_("Error getting genres"))
518                 self.working = False
519
520 ###################################################
521
522 class PodcastCom(Screen):
523         skin = """
524                 <screen position="center,center" size="420,360" title="%s" >
525                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
526                 </screen>""" % _("Podcast")
527 \r
528         def __init__(self, session):
529                 self.session = session
530                 Screen.__init__(self, session)
531                 
532                 self.working = True
533                 self.urls = []
534                 
535                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
536                 
537                 self["list"] = MenuList([])
538                 
539                 self.onLayoutFinish.append(self.downloadMovies)
540
541         def ok(self):
542                 if self.working == False:
543                         if len(self.urls) > 0:
544                                 cur = self.urls[self["list"].getSelectedIndex()]
545                                 self.session.open(PodcastComGenre, cur)
546
547         def exit(self):
548                 if self.working == False:
549                         self.close()
550
551         def downloadMovies(self):
552                 getPage("http://podcast.com/home.php?subpage=_pages/channels_home.php").addCallback(self.showGenres).addErrback(self.error)
553
554         def showGenres(self, page):
555                 list = []
556                 reonecat = re.compile(r'<li><a href="(.+?)" title="(.+?)">(.+?)</a></li>', re.DOTALL)\r
557                 for url, title2, title in reonecat.findall(page):
558                         if not title.startswith("<"):\r
559                                 list.append(encodeUrl(title))\r
560                                 self.urls.append(url)\r
561                 self["list"].setList(list)
562                 self.working = False
563
564         def error(self, error=""):
565                 print "[Podcast] Error:", error
566                 self.instance.setTitle(_("Error getting genres"))
567                 self.working = False
568
569 ###################################################
570
571 class LocationSelection(Screen):
572         skin = """
573         <screen position="center,center" size="560,300" title="%s">
574                 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />
575                 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />
576                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />
577                 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />
578                 <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
579                 <widget name="filelist" position="10,45" size="550,255" scrollbarMode="showOnDemand" />
580         </screen>""" % _("Podcast")\r
581 \r
582         def __init__(self, session, dir="/"):\r
583                 Screen.__init__(self, session)\r
584                 \r
585                 self["key_green"] = Label(_("Select"))\r
586                 \r
587                 try: self["filelist"] = FileList(dir, showDirectories=True, showFiles=False)\r
588                 except: self["filelist"] = FileList("/", showDirectories, showFiles)\r
589                 \r
590                 self["actions"] = ActionMap(["ColorActions", "OkCancelActions"],\r
591                         {\r
592                                 "ok": self.okClicked,\r
593                                 "cancel": self.exit,\r
594                                 "green": self.select\r
595                         }, -1)
596                 
597                 self.onLayoutFinish.append(self.updateDirectoryName)\r
598                 \r
599         def okClicked(self):\r
600                 if self["filelist"].canDescent():\r
601                         self["filelist"].descent()\r
602                         self["filelist"].instance.moveSelectionTo(0)\r
603                         self.updateDirectoryName()\r
604 \r
605         def exit(self):\r
606                 self.close(None)\r
607 \r
608         def select(self):\r
609                 dir = self["filelist"].getCurrentDirectory()\r
610                 if dir is not None:\r
611                         self.close(dir)\r
612                 else:\r
613                         self.close(None)\r
614 \r
615         def updateDirectoryName(self):
616                 try:
617                         dir = self["filelist"].getCurrentDirectory()
618                         self.instance.setTitle(dir)
619                 except:
620                         self.instance.setTitle("?")
621
622 ###################################################
623
624 class PodcastConfig(ConfigListScreen, Screen):
625         skin = """
626         <screen position="center,center" size="560,180" title="%s">
627                 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />
628                 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />
629                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />
630                 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />
631                 <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
632                 <widget name="config" position="10,45" size="550,125" scrollbarMode="showOnDemand" />
633         </screen>""" % _("Podcast")
634
635         def __init__(self, session):
636                 Screen.__init__(self, session)
637                 
638                 self["key_green"] = Label(_("Save"))
639                 
640                 ConfigListScreen.__init__(self, [])
641                         
642                 
643                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions"], {"green": self.save, "cancel": self.exit}, -1)
644                 
645                 self.onLayoutFinish.append(self.createConfig)
646
647         def createConfig(self):
648                 self.deviceEntry = ConfigSelection(choices=[config.plugins.Podcast.bufferDevice.value], default=config.plugins.Podcast.bufferDevice.value)
649                 self["config"].list = [
650                         getConfigListEntry(_("Buffer:"), config.plugins.Podcast.buffer),
651                         getConfigListEntry(_("Buffer device:"), self.deviceEntry),
652                         getConfigListEntry(_("Buffer file handling:"), config.plugins.Podcast.keepStored)]
653
654         def keyLeft(self):
655                 ConfigListScreen.keyLeft(self)
656                 self.handleKeysLeftAndRight()
657
658         def keyRight(self):
659                 ConfigListScreen.keyRight(self)
660                 self.handleKeysLeftAndRight()
661
662         def handleKeysLeftAndRight(self):
663                 sel = self["config"].getCurrent()[1]
664                 if sel == self.deviceEntry:
665                         self.session.openWithCallback(self.locationSelected, LocationSelection, config.plugins.Podcast.bufferDevice.value)
666
667         def locationSelected(self, dir):
668                 if dir is not None and dir != "?":
669                         config.plugins.Podcast.bufferDevice.value = dir
670                         config.plugins.Podcast.bufferDevice.save()
671                         self.createConfig()
672
673         def save(self):
674                 for x in self["config"].list:
675                         x[1].save()
676                 self.close()
677
678         def exit(self):
679                 for x in self["config"].list:
680                         x[1].cancel()
681                 self.close()
682
683 ###################################################
684
685 class PodcastDeEpisodes(Screen):
686         skin = """
687                 <screen position="center,center" size="420,360" title="%s" >
688                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
689                 </screen>""" % _("Podcast")
690
691         def __init__(self, session, url):
692                 self.session = session
693                 Screen.__init__(self, session)
694                 
695                 self.working = True
696                 self.url = url
697                 self.urls = []
698                 
699                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
700                 
701                 self["list"] = MenuList([])
702                 
703                 self.onLayoutFinish.append(self.downloadMovies)
704
705         def ok(self):
706                 if self.working == False:
707                         self.instance.setTitle(_("Podcast"))
708                         if len(self.urls) > 0:
709                                 cur = self.urls[self["list"].getSelectedIndex()]
710                                 self.working = True
711                                 getPage(cur).addCallback(self.playPodcast).addErrback(self.error2)
712
713         def playPodcast(self, url):
714                 if url.__contains__('" id="control_download"'):
715                         self.working = False
716                         idx = url.index('" id="control_download"')
717                         url = url[:idx]
718                         while url.__contains__("http://"):
719                                 idx = url.index("http://")
720                                 url = url[idx+1:]
721                         url = "h%s"%url
722                         
723                         if config.plugins.Podcast.buffer.value:
724                                 file = url
725                                 while file.__contains__("/"):
726                                         idx = file.index("/")
727                                         file = file[idx+1:]
728                                 self.file = "%s%s" % (config.plugins.Podcast.bufferDevice.value, file)
729                                 self.session.openWithCallback(self.bufferCallback, PodcastBuffer, url, self.file)
730                         else:
731                                 ref = eServiceReference(4097, 0, url)
732                                 self.session.open(ChangedMoviePlayer, ref)
733                 else:
734                         self.error2()
735
736         def bufferCallback(self, callback):
737                 if callback is not None:
738                         ref = eServiceReference(4097, 0, self.file)
739                         self.session.openWithCallback(self.delete, ChangedMoviePlayer, ref)
740
741         def delete(self, callback=None):
742                 if bufferThread.downloading: #still downloading?
743                         bufferThread.stop()
744                 if config.plugins.Podcast.keepStored.value == "delete":
745                         remove(self.file)
746                 elif config.plugins.Podcast.keepStored.value == "ask":
747                         self.session.openWithCallback(self.deleteCallback, MessageBox, _("Delete this movie?"))
748
749         def deleteCallback(self, callback):
750                 if callback:
751                         remove(self.file)
752
753         def exit(self):
754                 if self.working == False:
755                         self.close()
756
757         def downloadMovies(self):
758                 getPage(self.url).addCallback(self.showEpisodes).addErrback(self.error)
759
760         def showEpisodes(self, page):
761                 list = []
762                 idx = page.index('<h3>')
763                 page = page[idx:]
764                 idx = page.index('</div></div>')
765                 page = page[:idx]
766                 reonecat = re.compile(r'<a href="(.+?)" title="(.+?)">', re.DOTALL)\r
767                 for url, title in reonecat.findall(page):
768                         if title.startswith("Episode: "):
769                                 title = title[9:]\r
770                         list.append(encodeUrl(title))\r
771                         self.urls.append(url)\r
772                 self["list"].setList(list)
773                 self.working = False
774
775         def error(self, error=""):
776                 print "[Podcast] Error:", error
777                 self.instance.setTitle(_("Error getting episodes"))
778                 self.working = False
779
780         def error2(self, error=""):
781                 print "[Podcast] Error: Error getting podcast url"
782                 self.instance.setTitle(_("Error getting podcast url"))
783                 self.working = False
784
785 ###################################################
786
787 class PodcastDePodcasts(Screen):
788         skin = """
789                 <screen position="center,center" size="420,360" title="%s" >
790                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
791                 </screen>""" % _("Podcast")
792
793         def __init__(self, session, url):
794                 self.session = session
795                 Screen.__init__(self, session)
796                 
797                 self.working = True
798                 self.url = url
799                 self.urls = []
800                 
801                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
802                 
803                 self["list"] = MenuList([])
804                 
805                 self.onLayoutFinish.append(self.downloadMovies)
806
807         def ok(self):
808                 if self.working == False:
809                         if len(self.urls) > 0:
810                                 cur = self.urls[self["list"].getSelectedIndex()]
811                                 self.session.open(PodcastDeEpisodes, cur)
812
813         def exit(self):
814                 if self.working == False:
815                         self.close()
816
817         def downloadMovies(self):
818                 getPage(self.url).addCallback(self.showPodcasts).addErrback(self.error)
819
820         def showPodcasts(self, page):
821                 list = []
822                 idx = page.index('<h4>Podcasts</h4>')
823                 page = page[idx:]
824                 idx = page.index('</div>')
825                 page = page[:idx]
826                 reonecat = re.compile(r'alt="(.+?)" class="(.+?)<a href="(.+?)" title="(.+?)">(.+?)<span class="(.+?)"></span>', re.DOTALL)\r
827                 for title, x, url, x2, x3, type in reonecat.findall(page):
828                         if type.__contains__("content_type_1_icon"):
829                                 text = _(" (Audio)")
830                         else:
831                                 text = _(" (Video)")\r
832                         list.append(encodeUrl(title+text))\r
833                         self.urls.append(url)\r
834                 self["list"].setList(list)
835                 self.working = False
836
837         def error(self, error=""):
838                 print "[Podcast] Error:", error
839                 self.instance.setTitle(_("Error getting podcasts"))
840                 self.working = False
841
842 ###################################################
843
844 class PodcastDeCategories(Screen):
845         skin = """
846                 <screen position="center,center" size="420,360" title="%s" >
847                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
848                 </screen>""" % _("Podcast")
849
850         def __init__(self, session, url):
851                 self.session = session
852                 Screen.__init__(self, session)
853                 
854                 self.working = True
855                 self.url = url
856                 self.urls = []
857                 
858                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
859                 
860                 self["list"] = MenuList([])
861                 
862                 self.onLayoutFinish.append(self.downloadMovies)
863
864         def ok(self):
865                 if self.working == False:
866                         if len(self.urls) > 0:
867                                 cur = self.urls[self["list"].getSelectedIndex()]
868                                 self.session.open(PodcastDePodcasts, cur)
869
870         def exit(self):
871                 if self.working == False:
872                         self.close()
873
874         def downloadMovies(self):
875                 getPage(self.url).addCallback(self.showCategories).addErrback(self.error)
876
877         def showCategories(self, page):
878                 list = []
879                 idx = page.index('<h3>')
880                 page = page[idx:]
881                 idx = page.index('</div>')
882                 page = page[:idx]
883                 reonecat = re.compile(r'<a href="(.+?)" title="(.+?)">', re.DOTALL)\r
884                 for url, title in reonecat.findall(page):\r
885                         list.append(encodeUrl(title))\r
886                         self.urls.append(url)\r
887                 self["list"].setList(list)
888                 self.working = False
889
890         def error(self, error=""):
891                 print "[Podcast] Error:", error
892                 self.instance.setTitle(_("Error getting categories"))
893                 self.working = False
894
895 ###################################################
896
897 class PodcastDe(Screen):
898         skin = """
899                 <screen position="center,center" size="420,360" title="%s" >
900                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
901                 </screen>""" % _("Podcast")
902
903         def __init__(self, session):
904                 self.session = session
905                 Screen.__init__(self, session)
906                 
907                 self.working = True
908                 self.urls = []
909                 
910                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.exit}, -1)
911                 
912                 self["list"] = MenuList([])
913                 
914                 self.onLayoutFinish.append(self.downloadMovies)
915
916         def ok(self):
917                 if self.working == False:
918                         if len(self.urls) > 0:
919                                 cur = self.urls[self["list"].getSelectedIndex()]
920                                 self.session.open(PodcastDeCategories, cur)
921
922         def exit(self):
923                 if self.working == False:
924                         self.close()
925
926         def downloadMovies(self):
927                 getPage("http://m.podcast.de/kategorien").addCallback(self.showCategories).addErrback(self.error)
928
929         def showCategories(self, page):
930                 list = []
931                 idx = page.index('<h3>')
932                 page = page[idx:]
933                 idx = page.index('</div>')
934                 page = page[:idx]
935                 reonecat = re.compile(r'<a href="(.+?)" title="(.+?)">', re.DOTALL)\r
936                 for url, title in reonecat.findall(page):\r
937                         list.append(encodeUrl(title))\r
938                         self.urls.append(url)\r
939                 self["list"].setList(list)
940                 self.working = False
941
942         def error(self, error=""):
943                 print "[Podcast] Error:", error
944                 self.instance.setTitle(_("Error getting categories"))
945                 self.working = False
946
947 ###################################################
948
949 class Podcast(Screen):
950         skin = """
951                 <screen position="center,center" size="420,360" title="%s" >
952                         <widget name="list" position="0,0" size="420,350" scrollbarMode="showOnDemand" />\r
953                 </screen>""" % _("Podcast")
954 \r
955         def __init__(self, session):
956                 self.session = session
957                 Screen.__init__(self, session)
958                 
959                 self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.ok, "cancel": self.close}, -1)
960                 
961                 self["list"] = MenuList([
962                         _("podcast.de"),
963                         _("podcast.com"),
964                         _("from xml"),
965                         _("configuration")])
966
967         def ok(self):
968                 cur = self["list"].getCurrent()
969                 if cur == _("podcast.de"):
970                         self.session.open(PodcastDe)
971                 elif cur == _("podcast.com"):
972                         self.session.open(PodcastCom)
973                 elif cur == _("from xml"):
974                         self.session.open(PodcastXML)
975                 else:
976                         self.session.open(PodcastConfig)
977
978 ###################################################
979
980 def main(session, **kwargs):
981         session.open(Podcast)
982
983 def Plugins(**kwargs):
984         return PluginDescriptor(name=_("Podcast"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)