def root(plugin): yield Listitem.from_dict( **{ "label": "Featured", "art": { "thumb": IMG_CATCHUP_SHOWS + "cms/TKSS_Carousal1.jpg", "icon": IMG_CATCHUP_SHOWS + "cms/TKSS_Carousal1.jpg", "fanart": IMG_CATCHUP_SHOWS + "cms/TKSS_Carousal1.jpg", }, "callback": Route.ref("/resources/lib/main:show_featured") }) for e in ["Genres", "Languages"]: yield Listitem.from_dict( **{ "label": e, "art": { "thumb": CONFIG[e][0].get("tvImg"), "icon": CONFIG[e][0].get("tvImg"), "fanart": CONFIG[e][0].get("promoImg"), }, "callback": Route.ref("/resources/lib/main:show_listby"), "params": { "by": e } })
def play_history(cls, callback, name, *args, **kwargs): """ Constructor to add "saved search" support to add-on. This will first link to a "sub" folder that lists all saved "search terms". From here, "search terms" can be created or removed. When a selection is made, the "callback" function that was given will be executed with all parameters forwarded on. Except with one extra parameter, ``search_query``, which is the "search term" that was selected. :param Callback callback: Function that will be called when the "listitem" is activated. :param args: "Positional" arguments that will be passed to the callback. :param kwargs: "Keyword" arguments that will be passed to the callback. """ if hasattr(callback, "route"): route = callback.route elif isinstance(callback, CallbackRef): route = callback else: route = dispatcher.get_route(callback) kwargs["first_load"] = True kwargs["_route"] = route.path item = cls() item.label = bold(name) item.art.global_thumb("search.png") item.info["plot"] = Script.localize(localized.SEARCH_PLOT) item.set_callback( Route.ref("/resources/lib/play_from_search:saved_searches"), *args, **kwargs) return item
def buildTray(self, items, nextPageUrl=None, allResultsPageUrl=None): for eachItem in items: yield Listitem().from_dict(**self._buildItem(eachItem)) if nextPageUrl: yield Listitem().next_page(url=nextPageUrl) if allResultsPageUrl: item = Listitem() item.label = "All Episodes" item.art.global_thumb("playlist.png") item.set_callback( Route.ref("/resources/lib/main:tray_list"), url=allResultsPageUrl) yield item
def show_listby(plugin, by): for each in CONFIG[by]: yield Listitem.from_dict(**{ "label": each.get("name"), "art": { "thumb": each.get("tvImg"), "icon": each.get("tvImg"), "fanart": each.get("promoImg") }, "callback": Route.ref("/resources/lib/main:show_category"), "params": {"category_id": each.get("name").replace(" ", ""), "by": by} })
def buildMenu(self, menuItems): for each in menuItems: if not each.get("pageUri"): continue item = Listitem() item.label = each.get("name") item.art['fanart'] = "https://secure-media.hotstar.com/static/firetv/v1/poster_%s_in.jpg" % each.get( "name").lower() if not each.get("name").lower() == "genres" else "https://secure-media.hotstar.com/static/firetv/v1/poster_genre_in.jpg" item.set_callback(Route.ref("/resources/lib/main:menu_list") if each.get("pageType") else Route.ref( "/resources/lib/main:tray_list"), url=updateQueryParams(each.get("pageUri"), {"tas": "15"})) item.art.local_thumb(each.get("name").lower() + ".png") yield item
def show_epg(plugin, day, channel_id): resp = urlquick.get(CATCHUP_SRC.format(day, channel_id), max_age=-1).json() epg = sorted( resp['epg'], key=lambda show: show['startEpoch'], reverse=True) livetext = '[COLOR red] [ LIVE ] [/COLOR]' for each in epg: current_epoch = int(time()*1000) if not each['stbCatchupAvailable'] or each['startEpoch'] > current_epoch: continue islive = each['startEpoch'] < current_epoch and each['endEpoch'] > current_epoch showtime = ' '+livetext if islive else datetime.fromtimestamp( int(each['startEpoch']*.001)).strftime(' [ %I:%M %p -') + datetime.fromtimestamp(int(each['endEpoch']*.001)).strftime(' %I:%M %p ] %a') yield Listitem.from_dict(**{ "label": each['showname'] + showtime, "art": { 'thumb': IMG_CATCHUP_SHOWS+each['episodePoster'], 'icon': IMG_CATCHUP_SHOWS+each['episodePoster'], 'fanart': IMG_CATCHUP_SHOWS+each['episodePoster'], }, "callback": play, "info": { 'title': each['showname'] + showtime, 'originaltitle': each['showname'], "tvshowtitle": each['showname'], 'genre': each['showGenre'], 'plot': each['description'], "episodeguide": each.get("episode_desc"), 'episode': 0 if each['episode_num'] == -1 else each['episode_num'], 'cast': each['starCast'].split(', '), 'director': each['director'], 'duration': each['duration']*60, 'tag': each['keywords'], 'mediatype': 'episode', }, "params": { "channel_id": each.get("channel_id"), "showtime": None if islive else each.get("showtime", "").replace(":", ""), "srno": None if islive else datetime.fromtimestamp(int(each.get("startEpoch", 0)*.001)).strftime('%Y%m%d') } }) if int(day) == 0: for i in range(-1, -7, -1): label = 'Yesterday' if i == - \ 1 else (date.today() + timedelta(days=i)).strftime('%A %d %B') yield Listitem.from_dict(**{ "label": label, "callback": Route.ref("/resources/lib/main:show_epg"), "params": { "day": i, "channel_id": channel_id } })
def buildPage(self, items, nextPageUrl=None): for each in items: if each.get("traySource", "") in ["THIRD_PARTY"]: continue tray_url = "" if each.get("uri"): tray_url = updateQueryParams(each.get("uri"), {"tas": "15"}) if each.get("traySource") == "GRAVITY": path = TRAY_IDENTIFIERS.get(each.get("addIdentifier")) if path: tray_url = PERSONA_BASE_URL + path else: continue art = info = None aItems = deep_get(each, "assets.items") if aItems and len(aItems) > 0: info = { "plot": "Contains : " + " | ".join([x.get("title") for x in aItems]) } art = { "thumb": IMG_THUMB_H_URL % deep_get(aItems[0], "images.h"), "icon": IMG_THUMB_H_URL % deep_get(aItems[0], "images.h"), "poster": IMG_POSTER_V_URL % (deep_get(aItems[0], "images.v") or deep_get(aItems[0], "images.h")), "fanart": IMG_FANART_H_URL % deep_get(aItems[0], "images.h"), } yield Listitem().from_dict(**{ "label": "Carousel" if each.get("layoutType", "") == "MASTHEAD" else each.get("title"), "art": art, "info": info, "callback": Route.ref("/resources/lib/main:tray_list"), "properties": { "IsPlayable": False }, "params": { "url": tray_url, } }) if nextPageUrl: yield Listitem().next_page(url=nextPageUrl)
def generic_menu(plugin, item_id=None, **kwargs): """Build 'item_id' menu of the addon Args: plugin (codequick.script.Script) item_id (str): Menu to build (e.g. root) Returns: Iterator[codequick.listing.Listitem]: Kodi 'item_id' menu """ if item_id is None: # Fix https://github.com/Catch-up-TV-and-More/plugin.video.catchuptvandmore/issues/304 xbmc.executebuiltin("Action(Back,%s)" % xbmcgui.getCurrentWindowId()) yield False else: menu_id = item_id # If 'menu_id' menu contains only one item, directly open this item plugin.redirect_single_item = True # Get ordered 'menu_id' menu # without disabled and hidden items menu = get_sorted_menu(plugin, menu_id) if not menu: # If the selected menu is empty just reload the current menu yield False for index, (item_order, item_id, item_infos) in enumerate(menu): item = Listitem() # Set item label item.label = get_item_label(item_id, item_infos) # Set item art if 'thumb' in item_infos: item.art["thumb"] = get_item_media_path(item_infos['thumb']) if 'fanart' in item_infos: item.art["fanart"] = get_item_media_path( item_infos['fanart']) # Set item additional params if 'xmltv_id' in item_infos: item.params['xmltv_id'] = item_infos['xmltv_id'] item.params['item_id'] = item_id # Set callback function for this item if 'route' in item_infos: item.set_callback((Route.ref(item_infos['route']))) elif 'resolver' in item_infos: item.set_callback((Resolver.ref(item_infos['resolver']))) else: # This case should not happen # Ignore this item to prevent any error for this menu continue # Add needed context menus to this item add_context_menus_to_item(item, item_id, index, menu_id, len(menu), is_playable='resolver' in item_infos, item_infos=item_infos) yield item
def show_featured(plugin, id=None): resp = urlquick.get(FEATURED_SRC, headers={ "usergroup": "tvYR7NSNn7rymo3F", "os": "android", "devicetype": "phone", "versionCode": "226" }, max_age=-1).json() for each in resp.get("featuredNewData", []): if id: if int(each.get("id", 0)) == int(id): data = each.get("data", []) for child in data: info_dict = { "art": { "thumb": IMG_CATCHUP_SHOWS + child.get("episodePoster", ""), "icon": IMG_CATCHUP_SHOWS + child.get("episodePoster", ""), "fanart": IMG_CATCHUP_SHOWS + child.get("episodePoster", ""), "clearart": IMG_CATCHUP + child.get("logoUrl", ""), "clearlogo": IMG_CATCHUP + child.get("logoUrl", ""), }, "info": { 'originaltitle': child.get("showname"), "tvshowtitle": child.get("showname"), "genre": child.get("showGenre"), "plot": child.get("description"), "episodeguide": child.get("episode_desc"), "episode": 0 if child.get("episode_num") == -1 else child.get("episode_num"), "cast": child.get("starCast", "").split(', '), "director": child.get("director"), "duration": child.get("duration") * 60, "tag": child.get("keywords"), "mediatype": "movie" if child.get("channel_category_name") == "Movies" else "episode", } } if child.get("showStatus") == "Now": info_dict[ "label"] = info_dict["info"]["title"] = child.get( "showname", "") + " [COLOR red] [ LIVE ] [/COLOR]" info_dict["callback"] = play info_dict["params"] = { "channel_id": child.get("channel_id") } yield Listitem.from_dict(**info_dict) elif child.get("showStatus") == "future": timetext = datetime.fromtimestamp( int(child.get("startEpoch", 0) * .001)).strftime( ' [ %I:%M %p -') + datetime.fromtimestamp( int(child.get("endEpoch", 0) * .001)).strftime(' %I:%M %p ] %a') info_dict["label"] = info_dict["info"][ "title"] = child.get("showname", "") + ( " [COLOR green]%s[/COLOR]" % timetext) info_dict["callback"] = "" yield Listitem.from_dict(**info_dict) elif child.get("showStatus") == "catchup": timetext = datetime.fromtimestamp( int(child.get("startEpoch", 0) * .001)).strftime( ' [ %I:%M %p -') + datetime.fromtimestamp( int(child.get("endEpoch", 0) * .001)).strftime(' %I:%M %p ] %a') info_dict["label"] = info_dict["info"][ "title"] = child.get("showname", "") + ( " [COLOR yellow]%s[/COLOR]" % timetext) info_dict["callback"] = play info_dict["params"] = { "channel_id": child.get("channel_id"), "showtime": child.get("showtime", "").replace(":", ""), "srno": datetime.fromtimestamp( int(child.get("startEpoch", 0) * .001)).strftime('%Y%m%d') } yield Listitem.from_dict(**info_dict) else: yield Listitem.from_dict( **{ "label": each.get("name"), "art": { "thumb": IMG_CATCHUP_SHOWS + each.get("data", [{}])[0].get("episodePoster"), "icon": IMG_CATCHUP_SHOWS + each.get("data", [{}])[0].get("episodePoster"), "fanart": IMG_CATCHUP_SHOWS + each.get("data", [{}])[0].get("episodePoster"), }, "callback": Route.ref("/resources/lib/main:show_featured"), "params": { "id": each.get("id") } })
def root(plugin): yield builder.buildSearch(Route.ref("/resources/lib/main:tray_list")) menuItmes = api.getMenu() yield from builder.buildMenu(menuItmes) yield builder.buildSettings()
def buildSettings(self): return Listitem.from_dict(Route.ref("/resources/lib/main:settings"), "Settings")
def _buildItem(self, item): context = [] if item.get("assetType") in ["CHANNEL", "GENRE", "GAME", "LANGUAGE", "SHOW", "SEASON"]: if item.get("assetType", "") in ["SHOW"] or item.get("pageType") in ["HERO_LANDING_PAGE", "NAVIGATION_LANDING_PAGE"]: callback = Route.ref("/resources/lib/main:menu_list") else: callback = Route.ref("/resources/lib/main:tray_list") params = {"url": item.get("uri")} else: if item.get("isSubTagged"): with PersistentDict("userdata.pickle") as db: subtag = deep_get(dict(db), "udata.subscriptions.in") if subtag: subtag = list(subtag.keys())[0] Script.log("Using subtag from subscription: %s" % subtag, lvl=Script.DEBUG) else: resp = urlquick.get( item.get("uri"), headers=BASE_HEADERS).json() item = deep_get(resp, "body.results.item") if item.get("features", [{}])[0].get("subType"): subtag = item.get("features", [{}])[ 0].get("subType") Script.log("Using subtag %s" % subtag, lvl=Script.DEBUG) else: subtag = "HotstarPremium" Script.log("No subType found.Using subtag %s as default" % subtag, lvl=Script.DEBUG) callback = Resolver.ref("/resources/lib/main:play_vod") params = { "contentId": item.get("contentId"), "subtag": item.get("isSubTagged") and "subs-tag:%s|" % subtag, "label": item.get("title"), "drm": "com.widevine.alpha" if item.get("encrypted") or item.get("clipType", "") == "LIVE" else False, "partner": "com.jio.jioplay.tv" if item.get("clipType", "") == "LIVE" else None } context.extend([("Select Playback", "PlayMedia(plugin://plugin.video.botallen.hotstar/resources/lib/main/play_vod/?_pickle_=%s)" % hexlify(dumps(dict({"ask": True}, **params))).decode("ascii"))]) if len(item.get("langObjs", [])) > 1: context.extend(map(lambda x: ("Play in %s" % x.get("name"), "PlayMedia(plugin://plugin.video.botallen.hotstar/resources/lib/main/play_vod/?_pickle_=%s)" % hexlify(dumps(dict({"lang": x.get("iso3code")}, **params))).decode("ascii")), item.get("langObjs", []))) label = item.get("title") if item.get("clipType", "") == "LIVE": label += " - [COLOR red]LIVE[/COLOR]" elif item.get("assetType") == "SEASON": label = "Season {0} ({1})".format( item.get("seasonNo"), item.get("episodeCnt")) props = {"IsPlayable": False} if item.get("watched"): props["ResumeTime"] = item.get( "watched", 0) * item.get("duration", 0) props["TotalTime"] = item.get("duration", 0) return { "label": label, "art": { "icon": IMG_THUMB_H_URL % deep_get(item, "images.h"), "thumb": IMG_THUMB_H_URL % deep_get(item, "images.h"), "fanart": IMG_FANART_H_URL % deep_get(item, "images.h"), "poster": IMG_POSTER_V_URL % ((deep_get(item, "images.v") or deep_get(item, "imageSets.DARK_THEME.v") or deep_get(item, "images.h"))) }, "info": { "genre": item.get("genre"), "year": item.get("year"), "episode": item.get("episodeNo") or item.get("episodeCnt"), "season": item.get("seasonNo") or item.get("seasonCnt"), "mpaa": item.get("parentalRatingName"), "plot": item.get("description"), "title": label, "sorttitle": item.get("shortTitle"), "duration": item.get("duration"), "studio": item.get("cpDisplayName"), "premiered": item.get("broadCastDate") and datetime.fromtimestamp(item.get("broadCastDate")).strftime("%Y-%m-%d"), "path": "", "trailer": "", "dateadded": item.get("broadCastDate") and datetime.fromtimestamp(item.get("broadCastDate")).strftime("%Y-%m-%d %H:%M:%S"), "mediatype": MEDIA_TYPE.get(item.get("assetType")) }, "properties": props, # TODO: Get Stream Info # "stream": { # # "video_codec": "h264", # "width": "1920", # "height": "1080", # # "audio_codec": "aac" # }, "callback": callback, "context": context, "params": params }
index, menu_id, len(menu), is_playable=(item_infos['callback'] == 'live_bridge'), item_infos=item_infos) ======= # Set item additional params if 'xmltv_id' in item_infos: item.params['xmltv_id'] = item_infos['xmltv_id'] item.params['item_id'] = item_id # Set callback function for this item if 'route' in item_infos: item.set_callback((Route.ref(item_infos['route']))) elif 'resolver' in item_infos: item.set_callback((Resolver.ref(item_infos['resolver']))) else: # This case should not happen # Ignore this item to prevent any error for this menu continue # Add needed context menus to this item add_context_menus_to_item(item, item_id, index, menu_id, len(menu), is_playable='resolver' in item_infos, item_infos=item_infos)