1 # -*- coding: UTF-8 -*-
2 from Plugins.Plugin import PluginDescriptor
3 from Tools.Downloader import downloadWithProgress
4 from enigma import ePicLoad, eServiceReference, getDesktop
5 from Screens.Screen import Screen
6 from Screens.EpgSelection import EPGSelection
7 from Screens.ChannelSelection import SimpleChannelSelection
8 from Screens.ChoiceBox import ChoiceBox
9 from Screens.VirtualKeyBoard import VirtualKeyBoard
10 from Components.ActionMap import ActionMap
11 from Components.Pixmap import Pixmap
12 from Components.Label import Label
13 from Components.ScrollLabel import ScrollLabel
14 from Components.Button import Button
15 from Components.AVSwitch import AVSwitch
16 from Components.MenuList import MenuList
17 from Components.ProgressBar import ProgressBar
18 from Components.Sources.StaticText import StaticText
19 from Components.Sources.Boolean import Boolean
20 from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS, SCOPE_SKIN_IMAGE
23 from urllib import quote_plus
24 except ImportError as ie:
25 from urllib.parse import quote_plus
27 from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigText, ConfigSelection
28 from Components.ConfigList import ConfigListScreen
29 from Components.PluginComponent import plugins
30 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
32 from HTMLParser import HTMLParser
34 sz_w = getDesktop(0).size().width()
38 return h.unescape(text)
40 config.plugins.imdb = ConfigSubsection()
41 config.plugins.imdb.showinplugins = ConfigYesNo(default = True)
42 config.plugins.imdb.ignore_tags = ConfigText(visible_width = 50, fixed_size = False)
43 config.plugins.imdb.language = ConfigSelection(default = None, choices = [(None, _("Default")),("en-us", _("English")),("fr-fr", _("French")),("de-de", _("German")),("it-it", _("Italian")),("es-es", _("Spanish"))])
47 def quoteEventName(eventName):
48 eventName = eventName.replace(' ','+')
49 return quote_plus(eventName, safe='+')
51 class IMDBChannelSelection(SimpleChannelSelection):
52 def __init__(self, session):
53 SimpleChannelSelection.__init__(self, session, _("Channel Selection"))
54 self.skinName = "SimpleChannelSelection"
56 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
58 "showEPGList": self.channelSelected
62 def channelSelected(self):
63 ref = self.getCurrentSelection()
64 if (ref.flags & 7) == 7:
66 elif not (ref.flags & eServiceReference.isMarker):
67 self.session.openWithCallback(
74 def epgClosed(self, ret = None):
78 class IMDBEPGSelection(EPGSelection):
79 def __init__(self, session, ref, openPlugin = True):
80 EPGSelection.__init__(self, session, ref)
81 self.skinName = "EPGSelection"
82 self["key_green"].setText(_("Lookup"))
83 self.openPlugin = openPlugin
85 def infoKeyPressed(self):
89 cur = self["list"].getCurrent()
101 self.close(evt.getEventName())
103 def onSelectionChanged(self):
109 <screen name="IMDBv2" position="center,110" size="1800,930" title="IMDb - Internet Movie Database">
110 <eLabel backgroundColor="grey" position="10,80" size="1780,1" />
111 <ePixmap pixmap="Default-FHD/skin_default/buttons/red.svg" position="10,5" size="300,70" />
112 <ePixmap pixmap="Default-FHD/skin_default/buttons/green.svg" position="310,5" size="300,70" />
113 <ePixmap pixmap="Default-FHD/skin_default/buttons/yellow.svg" position="610,5" size="300,70" />
114 <ePixmap pixmap="Default-FHD/skin_default/buttons/blue.svg" position="910,5" size="300,70" />
115 <widget backgroundColor="#9f1313" font="Regular;30" halign="center" name="key_red" position="10,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="300,70" transparent="1" valign="center" zPosition="1" />
116 <widget backgroundColor="#1f771f" font="Regular;30" halign="center" name="key_green" position="310,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="300,70" transparent="1" valign="center" zPosition="1" />
117 <widget backgroundColor="#a08500" font="Regular;30" halign="center" name="key_yellow" position="610,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="300,70" transparent="1" valign="center" zPosition="1" />
118 <widget backgroundColor="#18188b" font="Regular;30" halign="center" name="key_blue" position="910,5" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2" size="300,70" transparent="1" valign="center" zPosition="1" />
119 <widget font="Regular;34" halign="right" position="1650,25" render="Label" size="120,40" source="global.CurrentTime">
120 <convert type="ClockToText">Default</convert>
122 <widget font="Regular;34" halign="right" position="1240,25" render="Label" size="400,40" source="global.CurrentTime" >
123 <convert type="ClockToText">Date</convert>
125 <widget font="Regular;38" name="titlelabel" position="20,90" size="1780,45" foregroundColor="yellow"/>
126 <widget enableWrapAround="1" name="menu" position="20,150" scrollbarMode="showOnDemand" size="1760,720" />
127 <widget font="Regular;28" name="extralabel" position="20,180" size="1760,750" />
128 <widget font="Regular;30" halign="left" name="ratinglabel" position="370,150" size="1000,40" foregroundColor="yellow"/>
129 <widget name="starsbg" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/IMDb/starsbar_empty.svg" position="30,150" size="300,30" />
130 <widget name="stars" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/IMDb/starsbar_filled.svg" position="30,150" size="300,30" transparent="1" />
131 <widget name="poster" position="30,200" size="300,449" />
132 <widget font="Regular;30" name="detailslabel" position="370,210" size="750,400" />
133 <widget font="Regular;30" name="castlabel" position="1180,210" size="600,400" />
134 <widget font="Regular;30" name="storylinelabel" position="20,660" size="1760,210" />
135 <widget name="statusbar" halign="right" position="370,885" size="1400,35" font="Regular;30" foregroundColor="#b3b3b9" />
139 <screen name="IMDBv2" position="center,80" size="1200,610" title="IMDb - Internet Movie Database">
140 <ePixmap pixmap="skin_default/buttons/red.png" position="10,5" size="200,40"/>
141 <ePixmap pixmap="skin_default/buttons/green.png" position="210,5" size="200,40"/>
142 <ePixmap pixmap="skin_default/buttons/yellow.png" position="410,5" size="200,40"/>
143 <ePixmap pixmap="skin_default/buttons/blue.png" position="610,5" size="200,40"/>
144 <widget name="key_red" position="10,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2"/>
145 <widget name="key_green" position="210,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2"/>
146 <widget name="key_yellow" position="410,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2"/>
147 <widget name="key_blue" position="610,5" size="200,40" zPosition="1" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-2,-2"/>
148 <widget source="global.CurrentTime" render="Label" position="1130,12" size="60,25" font="Regular;22" halign="right">
149 <convert type="ClockToText">Default</convert>
151 <widget source="global.CurrentTime" render="Label" position="820,12" size="300,25" font="Regular;22" halign="right">
152 <convert type="ClockToText">Format:%A %d. %B</convert>
154 <eLabel position="10,50" size="1180,1" backgroundColor="grey"/>
155 <widget name="titlelabel" position="10,55" size="1180,30" valign="center" font="Regular;24" foregroundColor="yellow"/>
156 <widget name="menu" position="10,100" size="1180,480" zPosition="3" scrollbarMode="showOnDemand" enableWrapAround="1" />
157 <widget name="extralabel" position="10,100" size="1180,500" font="Regular;22" />
158 <widget name="ratinglabel" position="230,92" size="800,23" font="Regular;19" foregroundColor="yellow"/>
159 <widget name="starsbg" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/IMDb/starsbar_empty.svg" position="10,90" size="210,21"/>
160 <widget name="stars" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/IMDb/starsbar_filled.svg" position="10,90" size="210,21" transparent="1" />
161 <widget name="poster" position="22,120" size="185,278"/>
162 <widget name="detailslabel" position="240,130" size="450,270" font="Regular;20" />
163 <widget name="castlabel" position="720,130" size="470,270" font="Regular;20" />
164 <widget name="storylinelabel" position="20,410" size="1160,170" font="Regular;20" />
165 <widget name="statusbar" position="10,580" size="1180,25" halign="right" font="Regular;19" foregroundColor="#b3b3b9" />
167 def __init__(self, session, eventName, callbackNeeded=False):
168 Screen.__init__(self, session)
169 self.skinName = "IMDBv2"
171 for tag in config.plugins.imdb.ignore_tags.getValue().split(','):
172 eventName = eventName.replace(tag,'')
174 self.eventName = eventName
176 self.callbackNeeded = callbackNeeded
177 self.callbackData = ""
178 self.callbackGenre = ""
182 self.dictionary_init()
184 self["poster"] = Pixmap()
185 self.picload = ePicLoad()
186 self.picload_conn = self.picload.PictureData.connect(self.paintPosterPixmapCB)
188 self["stars"] = ProgressBar()
189 self["starsbg"] = Pixmap()
191 self["starsbg"].hide()
192 self.ratingstars = -1
194 self.setTitle(_("IMDb - Internet Movie Database"))
195 self["titlelabel"] = Label("")
196 self["titlelcd"] = StaticText("")
197 self["detailslabel"] = ScrollLabel("")
198 self["castlabel"] = ScrollLabel("")
199 self["storylinelabel"] = ScrollLabel("")
200 self["extralabel"] = ScrollLabel("")
201 self["statusbar"] = Label("")
202 self["ratinglabel"] = Label("")
204 self["menu"] = MenuList(self.resultlist)
207 self["key_red"] = Button(_("Exit"))
208 self["key_green"] = Button("")
209 self["key_yellow"] = Button("")
210 self["key_blue"] = Button("")
212 # 0 = multiple query selection menu page
213 # 1 = movie info page
214 # 2 = extra infos page
217 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "MovieSelectionActions", "DirectionActions"],
219 "ok": self.showDetails,
221 "down": self.pageDown,
223 "right": self.keyRight,
224 "left": self.keyLeft,
226 "green": self.showMenu,
227 "yellow": self.showDetails,
228 "blue": self.showExtras,
229 "contextMenu": self.contextMenuPressed,
230 "showEventInfo": self.showDetails
235 def title_setText(self, txt):
236 StaticText.setText(self["titlelcd"], txt)
237 self["titlelabel"].setText(txt)
240 if fileExists("/tmp/poster.jpg"):
241 os.remove("/tmp/poster.jpg")
242 if fileExists("/tmp/imdbquery.html"):
243 os.remove("/tmp/imdbquery.html")
244 if fileExists("/tmp/imdbquery2.html"):
245 os.remove("/tmp/imdbquery2.html")
246 if self.callbackNeeded:
247 self.close([self.callbackData, self.callbackGenre])
251 def dictionary_init(self):
252 self.generalinfomask = re.compile(
253 '<h1 itemprop="name" class=".*?>(?P<title>.*?)<.*?/h1>*'
254 '(?:.*?<div class="originalTitle">(?P<originaltitle>.*?)\s*\((?P<g_originaltitle>original title))*'
255 '(?:.*?<h4 class="inline">\s*(?P<g_director>Directors?):\s*</h4>.*?<a.*?>(?P<director>.*?)(?:\d+ more|</div>))*'
256 '(?:.*?<h4 class="inline">\s*(?P<g_creator>Creators?):\s*</h4>.*?<a.*?>(?P<creator>.*?)(?:\d+ more|</div>))*'
257 '(?:.*?<h4 class="inline">\s*(?P<g_writer>Writers?):\s*</h4>.*?<a.*?>(?P<writer>.*?)(?:\d+ more|</div>))*'
258 '(?:.*?<h4 class="float-left">(?P<g_seasons>Seasons?)\s*</h4>.*?<a.*?>(?P<seasons>(?:\d+|unknown)?)</a>)*'
259 '(?:.*?<h4 class="inline">\s*(?P<g_country>Country):\s*</h4>.*?<a.*?>(?P<country>.*?)</a>)*'
260 '(?:.*?<h4 class="inline">\s*(?P<g_premiere>Release Date).*?</h4>\s+(?P<premiere>.*?)\D+\s+<span)*'
261 '(?:.*?<h4 class="inline">(?P<g_runtime>Runtime):</h4>\s*(?P<runtime>.*?)</div>)*'
264 self.extrainfomask = re.compile(
265 '(?:.*?<h4 class="inline">(?P<g_keywords>Plot Keywords):</h4>(?P<keywords>.*?)(?:See All|</div>))*'
266 '(?:.*?<h4 class="inline">(?P<g_tagline>Taglines):</h4>\s*(?P<tagline>.*?)<)*'
267 '(?:.*?<h4 class="inline">(?P<g_cert>Certificate):.*?>(?P<cert>\d{1,2})<.*?(?:certification))*'
268 '(?:.*?<h4>(?P<g_mpaa>Motion Picture Rating).*?</h4>*(?P<mpaa>.*?)</span.*?(?:certification))*'
269 '(?:.*?<h4 class="inline">(?P<g_language>Language):</h4>\s*(?P<language>.*?)</div>)*'
270 '(?:.*?<h4 class="inline">(?P<g_locations>Filming Locations):</h4>.*?<a.*?>(?P<locations>.*?)</a>)*'
271 '(?:.*?<h4 class="inline">(?P<g_company>Production Co):</h4>\s*(?P<company>.*?)(?:See more|</div>))*'
272 '(?:.*?<h4 class="inline">(?P<g_sound>Sound Mix):</h4>\s*(?P<sound>.*?)</div>)*'
273 '(?:.*?<h4 class="inline">(?P<g_color>Color):</h4>\s*(?P<color>.*?)</div>)*'
274 '(?:.*?<h4 class="inline">(?P<g_aspect>Aspect Ratio):</h4>\s*(?P<aspect>.*?)(?:See more</a>|</div>))*'
275 '(?:.*?<h4>(?P<g_trivia>Trivia)</h4>\s*(?P<trivia>.*?)(?:See more|<span))*'
276 '(?:.*?<h4>(?P<g_goofs>Goofs)</h4>\s*(?P<goofs>.*?)(?:See more|<span))*'
277 '(?:.*?<h4>(?P<g_quotes>Quotes)</h4>.*?class="character">(?P<quotes>.*?)(?:See more))*'
278 '(?:.*?<h4>(?P<g_crazy>Crazy Credits)</h4>\s*(?P<crazy>.*?)(?:See more))*'
279 '(?:.*?<h4>(?P<g_connections>Connections)</h4>\s*(?P<connections>.*?)(?:See more|<span))*'
280 '(?:.*?<h2>(?P<g_comments>User Reviews)</h2>.*?href="/user/ur\d+/\?ref_=tt_urv".{0,1}>(?:<span itemprop="author">)(?P<commenter>.*?)</span>.*?<p\sitemprop="reviewBody">(?P<comment>.*?)</p>)*'
283 self.genreblockmask = re.compile('href="/genre/.*?\?ref_=tt_stry_gnr.*?\n.*?\s(?P<genre>.*?)</a>', re.S)
284 self.ratingmask = re.compile('<span itemprop="ratingValue">(?P<rating>.*?)</.*?itemprop="ratingCount">(?P<ratingcount>.*?)</', re.S)
285 self.castmask = re.compile('itemprop="actor".*?class="itemprop"\sitemprop="name">(?P<actor>.*?)</span>.*?class="character">(?P<character>.*?)(?:</a>|</div>|\(|<a href="#")', re.S)
286 self.postermask = re.compile('<div class="poster">.*?<img .*?src=\"(http.*?)\"', re.S)
287 self.storylinemask = re.compile('(?:.*?<h2>(?P<g_storyline>Storyline)</h2>.*?(?P<storyline>.*?)(?:see-more inline|</p>|Written))*', re.S)
289 self.htmltags = re.compile('<.*?>')
291 def resetLabels(self):
292 self["detailslabel"].setText("")
293 self["ratinglabel"].setText("")
294 self["castlabel"].setText("")
295 self["storylinelabel"].setText("")
296 self.title_setText("")
297 self["extralabel"].setText("")
298 self.ratingstars = -1
302 self["menu"].instance.moveSelection(self["menu"].instance.moveUp)
304 self["castlabel"].pageUp()
305 self["detailslabel"].pageUp()
306 self["storylinelabel"].pageUp()
308 self["extralabel"].pageUp()
312 self["menu"].instance.moveSelection(self["menu"].instance.moveDown)
314 self["castlabel"].pageDown()
315 self["detailslabel"].pageDown()
316 self["storylinelabel"].pageDown()
318 self["extralabel"].pageDown()
322 self["menu"].pageUp()
324 self["castlabel"].pageUp()
325 self["detailslabel"].pageUp()
326 self["storylinelabel"].pageUp()
328 self["extralabel"].pageUp()
332 self["menu"].pageDown()
334 self["castlabel"].pageDown()
335 self["detailslabel"].pageDown()
336 self["storylinelabel"].pageDown()
338 self["extralabel"].pageDown()
341 if ( self.Page is 1 or self.Page is 2 ) and self.resultlist:
344 self["starsbg"].hide()
345 self["ratinglabel"].hide()
346 self["castlabel"].hide()
347 self["storylinelabel"].hide()
348 self["poster"].hide()
349 self["extralabel"].hide()
350 self["detailslabel"].hide()
351 self.title_setText(_("Please select the matching entry"))
352 self["key_blue"].setText("")
353 self["key_green"].setText(_("Title Menu"))
354 self["key_yellow"].setText(_("Details"))
357 def showDetails(self):
358 self["ratinglabel"].show()
359 self["castlabel"].show()
360 self["detailslabel"].show()
361 self["storylinelabel"].show()
363 if self.resultlist and self.Page == 0:
364 link = self["menu"].getCurrent()[1]
365 title = self["menu"].getCurrent()[0]
366 self["statusbar"].setText(_("Re-Query IMDb: %s...") % (title))
367 localfile = "/tmp/imdbquery2.html"
368 fetchurl = "http://www.imdb.com/title/" + link
369 print("[IMDB] showDetails() downloading query " + fetchurl + " to " + localfile)
370 download = downloadWithProgress(fetchurl,localfile,headers=imdb_headers)
371 download.start().addCallback(self.IMDBquery2).addErrback(self.http_failed)
372 self.fetchurl = fetchurl
378 self["extralabel"].hide()
379 self["poster"].show()
380 if self.ratingstars > 0:
381 self["starsbg"].show()
383 self["stars"].setValue(self.ratingstars)
387 def showExtras(self):
389 self["extralabel"].show()
390 self["detailslabel"].hide()
391 self["castlabel"].hide()
392 self["storylinelabel"].hide()
393 self["poster"].hide()
395 self["starsbg"].hide()
396 self["ratinglabel"].hide()
399 def contextMenuPressed(self):
401 (_("Enter search"), self.openVirtualKeyBoard),
402 (_("Select from EPG"), self.openChannelSelection),
403 (_("Setup"), self.setup),
406 if fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/YTTrailer/plugin.py")):
408 (_("Play Trailer"), self.openYttrailer),
409 (_("Search Trailer"), self.searchYttrailer),
412 self.session.openWithCallback(
415 title=_("IMDb Menu"),
419 def menuCallback(self, ret = None):
422 def openYttrailer(self):
424 from Plugins.Extensions.YTTrailer.plugin import YTTrailer, baseEPGSelection__init__
425 except ImportError as ie:
427 if baseEPGSelection__init__ is None:
430 ytTrailer = YTTrailer(self.session)
431 ytTrailer.showTrailer(self.eventName)
433 def searchYttrailer(self):
435 from Plugins.Extensions.YTTrailer.plugin import YTTrailerList, baseEPGSelection__init__
436 except ImportError as ie:
438 if baseEPGSelection__init__ is None:
441 self.session.open(YTTrailerList, self.eventName)
443 def openVirtualKeyBoard(self):
444 self.session.openWithCallback(
445 self.gotSearchString,
447 title = _("Enter text to search for"),
448 text = self.eventName
451 def openChannelSelection(self):
452 self.session.openWithCallback(
453 self.gotSearchString,
457 def gotSearchString(self, ret = None):
463 self["ratinglabel"].show()
464 self["castlabel"].show()
465 self["storylinelabel"].show()
466 self["detailslabel"].show()
467 self["poster"].hide()
469 self["starsbg"].hide()
470 self.getIMDB(search=True)
472 def getIMDB(self, search=False):
474 if config.plugins.imdb.language.value:
475 imdb_headers = {'Accept-Language': config.plugins.imdb.language.value}
479 if not self.eventName:
480 s = self.session.nav.getCurrentService()
481 info = s and s.info()
482 event = info and info.getEvent(0) # 0 = now, 1 = next
484 self.eventName = event.getEventName()
486 self.eventName = self.session.nav.getCurrentlyPlayingServiceReference().toString()
487 self.eventName = self.eventName.split('/')
488 self.eventName = self.eventName[-1]
489 self.eventName = self.eventName.replace('.',' ')
490 self.eventName = self.eventName.split('-')
491 self.eventName = self.eventName[0]
492 if self.eventName.endswith(' '):
493 self.eventName = self.eventName[:-1]
496 self["statusbar"].setText(_("Query IMDb: %s") % (self.eventName))
497 localfile = "/tmp/imdbquery.html"
498 fetchurl = "http://www.imdb.com/find?ref_=nv_sr_fn&q=" + quoteEventName(self.eventName) + "&s=all"
499 print("[IMDB] getIMDB() Downloading Query " + fetchurl + " to " + localfile)
500 download = downloadWithProgress(fetchurl,localfile,headers=imdb_headers)
501 download.start().addCallback(self.IMDBquery).addErrback(self.http_failed)
504 self["statusbar"].setText(_("Couldn't get Eventname"))
506 def cleanhtml(self, in_html):
507 in_html = (re.subn(r'<(script).*?</\1>(?s)', '', in_html)[0])
508 in_html = (re.subn(r'<(style).*?</\1>(?s)', '', in_html)[0])
511 def IMDBquery(self,string):
512 self["statusbar"].setText(_("IMDb Download completed"))
514 self.inhtml = open("/tmp/imdbquery.html", "r").read()
515 self.inhtml = self.cleanhtml(self.inhtml)
517 self.generalinfos = self.generalinfomask.search(self.inhtml)
519 if self.generalinfos:
522 if not re.search('class="findHeader">No results found for', self.inhtml):
523 pos = self.inhtml.find("<table class=\"findList\">")
524 pos2 = self.inhtml.find("</table>",pos)
525 findlist = self.inhtml[pos:pos2]
526 searchresultmask = re.compile('<tr class=\"findResult (?:odd|even)\">.*?<td class=\"result_text\"> <a href=\"/title/(tt\d{7,7})/.*?\"\s?>(.*?)</a>.*?</td>', re.S)
527 searchresults = searchresultmask.finditer(findlist)
528 self.resultlist = [(self.htmltags.sub('',x.group(2)), x.group(1)) for x in searchresults]
529 Len = len(self.resultlist)
530 self["menu"].l.setList(self.resultlist)
532 self["key_green"].setText("")
533 self["statusbar"].setText(_("Re-Query IMDb: %s...") % (self.resultlist[0][0],))
534 self.eventName = self.resultlist[0][1]
535 localfile = "/tmp/imdbquery.html"
536 fetchurl = "http://www.imdb.com/find?ref_=nv_sr_fn&q=" + quoteEventName(self.eventName) + "&s=all"
537 download = downloadWithProgress(fetchurl,localfile,headers=imdb_headers)
538 download.start().addCallback(self.IMDBquery).addErrback(self.http_failed)
543 self["statusbar"].setText(_("No IMDb match.") + ' ' + self.eventName)
545 splitpos = self.eventName.find('(')
547 self.eventName = self.eventName[:splitpos-1]
548 self["statusbar"].setText(_("Re-Query IMDb: %s...") % (self.eventName))
549 localfile = "/tmp/imdbquery.html"
550 fetchurl = "http://www.imdb.com/find?ref_=nv_sr_fn&q=" + quoteEventName(self.eventName) + "&s=all"
551 download = downloadWithProgress(fetchurl,localfile,headers=imdb_headers)
552 download.start().addCallback(self.IMDBquery).addErrback(self.http_failed)
554 splitpos = self.eventName.find('-')
556 self.eventName = self.eventName[:splitpos-1].strip()
557 self["statusbar"].setText(_("Re-Query IMDb: %s...") % (self.eventName))
558 localfile = "/tmp/imdbquery.html"
559 fetchurl = "http://www.imdb.com/find?ref_=nv_sr_fn&q=" + quoteEventName(self.eventName) + "&s=all"
560 download = downloadWithProgress(fetchurl,localfile,headers=imdb_headers)
561 download.start().addCallback(self.IMDBquery).addErrback(self.http_failed)
563 self["statusbar"].setText(_("IMDb query failed!"))
565 def http_failed(self, failure_instance=None, error_message=""):
566 text = _("IMDb Download failed")
567 if error_message == "" and failure_instance is not None:
568 error_message = failure_instance.getErrorMessage()
569 text += ": " + error_message
570 print("[IMDB] ",text)
571 self["statusbar"].setText(text)
573 def IMDBquery2(self,string):
574 self["statusbar"].setText(_("IMDb Re-Download completed"))
575 self.inhtml = open("/tmp/imdbquery2.html", "r").read()
576 self.inhtml = self.cleanhtml(self.inhtml)
577 self.generalinfos = self.generalinfomask.search(self.inhtml)
582 Detailstext = _("No details found.")
583 if self.generalinfos:
584 self["key_yellow"].setText(_("Details"))
585 self["statusbar"].setText(_("IMDb Details parsed"))
586 Titeltext = self.generalinfos.group("title").replace(' ',' ').strip()
587 if len(Titeltext) > 57:
588 Titeltext = Titeltext[0:54] + "..."
589 self.title_setText(Titeltext)
592 stripmask = re.compile('\s{2,}', re.S)
594 for category in ("originaltitle", "premiere", "country", "runtime", "seasons"):
595 if self.generalinfos.group(category):
596 Detailstext += self.generalinfos.group('g_'+category).title() + ": " + stripmask.sub(' ', self.htmltags.sub('', self.generalinfos.group(category).replace('\n',' ').replace('<br>', '\n').replace('<br />','\n'))).replace(' | ',', ').strip() + "\n"
598 genreblock = self.genreblockmask.findall(self.inhtml)
601 if len(genreblock) > 1: s = 's'
602 Detailstext += "Genre%s: " % s
604 genres = self.htmltags.sub('', x)
605 Detailstext += genres + ", "
606 if Detailstext[-2:] == ", ":
607 Detailstext = Detailstext[:-2]
610 for category in ("director", "creator", "writer"):
611 if self.generalinfos.group(category):
612 striplink1 = re.compile('(<a href="/name/nm\d+.{0,1}\?ref_=tt_ov_..".{0,1}itemprop=\'url\'>)', re.S)
613 striplink2 = re.compile('(<a href="fullcredits\?ref_=tt_ov_..#.*?">)', re.S)
614 Detailstext += self.generalinfos.group('g_'+category) + ": " + striplink2.sub('', striplink1.sub('', stripmask.sub(' ', self.htmltags.sub('', self.generalinfos.group(category)).replace('\n','').replace('|','')))) + "\n"
616 rating = self.ratingmask.search(self.inhtml)
617 Ratingtext = _("no user rating yet")
619 ratingval = rating.group("rating")
620 if ratingval != '<span id="voteuser"></span>':
622 if rating.group("ratingcount"): count = ' (' + rating.group("ratingcount").replace(',','.') + ' ' + _("votes") +')'
623 Ratingtext = _("User Rating") + ": " + ratingval + "/10" + count
624 self.ratingstars = int(10*round(float(ratingval.replace(',','.')),1))
626 self["stars"].setValue(self.ratingstars)
627 self["starsbg"].show()
628 self["ratinglabel"].setText(str(Ratingtext))
630 castresult = self.castmask.finditer(self.inhtml)
634 Casttext += "\n" + self.htmltags.sub('', x.group('actor'))
635 if x.group('character'):
636 Casttext += " as " + stripmask.sub(' ', self.htmltags.sub('', x.group('character').replace('/ ...','').replace('\n','').replace(' ',''))).strip()
638 Casttext = "Cast: " + Casttext
640 Casttext = _("No cast list found in the database.")
641 self["castlabel"].setText(str(Casttext))
643 storylineresult = self.storylinemask.search(self.inhtml)
646 if storylineresult.group("g_storyline"):
647 Storyline = storylineresult.group('g_storyline') + ":\n" + re.sub('\s{5,30}',', ', self.htmltags.sub('', storylineresult.group('storyline').replace('\n','').replace('<br>', '\n').replace('<br />','\n').replace(' ','').replace('"','"').replace('<span class="','')).strip())
649 if Storyline == storylineresult.group('g_storyline') + ":\n":
650 self["storylinelabel"].hide()
652 self["storylinelabel"].setText(str(Storyline))
654 posterurl = self.postermask.search(self.inhtml)
655 if posterurl and posterurl.group(1).find("jpg") > 0:
656 posterurl = posterurl.group(1)
657 self["statusbar"].setText(_("Downloading Movie Poster: %s...") % (posterurl))
658 localfile = "/tmp/poster.jpg"
659 print("[IMDB] downloading poster " + posterurl + " to " + localfile)
660 download = downloadWithProgress(posterurl,localfile,headers=imdb_headers)
661 download.start().addCallback(self.IMDBPoster).addErrback(self.http_failed)
663 self.IMDBPoster("kein Poster")
665 extrainfos = self.extrainfomask.search(self.inhtml)
668 for category in ("tagline","keywords","cert","mpaa","language","color","aspect","company","sound","locations","trivia","goofs","quotes","crazy","connections"):
669 if extrainfos.group('g_'+category):
670 Extratext += extrainfos.group('g_'+category) + ":\n" + re.sub('\s{5,30}',', ', self.htmltags.sub('', extrainfos.group(category).replace('\n','').replace('<br>', '\n').replace('<br />','\n').replace('&view=simple&sort=alpha&ref_=tt_stry_pl" >',' ').replace(' ','').replace('"','"').replace('|','').replace(' : ',':').replace(', ',' / ')).strip()) + "\n\n"
671 if extrainfos.group("g_comments"):
672 stripmask = re.compile('\s{2,}', re.S)
673 Extratext += extrainfos.group("g_comments") + " [" + stripmask.sub(' ', self.htmltags.sub('', extrainfos.group("commenter"))) + "]:\n" + transHTML(self.htmltags.sub('',extrainfos.group("comment").replace("\n",' '))).strip()
675 self["extralabel"].setText(str(Extratext))
676 self["extralabel"].hide()
677 self["key_blue"].setText(_("Extra Info"))
679 self["key_blue"].setText("")
681 self["detailslabel"].setText(str(Detailstext))
683 def IMDBPoster(self,string):
684 self["statusbar"].setText(_("IMDb Details parsed"))
686 filename = "/tmp/poster.jpg"
688 filename = resolveFilename(SCOPE_PLUGINS, "Extensions/IMDb/no_poster.png")
689 sc = AVSwitch().getFramebufferScale()
690 self.picload.setPara((self["poster"].instance.size().width(), self["poster"].instance.size().height(), sc[0], sc[1], False, 1, "#00000000"))
691 self.picload.startDecode(filename)
693 def paintPosterPixmapCB(self, picInfo=None):
694 ptr = self.picload.getData()
696 self["poster"].instance.setPixmap(ptr)
697 self["poster"].show()
700 self.session.open(IMDbSetup)
702 def createSummary(self):
703 return IMDbLCDScreenV2
705 class IMDbLCDScreenV2(Screen):
707 """<screen title="IMDB Plugin" position="0,0" size="132,64" id="1">
708 <widget name="headline" font="Display;22" halign="center" position="1,3" size="130,22"/>
709 <widget source="parent.titlelcd" render="Label" font="Display;16" halign="center" valign="center" position="1,28" size="130,34"/>
711 """<screen title="IMDB Plugin" position="0,0" size="96,64" id="2">
712 <widget name="headline" font="Display;19" halign="center" position="0,2" size="96,20"/>
713 <widget source="parent.titlelcd" render="Label" font="Display;15" halign="center" valign="center" position="0,28" size="96,34"/>
715 """<screen title="IMDB Plugin" position="0,0" size="400,240" id="3">
716 <ePixmap position="0,0" size="400,240" pixmap="skin_default/display_bg.png" zPosition="-1"/>
717 <widget name="headline" font="Display;60" halign="center" position="0,5" size="400,60" transparent="1"/>
718 <eLabel backgroundColor="yellow" position="0,75" size="400,2" />
719 <widget source="parent.titlelcd" render="Label" font="Display;45" halign="center" valign="center" position="0,85" size="400,135" transparent="1"/>
722 def __init__(self, session, parent):
723 Screen.__init__(self, session, parent)
724 self["headline"] = Label(_("IMDb Plugin"))
726 class IMDbSetup(Screen, ConfigListScreen):
727 def __init__(self, session):
728 Screen.__init__(self, session)
729 self.skinName = "Setup"
731 self.setup_title = _("IMDb Setup")
732 self.onChangedEntry = []
734 self["key_green"] = StaticText(_("OK"))
735 self["key_red"] = StaticText(_("Cancel"))
736 self["description"] = Label("")
738 self["actions"] = ActionMap(["SetupActions"],
740 "cancel": self.keyCancel,
741 "save": self.keySave,
745 ConfigListScreen.__init__(self, self.list, session = self.session, on_change = self.changedEntry)
748 self.onLayoutFinish.append(self.layoutFinished)
750 def createSetup(self):
752 self.list.append(getConfigListEntry(_("IMDb query language"), config.plugins.imdb.language))
753 self.list.append(getConfigListEntry(_("Show in plugin browser"), config.plugins.imdb.showinplugins))
754 self.list.append(getConfigListEntry(_("Words / phrases to ignore (comma separated)"), config.plugins.imdb.ignore_tags))
755 self["config"].list = self.list
756 self["config"].l.setList(self.list)
758 def layoutFinished(self):
759 self.setTitle(_(self.setup_title))
761 def changedEntry(self):
762 self.item = self["config"].getCurrent()
763 for x in self.onChangedEntry:
766 if isinstance(self["config"].getCurrent()[1], ConfigYesNo) or isinstance(self["config"].getCurrent()[1], ConfigSelection):
771 def getCurrentEntry(self):
772 return self["config"].getCurrent() and self["config"].getCurrent()[0] or ""
774 def getCurrentValue(self):
775 return self["config"].getCurrent() and str(self["config"].getCurrent()[1].getText()) or ""
777 def getCurrentDescription(self):
778 return self["config"].getCurrent() and len(self["config"].getCurrent()) > 2 and self["config"].getCurrent()[2] or ""
780 def createSummary(self):
781 from Screens.Setup import SetupSummary
787 if config.plugins.imdb.language.value:
788 imdb_headers = {'Accept-Language': config.plugins.imdb.language.value}
791 if not config.plugins.imdb.showinplugins.value:
792 for plugin in plugins.getPlugins(PluginDescriptor.WHERE_PLUGINMENU):
793 if plugin.name == _("IMDb Details"):
794 plugins.removePlugin(plugin)
796 plugins.readPluginList(resolveFilename(SCOPE_PLUGINS))
799 def eventinfo(session, eventName="", **kwargs):
801 s = session.nav.getCurrentService()
804 event = info.getEvent(0) # 0 = now, 1 = next
805 eventName = event and event.getEventName() or ''
806 session.open(IMDB, eventName)
808 def main(session, eventName="", **kwargs):
809 session.open(IMDB, eventName)
811 pluginlist = PluginDescriptor(name=_("IMDb Details"), description=_("Query details from the Internet Movie Database"), icon="imdb.png", where=PluginDescriptor.WHERE_PLUGINMENU, fnc=main, needsRestart=False)
813 def Plugins(**kwargs):
814 l = [PluginDescriptor(name=_("IMDb Details") + "...",
815 description=_("Query details from the Internet Movie Database"),
816 where=PluginDescriptor.WHERE_EVENTINFO,
822 if config.plugins.imdb.showinplugins.value: