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