def create_api_episode_type(self, result_set): """ Creates a new MediaItem for an episode. This method creates a new MediaItem from the Regular Expression or Json results <result_set>. The method should be implemented by derived classes and are specific to the channel. :param dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ # This URL gives the URL that contains the show info with Season ID's url = "https://graph.kijk.nl/graphql-video" if not result_set.get("sources"): return None title = result_set["title"] season_number = result_set.get("seasonNumber") episode_number = result_set.get("tvSeasonEpisodeNumber") title_format = self.parentItem.metaData.get("title_format", "s{0:02d}e{1:02d} - {2}") if title is None: serie_title = result_set["series"]["title"] title = title_format.format(season_number, episode_number, serie_title) elif season_number is not None and episode_number is not None: title = title_format.format(season_number, episode_number, title) item = MediaItem(title, url, type="video") item.description = result_set.get("longDescription", result_set.get("description")) item.set_info_label("duration", int(result_set.get("duration", 0) or 0)) item.set_info_label("genre", result_set.get("displayGenre")) self.__get_artwork(item, result_set.get("imageMedia"), mode="thumb") updated = result_set["lastPubDate"] / 1000 date_time = DateHelper.get_date_from_posix(updated) item.set_date(date_time.year, date_time.month, date_time.day, date_time.hour, date_time.minute, date_time.second) # Find the media streams item.metaData["sources"] = result_set["sources"] item.metaData["subtitles"] = result_set.get("tracks", []) # DRM only no_drm_items = [src for src in result_set["sources"] if not src["drm"]] item.isDrmProtected = len(no_drm_items) == 0 return item
def create_video_item(self, result_set): """ Creates a MediaItem of type 'video' using the result_set from the regex. This method creates a new MediaItem from the Regular Expression or Json results <result_set>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.update_video_item method is called if the item is focussed or selected for playback. :param list[str]|dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'video' or 'audio' (despite the method's name). :rtype: MediaItem|None """ Logger.trace('starting FormatVideoItem for %s', self.channelName) # Logger.Trace(result_set) # the vmanProgramId (like 1019976) leads to http://anytime.tv4.se/webtv/metafileFlash.smil?p=1019976&bw=1000&emulate=true&sl=true program_id = result_set["id"] # Logger.Debug("ProgId = %s", programId) # We can either use M3u8 or Dash # url = "https://playback-api.b17g.net/media/%s?service=tv4&device=browser&protocol=hls" % (program_id,) url = "https://playback-api.b17g.net/media/%s?service=tv4&device=browser&protocol=dash" % ( program_id, ) name = result_set["title"] season = result_set.get("season", 0) episode = result_set.get("episode", 0) is_episodic = 0 < season < 1900 and not episode == 0 if is_episodic: episode_text = None if " del " in name: name, episode_text = name.split(" del ", 1) episode_text = episode_text.lstrip("0123456789") if episode_text: episode_text = episode_text.lstrip(" -") name = "{} - s{:02d}e{:02d} - {}".format( name, season, episode, episode_text) else: name = "{} - s{:02d}e{:02d}".format(name, season, episode) item = MediaItem(name, url) item.description = result_set["description"] if item.description is None: item.description = item.name if is_episodic: item.set_season_info(season, episode) # premium_expire_date_time=2099-12-31T00:00:00+01:00 expire_date = result_set.get("expire_date_time") if bool(expire_date): self.__set_expire_time(expire_date, item) date = result_set["broadcast_date_time"] (date_part, time_part) = date.split("T") (year, month, day) = date_part.split("-") (hour, minutes, rest1, zone) = time_part.split(":") item.set_date(year, month, day, hour, minutes, 00) broadcast_date = datetime.datetime(int(year), int(month), int(day), int(hour), int(minutes)) item.fanart = result_set.get("program_image", self.parentItem.fanart) thumb_url = result_set.get("image", result_set.get("program_image")) # some images need to come via a proxy: if thumb_url and "://img.b17g.net/" in thumb_url: item.thumb = "https://imageproxy.b17g.services/?format=jpg&shape=cut" \ "&quality=90&resize=520x293&source={}"\ .format(HtmlEntityHelper.url_encode(thumb_url)) else: item.thumb = thumb_url availability = result_set["availability"] # noinspection PyTypeChecker free_period = availability["availability_group_free"] # noinspection PyTypeChecker premium_period = availability["availability_group_premium"] now = datetime.datetime.now() if False and not premium_period == "0": # always premium free_expired = now - datetime.timedelta(days=99 * 365) elif free_period == "30+" or free_period is None: free_expired = broadcast_date + datetime.timedelta(days=99 * 365) else: free_expired = broadcast_date + datetime.timedelta( days=int(free_period)) Logger.trace( "Premium info for: %s\nPremium state: %s\nFree State: %s\nBroadcast %s vs Expired %s", name, premium_period, free_period, broadcast_date, free_expired) if now > free_expired: item.isPaid = True item.type = "video" item.complete = False item.isGeoLocked = result_set["is_geo_restricted"] item.isDrmProtected = result_set["is_drm_protected"] item.isLive = result_set.get("is_live", False) if item.isLive: item.name = "{}:{} - {}".format(hour, minutes, name) item.url = "{0}&is_live=true".format(item.url) if item.isDrmProtected: item.url = "{}&drm=widevine&is_drm=true".format(item.url) item.set_info_label("duration", int(result_set.get("duration", 0))) return item
def create_video_item(self, result_set): """ Creates a MediaItem of type 'video' using the result_set from the regex. This method creates a new MediaItem from the Regular Expression or Json results <result_set>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.update_video_item method is called if the item is focussed or selected for playback. :param list[str]|dict[str,dict[str,str] result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'video' or 'audio' (despite the method's name). :rtype: MediaItem|None """ Logger.trace(result_set) drm_locked = False geo_blocked = result_set["is_geo_blocked"] title = result_set["title"] if ("_links" not in result_set or "stream" not in result_set["_links"] or "href" not in result_set["_links"]["stream"]): Logger.warning("No streams found for %s", title) return None # the description description = result_set["description"].strip() # The long version summary = result_set["summary"].strip() # The short version # Logger.Trace("Comparing:\nDesc: %s\nSumm:%s", description, summary) if not description.startswith(summary): # the descripts starts with the summary. Don't show description = "%s\n\n%s" % (summary, description) video_type = result_set["type"] if not video_type == "program": title = "%s (%s)" % (title, video_type.title()) elif result_set["format_position"][ "is_episodic"]: # and resultSet["format_position"]["episode"] != "0": # make sure we show the episodes and seaso season = result_set["format_position"].get("season", 0) episode = int(result_set["format_position"]["episode"] or "0") # Was it a webisode? # webisode = result_set.get("webisode", False) # if the name had the episode in it, translate it if episode > 0 and season > 0: # and not webisode: description = "%s\n\n%s" % (title, description) title = "{0} - s{1:02d}e{2:02d}".format( result_set["format_title"], season, episode) else: Logger.debug( "Found episode '0' or websido '%s': using name instead of episode number", title) mpx_guid = result_set.get('mpx_guid') if mpx_guid is None: url = result_set["_links"]["stream"]["href"] else: # we can use mpx_guid and https://viafree.mtg-api.com/stream-links/viafree/web/se/clear-media-guids/{}/streams url = "https://viafree.mtg-api.com/stream-links/viafree/web/{}/clear-media-guids/{}/streams".format( self.language, mpx_guid) item = MediaItem(title, url) date_info = None date_format = "%Y-%m-%dT%H:%M:%S" if "broadcasts" in result_set and len(result_set["broadcasts"]) > 0: date_info = result_set["broadcasts"][0]["air_at"] Logger.trace("Date set from 'air_at'") if "playable_from" in result_set["broadcasts"][0]: start_date = result_set["broadcasts"][0]["playable_from"] playable_from = DateHelper.get_date_from_string( start_date[0:-6], date_format) playable_from = datetime.datetime(*playable_from[0:6]) if playable_from > datetime.datetime.now(): drm_locked = True elif "publish_at" in result_set: date_info = result_set["publish_at"] Logger.trace("Date set from 'publish_at'") if date_info is not None: # publish_at=2007-09-02T21:55:00+00:00 info = date_info.split("T") date_info = info[0] time_info = info[1] date_info = date_info.split("-") time_info = time_info.split(":") item.set_date(date_info[0], date_info[1], date_info[2], time_info[0], time_info[1], 0) item.type = "video" item.complete = False item.isGeoLocked = geo_blocked item.isDrmProtected = drm_locked thumb_data = result_set['_links'].get('image', None) if thumb_data is not None: # Older version # item.thumbUrl = thumb_data['href'].replace("{size}", "thumb") item.thumb = self.__get_thumb_image(thumb_data['href']) item.description = description # unpublish_at=2099-12-31T00:00:00+01:00 expire_date = result_set["unpublish_at"] if bool(expire_date): self.__set_expire_time(expire_date, item) srt = result_set.get("sami_path") if not srt: srt = result_set.get("subtitles_webvtt") if srt: Logger.debug("Storing SRT/WebVTT path: %s", srt) part = item.create_new_empty_media_part() part.Subtitle = srt item.set_info_label("duration", int(result_set.get("duration", 0))) return item
def create_api_video_asset_type(self, result_set): """ Creates a MediaItem of type 'video' using the result_set from the regex. This method creates a new MediaItem from the Regular Expression or Json results <result_set>. The method should be implemented by derived classes and are specific to the channel. If the item is completely processed an no further data needs to be fetched the self.complete property should be set to True. If not set to True, the self.update_video_item method is called if the item is focussed or selected for playback. :param list[str]|dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'video' or 'audio' (despite the method's name). :rtype: MediaItem|None """ Logger.trace('starting FormatVideoItem for %s', self.channelName) program_id = result_set["id"] url = "https://playback-api.b17g.net/media/{}?service=tv4&device=browser&protocol=dash".\ format(program_id) name = result_set["title"] season = result_set.get("season", 0) episode = result_set.get("episode", 0) is_episodic = 0 < season < 1900 and not episode == 0 if is_episodic: episode_text = None if " del " in name: name, episode_text = name.split(" del ", 1) episode_text = episode_text.lstrip("0123456789") if episode_text: episode_text = episode_text.lstrip(" -") name = "{} - s{:02d}e{:02d} - {}".format(name, season, episode, episode_text) else: name = "{} - s{:02d}e{:02d}".format(name, season, episode) item = MediaItem(name, url) item.description = result_set["description"] if item.description is None: item.description = item.name if is_episodic: item.set_season_info(season, episode) # premium_expire_date_time=2099-12-31T00:00:00+01:00 expire_in_days = result_set.get("daysLeftInService", 0) if 0 < expire_in_days < 10000: item.set_expire_datetime( timestamp=datetime.datetime.now() + datetime.timedelta(days=expire_in_days)) date = result_set["broadcastDateTime"] broadcast_date = DateHelper.get_datetime_from_string(date, "%Y-%m-%dT%H:%M:%SZ", "UTC") broadcast_date = broadcast_date.astimezone(self.__timezone) item.set_date(broadcast_date.year, broadcast_date.month, broadcast_date.day, broadcast_date.hour, broadcast_date.minute, 0) item.fanart = result_set.get("program_image", self.parentItem.fanart) thumb_url = result_set.get("image", result_set.get("program_image")) # some images need to come via a proxy: if thumb_url and "://img.b17g.net/" in thumb_url: item.thumb = "https://imageproxy.b17g.services/?format=jpg&shape=cut" \ "&quality=70&resize=520x293&source={}" \ .format(HtmlEntityHelper.url_encode(thumb_url)) else: item.thumb = thumb_url item.type = "video" item.complete = False item.isGeoLocked = True # For now, none are paid. # item.isPaid = not result_set.get("freemium", False) if "drmProtected" in result_set: item.isDrmProtected = result_set["drmProtected"] elif "is_drm_protected" in result_set: item.isDrmProtected = result_set["is_drm_protected"] item.isLive = result_set.get("live", False) if item.isLive: item.name = "{:02d}:{:02d} - {}".format(broadcast_date.hour, broadcast_date.minute, name) item.url = "{0}&is_live=true".format(item.url) if item.isDrmProtected: item.url = "{}&drm=widevine&is_drm=true".format(item.url) item.set_info_label("duration", int(result_set.get("duration", 0))) return item