fix query for PREMIERE eventnames "German Title (Original Title)" and tidy up whitespace
[enigma2-plugins.git] / imdb / src / plugin.py
1 # -*- coding: utf8 -*-
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
15 import re
16 import htmlentitydefs
17 import urllib
18
19 class IMDB(Screen):
20         skin = """
21                 <screen name="IMDB" position="90,95" size="560,420" title="Internet Movie Database Details Plugin" >
22                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
23                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
24                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
25                         <ePixmap pixmap="skin_default/buttons/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" />
40                 </screen>"""
41
42         def __init__(self, session, eventName, args = None):
43                 self.skin = IMDB.skin
44                 Screen.__init__(self, session)
45
46                 self.eventName = eventName
47
48                 self.dictionary_init()
49
50                 self["poster"] = Pixmap()
51
52                 self["stars"] = ProgressBar()
53                 self["starsbg"] = Pixmap()
54                 self["stars"].hide()
55                 self["starsbg"].hide()
56                 self.ratingstars = -1
57
58                 self["titellabel"] = Label("The Internet Movie Database")
59                 self["detailslabel"] = ScrollLabel("")
60                 self["castlabel"] = ScrollLabel("")
61                 self["extralabel"] = ScrollLabel("")
62                 self["statusbar"] = Label("")
63                 self["ratinglabel"] = Label("")
64                 self.resultlist = []
65                 self["menu"] = MenuList(self.resultlist)
66                 self["menu"].hide()
67
68                 self["key_red"] = Button(self._("Exit"))
69                 self["key_green"] = Button("")
70                 self["key_yellow"] = Button("")
71                 self["key_blue"] = Button("")
72
73                 # 0 = multiple query selection menu page
74                 # 1 = movie info page
75                 # 2 = extra infos page
76                 self.Page = 0
77
78                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "MovieSelectionActions", "DirectionActions"],
79                 {
80                         "ok": self.showDetails,
81                         "cancel": self.close,
82                         "down": self.pageDown,
83                         "up": self.pageUp,
84                         "red": self.close,
85                         "green": self.showMenu,
86                         "yellow": self.showDetails,
87                         "blue": self.showExtras,
88                         "showEventInfo": self.showDetails
89                 }, -1)
90
91                 self.getIMDB()
92
93         def dictionary_init(self):
94                 syslang = language.getLanguage()
95                 if syslang.find("de") is -1:
96                         self.IMDBlanguage = ""  # set to empty ("") for english version
97                 else:
98                         self.IMDBlanguage = "german." # it's a subdomain, so add a '.' at the end
99
100                 self.dict = {}
101                 self.dict["of"]="von"
102                 self.dict[" as "]=" als "
103                 self.dict["Ambiguous results"]="Kein eindeutiger Treffer"
104                 self.dict["Please select the matching entry"]="Bitte passenden Eintrag auswählen"
105                 self.dict["No IMDb match."]="Keine passenden Einträge gefunden."
106                 self.dict["IMDb query failed!"]="IMDb-Query fehlgeschlagen!"
107                 self.dict["No details found."]="Keine Details gefunden."
108                 self.dict["no user rating yet"]="noch keine Nutzerwertung"
109                 self.dict["Cast: "]="Darsteller: "
110                 self.dict["No cast list found in the database."]="Keine Darstellerliste in der Datenbank gefunden."
111                 self.dict["Exit"]="Beenden"
112                 self.dict["Extra Info"]="Zusatzinfos"
113                 self.dict["Title Menu"]="Titelauswahl"
114
115                 self.htmltags = re.compile('<.*?>')
116
117                 self.generalinfomask = re.compile(
118                 '<h1>(?P<title>.*?) <.*?</h1>.*?'
119                 '(?:.*?<h5>(?P<g_director>Regisseur|Directors?):</h5>.*?>(?P<director>.*?)</a>)*'
120                 '(?:.*?<h5>(?P<g_creator>Sch\S*?pfer|Creators?):</h5>.*?>(?P<creator>.*?)</a>)*'
121                 '(?:.*?<h5>(?P<g_seasons>Seasons):</h5>(?:.*?)<a href=\".*?\">(?P<seasons>\d+?)</a>\s+?(?:<a class|\|\s+?<a href="episodes#season-unknown))*'
122                 '(?:.*?<h5>(?P<g_writer>Drehbuch|Writer).*?</h5>.*?>(?P<writer>.*?)</a>)*'
123                 '(?:.*?<h5>(?P<g_premiere>Premiere|Release Date).*?</h5>\s.*?\n?(?P<premiere>.*?)\n\s.*?<)*'
124                 '(?:.*?<h5>(?P<g_alternativ>Alternativ|Also Known As):</h5>(?P<alternativ>.*?)<br>\s{0,8}<a.*?>(?:mehr|more))*'
125                 '(?:.*?<h5>(?P<g_country>Produktionsland|Country):</h5>.*?<a.*?>(?P<country>.*?)</a>(?:.*?mehr|\n</div>))*'
126                 , re.DOTALL)
127
128                 self.extrainfomask = re.compile(
129                 '(?:.*?<h5>(?P<g_tagline>Werbezeile|Tagline?):</h5>\n(?P<tagline>.+?)<)*'
130                 '(?:.*?<h5>(?P<g_outline>Kurzbeschreibung|Plot Outline):</h5>(?P<outline>.+?)<)*'
131                 '(?:.*?<h5>(?P<g_synopsis>Plot Synopsis):</h5>(?:.*?)(?:<a href=\".*?\">)*?(?P<synopsis>.+?)(?:</a>|</div>))*'
132                 '(?:.*?<h5>(?P<g_keywords>Plot Keywords):</h5>(?P<keywords>.+?)(?:mehr|more</a>|</div>))*'
133                 '(?:.*?<h5>(?P<g_awards>Filmpreise|Awards):</h5>(?P<awards>.+?)(?:mehr|more</a>|</div>))*'
134                 '(?:.*?<h5>(?P<g_runtime>L\S*?nge|Runtime):</h5>(?P<runtime>.+?)<)*'
135                 '(?:.*?<h5>(?P<g_language>Sprache|Language):</h5>(?P<language>.+?)</div>)*'
136                 '(?:.*?<h5>(?P<g_color>Farbe|Color):</h5>(?P<color>.+?)</div>)*'
137                 '(?:.*?<h5>(?P<g_aspect>Seitenverh\S*?ltnis|Aspect Ratio):</h5>(?P<aspect>.+?)(?:mehr|more</a>|</div>))*'
138                 '(?:.*?<h5>(?P<g_sound>Tonverfahren|Sound Mix):</h5>(?P<sound>.+?)</div>)*'
139                 '(?:.*?<h5>(?P<g_cert>Altersfreigabe|Certification):</h5>(?P<cert>.+?)</div>)*'
140                 '(?:.*?<h5>(?P<g_locations>Drehorte|Filming Locations):</h5>(?P<locations>.+?)(?:mehr|more</a>|</div>))*'
141                 '(?:.*?<h5>(?P<g_company>Firma|Company):</h5>(?P<company>.+?)(?:mehr|more</a>|</div>))*'
142                 '(?:.*?<h5>(?P<g_trivia>Dies und das|Trivia):</h5>(?P<trivia>.+?)(?:mehr|more</a>|</div>))*'
143                 '(?:.*?<h5>(?P<g_goofs>Pannen|Goofs):</h5>(?P<goofs>.+?)(?:mehr|more</a>|</div>))*'
144                 '(?:.*?<h5>(?P<g_quotes>Dialogzitate|Quotes):</h5>(?P<quotes>.+?)(?:mehr|more</a>|</div>))*'
145                 '(?:.*?<h5>(?P<g_connections>Bez\S*?ge zu anderen Titeln|Movie Connections):</h5>(?P<connections>.+?)(?:mehr|more</a>|</div>))*'
146                 '(?:.*?<h3>(?P<g_comments>Nutzerkommentare|User Comments)</h3>.*?<a href="/user/ur\d{7,7}/comments">(?P<commenter>.+?)\n</div>.*?<p>(?P<comment>.+?)</p>)*'
147                 , re.DOTALL)
148
149         def _(self, in_string):
150                 out_string = in_string
151                 if ((self.IMDBlanguage).find("german")) != -1:
152                         out_string = self.dict.get(in_string, in_string)
153                 return out_string
154
155         def resetLabels(self):
156                 self["detailslabel"].setText("")
157                 self["ratinglabel"].setText("")
158                 self["titellabel"].setText("")
159                 self["castlabel"].setText("")
160                 self["titellabel"].setText("")
161                 self["extralabel"].setText("")
162                 self.ratingstars = -1
163
164         def pageUp(self):
165                 if self.Page == 0:
166                         self["menu"].instance.moveSelection(self["menu"].instance.moveUp)
167                 if self.Page == 1:
168                         self["castlabel"].pageUp()
169                         self["detailslabel"].pageUp()
170                 if self.Page == 2:
171                         self["extralabel"].pageUp()
172
173         def pageDown(self):
174                 if self.Page == 0:
175                         self["menu"].instance.moveSelection(self["menu"].instance.moveDown)
176                 if self.Page == 1:
177                         self["castlabel"].pageDown()
178                         self["detailslabel"].pageDown()
179                 if self.Page == 2:
180                         self["extralabel"].pageDown()
181
182         def showMenu(self):
183                 if ( self.Page is 1 or self.Page is 2 ) and self.resultlist:
184                         self["menu"].show()
185                         self["stars"].hide()
186                         self["starsbg"].hide()
187                         self["ratinglabel"].hide()
188                         self["castlabel"].hide()
189                         self["poster"].hide()
190                         self["extralabel"].hide()
191                         self["titellabel"].setText(self._("Ambiguous results"))
192                         self["detailslabel"].setText(self._("Please select the matching entry"))
193                         self["detailslabel"].show()
194                         self["key_blue"].setText("")
195                         self["key_green"].setText(self._("Title Menu"))
196                         self["key_yellow"].setText(self._("Details"))
197                         self.Page = 0
198
199         def showDetails(self):
200                 self["ratinglabel"].show()
201                 self["castlabel"].show()
202                 self["detailslabel"].show()
203
204                 if self.resultlist and self.Page == 0:
205                         link = self["menu"].getCurrent()[1]
206                         title = self["menu"].getCurrent()[0]
207                         self["statusbar"].setText("Re-Query IMDb: "+title+"...")
208                         localfile = "/home/root/imdbquery2.html"
209                         fetchurl = "http://" + self.IMDBlanguage + "imdb.com/title/" + link
210                         print "[IMDB] downloading query " + fetchurl + " to " + localfile
211                         downloadPage(fetchurl,localfile).addCallback(self.IMDBquery2).addErrback(self.fetchFailed)
212                         self["menu"].hide()
213                         self.resetLabels()
214                         self.Page = 1
215
216                 if self.Page == 2:
217                         self["extralabel"].hide()
218                         self["poster"].show()
219                         if self.ratingstars > 0:
220                                 self["starsbg"].show()
221                                 self["stars"].show()
222                                 self["stars"].setValue(self.ratingstars)
223
224                         self.Page = 1
225
226         def showExtras(self):
227                 if self.Page == 1:
228                         self["extralabel"].show()
229                         self["detailslabel"].hide()
230                         self["castlabel"].hide()
231                         self["poster"].hide()
232                         self["stars"].hide()
233                         self["starsbg"].hide()
234                         self["ratinglabel"].hide()
235                         self.Page = 2
236
237         def getIMDB(self):
238                 self.resetLabels()
239                 if self.eventName is "":
240                         s = self.session.nav.getCurrentService()
241                         info = s.info()
242                         event = info.getEvent(0) # 0 = now, 1 = next
243                         if event:
244                                 self.eventName = event.getEventName()
245                 if self.eventName is not "":
246                         self["statusbar"].setText("Query IMDb: " + self.eventName + "...")
247                         event_quoted = urllib.quote(self.eventName.decode('utf8').encode('latin-1','ignore'))
248                         localfile = "/home/root/imdbquery.html"
249                         fetchurl = "http://" + self.IMDBlanguage + "imdb.com/find?q=" + event_quoted + "&s=tt&site=aka"
250                         print "[IMDB] Downloading Query " + fetchurl + " to " + localfile
251                         downloadPage(fetchurl,localfile).addCallback(self.IMDBquery).addErrback(self.fetchFailed)
252                 else:
253                         self["statusbar"].setText("Could't get Eventname -_-")
254
255         def fetchFailed(self,string):
256                 print "[IMDB] fetch failed " + string
257                 self["statusbar"].setText("IMDb Download failed -_-")
258
259         def html2utf8(self,in_html):
260                 htmlentitynumbermask = re.compile('(&#(\d{1,5}?);)')
261                 htmlentitynamemask = re.compile('(&(\D{1,5}?);)')
262
263                 entities = htmlentitynamemask.finditer(in_html)
264                 entitydict = {}
265
266                 for x in entities:
267                         entitydict[x.group(1)] = x.group(2)
268
269                 for key, name in entitydict.items():
270                         entitydict[key] = htmlentitydefs.name2codepoint[name]
271
272                 entities = htmlentitynumbermask.finditer(in_html)
273
274                 for x in entities:
275                         entitydict[x.group(1)] = x.group(2)
276
277                 for key, codepoint in entitydict.items():
278                         in_html = in_html.replace(key, (unichr(int(codepoint)).encode('latin-1')))
279
280                 self.inhtml = in_html.decode('latin-1').encode('utf8')
281
282         def IMDBquery(self,string):
283                 print "[IMDBquery]"
284                 self["statusbar"].setText("IMDb Download completed")
285
286                 self.html2utf8(open("/home/root/imdbquery.html", "r").read())
287
288                 self.generalinfos = self.generalinfomask.search(self.inhtml)
289
290                 if self.generalinfos:
291                         self.IMDBparse()
292                 else:
293                         if re.search("<title>(?:IMDb.{0,9}Search|IMDb Titelsuche)</title>", self.inhtml):
294                                 searchresultmask = re.compile("href=\".*?/title/(tt\d{7,7})/\">(.*?)</td>", re.DOTALL)
295                                 searchresults = searchresultmask.finditer(self.inhtml)
296                                 self.resultlist = []
297                                 if searchresults:
298                                         for x in searchresults:
299                                                 self.resultlist.append((self.htmltags.sub('',x.group(2)), x.group(1)))
300                                         self["menu"].l.setList(self.resultlist)
301                                 if len(self.resultlist) > 1:
302                                         self.Page = 1
303                                         self.showMenu()
304                                 else:
305                                         self["detailslabel"].setText(self._("No IMDb match."))
306                                         self["statusbar"].setText("No IMDb match")
307                         else:
308                                 splitpos = self.eventName.find('(')
309                                 if splitpos > 0 and self.eventName.endswith(')'):
310                                         self.eventName = self.eventName[splitpos+1:-1]
311                                         self["statusbar"].setText("Re-Query IMDb: " + self.eventName + "...")
312                                         event_quoted = urllib.quote(self.eventName.decode('utf8').encode('latin-1','ignore'))
313                                         localfile = "/home/root/imdbquery.html"
314                                         fetchurl = "http://" + self.IMDBlanguage + "imdb.com/find?q=" + event_quoted + "&s=tt&site=aka"
315                                         print "[IMDB] Downloading Query " + fetchurl + " to " + localfile
316                                         downloadPage(fetchurl,localfile).addCallback(self.IMDBquery).addErrback(self.fetchFailed)
317                                 else:
318                                         self["detailslabel"].setText(self._("IMDb query failed!"))
319
320         def IMDBquery2(self,string):
321                 self["statusbar"].setText("IMDb Re-Download completed")
322                 self.html2utf8(open("/home/root/imdbquery2.html", "r").read())
323                 self.generalinfos = self.generalinfomask.search(self.inhtml)
324                 self.IMDBparse()
325
326         def IMDBparse(self):
327                 print "[IMDBparse]"
328                 self.Page = 1
329                 Detailstext = self._("No details found.")
330                 if self.generalinfos:
331                         self["key_yellow"].setText(self._("Details"))
332                         self["statusbar"].setText("IMDb Details parsed ^^")
333
334                         Titeltext = self.generalinfos.group("title")
335                         if len(Titeltext) > 57:
336                                 Titeltext = Titeltext[0:54] + "..."
337                         self["titellabel"].setText(Titeltext)
338
339                         Detailstext = ""
340
341                         genreblockmask = re.compile('<h5>Genre:</h5>(.*?)(?:mehr|more|</div>)', re.DOTALL)
342                         genreblock = genreblockmask.findall(self.inhtml)
343                         genremask = re.compile('\">(.*?)</a')
344                         if genreblock:
345                                 genres = genremask.finditer(genreblock[0])
346                                 if genres:
347                                         Detailstext += "Genre: "
348                                         for x in genres:
349                                                 Detailstext += x.group(1) + " "
350
351                         detailscategories = ["director", "creator", "writer", "premiere", "seasons", "country"]
352
353                         for category in detailscategories:
354                                 if self.generalinfos.group('g_'+category):
355                                         Detailstext += "\n" + self.generalinfos.group('g_'+category) + ": " + self.generalinfos.group(category)
356
357                         if self.generalinfos.group("alternativ"):
358                                 Detailstext += "\n" + self.generalinfos.group("g_alternativ") + ": " + self.htmltags.sub('',(self.generalinfos.group("alternativ").replace('\n','').replace("<br>",'\n').replace("  ",' ')))
359
360                         ratingmask = re.compile('(?P<g_rating>Nutzer-Bewertung|User Rating):</b>.{0,2}<b>(?P<rating>.*?)/10</b>', re.DOTALL)
361                         rating = ratingmask.search(self.inhtml)
362                         Ratingtext = self._("no user rating yet")
363                         if rating:
364                                 Ratingtext = rating.group("g_rating") + ": " + rating.group("rating") + " / 10"
365                                 self.ratingstars = int(10*round(float(rating.group("rating")),1))
366                                 self["stars"].show()
367                                 self["stars"].setValue(self.ratingstars)
368                                 self["starsbg"].show()
369                         self["ratinglabel"].setText(Ratingtext)
370
371                         castmask = re.compile('<td class="nm">.*?>(.*?)</a>.*?<td class="char">(?:<a.*?>)?(.*?)(?:</a>)?</td>', re.DOTALL)
372                         castresult = castmask.finditer(self.inhtml)
373                         if castresult:
374                                 Casttext = ""
375                                 for x in castresult:
376                                         Casttext += "\n" + self.htmltags.sub('', x.group(1))
377                                         if x.group(2):
378                                                 Casttext += self._(" als ") + self.htmltags.sub('', x.group(2).replace('/ ...',''))
379                                 if Casttext is not "":
380                                         Casttext = self._("Cast: ") + Casttext
381                                 else:
382                                         Casttext = self._("No cast list found in the database.")
383                                 self["castlabel"].setText(Casttext)
384
385                         postermask = re.compile('<div class="photo">.*?<img .*? src=\"(http.*?)\" .*?>', re.DOTALL)
386                         posterurl = postermask.search(self.inhtml).group(1)
387                         if posterurl.find("jpg") > 0:
388                                 self["statusbar"].setText("Downloading Movie Poster: "+posterurl+"...")
389                                 localfile = "/home/root/poster.jpg"
390                                 print "[IMDB] downloading poster " + posterurl + " to " + localfile
391                                 downloadPage(posterurl,localfile).addCallback(self.IMDBPoster).addErrback(self.fetchFailed)
392                         else:
393                                 self.IMDBPoster("kein Poster")
394
395                         extrainfos = self.extrainfomask.search(self.inhtml)
396
397                         if extrainfos:
398                                 Extratext = "Extra Info\n"
399                                 extracategories = ["tagline","outline","synopsis","keywords","awards","runtime","language","color","aspect","sound","cert","locations","company","trivia","goofs","quotes","connections"]
400
401                                 for category in extracategories:
402                                         if extrainfos.group('g_'+category):
403                                                 Extratext += extrainfos.group('g_'+category) + ": " + self.htmltags.sub('',extrainfos.group(category).replace("\n",'').replace("<br>",'\n')) + "\n"
404                                 if extrainfos.group("g_comments"):
405                                         Extratext += extrainfos.group("g_comments") + " [" + self.htmltags.sub('',extrainfos.group("commenter")) + "]: " + self.htmltags.sub('',extrainfos.group("comment").replace("\n",' ')) + "\n"
406
407                                 self["extralabel"].setText(Extratext)
408                                 self["extralabel"].hide()
409                                 self["key_blue"].setText(self._("Extra Info"))
410
411                 self["detailslabel"].setText(Detailstext)
412
413         def IMDBPoster(self,string):
414                 self["statusbar"].setText("IMDb Details parsed ^^")
415                 if not string:
416                         filename = "/home/root/poster.jpg"
417                 else:
418                         filename = "/usr/lib/enigma2/python/Plugins/Extensions/IMDb/no_poster.png"
419                 pixmap = loadPic(filename, 96,140, AVSwitch().getAspectRatioSetting()/2,1,0,0)
420                 if pixmap is not None:
421                         self["poster"].instance.setPixmap(pixmap.__deref__())
422                         self["poster"].show()
423
424         def createSummary(self):
425                 return IMDbLCDScreen
426
427 class IMDbLCDScreen(Screen):
428         skin = """
429         <screen position="0,0" size="132,64" title="IMDB Plugin">
430                 <widget name="headline" position="4,0" size="128,22" font="Regular;20"/>
431                 <widget source="session.Event_Now" render="Label" position="6,26" size="120,34" font="Regular;14" >
432                         <convert type="EventName">Name</convert>
433                 </widget>
434         </screen>"""
435
436         def __init__(self, session, parent):
437                 Screen.__init__(self, session)
438                 self["headline"] = Label("IMDB Plugin")
439
440 def main(session, eventName="", **kwargs):
441         session.open(IMDB, eventName)
442
443 def Plugins(**kwargs):
444         try:
445                 wherelist = [PluginDescriptor.WHERE_EVENTINFO, PluginDescriptor.WHERE_PLUGINMENU]
446                 return PluginDescriptor(name="IMDb Details",
447                                 description=_("Query details from the Internet Movie Database"),
448                                 icon="imdb.png",
449                                 where = wherelist,
450                                 fnc=main)
451         except AttributeError:
452                 wherelist = [PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU]
453                 return PluginDescriptor(name="IMDb Details",
454                                 description=_("Query details from the Internet Movie Database"),
455                                 icon="imdb.png",
456                                 where = wherelist,
457                                 fnc=main)