# -*- coding: UTF-8 -*-
from Plugins.Plugin import PluginDescriptor
from Tools.Downloader import downloadWithProgress
from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS
from twisted.web.client import getPage
from enigma import ePicLoad, eServiceReference, getDesktop
from Screens.Screen import Screen
from Screens.ChoiceBox import ChoiceBox
from Screens.VirtualKeyBoard import VirtualKeyBoard
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.ProgressBar import ProgressBar
from Components.Sources.StaticText import StaticText
from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigText, ConfigSelection
from Components.ConfigList import ConfigListScreen
from Components.PluginComponent import plugins
import os, re, random, string, six
from six.moves.urllib.parse import quote_plus
try:
import htmlentitydefs
except ImportError as ie:
from html import entities as htmlentitydefs
unichr = chr
sz_w = getDesktop(0).size().width()
config.plugins.imdb = ConfigSubsection()
config.plugins.imdb.showinplugins = ConfigYesNo(default = True)
config.plugins.imdb.showepisodeinfo = ConfigYesNo(default = True)
config.plugins.imdb.origskin = ConfigYesNo(default = True)
config.plugins.imdb.ignore_tags = ConfigText(visible_width = 50, fixed_size = False)
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"))])
imdb_headers = {}
agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
def quoteEventName(eventName):
try:
text = eventName.decode('utf8').replace(u'\x86', u'').replace(u'\x87', u'').encode('utf8')
except:
text = eventName
return quote_plus(text, safe="+")
class IMDB(Screen):
if sz_w == 1920:
skin = """
Default
Date
"""
else:
skin = """
Default
Format:%A %d. %B
"""
NBSP = unichr(htmlentitydefs.name2codepoint['nbsp']).encode("utf8")
def __init__(self, session, eventName, callbackNeeded=False):
Screen.__init__(self, session)
if config.plugins.imdb.origskin.value:
self.skinName = ''.join([random.choice(string.ascii_letters + string.digits) for n in xrange(32)])
else:
self.skinName = "IMDBv2"
for tag in config.plugins.imdb.ignore_tags.getValue().split(','):
eventName = eventName.replace(tag,'')
self.eventName = eventName
self.callbackNeeded = callbackNeeded
self.callbackData = ""
self.callbackGenre = ""
self.manualsearch = False
self.dictionary_init()
self["poster"] = Pixmap()
self.picload = ePicLoad()
self.picload_conn = self.picload.PictureData.connect(self.paintPosterPixmapCB)
self["stars"] = ProgressBar()
self["starsbg"] = Pixmap()
self["stars"].hide()
self["starsbg"].hide()
self.ratingstars = -1
self.setTitle(_("IMDb - Internet Movie Database"))
self["titlelabel"] = Label("")
self["titlelcd"] = StaticText("")
self["detailslabel"] = ScrollLabel("")
self["castlabel"] = ScrollLabel("")
self["storylinelabel"] = ScrollLabel("")
self["extralabel"] = ScrollLabel("")
self["statusbar"] = Label("")
self["ratinglabel"] = Label("")
self.resultlist = []
self["menu"] = MenuList(self.resultlist)
self["menu"].hide()
self["key_red"] = Button(_("Search"))
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.exit,
"down": self.pageDown,
"up": self.pageUp,
"right": self.keyRight,
"left": self.keyLeft,
"red": self.openVirtualKeyBoard,
"green": self.showMenu,
"yellow": self.showDetails,
"blue": self.showExtras,
"contextMenu": self.contextMenuPressed,
"showEventInfo": self.showDetails
}, -1)
self.getIMDB()
def title_setText(self, txt):
StaticText.setText(self["titlelcd"], txt)
self["titlelabel"].setText(txt)
def exit(self):
if fileExists("/tmp/poster.jpg"):
os.remove("/tmp/poster.jpg")
if self.callbackNeeded:
self.close([self.callbackData, self.callbackGenre])
else:
self.close()
def dictionary_init(self):
self.generalinfomask = re.compile(
'
(?P.*?)*'
'(?:.*?>(?PEpisodes)(?P.*?))?'
'(?:.*?class="OriginalTitle__OriginalTitleText.*?>(?P.*?):\s.*?(?P.*?).*?(?P\d+)\s(?Pseasons?))?'
'(?:.*?(?PDirectors?)(?:|).*?(?P.*?))?'
'(?:.*?(?PCreators?)(?:|).*?(?P.*?))?'
'(?:.*?(?PWriters?)(?:|).*?(?P.*?))?'
'(?:.*?(?PRelease date).*?(?P.*?))?'
'(?:.*?(?PCountr.*?of origin).*?(?P.*?))?'
'(?:.*?(?PAlso known as).*?(?P.*?))?'
'(?:.*?techspec_runtime.*?>(?PRuntime).*?(?P.*?)(?P.+?))?'
'(?:.*?(?PTaglines?)(?:|).*?(?P.*?))?'
'(?:.*?(?PCertificate|Motion Picture Rating \(MPAA\)).*?(?P.*?))?'
'(?:.*?(?PTrivia)(?P.+?))?'
'(?:.*?(?PGoofs)(?P.+?))?'
'(?:.*?(?PQuotes)(?P.+?))?'
'(?:.*?(?PCrazy credits)(?P.+?))?'
'(?:.*?(?PAlternate versions)(?P.+?))?'
'(?:.*?(?PConnections)(?P.+?))?'
'(?:.*?(?PSoundtracks)(?P.+?))?'
'(?:.*?(?PUser review)s.*?.*?(?P.*?)(?P.+?).*?.*?(?P.+?))?'
'(?:.*?(?PLanguages?).*?(?P.*?))?'
'(?:.*?(?PFilming locations?).*?(?P.*?))?'
'(?:.*?(?PProduction compan.*?).*?(?P.*?))?'
'(?:.*?(?PColor).*?(?P.*?))?'
'(?:.*?(?PSound mix).*?(?P.*?))?'
'(?:.*?(?PAspect ratio).*?(?P.*?))?', re.S)
self.awardsmask = re.compile('(?P.+?)', re.S)
self.keywordsmask = re.compile('data-testid="storyline-plot-keywords">(?P.*?)', re.S)
self.boxofficemask = re.compile('(?PBox office)Budget.*?list-content-item">(?P.*?).*?list-content-item">(?P.*?).*?list-content-item">(?P.*?).*?list-content-item">(?P.*?).*?list-content-item">(?P.*?)', re.S)
self.genreblockmask = re.compile('(?PGenres?).*?(?P.*?)', re.S)
self.ratingmask = re.compile('(?P.*?).*?(?P.*?)(?P.*?)(?:(?P.*?))?(?:(?P.*?))?', re.S)
self.postermask = re.compile('(?P.*?).*?.*?data-testid="storyline.*?(?PStoryline)', re.S)
self.htmltags = re.compile('<.*?>', re.S)
self.allhtmltags = re.compile('<.*>', re.S)
def resetLabels(self):
self["detailslabel"].setText("")
self["ratinglabel"].setText("")
self["castlabel"].setText("")
self["storylinelabel"].setText("")
if not len(self.resultlist) >= 1:
self["key_green"].setText("")
self["key_yellow"].setText("")
self["key_blue"].setText("")
self.title_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()
self["storylinelabel"].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()
self["storylinelabel"].pageDown()
if self.Page == 2:
self["extralabel"].pageDown()
def keyLeft(self):
if self.Page == 0:
self["menu"].pageUp()
if self.Page == 1:
self["castlabel"].pageUp()
self["detailslabel"].pageUp()
self["storylinelabel"].pageUp()
if self.Page == 2:
self["extralabel"].pageUp()
def keyRight(self):
if self.Page == 0:
self["menu"].pageDown()
if self.Page == 1:
self["castlabel"].pageDown()
self["detailslabel"].pageDown()
self["storylinelabel"].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["storylinelabel"].hide()
self["poster"].hide()
self["extralabel"].hide()
self["detailslabel"].hide()
self.title_setText(_("Please select the matching entry"))
self["key_blue"].setText("")
self["key_green"].setText(_("Title Menu"))
self["key_yellow"].setText("")
self["statusbar"].setText("")
self.Page = 0
def showDetails(self):
self["ratinglabel"].show()
self["castlabel"].show()
self["detailslabel"].show()
self["storylinelabel"].show()
self["menu"].hide()
if self.resultlist and self.Page == 0:
link = self["menu"].getCurrent()[1]
title = self["menu"].getCurrent()[0]
self["statusbar"].setText(_("Re-Query IMDb: %s...") % (title))
fetchurl = "https://www.imdb.com/title/" + link + "/"
print("[IMDB] showDetails() downloading query " + fetchurl)
getPage(fetchurl, agent=agent, headers=imdb_headers).addCallback(self.IMDBquery2).addErrback(self.http_failed)
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 and self['key_blue'].getText():
self["extralabel"].show()
self["detailslabel"].hide()
self["castlabel"].hide()
self["storylinelabel"].hide()
self["poster"].hide()
self["stars"].hide()
self["starsbg"].hide()
self["ratinglabel"].hide()
self.Page = 2
def contextMenuPressed(self):
list = [(_("Setup"), self.setup),]
if fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/YTTrailer/plugin.py")):
list.extend((
(_("Play Trailer"), self.openYttrailer),
(_("Search Trailer"), self.searchYttrailer),
))
self.session.openWithCallback(self.menuCallback, ChoiceBox, title=_("IMDb Menu"), list = list,)
else:
self.setup()
def menuCallback(self, ret = None):
ret and ret[1]()
def openYttrailer(self):
try:
from Plugins.Extensions.YTTrailer.plugin import YTTrailer, baseEPGSelection__init__
except ImportError as ie:
pass
if baseEPGSelection__init__ is None:
return
ytTrailer = YTTrailer(self.session)
ytTrailer.showTrailer(self.eventName)
def searchYttrailer(self):
try:
from Plugins.Extensions.YTTrailer.plugin import YTTrailerList, baseEPGSelection__init__
except ImportError as ie:
pass
if baseEPGSelection__init__ is None:
return
self.session.open(YTTrailerList, self.eventName)
def openVirtualKeyBoard(self):
if self.manualsearch:
text = self.eventName
else:
text = ''
self.session.openWithCallback(self.gotSearchString, VirtualKeyBoard, title = _("Enter text to search for"), text = text)
def gotSearchString(self, ret = None):
if ret:
self.eventName = ret
self.Page = 0
self.resultlist = []
self["menu"].hide()
self["ratinglabel"].show()
self["castlabel"].show()
self["storylinelabel"].show()
self["detailslabel"].show()
self["poster"].hide()
self["stars"].hide()
self["starsbg"].hide()
self.manualsearch = True
self.getIMDB()
def getIMDB(self):
global imdb_headers
#if config.plugins.imdb.language.value:
# imdb_headers = {'Accept-Language': config.plugins.imdb.language.value}
#else:
imdb_headers = {}
self.resetLabels()
if not self.eventName:
s = self.session.nav.getCurrentService()
info = s and s.info()
event = info and info.getEvent(0) # 0 = now, 1 = next
if event:
self.eventName = event.getEventName()
else:
self.eventName = self.session.nav.getCurrentlyPlayingServiceReference().toString()
self.eventName = self.eventName.split('/')
self.eventName = self.eventName[-1]
self.eventName = self.eventName.replace('.',' ')
self.eventName = self.eventName.split('-')
self.eventName = self.eventName[0]
if self.eventName.endswith(' '):
self.eventName = self.eventName[:-1]
if self.eventName:
self["statusbar"].setText(_("Query IMDb: %s") % (self.eventName))
fetchurl = "https://www.imdb.com/find?ref_=nv_sr_fn&q=" + quoteEventName(self.eventName) + "&s=all"
print("[IMDB] getIMDB() Downloading Query " + fetchurl)
getPage(fetchurl, agent=agent, headers=imdb_headers).addCallback(self.IMDBquery).addErrback(self.http_failed)
else:
self["statusbar"].setText(_("Couldn't get Eventname"))
def html2utf8(self, in_html):
utf8 = ('charSet="utf-8"' in in_html or 'charset="utf-8"' in in_html or 'charSet=utf-8' in in_html or 'charset=utf-8' in in_html)
start = in_html.find('