def create_live_channel_item(self, result_set): """ Creates a MediaItem of type 'video' for live 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] 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 """ # noinspection PyTypeChecker url = "{}{}?apiKey={}".format(self.baseUrl, result_set["_links"]["manifest"]["href"], self.__api_key) live_data = result_set["_embedded"]["playback"] # type: dict item = MediaItem(live_data["title"], url) item.type = "video" item.isLive = True item.isGeoLocked = live_data.get("isGeoBlocked") # noinspection PyTypeChecker self.__get_image(live_data["posters"][0]["image"]["items"], "pixelWidth", "url") return item
def create_live_channel(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,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) item = MediaItem(result_set[0], result_set[1]) item.type = "video" item.isGeoLocked = result_set[3].lower() == "true" date_time = DateHelper.get_date_from_posix(int(result_set[2]) * 1 / 1000) item.set_date(date_time.year, date_time.month, date_time.day, date_time.hour, date_time.minute, date_time.second) thumb = result_set[4] if not thumb.startswith("http"): thumb = "%s%s" % (self.baseUrl, thumb) item.thumb = thumb return item
def create_json_episode_item_sok(self, result_set): """ Creates a new MediaItem for search results. 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 list[str]|dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ Logger.trace(result_set) url = result_set["url"] if url.startswith("/video") or url.startswith("/genre") or url.startswith('/oppetarkiv'): return None url = "%s%s" % (self.baseUrl, url, ) item = MediaItem(result_set['title'], url) item.icon = self.icon item.thumb = result_set.get("thumbnail", self.noImage) if item.thumb.startswith("//"): item.thumb = "https:%s" % (item.thumb, ) item.thumb = item.thumb.replace("/small/", "/large/") item.isGeoLocked = result_set.get('onlyAvailableInSweden', False) item.complete = True return item
def create_json_episode_item(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 list[str]|dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ Logger.trace(result_set) if "titleArticleId" in result_set: return None url = "%s%s" % (self.baseUrl, result_set['contentUrl'],) if "/video/" in url: return None item = MediaItem(result_set['programTitle'], url) item.icon = self.icon item.isGeoLocked = result_set.get('onlyAvailableInSweden', False) item.description = result_set.get('description') thumb = self.noImage if "poster" in result_set: thumb = result_set["poster"] thumb = self.__get_thumb(thumb or self.noImage) item.thumb = thumb return item
def create_channel_item(self, channel): """ Creates a MediaItem of type 'video' for a live channel 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 channel: 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(channel) title = channel["programmeTitle"] episode = channel.get("episodeTitle", None) thumb = self.noImage channel_title = channel["channelName"] description = channel.get("description") channel_id = channel["channel"].lower() if channel_id == "svtbarn": channel_id = "barnkanalen" date_format = "%Y-%m-%dT%H:%M:%S" start_time = DateHelper.get_date_from_string( channel["publishingTime"][:19], date_format) end_time = DateHelper.get_date_from_string( channel["publishingEndTime"][:19], date_format) if episode: title = "%s: %s - %s (%02d:%02d - %02d:%02d)" \ % (channel_title, title, episode, start_time.tm_hour, start_time.tm_min, end_time.tm_hour, end_time.tm_min) else: title = "%s: %s (%02d:%02d - %02d:%02d)" \ % (channel_title, title, start_time.tm_hour, start_time.tm_min, end_time.tm_hour, end_time.tm_min) channel_item = MediaItem( title, "https://www.svt.se/videoplayer-api/video/ch-%s" % (channel_id.lower(), )) channel_item.type = "video" channel_item.description = description channel_item.isLive = True channel_item.isGeoLocked = True channel_item.thumb = thumb if "titlePageThumbnailIds" in channel and channel[ "titlePageThumbnailIds"]: channel_item.thumb = "https://www.svtstatic.se/image/wide/650/%s.jpg" % ( channel["titlePageThumbnailIds"][0], ) return channel_item
def create_instalment_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,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 """ title = result_set["titles"]["title"] sub_title = result_set["titles"]["subtitle"] # noinspection PyTypeChecker if result_set.get("availability", {}).get("status", "available") != "available": Logger.debug("Found '%s' with a non-available status", title) return None url = "https://psapi.nrk.no/programs/{}?apiKey={}".format( result_set["prfId"], self.__api_key) item = MediaItem(title, url) item.type = 'video' item.thumb = self.__get_image(result_set["image"], "width", "url") item.fanart = self.parentItem.fanart # noinspection PyTypeChecker item.isGeoLocked = result_set.get("usageRights", {}).get( "geoBlock", {}).get("isGeoBlocked", False) if sub_title and sub_title.strip(): item.description = sub_title if "firstTransmissionDateDisplayValue" in result_set: Logger.trace("Using 'firstTransmissionDateDisplayValue' for date") day, month, year = result_set[ "firstTransmissionDateDisplayValue"].split(".") item.set_date(year, month, day) elif "usageRights" in result_set and "from" in result_set[ "usageRights"] and result_set["usageRights"][ "from"] is not None: Logger.trace("Using 'usageRights.from.date' for date") # noinspection PyTypeChecker date_value = result_set["usageRights"]["from"]["date"].split( "+")[0] time_stamp = DateHelper.get_date_from_string( date_value, date_format="%Y-%m-%dT%H:%M:%S") item.set_date(*time_stamp[0:6]) return item
def StievieCreateEpgItems(self, epg): Logger.Trace(epg) Logger.Debug("Processing EPG for channel %s", epg["id"]) items = [] summerTime = time.localtime().tm_isdst now = datetime.datetime.now() for resultSet in epg["items"]: # if not resultSet["parentSeriesOID"]: # continue # Does not always work # videoId = resultSet["epgId"].replace("-", "_") # url = "https://vod.medialaan.io/vod/v2/videos/%s_Stievie_free" % (videoId, ) videoId = resultSet["programOID"] url = "https://vod.medialaan.io/vod/v2/videos?episodeIds=%s&limit=10&offset=0&sort=broadcastDate&sortDirection=asc" % (videoId, ) title = resultSet["title"] if resultSet["episode"] and resultSet["season"]: title = "%s - s%02de%02d" % (title, resultSet["season"], resultSet["episode"]) if "startTime" in resultSet and resultSet["startTime"]: dateTime = resultSet["startTime"] dateValue = DateHelper.GetDateFromString(dateTime, dateFormat="%Y-%m-%dT%H:%M:%S.000Z") # Convert to Belgium posix time stamp dateValue2 = time.mktime(dateValue) + (1 + summerTime) * 60 * 60 # Conver the posix to a time stamp startTime = DateHelper.GetDateFromPosix(dateValue2) title = "%02d:%02d - %s" % (startTime.hour, startTime.minute, title) # Check for items in their black-out period if "blackout" in resultSet and resultSet["blackout"]["enabled"]: blackoutDuration = resultSet["blackout"]["duration"] blackoutStart = startTime + datetime.timedelta(seconds=blackoutDuration) if blackoutStart < now: Logger.Debug("Found item in Black-out period: %s (started at %s)", title, blackoutStart) continue # else: # startTime = self.parentItem.metaData["airDate"] item = MediaItem(title, url) item.type = "video" item.isGeoLocked = resultSet["geoblock"] item.description = resultSet["shortDescription"] # item.SetDate(startTime.year, startTime.month, startTime.day) if "images" in resultSet and resultSet["images"] and "styles" in resultSet["images"][0]: images = resultSet["images"][0]["styles"] # if "1520x855" in images: # item.fanart = images["1520x855"] if "400x225" in images: item.thumb = images["400x225"] items.append(item) return items
def create_json_genre_item(self, result_set): """ Creates a MediaItem of type 'folder/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. :param list[str]|dict result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ if "__typename" not in result_set: return None item_type = result_set["__typename"].lower() if item_type not in ("episode", "single", "clip", "tvseries") or "name" not in result_set: return None Logger.trace("%s->%s", item_type, result_set) title = result_set["name"] if item_type == 'episode' and "parent" in result_set: # noinspection PyTypeChecker parent_data = self.__apollo_data[result_set["parent"]["id"]] parent_title = parent_data["name"] title = "{} - {}".format(parent_title, title) if item_type == "clip": url = "https://www.svtplay.se/klipp/{}/".format(result_set["id"]) elif "urls" in result_set: # noinspection PyTypeChecker url_data = self.__apollo_data[result_set["urls"]["id"]] url = url_data["svtplay"] url = "{}{}".format(self.baseUrl, url) else: Logger.debug("No url found for: %s", title) return None item = MediaItem(title, url) item.description = result_set.get("longDescription") item.fanart = self.parentItem.fanart item.type = "video" if item_type != "tvseries" else "folder" if "image" in result_set: # noinspection PyTypeChecker image = result_set["image"]["id"] image_data = self.__apollo_data[image] image_url = "https://www.svtstatic.se/image/medium/520/{id}/{changed}".format(**image_data) item.thumb = image_url if "restrictions" in result_set: # noinspection PyTypeChecker restrictions = self.__apollo_data[result_set["restrictions"]["id"]] item.isGeoLocked = restrictions.get('onlyAvailableInSweden', False) 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,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) thumb_url = result_set[0] if thumb_url.startswith("//"): thumb_url = "http:%s" % (thumb_url, ) elif not thumb_url.startswith("http"): thumb_url = "%s%s" % (self.baseUrl, thumb_url) Logger.trace(thumb_url) season = result_set[1] if season: name = "%s - %s" % (season, result_set[2]) else: name = result_set[2] video_id = result_set[4] url = "http://www.oppetarkiv.se/video/%s?output=json" % (video_id, ) item = MediaItem(name, url) item.type = 'video' item.icon = self.icon item.thumb = thumb_url date = result_set[5] date_key = 'datetime="' if date_key in date: date = date[date.index(date_key) + len(date_key):date.index("T")] date = date.split("-") year = date[0] month = date[1] day = date[2] Logger.trace("%s - %s-%s-%s", date, year, month, day) item.set_date(year, month, day) else: Logger.debug("No date found") item.complete = False item.isGeoLocked = True return item
def create_category_item(self, result_set): """ Creates a MediaItem of type 'video/folder' 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,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) url = result_set["Url"] if "http://" not in url and "https://" not in url: url = "%s%s" % (self.baseUrl, url) thumb = result_set["Thumb"] if thumb.startswith("//"): thumb = "https:%s" % (thumb, ) item = MediaItem(result_set['Title'], url) item.icon = self.icon item.thumb = thumb item.isGeoLocked = result_set["Abroad"] == "false" if result_set["Date1"] is not None and result_set["Date1"].lower( ) != "imorgon": year, month, day, hour, minutes = self.__get_date( result_set["Date1"], result_set["Date2"], result_set["Date3"]) item.set_date(year, month, day, hour, minutes, 0) if "/video/" in url: item.type = "video" video_id = url.split("/")[4] item.url = "https://www.svtplay.se/video/%s?type=embed&output=json" % ( video_id, ) # else: # # make sure we get the right tab for displaying # item.url = "%s?tab=program" % (item.url, ) return item
def __create_json_episode_item(self, result_set, check_channel=True): """ 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 list[str]|dict[str,any] result_set: The result_set of the self.episodeItemRegex :param bool check_channel: Compare channel ID's and ignore that that do not match. :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ Logger.trace(result_set) # make sure we use ID as GUID if "id" in result_set: result_set["guid"] = result_set["id"] if check_channel and self.channelId is not None: channels = [int(c["guid"]) for c in result_set.get("channels", [])] valid_channel_found = any( [c for c in channels if c in self.channelId]) if not valid_channel_found: Logger.trace("Found item for wrong channel %s instead of %s", channels, self.channelId) return None # For now we keep using the API, otherwise we need to do more complex VideoItem parsing if self.useNewPages: raise NotImplementedError("The 'slug' part is no longer working") # So this no longer works # category_slug = self.__categories[result_set["category"]]["guid"] # url = "%s/%s/%s" % (self.baseUrl, category_slug, result_set['slug']) else: url = "http://playapi.mtgx.tv/v3/videos?format=%(guid)s&order=-airdate&type=program" % result_set item = MediaItem(result_set['title'], url) item.icon = self.icon item.thumb = self.__get_thumb_image( result_set.get("image") or self.noImage) # No fanart for now # item.fanart = self.__get_thumb_image(resultSet.get("image") or self.fanart, fanartSize=True) item.isGeoLocked = result_set.get('onlyAvailableInSweden', False) return item
def create_json_video(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 dict[str,any|None] 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 """ video_id = result_set['id'] # Categories to use # category = result_set["maincategory"].title() # subcategory = result_set["subcategory"].title() url = "https://api.nos.nl/mobile/video/%s/phone.json" % (video_id, ) item = MediaItem(result_set['title'], url, type="video") item.icon = self.icon if 'image' in result_set: images = result_set['image']["formats"] matched_image = images[-1] for image in images: if image["width"] >= 720: matched_image = image break item.thumb = matched_image["url"].values()[0] item.description = result_set["description"] item.complete = False item.isGeoLocked = result_set.get("geoprotection", False) # set the date and time date = result_set["published_at"] time_stamp = DateHelper.get_date_from_string(date, date_format="%Y-%m-%dT%H:%M:%S+{0}".format(date[-4:])) item.set_date(*time_stamp[0:6]) return item
def create_series_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 """ title = result_set["title"] sub_title = result_set.get("episodeTitle", None) if sub_title: title = "{} - {}".format(title, sub_title) if not result_set["usageRights"].get("hasRightsNow", True): Logger.debug("Found '%s' without 'usageRights'", title) return None url = "https://psapi.nrk.no/programs/{}?apiKey={}".format( result_set["id"], self.__api_key) item = MediaItem(title, url) item.type = 'video' # noinspection PyTypeChecker item.thumb = self.__get_image(result_set["image"]["webImages"], "pixelWidth", "imageUrl") item.description = result_set.get("longDescription", "") if not item.description: item.description = result_set.get("shortDescription", "") item.isGeoLocked = result_set.get("usageRights", {}).get("isGeoBlocked", False) self.__set_date(result_set, item) return item
def __create_generic_item(self, result_set, expected_item_type, url_format): video_info = result_set["attributes"] name = video_info["name"] if expected_item_type != result_set["type"]: Logger.warning("Not %s, excluding %s", expected_item_type, name) return None channel_id = int( result_set["relationships"]["primaryChannel"]["data"]["id"]) if self.primaryChannelId is not None and channel_id != self.primaryChannelId: return None item_id = result_set["id"] # Show the slug? # showSlug = video_info["alternateId"] url = url_format.format(item_id) item = MediaItem(name, url) item.description = video_info.get("description") geo_info = video_info.get("geoRestrictions", {"countries": ["world"]}) item.isGeoLocked = "world" not in geo_info.get("countries") # set the images if "images" in result_set["relationships"]: thumb_id = result_set["relationships"]["images"]["data"][0]["id"] item.thumb = self.imageLookup.get(thumb_id, self.noImage) if item.thumb == self.noImage: Logger.warning("No thumb found for %s", thumb_id) # paid or not? if "contentPackages" in result_set["relationships"]: item.isPaid = not any( filter(lambda p: p["id"].lower() == "free", result_set["relationships"]["contentPackages"]["data"])) else: item.isPaid = False return item
def create_episode_item(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 list[str]|dict[str,str] result_set: The result_set of the self.episodeItemRegex :return: A new MediaItem of type 'folder'. :rtype: MediaItem|None """ Logger.trace(result_set) genres = result_set[0] if self.__genre and self.__genre not in genres: Logger.debug("Item '%s' filtered due to genre: %s", result_set[2], genres) return None url = result_set[1] if "&" in url: url = HtmlEntityHelper.convert_html_entities(url) if not url.startswith("http:"): url = "%s%s" % (self.baseUrl, url) # get the ajax page for less bandwidth url = "%s?sida=1&sort=tid_stigande&embed=true" % (url, ) item = MediaItem(result_set[2], url) item.icon = self.icon item.thumb = self.noImage item.complete = True item.isGeoLocked = True return item
def get_live_items(self, data): """ Adds live stream items. The return values should always be instantiated in at least ("", []). :param str data: The retrieve data that was loaded for the current item and URL. :return: A tuple of the data and a list of MediaItems that were generated. :rtype: tuple[str|JsonHelper,list[MediaItem]] """ Logger.info("Fetching episode items") items = [] live_items = MediaItem("\a.: Live TV :.", "") live_items.thumb = self.noImage live_items.icon = self.icon items.append(live_items) live_base = "http://il.srgssr.ch/integrationlayer/1.0/ue/srf/video/play/%s.json" live_channels = { "SRF 1 live": ("c4927fcf-e1a0-0001-7edd-1ef01d441651", "srf1.png"), "SRF zwei live": ("c49c1d64-9f60-0001-1c36-43c288c01a10", "srf2.png"), "SRF info live": ("c49c1d73-2f70-0001-138a-15e0c4ccd3d0", "srfinfo.png") } for live_item in live_channels.keys(): item = MediaItem(live_item, live_base % (live_channels[live_item][0], )) item.thumb = self.get_image_location(live_channels[live_item][1]) item.icon = self.icon item.isGeoLocked = True item.type = "video" live_items.items.append(item) return data, items
def add_live_channels_and_folders(self, data): """ Performs pre-process actions for data processing. Accepts an data from the process_folder_list method, BEFORE the items are processed. Allows setting of parameters (like title etc) for the channel. Inside this method the <data> could be changed and additional items can be created. The return values should always be instantiated in at least ("", []). :param str data: The retrieve data that was loaded for the current item and URL. :return: A tuple of the data and a list of MediaItems that were generated. :rtype: tuple[str|JsonHelper,list[MediaItem]] """ Logger.info("Generating Live channels") items = [] live_channels = [ { "name": "BBC 1 HD", "code": "bbc_one_hd", "image": "bbc1large.png" }, { "name": "BBC 2 HD", "code": "bbc_two_hd", "image": "bbc2large.png" }, { "name": "BBC 3 HD", "code": "bbc_three_hd", "image": "bbc3large.png" }, { "name": "BBC 4 HD", "code": "bbc_four_hd", "image": "bbc4large.png" }, { "name": "CBBC", "code": "cbbc_hd", "image": "cbbclarge.png" }, { "name": "CBeebies", "code": "cbeebies_hd", "image": "cbeebieslarge.png" }, { "name": "BBC News Channel", "code": "bbc_news24", "image": "bbcnewslarge.png" }, { "name": "BBC Parliament", "code": "bbc_parliament", "image": "bbcparliamentlarge.png" }, { "name": "Alba", "code": "bbc_alba", "image": "bbcalbalarge.png" }, { "name": "S4C", "code": "s4cpbs", "image": "bbchdlarge.png" }, { "name": "BBC One London", "code": "bbc_one_london", "image": "bbchdlarge.png" }, { "name": "BBC One Scotland", "code": "bbc_one_scotland_hd", "image": "bbchdlarge.png" }, { "name": "BBC One Northern Ireland", "code": "bbc_one_northern_ireland_hd", "image": "bbchdlarge.png" }, { "name": "BBC One Wales", "code": "bbc_one_wales_hd", "image": "bbchdlarge.png" }, { "name": "BBC Two Scotland", "code": "bbc_two_scotland", "image": "bbchdlarge.png" }, { "name": "BBC Two Northern Ireland", "code": "bbc_two_northern_ireland_digital", "image": "bbchdlarge.png" }, { "name": "BBC Two Wales", "code": "bbc_two_wales_digital", "image": "bbchdlarge.png" }, ] live = MediaItem("Live Channels", "") live.dontGroup = True live.type = "folder" items.append(live) for channel in live_channels: url = "http://a.files.bbci.co.uk/media/live/manifesto/audio_video/simulcast/hds/uk/pc/ak/%(code)s.f4m" % channel item = MediaItem(channel["name"], url) item.isGeoLocked = True item.isLive = True item.type = "video" item.complete = False item.thumb = self.get_image_location(channel["image"]) live.items.append(item) extra = MediaItem("Shows (A-Z)", "#alphalisting") extra.complete = True extra.icon = self.icon extra.thumb = self.noImage extra.description = "Alphabetical show listing of BBC shows" extra.dontGroup = True extra.set_date(2200, 1, 1, text="") items.append(extra) return data, items
def load_programs(self, data): """ Performs pre-process actions for data processing. Accepts an data from the process_folder_list method, BEFORE the items are processed. Allows setting of parameters (like title etc) for the channel. Inside this method the <data> could be changed and additional items can be created. The return values should always be instantiated in at least ("", []). :param str data: The retrieve data that was loaded for the current item and URL. :return: A tuple of the data and a list of MediaItems that were generated. :rtype: tuple[str|JsonHelper,list[MediaItem]] """ items = [] # fetch al pages p = 1 url_format = "https://{0}/content/shows?" \ "include=images" \ "&page%5Bsize%5D=100&page%5Bnumber%5D={{0}}".format(self.baseUrlApi) # "include=images%2CprimaryChannel" \ url = url_format.format(p) data = UriHandler.open(url, proxy=self.proxy) json = JsonHelper(data) pages = json.get_value("meta", "totalPages") programs = json.get_value("data") or [] # extract the images self.__update_image_lookup(json) for p in range(2, pages + 1, 1): url = url_format.format(p) Logger.debug("Loading: %s", url) data = UriHandler.open(url, proxy=self.proxy) json = JsonHelper(data) programs += json.get_value("data") or [] # extract the images self.__update_image_lookup(json) Logger.debug("Found a total of %s items over %s pages", len(programs), pages) for p in programs: item = self.create_program_item(p) if item is not None: items.append(item) if self.recentUrl: recent_text = LanguageHelper.get_localized_string( LanguageHelper.Recent) recent = MediaItem("\b.: {} :.".format(recent_text), self.recentUrl) recent.dontGroup = True recent.fanart = self.fanart items.append(recent) # live items if self.liveUrl: live = MediaItem("\b.: Live :.", self.liveUrl) live.type = "video" live.dontGroup = True live.isGeoLocked = True live.isLive = True live.fanart = self.fanart items.append(live) search = MediaItem("\a.: Sök :.", "searchSite") search.type = "folder" search.dontGroup = True search.fanart = self.fanart items.append(search) return data, items
def create_generic_item(self, result_set, program_type): """ Creates a MediaItem of type 'video' or 'folder' using the result_set from the regex and a basic set of values. 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 """ title = result_set["title"] if not result_set.get("hasOndemandRights", True): Logger.debug("Item '%s' has no on-demand rights", title) return None item_id = result_set["id"] if program_type == "programme": url = "https://psapi.nrk.no/programs/{}?apiKey={}".format( item_id, self.__api_key) item = MediaItem(title, url) item.type = 'video' else: use_old_series_api = False if use_old_series_api: url = "https://psapi.nrk.no/series/{}?apiKey={}".format( item_id, self.__api_key) else: url = "https://psapi.nrk.no/tv/catalog/series/{}?apiKey={}".format( item_id, self.__api_key) item = MediaItem(title, url) item.type = 'folder' item.icon = self.icon item.isGeoLocked = result_set.get( "isGeoBlocked", result_set.get("usageRights", {}).get("isGeoBlocked", False)) description = result_set.get("description") if description and description.lower() != "no description": item.description = description if "image" not in result_set or "webImages" not in result_set["image"]: return item # noinspection PyTypeChecker item.thumb = self.__get_image(result_set["image"]["webImages"], "pixelWidth", "imageUrl") # see if there is a date? self.__set_date(result_set, item) 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 dict[str,dict|None] 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) title = result_set["title"] if "subTitle" in result_set: title = "%s - %s" % (title, result_set["subTitle"]) mgid = result_set["id"].split(":")[-1] url = "http://feeds.mtvnservices.com/od/feed/intl-mrss-player-feed" \ "?mgid=mgid:arc:episode:mtvplay.com:%s" \ "&ep=%s" \ "&episodeType=segmented" \ "&imageEp=android.playplex.mtv.%s" \ "&arcEp=android.playplex.mtv.%s" \ % (mgid, self.__backgroundServiceEp, self.__region.lower(), self.__region.lower()) item = MediaItem(title, url) item.type = "video" item.icon = self.icon item.description = result_set.get("description", None) item.thumb = self.parentItem.thumb item.fanart = self.parentItem.fanart item.isGeoLocked = True images = result_set.get("images", []) if images: # mgid:file:gsp:scenic:/international/mtv.nl/playplex/dutch-ridiculousness/Dutch_Ridiculousness_Landscape.png # http://playplex.mtvnimages.com/uri/mgid:file:gsp:scenic:/international/mtv.nl/playplex/dutch-ridiculousness/Dutch_Ridiculousness_Landscape.png for image in images: if image["width"] > 500: pass # no fanart here else: item.thumb = "http://playplex.mtvnimages.com/uri/%(url)s" % image date = result_set.get("originalAirDate", None) if not date: date = result_set.get("originalPublishDate", None) if date: time_stamp = date["timestamp"] date_time = DateHelper.get_date_from_posix(time_stamp) item.set_date(date_time.year, date_time.month, date_time.day, date_time.hour, date_time.minute, date_time.second) return item
def create_recent_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(result_set) show_title = result_set["abstract_name"] episode_title = result_set["title"] title = "{} - {}".format(show_title, episode_title) description = result_set.get("synopsis") uuid = result_set["uuid"] url = "http://www.rtl.nl/system/s4m/xldata/ux/%s?context=rtlxl&" \ "d=pc&fmt=adaptive&version=3" % (uuid, ) # The JSON urls do not yet work # url = "http://www.rtl.nl/system/s4m/vfd/version=1/d=pc/output=json/" \ # "fun=abstract/uuid=%s/fmt=smooth" % (uuid,) item = MediaItem(title.title(), url) item.type = "video" item.description = description item.thumb = "%s%s" % ( self.posterBase, uuid, ) audience = result_set.get("audience") Logger.debug("Found audience: %s", audience) item.isGeoLocked = audience == "ALLEEN_NL" # We can play the DRM stuff # item.isDrmProtected = audience == "DRM" station = result_set.get("station", None) if station: item.name = "{} ({})".format(item.name, station) icon = self.largeIconSet.get(station.lower(), None) if icon: Logger.trace("Setting icon to: %s", icon) item.icon = icon # 2018-12-05T19:30:00.000Z date_time = result_set.get("dateTime", None) if date_time: date_time = DateHelper.get_date_from_string( date_time[:-5], "%Y-%m-%dT%H:%M:%S") # The time is in UTC, and the show as at UTC+1 date_time = datetime.datetime(*date_time[:6]) + datetime.timedelta( hours=1) item.name = "{:02d}:{:02d}: {}".format(date_time.hour, date_time.minute, item.name) item.set_date(date_time.year, date_time.month, date_time.day, date_time.hour, date_time.minute, date_time.second) 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) url = "https://playback-api.b17g.net/media/%s?service=tv4&device=browser&protocol=hls" % ( program_id, ) name = result_set["title"] item = MediaItem(name, url) item.description = result_set["description"] if item.description is None: item.description = item.name # premium_expire_date_time=2099-12-31T00:00:00+01:00 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)) 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.icon = self.icon 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.url = "{0}&is_live=true".format(item.url) return item
def create_json_item(self, result_set): # NOSONAR """ 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(result_set) # determine the title program_title = result_set.get("programTitle", "") or "" show_title = result_set.get("title", "") or "" if show_title == "" and program_title != "": title = program_title elif show_title != "" and program_title == "": title = show_title elif program_title == "" and show_title == "": Logger.warning("Could not find title for item: %s", result_set) return None elif show_title != "" and show_title != program_title: title = "%s - %s" % (program_title, show_title) else: # they are the same title = show_title # NOSONAR if "live" in result_set and result_set["live"]: title = "%s (·Live·)" % (title, ) item_type = result_set.get("contentType") if "contentUrl" in result_set: if "versions" in result_set and bool(result_set["versions"]): video_id = result_set["versions"][0]["id"] else: video_id = result_set["id"] url = "https://api.svt.se/videoplayer-api/video/{}".format( video_id) else: url = result_set["url"] broad_cast_date = result_set.get("broadcastDate", None) if item_type in ("videoEpisod", "videoKlipp", "singel"): if "/video/" not in url and "/klipp/" not in url: Logger.warning( "Found video item without a /video/ or /klipp/ url.") return None item_type = "video" if "programVersionId" in result_set: url = "https://www.svt.se/videoplayer-api/video/%s" % ( result_set["programVersionId"], ) elif not url.startswith("http"): url = "%s%s" % (self.baseUrl, url) else: item_type = "folder" url = "%s%s" % (self.baseUrl, url) item = MediaItem(title, url) item.icon = self.icon item.type = item_type item.isGeoLocked = result_set.get("onlyAvailableInSweden", False) item.description = result_set.get("description", "") if "season" in result_set and "episodeNumber" in result_set and result_set[ "episodeNumber"]: season = int(result_set["season"]) episode = int(result_set["episodeNumber"]) if season > 0 and episode > 0: item.name = "s%02de%02d - %s" % (season, episode, item.name) item.set_season_info(season, episode) thumb = self.noImage if self.parentItem: thumb = self.parentItem.thumb for image_key in ("image", "imageMedium", "thumbnailMedium", "thumbnail", "poster"): if image_key in result_set and result_set[image_key] is not None: thumb = result_set[image_key] break item.thumb = self.__get_thumb(thumb or self.noImage) if broad_cast_date is not None: if "+" in broad_cast_date: broad_cast_date = broad_cast_date.rsplit("+")[0] time_stamp = DateHelper.get_date_from_string( broad_cast_date, "%Y-%m-%dT%H:%M:%S") item.set_date(*time_stamp[0:6]) # Set the expire date expire_date = result_set.get("expireDate") if expire_date is not None: expire_date = expire_date.split("+")[0].replace("T", " ") year = expire_date.split("-")[0] if len(year ) == 4 and int(year) < datetime.datetime.now().year + 50: item.description = \ "{}\n\n{}: {}".format(item.description or "", self.__expires_text, expire_date) length = result_set.get("materialLength", 0) if length > 0: item.set_info_label(MediaItem.LabelDuration, length) 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 = int(resultSet["format_position"]["season"]) episode = int(result_set["format_position"]["episode"] or "0") webisode = result_set.get("webisode", False) # if the name had the episode in it, translate it if episode > 0 and not webisode: description = "%s\n\n%s" % (title, description) title = "%s - %s %s %s %s" % ( result_set["format_title"], self.seasonLabel, result_set["format_position"]["season"], self.episodeLabel, result_set["format_position"]["episode"]) else: Logger.debug( "Found episode number '0' for '%s', " "using name instead of episode number", title) url = result_set["_links"]["stream"]["href"] 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.icon = self.icon 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 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 return item