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