def __send_log(self): """ Send log files via Pastbin or Gist. """ from resources.lib.helpers.logsender import LogSender sender_mode = 'hastebin' log_sender = LogSender(Config.logSenderApi, logger=Logger.instance(), mode=sender_mode) try: title = LanguageHelper.get_localized_string( LanguageHelper.LogPostSuccessTitle) url_text = LanguageHelper.get_localized_string( LanguageHelper.LogPostLogUrl) files_to_send = [ Logger.instance().logFileName, Logger.instance().logFileName.replace(".log", ".old.log") ] if sender_mode != "gist": paste_url = log_sender.send_file(Config.logFileNameAddon, files_to_send[0]) else: paste_url = log_sender.send_files(Config.logFileNameAddon, files_to_send) XbmcWrapper.show_dialog(title, url_text % (paste_url, )) except Exception as e: Logger.error("Error sending %s", Config.logFileNameAddon, exc_info=True) title = LanguageHelper.get_localized_string( LanguageHelper.LogPostErrorTitle) error_text = LanguageHelper.get_localized_string( LanguageHelper.LogPostError) error = error_text % (str(e), ) XbmcWrapper.show_dialog(title, error.strip(": "))
def __show_first_time_message(self, channel_info): """ Checks if it is the first time a channel is executed and if a first time message is available it will be shown. Shows a message dialog if the message should be shown. Make sure that each line fits in a single line of a Kodi Dialog box (50 chars). :param ChannelInfo channel_info: The ChannelInfo to show a message for. """ hide_first_time = AddonSettings.hide_first_time_messages() if channel_info.firstTimeMessage: if not hide_first_time: Logger.info( "Showing first time message '%s' for channel chn_%s.", channel_info.firstTimeMessage, channel_info.moduleName) title = LanguageHelper.get_localized_string( LanguageHelper.ChannelMessageId) XbmcWrapper.show_dialog( title, channel_info.firstTimeMessage.split("|")) else: Logger.debug( "Not showing first time message due to add-on setting set to '%s'.", hide_first_time) return
def toggle_cloak(self): """ Toggles the cloaking (showing/hiding) of the selected folder. """ item = self._pickler.de_pickle_media_item( self.params[self.keywordPickle]) Logger.info("Cloaking current item: %s", item) c = Cloaker(self.channelObject, AddonSettings.store(LOCAL), logger=Logger.instance()) if c.is_cloaked(item.url): c.un_cloak(item.url) self.refresh() return first_time = c.cloak(item.url) if first_time: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string( LanguageHelper.CloakFirstTime), LanguageHelper.get_localized_string( LanguageHelper.CloakMessage)) del c self.refresh()
def log_on(self): """ Logs on to a website, using an url. First checks if the channel requires log on. If so and it's not already logged on, it should handle the log on. That part should be implemented by the specific channel. More arguments can be passed on, but must be handled by custom code. After a successful log on the self.loggedOn property is set to True and True is returned. :return: indication if the login was successful. :rtype: bool """ if self.__idToken: return True # check if there is a refresh token # refresh token: viervijfzes_refresh_token refresh_token = AddonSettings.get_setting("viervijfzes_refresh_token") client = AwsIdp("eu-west-1_dViSsKM5Y", "6s1h851s8uplco5h6mqh1jac8m", proxy=self.proxy, logger=Logger.instance()) if refresh_token: id_token = client.renew_token(refresh_token) if id_token: self.__idToken = id_token return True else: Logger.info("Extending token for VierVijfZes failed.") # username: viervijfzes_username username = AddonSettings.get_setting("viervijfzes_username") # password: viervijfzes_password v = Vault() password = v.get_setting("viervijfzes_password") if not username or not password: XbmcWrapper.show_dialog( title=None, lines=LanguageHelper.get_localized_string( LanguageHelper.MissingCredentials), ) return False id_token, refresh_token = client.authenticate(username, password) if not id_token or not refresh_token: Logger.error("Error getting a new token. Wrong password?") return False self.__idToken = id_token AddonSettings.set_setting("viervijfzes_refresh_token", refresh_token) return True
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug('Starting update_video_item for %s (%s)', item.name, self.channelName) if "index.html" in item.url: data = UriHandler.open( item.url, additional_headers={"Referer": "http://www.{}/".format(self.__country_id)} ) json_data = JsonHelper(data) guid = json_data.get_value("feed", "items", 0, "guid") url = "https://media-utils.mtvnservices.com/services/MediaGenerator/" \ "{}?arcStage=live&format=json&acceptMethods=hls&clang=nl" \ "&https=true".format(guid) else: url = item.url data = UriHandler.open(url) json_data = JsonHelper(data) url = json_data.get_value("package", "video", "item", 0, "rendition", 0, "src") if not url: error = json_data.get_value("package", "video", "item", 0, "text") Logger.error("Error resolving url: %s", error) XbmcWrapper.show_dialog(LanguageHelper.ErrorId, error) return item item.MediaItemParts = [] part = item.create_new_empty_media_part() part.append_media_stream(url, 0) item.complete = True return item
def __update_video_from_mpd(self, item, mpd_info, use_adaptive_with_encryption): """ Updates an existing MediaItem with more data based on an MPD stream. :param dict[str,str] mpd_info: Stream info retrieved from the stream json. :param bool use_adaptive_with_encryption: Do we use the Adaptive InputStream add-on? :param MediaItem item: The original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ Logger.debug("Updating streams using BrightCove data.") part = item.create_new_empty_media_part() mpd_manifest_url = "https:{0}".format(mpd_info["mediaLocator"]) mpd_data = UriHandler.open(mpd_manifest_url, proxy=self.proxy) subtitles = Regexer.do_regex(r'<BaseURL>([^<]+\.vtt)</BaseURL>', mpd_data) if subtitles: Logger.debug("Found subtitle: %s", subtitles[0]) subtitle = SubtitleHelper.download_subtitle(subtitles[0], proxy=self.proxy, format="webvtt") part.Subtitle = subtitle if use_adaptive_with_encryption: # We can use the adaptive add-on with encryption Logger.info("Using MPD InputStreamAddon") license_url = Regexer.do_regex('licenseUrl="([^"]+)"', mpd_data)[0] token = "Bearer {0}".format(mpd_info["playToken"]) key_headers = {"Authorization": token} license_key = Mpd.get_license_key(license_url, key_headers=key_headers) stream = part.append_media_stream(mpd_manifest_url, 0) Mpd.set_input_stream_addon_input(stream, self.proxy, license_key=license_key) item.complete = True else: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item
def __show_warnings(self, media_item): """ Show playback warnings for this MediaItem :param MediaItem media_item: The current MediaItem that will be played. """ if (media_item.isDrmProtected or media_item.isPaid) and AddonSettings.show_drm_paid_warning(): if media_item.isDrmProtected: Logger.debug("Showing DRM Warning message") title = LanguageHelper.get_localized_string(LanguageHelper.DrmTitle) message = LanguageHelper.get_localized_string(LanguageHelper.DrmText) XbmcWrapper.show_dialog(title, message) elif media_item.isPaid: Logger.debug("Showing Paid Warning message") title = LanguageHelper.get_localized_string(LanguageHelper.PaidTitle) message = LanguageHelper.get_localized_string(LanguageHelper.PaidText) XbmcWrapper.show_dialog(title, message)
def process_video_item(self, item): """ Process a video item using the required dataparsers :param MediaItem item: The Item to update :return: An updated item. :rtype: MediaItem """ data_parsers = self.__get_data_parsers(item.url) if not data_parsers: Logger.error("No dataparsers found cannot update item.") return item data_parsers = [d for d in data_parsers if d.Updater is not None] if len(data_parsers) < 1: Logger.warning("No DataParsers with Updaters found.") return item if len(data_parsers) > 1: Logger.warning( "More than 2 DataParsers with Updaters found. Only using first one." ) data_parser = data_parsers[0] if not data_parser.Updater: Logger.error("No videoupdater found cannot update item.") return item if data_parser.LogOnRequired: Logger.info("One or more dataparsers require logging in.") self.loggedOn = self.log_on() if not self.loggedOn: Logger.warning("Could not log on for: %s", self) title = LanguageHelper.get_localized_string( LanguageHelper.LoginErrorTitle) text = LanguageHelper.get_localized_string( LanguageHelper.LoginErrorText) XbmcWrapper.show_dialog(title, text) Logger.debug("Processing Updater from %s", data_parser) return data_parser.Updater(item)
def __update_dash_video(self, item, stream_info): """ :param MediaItem item: The item that was updated :param JsonHelper stream_info: The stream info """ if not AddonSettings.use_adaptive_stream_add_on(with_encryption=True): XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item playback_item = stream_info.get_value("playbackItem") stream_url = playback_item["manifestUrl"] part = item.create_new_empty_media_part() stream = part.append_media_stream(stream_url, 0) license_info = playback_item.get("license", None) if license_info is not None: license_key_token = license_info["token"] auth_token = license_info["castlabsToken"] header = { "x-dt-auth-token": auth_token, "content-type": "application/octstream" } license_url = license_info["castlabsServer"] license_key = Mpd.get_license_key(license_url, key_value=license_key_token, key_headers=header) Mpd.set_input_stream_addon_input(stream, proxy=self.proxy, license_key=license_key) item.isDrmProtected = False else: Mpd.set_input_stream_addon_input(stream, proxy=self.proxy) item.complete = True return item
def __update_embedded_video(self, item): """ Updates video items that are encrypted. This could be the default for Krypton! :param MediaItem item: The item to update. :return: An updated item. :rtype: MediaItem """ data = UriHandler.open(item.url, proxy=self.proxy) if UriHandler.instance().status.code == 404: title, message = Regexer.do_regex( r'<h1>([^<]+)</h1>\W+<p>([^<]+)<', data)[0] XbmcWrapper.show_dialog(title, message) return item start_needle = "var playerConfig =" start_data = data.index(start_needle) + len(start_needle) end_data = data.index("var talpaPlayer") data = data[start_data:end_data].strip().rstrip(";") json = JsonHelper(data) has_drm_only = True adaptive_available = AddonSettings.use_adaptive_stream_add_on( with_encryption=False, channel=self) adaptive_available_encrypted = AddonSettings.use_adaptive_stream_add_on( with_encryption=True, channel=self) for play_list_entry in json.get_value("playlist"): part = item.create_new_empty_media_part() for source in play_list_entry["sources"]: stream_type = source["type"] stream_url = source["file"] stream_drm = source.get("drm") if not stream_drm: has_drm_only = False if stream_type == "m3u8": Logger.debug("Found non-encrypted M3u8 stream: %s", stream_url) M3u8.update_part_with_m3u8_streams(part, stream_url, proxy=self.proxy, channel=self) item.complete = True elif stream_type == "dash" and adaptive_available: Logger.debug("Found non-encrypted Dash stream: %s", stream_url) stream = part.append_media_stream(stream_url, 1) Mpd.set_input_stream_addon_input(stream, proxy=self.proxy) item.complete = True else: Logger.debug("Unknown stream source: %s", source) else: compatible_drm = "widevine" if compatible_drm not in stream_drm or stream_type != "dash": Logger.debug("Found encrypted %s stream: %s", stream_type, stream_url) continue Logger.debug("Found Widevine encrypted Dash stream: %s", stream_url) license_url = stream_drm[compatible_drm]["url"] pid = stream_drm[compatible_drm]["releasePid"] encryption_json = '{"getRawWidevineLicense":' \ '{"releasePid":"%s", "widevineChallenge":"b{SSM}"}' \ '}' % (pid,) headers = { "Content-Type": "application/json", "Origin": "https://embed.kijk.nl", "Referer": stream_url } encryption_key = Mpd.get_license_key( license_url, key_type=None, key_value=encryption_json, key_headers=headers) stream = part.append_media_stream(stream_url, 0) Mpd.set_input_stream_addon_input( stream, proxy=self.proxy, license_key=encryption_key) item.complete = True subs = [ s['file'] for s in play_list_entry.get("tracks", []) if s.get('kind') == "captions" ] if subs: subtitle = SubtitleHelper.download_subtitle(subs[0], format="webvtt") part.Subtitle = subtitle if has_drm_only and not adaptive_available_encrypted: XbmcWrapper.show_dialog( LanguageHelper.get_localized_string(LanguageHelper.DrmTitle), LanguageHelper.get_localized_string( LanguageHelper.WidevineLeiaRequired)) return item
def update_video_item(self, item): """ Updates an existing MediaItem with more data. Used to update none complete MediaItems (self.complete = False). This could include opening the item's URL to fetch more data and then process that data or retrieve it's real media-URL. The method should at least: * cache the thumbnail to disk (use self.noImage if no thumb is available). * set at least one MediaItemPart with a single MediaStream. * set self.complete = True. if the returned item does not have a MediaItemPart then the self.complete flag will automatically be set back to False. :param MediaItem item: the original MediaItem that needs updating. :return: The original item with more data added to it's properties. :rtype: MediaItem """ if item.metaData.get(self.__REQUIRES_LOGIN, False): logged_in = self.log_on() if not logged_in: XbmcWrapper.show_dialog(LanguageHelper.LoginErrorTitle, LanguageHelper.LoginErrorText) return item video_data = UriHandler.open(item.url, proxy=self.proxy, additional_headers=self.localIP) if not video_data: return item video_data = JsonHelper(video_data) video_info = video_data.get_value("data", "attributes") errors = video_data.get_value("errors") Logger.error("Error updating items: %s", errors) if errors: return item part = item.create_new_empty_media_part() m3u8url = video_info["streaming"]["hls"]["url"] m3u8data = UriHandler.open(m3u8url, self.proxy) if AddonSettings.use_adaptive_stream_add_on(): stream = part.append_media_stream(m3u8url, 0) item.complete = True M3u8.set_input_stream_addon_input(stream, self.proxy) else: # user agent for all sub m3u8 and ts requests needs to be the same part.HttpHeaders[ "user-agent"] = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-GB; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13 (.NET CLR 3.5.30729)" for s, b, a in M3u8.get_streams_from_m3u8( m3u8url, self.proxy, append_query_string=False, map_audio=True, play_list_data=m3u8data): item.complete = True if a: audio_part = a.split("-prog_index.m3u8", 1)[0] audio_id = audio_part.rsplit("/", 1)[-1] s = s.replace("-prog_index.m3u8", "-{0}-prog_index.m3u8".format(audio_id)) part.append_media_stream(s, b) if self.language == "se": vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data, language="sv") elif self.language == "dk": vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data, language="da") else: vtt_url = M3u8.get_subtitle(m3u8url, self.proxy, m3u8data) # https://dplaynordics-vod-80.akamaized.net/dplaydni/259/0/hls/243241001/1112635959-prog_index.m3u8?version_hash=bb753129&hdnts=st=1518218118~exp=1518304518~acl=/*~hmac=bdeefe0ec880f8614e14af4d4a5ca4d3260bf2eaa8559e1eb8ba788645f2087a vtt_url = vtt_url.replace("-prog_index.m3u8", "-0.vtt") part.Subtitle = SubtitleHelper.download_subtitle(vtt_url, format='srt', proxy=self.proxy) # if the user has premium, don't show any warnings if self.__has_premium: item.isPaid = False return item