2 from Plugins.Plugin import PluginDescriptor
3 from twisted.web.client import downloadPage
4 from enigma import ePicLoad
5 from Screens.Screen import Screen
6 from Components.ActionMap import ActionMap
7 from Components.Pixmap import Pixmap
8 from Components.Label import Label
9 from Components.ScrollLabel import ScrollLabel
10 from Components.Button import Button
11 from Components.AVSwitch import AVSwitch
12 from Components.MenuList import MenuList
13 from Components.Language import language
14 from Components.ProgressBar import ProgressBar
15 from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
22 <screen name="OFDb" position="90,95" size="560,420" title="Internet Movie Database Details Plugin" >
23 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
24 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
25 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
26 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
27 <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#9f1313" transparent="1" />
28 <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
29 <widget name="key_yellow" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
30 <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
31 <widget name="titellabel" position="10,40" size="330,45" valign="center" font="Regular;22"/>
32 <widget name="detailslabel" position="105,90" size="445,140" font="Regular;18" />
33 <widget name="castlabel" position="10,235" size="540,155" font="Regular;18" />
34 <widget name="extralabel" position="10,40" size="540,350" font="Regular;18" />
35 <widget name="ratinglabel" position="340,62" size="210,20" halign="center" font="Regular;18" foregroundColor="#f0b400"/>
36 <widget name="statusbar" position="10,404" size="540,16" font="Regular;16" foregroundColor="#cccccc" />
37 <widget name="poster" position="4,90" size="96,140" alphatest="on" />
38 <widget name="menu" position="10,115" size="540,275" zPosition="3" scrollbarMode="showOnDemand" />
39 <widget name="starsbg" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/OFDb/starsbar_empty.png" position="340,40" zPosition="0" size="210,21" transparent="1" alphatest="on" />
40 <widget name="stars" position="340,40" size="210,21" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/OFDb/starsbar_filled.png" transparent="1" />
43 def __init__(self, session, eventName, args = None):
45 Screen.__init__(self, session)
46 self.eventName = eventName
47 self.dictionary_init()
48 self["poster"] = Pixmap()
49 self.picload = ePicLoad()
50 self.picload.PictureData.get().append(self.paintPosterPixmapCB)
52 self["stars"] = ProgressBar()
53 self["starsbg"] = Pixmap()
55 self["starsbg"].hide()
57 self["titellabel"] = Label("The Internet Movie Database")
58 self["detailslabel"] = ScrollLabel("")
59 self["castlabel"] = ScrollLabel("")
60 self["extralabel"] = ScrollLabel("")
61 self["statusbar"] = Label("")
62 self["ratinglabel"] = Label("")
64 self["menu"] = MenuList(self.resultlist)
66 self["key_red"] = Button(self._("Exit"))
67 self["key_green"] = Button("")
68 self["key_yellow"] = Button("")
69 self["key_blue"] = Button("")
70 # 0 = multiple query selection menu page
72 # 2 = extra infos page
75 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "MovieSelectionActions", "DirectionActions"],
77 "ok": self.showDetails,
79 "down": self.pageDown,
82 "green": self.showMenu,
83 "yellow": self.showDetails,
84 "blue": self.showExtras,
85 "showEventInfo": self.showDetails
90 def dictionary_init(self):
91 syslang = language.getLanguage()
92 if syslang.find("de") is -1:
93 self.OFDBlanguage = "" # set to empty ("") for english version
95 self.OFDBlanguage = "german." # it's a subdomain, so add a '.' at the end
99 self.dict[" as "]=" als "
100 self.dict["Ambiguous results"]="Kein eindeutiger Treffer"
101 self.dict["Please select the matching entry"]="Bitte passenden Eintrag auswählen"
102 self.dict["No OFDb match."]="Keine passenden Einträge gefunden."
103 self.dict["OFDb query failed!"]="OFDb-Query fehlgeschlagen!"
104 self.dict["No details found."]="Keine Details gefunden."
105 self.dict["no user rating yet"]="noch keine Nutzerwertung"
106 self.dict["Cast: "]="Darsteller: "
107 self.dict["No cast list found in the database."]="Keine Darstellerliste in der Datenbank gefunden."
108 self.dict["Exit"]="Beenden"
109 self.dict["Extra Info"]="Zusatzinfos"
110 self.dict["Title Menu"]="Titelauswahl"
112 self.htmltags = re.compile('<.*?>')
114 self.generalinfomask = re.compile(
115 '<title>OFDb - (?P<title>.*?)</title>.*?'
116 '(?P<g_original>Originaltitel):[\s\S]*?class=\"Daten\">(?P<original>.*?)</td>'
117 '(?:.*?(?P<g_country>Herstellungsland):[\s\S]*?class="Daten">(?P<country>.*?)(?:\.\.\.|</td>))*'
118 '(?:.*?(?P<g_year>Erscheinungsjahr):[\s\S]*?class="Daten">(?P<year>.*?)</td>)*'
119 '(?:.*?(?P<g_director>Regie):[\s\S]*?class="Daten">(?P<director>.*?)(?:\.\.\.|</td>))*'
122 def _(self, in_string):
123 out_string = in_string
124 if ((self.OFDBlanguage).find("german")) != -1:
125 out_string = self.dict.get(in_string, in_string)
128 def resetLabels(self):
129 self["detailslabel"].setText("")
130 self["ratinglabel"].setText("")
131 self["titellabel"].setText("")
132 self["castlabel"].setText("")
133 self["titellabel"].setText("")
134 self["extralabel"].setText("")
135 self.ratingstars = -1
139 self["menu"].instance.moveSelection(self["menu"].instance.moveUp)
141 self["castlabel"].pageUp()
142 self["detailslabel"].pageUp()
144 self["extralabel"].pageUp()
148 self["menu"].instance.moveSelection(self["menu"].instance.moveDown)
150 self["castlabel"].pageDown()
151 self["detailslabel"].pageDown()
153 self["extralabel"].pageDown()
156 if ( self.Page is 1 or self.Page is 2 ) and self.resultlist:
159 self["starsbg"].hide()
160 self["ratinglabel"].hide()
161 self["castlabel"].hide()
162 self["poster"].hide()
163 self["extralabel"].hide()
164 self["titellabel"].setText(self._("Ambiguous results"))
165 self["detailslabel"].setText(self._("Please select the matching entry"))
166 self["detailslabel"].show()
167 self["key_blue"].setText("")
168 self["key_green"].setText(self._("Title Menu"))
169 self["key_yellow"].setText(self._("Details"))
172 def showDetails(self):
173 self["ratinglabel"].show()
174 self["castlabel"].show()
175 self["detailslabel"].show()
177 if self.resultlist and self.Page == 0:
178 link = self["menu"].getCurrent()[1]
179 title = self["menu"].getCurrent()[0]
180 self["statusbar"].setText("Re-Query OFDb: "+title+"...")
181 localfile = "/tmp/ofdbquery2.html"
182 fetchurl = "http://www.ofdb.de/film/" + link
183 print "[OFDb] downloading query " + fetchurl + " to " + localfile
184 downloadPage(fetchurl,localfile).addCallback(self.OFDBquery2).addErrback(self.fetchFailed)
190 self["extralabel"].hide()
191 self["poster"].show()
192 if self.ratingstars > 0:
193 self["starsbg"].show()
195 self["stars"].setValue(self.ratingstars)
199 def showExtras(self):
201 self["extralabel"].show()
202 self["detailslabel"].hide()
203 self["castlabel"].hide()
204 self["poster"].hide()
206 self["starsbg"].hide()
207 self["ratinglabel"].hide()
212 if self.eventName is "":
213 s = self.session.nav.getCurrentService()
215 event = info.getEvent(0) # 0 = now, 1 = next
217 self.eventName = event.getEventName()
219 pos = self.eventName.index("(")
220 self.eventName=self.eventName[0:pos]
224 if self.eventName is not "":
225 self["statusbar"].setText("Query OFDb: " + self.eventName + "...")
227 self.eventName = urllib.quote(self.eventName)
229 self.eventName = urllib.quote(self.eventName.decode('utf8').encode('ascii','ignore'))
230 localfile = "/tmp/ofdbquery.html"
231 fetchurl = "http://www.ofdb.de/view.php?page=suchergebnis&Kat=DTitel&SText=" + self.eventName
232 print "[OFDb] Downloading Query " + fetchurl + " to " + localfile
233 downloadPage(fetchurl,localfile).addCallback(self.OFDBquery).addErrback(self.fetchFailed)
235 self["statusbar"].setText("Could't get Eventname -_-")
237 def fetchFailed(self,string):
238 print "[OFDb] fetch failed " + string
239 self["statusbar"].setText("OFDb Download failed -_-")
241 def html2utf8(self,in_html):
242 htmlentitynumbermask = re.compile('(&#(\d{1,5}?);)')
243 htmlentitynamemask = re.compile('(&(\D{1,5}?);)')
245 entities = htmlentitynamemask.finditer(in_html)
249 entitydict[x.group(1)] = x.group(2)
251 for key, name in entitydict.items():
252 entitydict[key] = htmlentitydefs.name2codepoint[name]
254 entities = htmlentitynumbermask.finditer(in_html)
257 entitydict[x.group(1)] = x.group(2)
259 for key, codepoint in entitydict.items():
260 in_html = in_html.replace(key, (unichr(int(codepoint)).encode('utf8')))
262 self.inhtml = in_html
264 def OFDBquery(self,string):
266 self["statusbar"].setText("OFDb Download completed")
268 self.html2utf8(open("/tmp/ofdbquery.html", "r").read())
270 self.generalinfos = self.generalinfomask.search(self.inhtml)
272 if self.generalinfos:
275 if re.search("<title>OFDb - Suchergebnis</title>", self.inhtml):
276 searchresultmask = re.compile("<br>(\d{1,3}\.) <a href=\"film/(.*?)\"(?:.*?)\)\">(.*?)</a>", re.DOTALL)
277 searchresults = searchresultmask.finditer(self.inhtml)
280 for x in searchresults:
281 self.resultlist.append((self.htmltags.sub('',x.group(3)), x.group(2)))
282 self["menu"].l.setList(self.resultlist)
283 if len(self.resultlist) == 1:
285 self["extralabel"].hide()
287 elif len(self.resultlist) > 1:
291 self["detailslabel"].setText(self._("No OFDb match."))
292 self["statusbar"].setText("No OFDb match")
294 self["detailslabel"].setText(self._("OFDb query failed!"))
296 def OFDBquery2(self,string):
297 self["statusbar"].setText("OFDb Re-Download completed")
298 self.html2utf8(open("/tmp/ofdbquery2.html", "r").read())
299 self.generalinfos = self.generalinfomask.search(self.inhtml)
305 Detailstext = self._("No details found.")
306 if self.generalinfos:
307 self["key_yellow"].setText(self._("Details"))
308 self["statusbar"].setText("OFDb Details parsed ^^")
310 Titeltext = self.generalinfos.group("title")
311 if len(Titeltext) > 57:
312 Titeltext = Titeltext[0:54] + "..."
313 self["titellabel"].setText(Titeltext)
317 genreblockmask = re.compile('Genre\(s\):(?:[\s\S]*?)class=\"Daten\">(.*?)</tr>', re.DOTALL)
318 genreblock = genreblockmask.findall(self.inhtml)
319 genremask = re.compile('\">(.*?)</a')
321 genres = genremask.finditer(genreblock[0])
323 Detailstext += "Genre: "
325 Detailstext += self.htmltags.sub('', x.group(1)) + " "
327 detailscategories = ["director", "year", "country", "original"]
329 for category in detailscategories:
330 if self.generalinfos.group('g_'+category):
331 Detailstext += "\n" + self.generalinfos.group('g_'+category) + ": " + self.htmltags.sub('', self.generalinfos.group(category).replace("<br>",' '))
333 self["detailslabel"].setText(Detailstext)
335 #if self.generalinfos.group("alternativ"):
336 #Detailstext += "\n" + self.generalinfos.group("g_alternativ") + ": " + self.htmltags.sub('',(self.generalinfos.group("alternativ").replace('\n','').replace("<br>",'\n').replace(" ",' ')))
338 ratingmask = re.compile('<td>[\s\S]*notenskala.*(?P<g_rating>Note: )(?P<rating>\d.\d{2,2})[\s\S]*</td>', re.DOTALL)
339 rating = ratingmask.search(self.inhtml)
340 Ratingtext = self._("no user rating yet")
342 Ratingtext = rating.group("g_rating") + rating.group("rating") + " / 10"
343 self.ratingstars = int(10*round(float(rating.group("rating")),1))
345 self["stars"].setValue(self.ratingstars)
346 self["starsbg"].show()
347 self["ratinglabel"].setText(Ratingtext)
349 castblockmask = re.compile('Darsteller:[\s\S]*?class=\"Daten\">(.*?)(?:\.\.\.|\xbb)', re.DOTALL)
350 castblock = castblockmask.findall(self.inhtml)
351 castmask = re.compile('\">(.*?)</a')
354 cast = castmask.finditer(castblock[0])
357 Casttext += "\n" + self.htmltags.sub('', x.group(1))
358 if Casttext is not "":
359 Casttext = self._("Cast: ") + Casttext
361 Casttext = self._("No cast list found in the database.")
362 self["castlabel"].setText(Casttext)
364 postermask = re.compile('<img src=\"(http://img.ofdb.de/film.*?)\" alt', re.DOTALL)
365 posterurl = postermask.search(self.inhtml)
366 if posterurl and posterurl.group(1).find("jpg") > 0:
367 posterurl = posterurl.group(1)
368 self["statusbar"].setText("Downloading Movie Poster: "+posterurl+"...")
369 localfile = "/tmp/poster.jpg"
370 print "[OFDb] downloading poster " + posterurl + " to " + localfile
371 downloadPage(posterurl,localfile).addCallback(self.OFDBPoster).addErrback(self.fetchFailed)
373 print "no jpg poster!"
374 self.OFDBPoster("kein Poster")
376 self["detailslabel"].setText(Detailstext)
378 def OFDBPoster(self,string):
379 self["statusbar"].setText("OFDb Details parsed ^^")
381 filename = "/tmp/poster.jpg"
383 filename = resolveFilename(SCOPE_PLUGINS, "Extensions/OFDb/no_poster.png")
384 sc = AVSwitch().getFramebufferScale()
385 self.picload.setPara((self["poster"].instance.size().width(), self["poster"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
386 self.picload.startDecode(filename)
388 def paintPosterPixmapCB(self, picInfo=None):
389 ptr = self.picload.getData()
391 self["poster"].instance.setPixmap(ptr.__deref__())
392 self["poster"].show()
394 def createSummary(self):
397 class OFDbLCDScreen(Screen):
399 <screen position="0,0" size="132,64" title="OFDb Plugin">
400 <widget name="headline" position="4,0" size="128,22" font="Regular;20"/>
401 <widget source="session.Event_Now" render="Label" position="6,26" size="120,34" font="Regular;14" >
402 <convert type="EventName">Name</convert>
406 def __init__(self, session, parent):
407 Screen.__init__(self, session)
408 self["headline"] = Label("OFDb Plugin")
410 def main(session, eventName="", **kwargs):
411 session.open(OFDB, eventName)
413 def Plugins(**kwargs):
415 wherelist = [PluginDescriptor.WHERE_EVENTINFO, PluginDescriptor.WHERE_PLUGINMENU]
416 return PluginDescriptor(name="OFDb Details",
417 description=_("Query details from the Online-Filmdatenbank"),
421 except AttributeError:
422 wherelist = [PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU]
423 return PluginDescriptor(name="OFDb Details",
424 description=_("Query details from the Online-Filmdatenbank"),