add new plugin to query movie details from ofdb.de
authorAndreas Frisch <andreas.frisch@multimedia-labs.de>
Fri, 2 May 2008 13:59:37 +0000 (13:59 +0000)
committerAndreas Frisch <andreas.frisch@multimedia-labs.de>
Fri, 2 May 2008 13:59:37 +0000 (13:59 +0000)
ofdb/CONTROL/control [new file with mode: 0755]
ofdb/Makefile.am [new file with mode: 0755]
ofdb/src/Makefile.am [new file with mode: 0755]
ofdb/src/__init__.py [new file with mode: 0644]
ofdb/src/no_poster.png [new file with mode: 0644]
ofdb/src/ofdb.png [new file with mode: 0755]
ofdb/src/plugin.py [new file with mode: 0644]
ofdb/src/starsbar_empty.png [new file with mode: 0644]
ofdb/src/starsbar_filled.png [new file with mode: 0644]

diff --git a/ofdb/CONTROL/control b/ofdb/CONTROL/control
new file mode 100755 (executable)
index 0000000..dbda05f
--- /dev/null
@@ -0,0 +1,10 @@
+Package: enigma2-plugin-extensions-ofdb
+Version: 0.1-20080502-r0
+Description: query movie details from the Online Film Datenbank
+Architecture: mipsel
+Section: extra
+Priority: optional
+Maintainer: fraxinas <andreas.frisch@multimedia-labs.de>
+Homepage: n/a
+Depends: enigma2(>1.0cvs20070908), python-html, twisted-web
+Source: http://schwerkraft.elitedvb.net/scm/?group_id=11
diff --git a/ofdb/Makefile.am b/ofdb/Makefile.am
new file mode 100755 (executable)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/ofdb/src/Makefile.am b/ofdb/src/Makefile.am
new file mode 100755 (executable)
index 0000000..d88caf8
--- /dev/null
@@ -0,0 +1,4 @@
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/OFDb\r
+\r
+install_PYTHON = __init__.py plugin.py\r
+install_DATA = ofdb.png  no_poster.png starsbar_empty.png  starsbar_filled.png
\ No newline at end of file
diff --git a/ofdb/src/__init__.py b/ofdb/src/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/ofdb/src/no_poster.png b/ofdb/src/no_poster.png
new file mode 100644 (file)
index 0000000..8f612a3
Binary files /dev/null and b/ofdb/src/no_poster.png differ
diff --git a/ofdb/src/ofdb.png b/ofdb/src/ofdb.png
new file mode 100755 (executable)
index 0000000..2eabf08
Binary files /dev/null and b/ofdb/src/ofdb.png differ
diff --git a/ofdb/src/plugin.py b/ofdb/src/plugin.py
new file mode 100644 (file)
index 0000000..c04e4d5
--- /dev/null
@@ -0,0 +1,412 @@
+# -*- coding: utf8 -*-
+from Plugins.Plugin import PluginDescriptor
+from twisted.web.client import downloadPage
+from enigma import loadPic
+from Screens.Screen import Screen
+from Components.ActionMap import ActionMap
+from Components.Pixmap import Pixmap
+from Components.Label import Label
+from Components.ScrollLabel import ScrollLabel
+from Components.Button import Button
+from Components.AVSwitch import AVSwitch
+from Components.MenuList import MenuList
+from Components.Language import language
+from Components.ProgressBar import ProgressBar
+import re
+import htmlentitydefs
+import urllib
+
+class OFDB(Screen):
+       skin = """
+               <screen name="OFDb" position="90,95" size="560,420" title="Internet Movie Database Details Plugin" >
+                       <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" zPosition="0" size="140,40" transparent="1" alphatest="on" />
+                       <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#9f1313" transparent="1" />
+                       <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+                       <widget name="key_yellow" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
+                       <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
+                       <widget name="titellabel" position="10,40" size="330,45" valign="center" font="Regular;22"/>
+                       <widget name="detailslabel" position="105,90" size="445,140" font="Regular;18" />
+                       <widget name="castlabel" position="10,235" size="540,155" font="Regular;18" />
+                       <widget name="extralabel" position="10,40" size="540,350" font="Regular;18" />
+                       <widget name="ratinglabel" position="340,62" size="210,20" halign="center" font="Regular;18" foregroundColor="#f0b400"/>
+                       <widget name="statusbar" position="10,404" size="540,16" font="Regular;16" foregroundColor="#cccccc" />
+                       <widget name="poster" position="4,90" size="96,140" alphatest="on" />
+                       <widget name="menu" position="10,115" size="540,275" zPosition="3" scrollbarMode="showOnDemand" />
+                       <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" />
+                       <widget name="stars" position="340,40" size="210,21" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/OFDb/starsbar_filled.png" transparent="1" />
+               </screen>"""
+
+       def __init__(self, session, eventName, args = None):
+               self.skin = OFDB.skin
+               Screen.__init__(self, session)
+               self.eventName = eventName
+               self.dictionary_init()
+               self["poster"] = Pixmap()
+               self["stars"] = ProgressBar()
+               self["starsbg"] = Pixmap()
+               self["stars"].hide()
+               self["starsbg"].hide()
+               self.ratingstars = -1
+               self["titellabel"] = Label("The Internet Movie Database")
+               self["detailslabel"] = ScrollLabel("")
+               self["castlabel"] = ScrollLabel("")
+               self["extralabel"] = ScrollLabel("")
+               self["statusbar"] = Label("")
+               self["ratinglabel"] = Label("")
+               self.resultlist = []
+               self["menu"] = MenuList(self.resultlist)
+               self["menu"].hide()
+               self["key_red"] = Button(self._("Exit"))
+               self["key_green"] = Button("")
+               self["key_yellow"] = Button("")
+               self["key_blue"] = Button("")
+               # 0 = multiple query selection menu page
+               # 1 = movie info page
+               # 2 = extra infos page
+               self.Page = 0
+
+               self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "MovieSelectionActions", "DirectionActions"],
+               {
+                       "ok": self.showDetails,
+                       "cancel": self.close,
+                       "down": self.pageDown,
+                       "up": self.pageUp,
+                       "red": self.close,
+                       "green": self.showMenu,
+                       "yellow": self.showDetails,
+                       "blue": self.showExtras,
+                       "showEventInfo": self.showDetails
+               }, -1)
+               
+               self.getOFDB()
+
+       def dictionary_init(self):
+               syslang = language.getLanguage()
+               if syslang.find("de") is -1:
+                       self.OFDBlanguage = ""  # set to empty ("") for english version
+               else:
+                       self.OFDBlanguage = "german." # it's a subdomain, so add a '.' at the end
+
+               self.dict = {}
+               self.dict["of"]="von"
+               self.dict[" as "]=" als "
+               self.dict["Ambiguous results"]="Kein eindeutiger Treffer"
+               self.dict["Please select the matching entry"]="Bitte passenden Eintrag auswählen"
+               self.dict["No OFDb match."]="Keine passenden Einträge gefunden."
+               self.dict["OFDb query failed!"]="OFDb-Query fehlgeschlagen!"
+               self.dict["No details found."]="Keine Details gefunden."
+               self.dict["no user rating yet"]="noch keine Nutzerwertung"
+               self.dict["Cast: "]="Darsteller: "
+               self.dict["No cast list found in the database."]="Keine Darstellerliste in der Datenbank gefunden."
+               self.dict["Exit"]="Beenden"
+               self.dict["Extra Info"]="Zusatzinfos"
+               self.dict["Title Menu"]="Titelauswahl"
+
+               self.htmltags = re.compile('<.*?>')
+
+               self.generalinfomask = re.compile(
+               '<title>OFDb - (?P<title>.*?)</title>.*?'
+               '(?P<g_original>Originaltitel):[\s\S]*?class=\"Daten\">(?P<original>.*?)</td>'
+               '(?:.*?(?P<g_country>Herstellungsland):[\s\S]*?class="Daten">(?P<country>.*?)(?:\.\.\.|</td>))*'
+               '(?:.*?(?P<g_year>Erscheinungsjahr):[\s\S]*?class="Daten">(?P<year>.*?)</td>)*'
+               '(?:.*?(?P<g_director>Regie):[\s\S]*?class="Daten">(?P<director>.*?)(?:\.\.\.|</td>))*'
+               , re.DOTALL)
+
+       def _(self, in_string):
+               out_string = in_string
+               if ((self.OFDBlanguage).find("german")) != -1:
+                       out_string = self.dict.get(in_string, in_string)
+               return out_string
+
+       def resetLabels(self):
+               self["detailslabel"].setText("")
+               self["ratinglabel"].setText("")
+               self["titellabel"].setText("")
+               self["castlabel"].setText("")
+               self["titellabel"].setText("")
+               self["extralabel"].setText("")
+               self.ratingstars = -1
+
+       def pageUp(self):
+               if self.Page == 0:
+                       self["menu"].instance.moveSelection(self["menu"].instance.moveUp)
+               if self.Page == 1:
+                       self["castlabel"].pageUp()
+                       self["detailslabel"].pageUp()
+               if self.Page == 2:
+                       self["extralabel"].pageUp()
+       
+       def pageDown(self):
+               if self.Page == 0:
+                       self["menu"].instance.moveSelection(self["menu"].instance.moveDown)
+               if self.Page == 1:
+                       self["castlabel"].pageDown()
+                       self["detailslabel"].pageDown()
+               if self.Page == 2:
+                       self["extralabel"].pageDown()
+
+       def showMenu(self):
+               if ( self.Page is 1 or self.Page is 2 ) and self.resultlist:
+                       self["menu"].show()
+                       self["stars"].hide()
+                       self["starsbg"].hide()
+                       self["ratinglabel"].hide()
+                       self["castlabel"].hide()
+                       self["poster"].hide()
+                       self["extralabel"].hide()
+                       self["titellabel"].setText(self._("Ambiguous results"))
+                       self["detailslabel"].setText(self._("Please select the matching entry"))
+                       self["detailslabel"].show()
+                       self["key_blue"].setText("")
+                       self["key_green"].setText(self._("Title Menu"))
+                       self["key_yellow"].setText(self._("Details"))
+                       self.Page = 0
+
+       def showDetails(self):
+               self["ratinglabel"].show()
+               self["castlabel"].show()
+               self["detailslabel"].show()
+
+               if self.resultlist and self.Page == 0:
+                       link = self["menu"].getCurrent()[1]
+                       title = self["menu"].getCurrent()[0]
+                       self["statusbar"].setText("Re-Query OFDb: "+title+"...")
+                       localfile = "/home/root/ofdbquery2.html"
+                       fetchurl = "http://www.ofdb.de/film/" + link
+                       print "[OFDb] downloading query " + fetchurl + " to " + localfile
+                       downloadPage(fetchurl,localfile).addCallback(self.OFDBquery2).addErrback(self.fetchFailed)
+                       self["menu"].hide()
+                       self.resetLabels()
+                       self.Page = 1
+
+               if self.Page == 2:
+                       self["extralabel"].hide()
+                       self["poster"].show()
+                       if self.ratingstars > 0:
+                               self["starsbg"].show()
+                               self["stars"].show()
+                               self["stars"].setValue(self.ratingstars)
+
+                       self.Page = 1
+
+       def showExtras(self):
+               if self.Page == 1:
+                       self["extralabel"].show()
+                       self["detailslabel"].hide()
+                       self["castlabel"].hide()
+                       self["poster"].hide()
+                       self["stars"].hide()
+                       self["starsbg"].hide()
+                       self["ratinglabel"].hide()
+                       self.Page = 2
+
+       def getOFDB(self):
+               self.resetLabels()
+               if self.eventName is "":
+                       s = self.session.nav.getCurrentService()
+                       info = s.info()
+                       event = info.getEvent(0) # 0 = now, 1 = next
+                       if event:
+                               self.eventName = event.getEventName()
+
+               if self.eventName is not "":
+                       self["statusbar"].setText("Query OFDb: " + self.eventName + "...")
+                       try:
+                               self.eventName = urllib.quote(self.eventName)
+                       except:
+                               self.eventName = urllib.quote(self.eventName.decode('utf8').encode('ascii','ignore'))
+                       localfile = "/home/root/ofdbquery.html"
+                       fetchurl = "http://www.ofdb.de/view.php?page=suchergebnis&Kat=DTitel&SText=" + self.eventName
+                       print "[OFDb] Downloading Query " + fetchurl + " to " + localfile
+                       downloadPage(fetchurl,localfile).addCallback(self.OFDBquery).addErrback(self.fetchFailed)
+               else:
+                       self["statusbar"].setText("Could't get Eventname -_-")
+
+       def fetchFailed(self,string):
+               print "[OFDb] fetch failed " + string
+               self["statusbar"].setText("OFDb Download failed -_-")
+
+       def html2utf8(self,in_html):
+               htmlentitynumbermask = re.compile('(&#(\d{1,5}?);)')
+               htmlentitynamemask = re.compile('(&(\D{1,5}?);)')
+               
+               entities = htmlentitynamemask.finditer(in_html)
+               entitydict = {}
+
+               for x in entities:
+                       entitydict[x.group(1)] = x.group(2)
+
+               for key, name in entitydict.items():
+                       entitydict[key] = htmlentitydefs.name2codepoint[name]
+
+               entities = htmlentitynumbermask.finditer(in_html)
+
+               for x in entities:
+                       entitydict[x.group(1)] = x.group(2)
+
+               for key, codepoint in entitydict.items():
+                       in_html = in_html.replace(key, (unichr(int(codepoint)).encode('utf8')))
+
+               self.inhtml = in_html
+
+       def OFDBquery(self,string):
+               print "[OFDBquery]"
+               self["statusbar"].setText("OFDb Download completed")
+
+               self.html2utf8(open("/home/root/ofdbquery.html", "r").read())
+
+               self.generalinfos = self.generalinfomask.search(self.inhtml)
+
+               if self.generalinfos:
+                       self.OFDBparse()
+               else:
+                       if re.search("<title>OFDb - Suchergebnis</title>", self.inhtml):
+                               searchresultmask = re.compile("<br>(\d{1,3}\.) <a href=\"film/(.*?)\"(?:.*?)\)\">(.*?)</a>", re.DOTALL)
+                               searchresults = searchresultmask.finditer(self.inhtml)
+                               self.resultlist = []
+                               if searchresults:
+                                       for x in searchresults:
+                                               self.resultlist.append((self.htmltags.sub('',x.group(3)), x.group(2)))
+                                       self["menu"].l.setList(self.resultlist)
+                               if len(self.resultlist) == 1:
+                                       self.Page = 0
+                                       self["extralabel"].hide()
+                                       self.showDetails()
+                               elif len(self.resultlist) > 1:
+                                       self.Page = 1
+                                       self.showMenu()
+                               else:
+                                       self["detailslabel"].setText(self._("No OFDb match."))
+                                       self["statusbar"].setText("No OFDb match")
+                       else:
+                               self["detailslabel"].setText(self._("OFDb query failed!"))
+
+       def OFDBquery2(self,string):
+               self["statusbar"].setText("OFDb Re-Download completed")
+               self.html2utf8(open("/home/root/ofdbquery2.html", "r").read())
+               self.generalinfos = self.generalinfomask.search(self.inhtml)
+               self.OFDBparse()
+
+       def OFDBparse(self):
+               print "[OFDBparse]"
+               self.Page = 1
+               Detailstext = self._("No details found.")
+               if self.generalinfos:
+                       self["key_yellow"].setText(self._("Details"))
+                       self["statusbar"].setText("OFDb Details parsed ^^")
+                       
+                       Titeltext = self.generalinfos.group("title")
+                       if len(Titeltext) > 57:
+                               Titeltext = Titeltext[0:54] + "..."
+                       self["titellabel"].setText(Titeltext)
+
+                       Detailstext = ""
+
+                       genreblockmask = re.compile('Genre\(s\):(?:[\s\S]*?)class=\"Daten\">(.*?)</tr>', re.DOTALL)
+                       genreblock = genreblockmask.findall(self.inhtml)
+                       genremask = re.compile('\">(.*?)</a')
+                       if genreblock:
+                               genres = genremask.finditer(genreblock[0])
+                               if genres:
+                                       Detailstext += "Genre: "
+                                       for x in genres:
+                                               Detailstext += self.htmltags.sub('', x.group(1)) + " "
+
+                       detailscategories = ["director", "year", "country", "original"]
+
+                       for category in detailscategories:
+                               if self.generalinfos.group('g_'+category):
+                                       Detailstext += "\n" + self.generalinfos.group('g_'+category) + ": " + self.htmltags.sub('', self.generalinfos.group(category).replace("<br>",' '))
+
+                       self["detailslabel"].setText(Detailstext)
+
+                       #if self.generalinfos.group("alternativ"):
+                               #Detailstext += "\n" + self.generalinfos.group("g_alternativ") + ": " + self.htmltags.sub('',(self.generalinfos.group("alternativ").replace('\n','').replace("<br>",'\n').replace("  ",' ')))
+
+                       ratingmask = re.compile('<td>[\s\S]*notenskala.*(?P<g_rating>Note: )(?P<rating>\d.\d{2,2})[\s\S]*</td>', re.DOTALL)
+                       rating = ratingmask.search(self.inhtml)
+                       Ratingtext = self._("no user rating yet")
+                       if rating:
+                               Ratingtext = rating.group("g_rating") + rating.group("rating") + " / 10"
+                               self.ratingstars = int(10*round(float(rating.group("rating")),1))
+                               self["stars"].show()
+                               self["stars"].setValue(self.ratingstars)
+                               self["starsbg"].show()
+                       self["ratinglabel"].setText(Ratingtext)
+
+                       castblockmask = re.compile('Darsteller:[\s\S]*?class=\"Daten\">(.*?)(?:\.\.\.|\xbb)', re.DOTALL)
+                       castblock = castblockmask.findall(self.inhtml)
+                       castmask = re.compile('\">(.*?)</a')
+                       Casttext = ""
+                       if castblock:
+                               cast = castmask.finditer(castblock[0])
+                               if cast:
+                                       for x in cast:
+                                               Casttext += "\n" + self.htmltags.sub('', x.group(1))
+                                       if Casttext is not "":
+                                               Casttext = self._("Cast: ") + Casttext
+                                       else:
+                                               Casttext = self._("No cast list found in the database.")
+                                       self["castlabel"].setText(Casttext)
+                       print Casttext
+                       
+                       postermask = re.compile('<img src=\"(http://img.ofdb.de/film.*?)\" alt', re.DOTALL)
+                       posterurl = postermask.search(self.inhtml).group(1)
+                       if posterurl.find("jpg") > 0:
+                               self["statusbar"].setText("Downloading Movie Poster: "+posterurl+"...")
+                               localfile = "/home/root/poster.jpg"
+                               print "[OFDb] downloading poster " + posterurl + " to " + localfile
+                               downloadPage(posterurl,localfile).addCallback(self.OFDBPoster).addErrback(self.fetchFailed)
+                       else:
+                               self.OFDBPoster("kein Poster")
+
+               self["detailslabel"].setText(Detailstext)
+               
+       def OFDBPoster(self,string):
+               self["statusbar"].setText("OFDb Details parsed ^^")
+               if not string:
+                       filename = "/home/root/poster.jpg"
+               else:
+                       filename = "/usr/lib/enigma2/python/Plugins/Extensions/OFDb/no_poster.png"
+               pixmap = loadPic(filename, 96,140, AVSwitch().getAspectRatioSetting()/2,1,0,0)
+               if pixmap is not None:
+                       self["poster"].instance.setPixmap(pixmap.__deref__())
+                       self["poster"].show()
+
+       def createSummary(self):
+               return OFDbLCDScreen
+
+class OFDbLCDScreen(Screen):
+       skin = """
+       <screen position="0,0" size="132,64" title="OFDb Plugin">
+               <widget name="headline" position="4,0" size="128,22" font="Regular;20"/>
+               <widget source="session.Event_Now" render="Label" position="6,26" size="120,34" font="Regular;14" >
+                       <convert type="EventName">Name</convert>
+               </widget>
+       </screen>"""
+
+       def __init__(self, session, parent):
+               Screen.__init__(self, session)
+               self["headline"] = Label("OFDb Plugin")
+
+def main(session, eventName="", **kwargs):
+       session.open(OFDB, eventName)
+       
+def Plugins(**kwargs):
+       try:
+               wherelist = [PluginDescriptor.WHERE_EVENTINFO, PluginDescriptor.WHERE_PLUGINMENU]
+               return PluginDescriptor(name="OFDb Details",
+                               description=_("Query details from the Online-Filmdatenbank"),
+                               icon="ofdb.png",
+                               where = wherelist,
+                               fnc=main)
+       except AttributeError:
+               wherelist = [PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU]
+               return PluginDescriptor(name="OFDb Details",
+                               description=_("Query details from the Online-Filmdatenbank"),
+                               icon="ofdb.png",
+                               where = wherelist,
+                               fnc=main)
diff --git a/ofdb/src/starsbar_empty.png b/ofdb/src/starsbar_empty.png
new file mode 100644 (file)
index 0000000..f144bef
Binary files /dev/null and b/ofdb/src/starsbar_empty.png differ
diff --git a/ofdb/src/starsbar_filled.png b/ofdb/src/starsbar_filled.png
new file mode 100644 (file)
index 0000000..3bab73d
Binary files /dev/null and b/ofdb/src/starsbar_filled.png differ