2 from Plugins.Plugin import PluginDescriptor
3 from twisted.web.client import downloadPage
4 from enigma import loadPic
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
21 <screen name="IMDB" position="90,95" size="560,420" title="Internet Movie Database Details Plugin" >
22 <ePixmap pixmap="skin_default/key-red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
23 <ePixmap pixmap="skin_default/key-green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
24 <ePixmap pixmap="skin_default/key-yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
25 <ePixmap pixmap="skin_default/key-blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
26 <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#9f1313" transparent="1" />
27 <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
28 <widget name="key_yellow" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
29 <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
30 <widget name="titellabel" position="10,40" size="330,45" valign="center" font="Regular;22"/>
31 <widget name="detailslabel" position="105,90" size="445,140" font="Regular;18" />
32 <widget name="castlabel" position="10,235" size="540,155" font="Regular;18" />
33 <widget name="extralabel" position="10,40" size="540,350" font="Regular;18" />
34 <widget name="ratinglabel" position="340,62" size="210,20" halign="center" font="Regular;18" foregroundColor="#f0b400"/>
35 <widget name="statusbar" position="10,404" size="540,16" font="Regular;16" foregroundColor="#cccccc" />
36 <widget name="poster" position="4,90" size="96,140" alphatest="on" />
37 <widget name="menu" position="10,115" size="540,275" zPosition="3" scrollbarMode="showOnDemand" />
38 <widget name="starsbg" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/IMDb/starsbar_empty.png" position="340,40" zPosition="0" size="210,21" transparent="1" alphatest="on" />
39 <widget name="stars" position="340,40" size="210,21" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/IMDb/starsbar_filled.png" transparent="1" />
42 def __init__(self, session, eventName, args = None):
44 Screen.__init__(self, session)
46 self.eventName = eventName
48 self.dictionary_init()
50 self["poster"] = Pixmap()
51 #self.preview = Pixmap()
53 self["stars"] = ProgressBar()
54 self["starsbg"] = Pixmap()
56 self["starsbg"].hide()
59 self["titellabel"] = Label("The Internet Movie Database")
60 self["detailslabel"] = ScrollLabel("")
61 self["castlabel"] = ScrollLabel("")
62 self["extralabel"] = ScrollLabel("")
63 self["statusbar"] = Label("")
64 self["ratinglabel"] = Label("")
66 self["menu"] = MenuList(self.resultlist)
69 self["key_red"] = Button(self._("Exit"))
70 self["key_green"] = Button("")
71 self["key_yellow"] = Button("")
72 self["key_blue"] = Button("")
74 # 0 = multiple query selection menu page
76 # 2 = extra infos page
79 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "MovieSelectionActions", "DirectionActions"],
81 "ok": self.showDetails,
83 "down": self.pageDown,
86 "green": self.showMenu,
87 "yellow": self.showDetails,
88 "blue": self.showExtras,
89 "showEventInfo": self.showDetails
94 def dictionary_init(self):
95 syslang = language.getLanguage()
96 if syslang.find("de") is -1:
97 self.IMDBlanguage = "" # set to empty ("") for english version
99 self.IMDBlanguage = "german." # it's a subdomain, so add a '.' at the end
102 self.dict["of"]="von"
103 self.dict[" as "]=" als "
104 self.dict["Ambiguous results"]="Kein eindeutiger Treffer"
105 self.dict["Please select the matching entry"]="Bitte passenden Eintrag auswählen"
106 self.dict["No IMDb match."]="Keine passenden Einträge gefunden."
107 self.dict["IMDb query failed!"]="IMDb-Query fehlgeschlagen!"
108 self.dict["No details found."]="Keine Details gefunden."
109 self.dict["no user rating yet"]="noch keine Nutzerwertung"
110 self.dict["Cast: "]="Darsteller: "
111 self.dict["No cast list found in the database."]="Keine Darstellerliste in der Datenbank gefunden."
112 self.dict["Exit"]="Beenden"
113 self.dict["Extra Info"]="Zusatzinfos"
114 self.dict["Title Menu"]="Titelauswahl"
116 self.htmltags = re.compile('<.*?>')
118 self.generalinfomask = re.compile(
119 '<h1>(?P<title>.*?) <.*?</h1>.*?'
120 '(?:.*?<h5>(?P<g_director>Regisseur|Directors?):</h5>.*?>(?P<director>.*?)</a>)*'
121 '(?:.*?<h5>(?P<g_creator>Sch\S*?pfer|Creators?):</h5>.*?>(?P<creator>.*?)</a>)*'
122 '(?:.*?<h5>(?P<g_seasons>Seasons):</h5>(?:.*?)<a href=\".*?\">(?P<seasons>\d+?)</a>\s+?(?:<a class|\|\s+?<a href="episodes#season-unknown))*'
123 '(?:.*?<h5>(?P<g_writer>Drehbuch|Writer).*?</h5>.*?>(?P<writer>.*?)</a>)*'
124 '(?:.*?<h5>(?P<g_premiere>Premiere|Release Date).*?</h5>\s.*?\n?(?P<premiere>.*?)\n\s.*?<)*'
125 '(?:.*?<h5>(?P<g_alternativ>Alternativ|Also Known As):</h5>(?P<alternativ>.*?)<br>\s{0,8}<a.*?>(?:mehr|more))*'
126 '(?:.*?<h5>(?P<g_country>Produktionsland|Country):</h5>.*?<a.*?>(?P<country>.*?)</a>(?:.*?mehr|\n</div>))*'
129 self.extrainfomask = re.compile(
130 '(?:.*?<h5>(?P<g_tagline>Werbezeile|Tagline?):</h5>\n(?P<tagline>.+?)<)*'
131 '(?:.*?<h5>(?P<g_outline>Kurzbeschreibung|Plot Outline):</h5>(?P<outline>.+?)<)*'
132 '(?:.*?<h5>(?P<g_synopsis>Plot Synopsis):</h5>(?:.*?)(?:<a href=\".*?\">)*?(?P<synopsis>.+?)(?:</a>|</div>))*'
133 '(?:.*?<h5>(?P<g_keywords>Plot Keywords):</h5>(?P<keywords>.+?)(?:mehr|more</a>|</div>))*'
134 '(?:.*?<h5>(?P<g_awards>Filmpreise|Awards):</h5>(?P<awards>.+?)(?:mehr|more</a>|</div>))*'
135 '(?:.*?<h5>(?P<g_runtime>L\S*?nge|Runtime):</h5>(?P<runtime>.+?)<)*'
136 '(?:.*?<h5>(?P<g_language>Sprache|Language):</h5>(?P<language>.+?)</div>)*'
137 '(?:.*?<h5>(?P<g_color>Farbe|Color):</h5>(?P<color>.+?)</div>)*'
138 '(?:.*?<h5>(?P<g_aspect>Seitenverh\S*?ltnis|Aspect Ratio):</h5>(?P<aspect>.+?)(?:mehr|more</a>|</div>))*'
139 '(?:.*?<h5>(?P<g_sound>Tonverfahren|Sound Mix):</h5>(?P<sound>.+?)</div>)*'
140 '(?:.*?<h5>(?P<g_cert>Altersfreigabe|Certification):</h5>(?P<cert>.+?)</div>)*'
141 '(?:.*?<h5>(?P<g_locations>Drehorte|Filming Locations):</h5>(?P<locations>.+?)(?:mehr|more</a>|</div>))*'
142 '(?:.*?<h5>(?P<g_company>Firma|Company):</h5>(?P<company>.+?)(?:mehr|more</a>|</div>))*'
143 '(?:.*?<h5>(?P<g_trivia>Dies und das|Trivia):</h5>(?P<trivia>.+?)(?:mehr|more</a>|</div>))*'
144 '(?:.*?<h5>(?P<g_goofs>Pannen|Goofs):</h5>(?P<goofs>.+?)(?:mehr|more</a>|</div>))*'
145 '(?:.*?<h5>(?P<g_quotes>Dialogzitate|Quotes):</h5>(?P<quotes>.+?)(?:mehr|more</a>|</div>))*'
146 '(?:.*?<h5>(?P<g_connections>Bez\S*?ge zu anderen Titeln|Movie Connections):</h5>(?P<connections>.+?)(?:mehr|more</a>|</div>))*'
147 '(?:.*?<h3>(?P<g_comments>Nutzerkommentare|User Comments)</h3>.*?<a href="/user/ur\d{7,7}/comments">(?P<commenter>.+?)\n</div>.*?<p>(?P<comment>.+?)</p>)*'
150 def _(self, in_string):
151 out_string = in_string
152 if ((self.IMDBlanguage).find("german")) != -1:
153 out_string = self.dict.get(in_string, in_string)
156 def resetLabels(self):
157 self["detailslabel"].setText("")
158 self["ratinglabel"].setText("")
159 self["titellabel"].setText("")
160 self["castlabel"].setText("")
161 self["titellabel"].setText("")
162 self["extralabel"].setText("")
163 self.ratingstars = -1
167 self["menu"].instance.moveSelection(self["menu"].instance.moveUp)
169 self["castlabel"].pageUp()
170 self["detailslabel"].pageUp()
172 self["extralabel"].pageUp()
176 self["menu"].instance.moveSelection(self["menu"].instance.moveDown)
178 self["castlabel"].pageDown()
179 self["detailslabel"].pageDown()
181 self["extralabel"].pageDown()
184 if ( self.Page is 1 or self.Page is 2 ) and self.resultlist:
187 self["starsbg"].hide()
188 self["ratinglabel"].hide()
189 self["castlabel"].hide()
190 self["poster"].hide()
191 self["extralabel"].hide()
192 self["titellabel"].setText(self._("Ambiguous results"))
193 self["detailslabel"].setText(self._("Please select the matching entry"))
194 self["detailslabel"].show()
195 self["key_blue"].setText("")
196 self["key_green"].setText(self._("Title Menu"))
197 self["key_yellow"].setText(self._("Details"))
200 def showDetails(self):
201 self["ratinglabel"].show()
202 self["castlabel"].show()
203 self["detailslabel"].show()
205 if self.resultlist and self.Page == 0:
206 link = self["menu"].getCurrent()[1]
207 title = self["menu"].getCurrent()[0]
208 self["statusbar"].setText("Re-Query IMDb: "+title+"...")
209 localfile = "/home/root/imdbquery2.html"
210 fetchurl = "http://" + self.IMDBlanguage + "imdb.com/title/" + link
211 print "[IMDB] downloading query " + fetchurl + " to " + localfile
212 downloadPage(fetchurl,localfile).addCallback(self.IMDBquery2).addErrback(self.fetchFailed)
218 self["extralabel"].hide()
219 self["poster"].show()
220 if self.ratingstars > 0:
221 self["starsbg"].show()
223 self["stars"].setValue(self.ratingstars)
227 def showExtras(self):
229 self["extralabel"].show()
230 self["detailslabel"].hide()
231 self["castlabel"].hide()
232 self["poster"].hide()
234 self["starsbg"].hide()
235 self["ratinglabel"].hide()
240 if self.eventName is "":
241 s = self.session.nav.getCurrentService()
243 event = info.getEvent(0) # 0 = now, 1 = next
245 self.eventName = event.getEventName()
246 if self.eventName is not "":
247 self["statusbar"].setText("Query IMDb: " + self.eventName + "...")
248 self.eventName = urllib.quote(self.eventName.decode('utf8').encode('latin-1','ignore'))
249 localfile = "/home/root/imdbquery.html"
250 fetchurl = "http://" + self.IMDBlanguage + "imdb.com/find?q=" + self.eventName + "&s=tt&site=aka"
251 print "[IMDB] Downloading Query " + fetchurl + " to " + localfile
252 downloadPage(fetchurl,localfile).addCallback(self.IMDBquery).addErrback(self.fetchFailed)
254 self["statusbar"].setText("Could't get Eventname -_-")
256 def fetchFailed(self,string):
257 print "[IMDB] fetch failed " + string
258 self["statusbar"].setText("IMDb Download failed -_-")
260 def html2utf8(self,in_html):
261 htmlentitynumbermask = re.compile('(&#(\d{1,5}?);)')
262 htmlentitynamemask = re.compile('(&(\D{1,5}?);)')
264 entities = htmlentitynamemask.finditer(in_html)
268 entitydict[x.group(1)] = x.group(2)
270 for key, name in entitydict.items():
271 entitydict[key] = htmlentitydefs.name2codepoint[name]
273 entities = htmlentitynumbermask.finditer(in_html)
276 entitydict[x.group(1)] = x.group(2)
278 for key, codepoint in entitydict.items():
279 in_html = in_html.replace(key, (unichr(int(codepoint)).encode('latin-1')))
281 self.inhtml = in_html.decode('latin-1').encode('utf8')
283 def IMDBquery(self,string):
285 self["statusbar"].setText("IMDb Download completed")
287 self.html2utf8(open("/home/root/imdbquery.html", "r").read())
289 self.generalinfos = self.generalinfomask.search(self.inhtml)
291 if self.generalinfos:
294 if re.search("<title>IMDb.{0,9}Search</title>", self.inhtml):
295 searchresultmask = re.compile("href=\".*?/title/(tt\d{7,7})/\">(.*?)</td>", re.DOTALL)
296 searchresults = searchresultmask.finditer(self.inhtml)
299 for x in searchresults:
300 self.resultlist.append((self.htmltags.sub('',x.group(2)), x.group(1)))
301 self["menu"].l.setList(self.resultlist)
302 if len(self.resultlist) > 1:
306 self["detailslabel"].setText(self._("No IMDb match."))
307 self["statusbar"].setText("No IMDb match")
309 self["detailslabel"].setText(self._("IMDb query failed!"))
311 def IMDBquery2(self,string):
312 self["statusbar"].setText("IMDb Re-Download completed")
313 self.html2utf8(open("/home/root/imdbquery2.html", "r").read())
314 self.generalinfos = self.generalinfomask.search(self.inhtml)
320 Detailstext = self._("No details found.")
321 if self.generalinfos:
322 self["key_yellow"].setText(self._("Details"))
323 self["statusbar"].setText("IMDb Details parsed ^^")
325 Titeltext = self.generalinfos.group("title")
326 if len(Titeltext) > 57:
327 Titeltext = Titeltext[0:54] + "..."
328 self["titellabel"].setText(Titeltext)
332 genreblockmask = re.compile('<h5>Genre:</h5>(.*?)(?:mehr|more|</div>)', re.DOTALL)
333 genreblock = genreblockmask.findall(self.inhtml)
334 genremask = re.compile('\">(.*?)</a')
336 genres = genremask.finditer(genreblock[0])
338 Detailstext += "Genre: "
340 Detailstext += x.group(1) + " "
342 detailscategories = ["director", "creator", "writer", "premiere", "seasons", "country"]
344 for category in detailscategories:
345 if self.generalinfos.group('g_'+category):
346 Detailstext += "\n" + self.generalinfos.group('g_'+category) + ": " + self.generalinfos.group(category)
348 if self.generalinfos.group("alternativ"):
349 Detailstext += "\n" + self.generalinfos.group("g_alternativ") + ": " + self.htmltags.sub('',(self.generalinfos.group("alternativ").replace('\n','').replace("<br>",'\n').replace(" ",' ')))
351 ratingmask = re.compile('(?P<g_rating>Nutzer-Bewertung|User Rating):</b>.{0,2}<b>(?P<rating>.*?)/10</b>', re.DOTALL)
352 rating = ratingmask.search(self.inhtml)
353 Ratingtext = self._("no user rating yet")
355 Ratingtext = rating.group("g_rating") + ": " + rating.group("rating") + " / 10"
356 self.ratingstars = int(10*round(float(rating.group("rating")),1))
358 self["stars"].setValue(self.ratingstars)
359 self["starsbg"].show()
360 self["ratinglabel"].setText(Ratingtext)
362 castmask = re.compile('<td class="nm">.*?>(.*?)</a>.*?<td class="char">(?:<a.*?>)?(.*?)(?:</a>)?</td>', re.DOTALL)
363 castresult = castmask.finditer(self.inhtml)
367 Casttext += "\n" + self.htmltags.sub('', x.group(1))
369 Casttext += self._(" als ") + self.htmltags.sub('', x.group(2).replace('/ ...',''))
370 if Casttext is not "":
371 Casttext = self._("Cast: ") + Casttext
373 Casttext = self._("No cast list found in the database.")
374 self["castlabel"].setText(Casttext)
376 postermask = re.compile('<div class="photo">.*?<img .*? src=\"(http.*?)\" .*?>', re.DOTALL)
377 posterurl = postermask.search(self.inhtml).group(1)
378 if posterurl.find("jpg") > 0:
379 self["statusbar"].setText("Downloading Movie Poster: "+posterurl+"...")
380 localfile = "/home/root/poster.jpg"
381 print "[IMDB] downloading poster " + posterurl + " to " + localfile
382 downloadPage(posterurl,localfile).addCallback(self.IMDBPoster).addErrback(self.fetchFailed)
384 self.IMDBPoster("kein Poster")
386 extrainfos = self.extrainfomask.search(self.inhtml)
389 Extratext = "Extra Info\n"
390 extracategories = ["tagline","outline","synopsis","keywords","awards","runtime","language","color","aspect","sound","cert","locations","company","trivia","goofs","quotes","connections"]
392 for category in extracategories:
393 if extrainfos.group('g_'+category):
394 Extratext += extrainfos.group('g_'+category) + ": " + self.htmltags.sub('',extrainfos.group(category).replace("\n",'').replace("<br>",'\n')) + "\n"
395 if extrainfos.group("g_comments"):
396 Extratext += extrainfos.group("g_comments") + " [" + self.htmltags.sub('',extrainfos.group("commenter")) + "]: " + self.htmltags.sub('',extrainfos.group("comment").replace("\n",' ')) + "\n"
398 self["extralabel"].setText(Extratext)
399 self["extralabel"].hide()
400 self["key_blue"].setText(self._("Extra Info"))
402 self["detailslabel"].setText(Detailstext)
404 def IMDBPoster(self,string):
405 self["statusbar"].setText("IMDb Details parsed ^^")
407 filename = "/home/root/poster.jpg"
409 filename = "/usr/lib/enigma2/python/Plugins/Extensions/IMDb/no_poster.png"
410 pixmap = loadPic(filename, 96,140, AVSwitch().getAspectRatioSetting()/2,1,0,0)
411 if pixmap is not None:
412 self["poster"].instance.setPixmap(pixmap.__deref__())
413 #self["poster"].move(4,90)
414 self["poster"].show()
416 def createSummary(self):
419 class IMDbLCDScreen(Screen):
421 <screen position="0,0" size="132,64" title="IMDB Plugin">
422 <widget name="headline" position="4,0" size="128,22" font="Regular;20"/>
423 <widget source="session.Event_Now" render="Label" position="6,26" size="120,34" font="Regular;14" >
424 <convert type="EventName">Name</convert>
428 def __init__(self, session, parent):
429 Screen.__init__(self, session)
430 self["headline"] = Label("IMDB Plugin")
432 def main(session, eventName="", **kwargs):
433 session.open(IMDB, eventName)
435 def Plugins(**kwargs):
437 wherelist = [PluginDescriptor.WHERE_EVENTINFO, PluginDescriptor.WHERE_PLUGINMENU]
438 return PluginDescriptor(name="IMDb Details",
439 description=_("Query details from the Internet Movie Database"),
443 except AttributeError:
444 wherelist = [PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU]
445 return PluginDescriptor(name="IMDb Details",
446 description=_("Query details from the Internet Movie Database"),