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