diff options
Diffstat (limited to 'plugin.video.viaplay/resources/lib/kodihelper.py')
-rw-r--r-- | plugin.video.viaplay/resources/lib/kodihelper.py | 228 |
1 files changed, 228 insertions, 0 deletions
diff --git a/plugin.video.viaplay/resources/lib/kodihelper.py b/plugin.video.viaplay/resources/lib/kodihelper.py new file mode 100644 index 0000000..8b1ea38 --- /dev/null +++ b/plugin.video.viaplay/resources/lib/kodihelper.py @@ -0,0 +1,228 @@ +import urllib + +from viaplay import Viaplay + +import xbmc +import xbmcvfs +import xbmcgui +import xbmcplugin +import inputstreamhelper +from xbmcaddon import Addon + + +class KodiHelper(object): + def __init__(self, base_url=None, handle=None): + addon = self.get_addon() + self.base_url = base_url + self.handle = handle + self.addon_path = xbmc.translatePath(addon.getAddonInfo('path')) + self.addon_profile = xbmc.translatePath(addon.getAddonInfo('profile')) + self.addon_name = addon.getAddonInfo('id') + self.addon_version = addon.getAddonInfo('version') + self.language = addon.getLocalizedString + self.logging_prefix = '[%s-%s]' % (self.addon_name, self.addon_version) + if not xbmcvfs.exists(self.addon_profile): + xbmcvfs.mkdir(self.addon_profile) + if self.get_setting('first_run'): + self.get_addon().openSettings() + self.set_setting('first_run', 'false') + self.vp = Viaplay(self.addon_profile, self.get_country_code(), True) + + def get_addon(self): + """Returns a fresh addon instance.""" + return Addon() + + def get_setting(self, setting_id): + addon = self.get_addon() + setting = addon.getSetting(setting_id) + if setting == 'true': + return True + elif setting == 'false': + return False + else: + return setting + + def set_setting(self, key, value): + return self.get_addon().setSetting(key, value) + + def log(self, string): + msg = '%s: %s' % (self.logging_prefix, string) + xbmc.log(msg=msg, level=xbmc.LOGDEBUG) + + def get_country_code(self): + country_id = self.get_setting('site') + if country_id == '0': + country_code = 'se' + elif country_id == '1': + country_code = 'dk' + elif country_id == '2': + country_code = 'no' + else: + country_code = 'fi' + + return country_code + + def get_sub_lang(self): + sub_lang_id = self.get_setting('sub_lang') + if sub_lang_id == '0': + sub_lang = 'sv' + elif sub_lang_id == '1': + sub_lang = 'da' + elif sub_lang_id == '2': + sub_lang = 'no' + else: + sub_lang = 'fi' + + return sub_lang + + def dialog(self, dialog_type, heading, message=None, options=None, nolabel=None, yeslabel=None): + dialog = xbmcgui.Dialog() + if dialog_type == 'ok': + dialog.ok(heading, message) + elif dialog_type == 'yesno': + return dialog.yesno(heading, message, nolabel=nolabel, yeslabel=yeslabel) + elif dialog_type == 'select': + ret = dialog.select(heading, options) + if ret > -1: + return ret + else: + return None + + def authorize(self): + try: + self.vp.validate_session() + return True + except self.vp.ViaplayError as error: + if not error.value == 'PersistentLoginError' or error.value == 'MissingSessionCookieError': + raise + else: + return self.device_registration() + + def log_out(self): + confirm = self.dialog('yesno', self.language(30042), self.language(30043)) + if confirm: + self.vp.log_out() + # send Kodi back to home screen + xbmc.executebuiltin('XBMC.Container.Update(path, replace)') + xbmc.executebuiltin('XBMC.ActivateWindow(Home)') + + def device_registration(self): + """Presents a dialog with information on how to activate the device. + Attempts to authorize the device using the interval returned by the activation data.""" + activation_data = self.vp.get_activation_data() + message = self.language(30039).format(activation_data['verificationUrl'], activation_data['userCode']) + dialog = xbmcgui.DialogProgress() + xbmc.sleep(200) # small delay to prevent DialogProgress from hanging + dialog.create(self.language(30040), message) + secs = 0 + expires = activation_data['expires'] + + while not xbmc.Monitor().abortRequested() and secs < expires: + try: + self.vp.authorize_device(activation_data) + dialog.close() + return True + except self.vp.ViaplayError as error: + # raise all non-pending authorization errors + if not error.value == 'DeviceAuthorizationPendingError': + raise + secs += activation_data['interval'] + percent = int(100 * float(secs) / float(expires)) + dialog.update(percent, message) + xbmc.Monitor().waitForAbort(activation_data['interval']) + if dialog.iscanceled(): + dialog.close() + return False + + dialog.close() + return False + + def get_user_input(self, heading, hidden=False): + keyboard = xbmc.Keyboard('', heading, hidden) + keyboard.doModal() + if keyboard.isConfirmed(): + query = keyboard.getText() + self.log('User input string: %s' % query) + else: + query = None + + if query and len(query) > 0: + return query + else: + return None + + def get_numeric_input(self, heading): + dialog = xbmcgui.Dialog() + numeric_input = dialog.numeric(0, heading) + + if len(numeric_input) > 0: + return str(numeric_input) + else: + return None + + def add_item(self, title, params, items=False, folder=True, playable=False, info=None, art=None, content=False): + addon = self.get_addon() + listitem = xbmcgui.ListItem(label=title) + + if playable: + listitem.setProperty('IsPlayable', 'true') + folder = False + if art: + listitem.setArt(art) + else: + art = { + 'icon': addon.getAddonInfo('icon'), + 'fanart': addon.getAddonInfo('fanart') + } + listitem.setArt(art) + if info: + listitem.setInfo('video', info) + if content: + xbmcplugin.setContent(self.handle, content) + + recursive_url = self.base_url + '?' + urllib.urlencode(params) + + if items is False: + xbmcplugin.addDirectoryItem(self.handle, recursive_url, listitem, folder) + else: + items.append((recursive_url, listitem, folder)) + return items + + def eod(self): + """Tell Kodi that the end of the directory listing is reached.""" + xbmcplugin.endOfDirectory(self.handle) + + def play(self, guid=None, url=None, pincode=None): + if url: + guid = self.vp.get_products(url)['products'][0]['system']['guid'] + elif guid: + pass + else: + self.log('No guid or URL supplied.') + return False + + try: + stream = self.vp.get_stream(guid, pincode=pincode) + except self.vp.ViaplayError as error: + if not error.value == 'ParentalGuidancePinChallengeNeededError': + raise + if pincode: + self.dialog(dialog_type='ok', heading=self.language(30033), message=self.language(30034)) + else: + pincode = self.get_numeric_input(self.language(30032)) + if pincode: + self.play(guid, pincode=pincode) + return + + ia_helper = inputstreamhelper.Helper('mpd', drm='widevine') + if ia_helper.check_inputstream(): + playitem = xbmcgui.ListItem(path=stream['mpd_url']) + playitem.setContentLookup(False) + playitem.setMimeType('application/xml+dash') # prevents HEAD request that causes 404 error + playitem.setProperty('inputstreamaddon', 'inputstream.adaptive') + playitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') + playitem.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha') + playitem.setProperty('inputstream.adaptive.license_key', stream['license_url'].replace('{widevineChallenge}', 'B{SSM}') + '|||JBlicense') + if self.get_setting('subtitles') and 'subtitles' in stream: + playitem.setSubtitles(self.vp.download_subtitles(stream['subtitles'], language_to_download=self.get_sub_lang())) + xbmcplugin.setResolvedUrl(self.handle, True, listitem=playitem) |