def root(plugin, content_type="video"): """ :param Route plugin: The plugin parent object. :param str content_type: The type of content been listed e.g. video, music. This is passed in from kodi and we have no use for it as of yet. """ yield Listitem.recent(video_list, url="newvideos.html") yield Listitem.from_dict(top_videos, bold(plugin.localize(TOP_VIDEOS))) yield Listitem.from_dict(watching_now, bold(plugin.localize(WATCHING_NOW))) yield Listitem.search(search_videos) # Fetch HTML Source url = url_constructor("/browse.html") resp = urlquick.get(url) root_elem = resp.parse("div", attrs={"id": "primary"}) for elem in root_elem.iterfind("ul/li"): img = elem.find(".//img") item = Listitem() # The image tag contains both the image url and title item.label = img.get("alt") item.art["thumb"] = img.get("src") url = elem.find("div/a").get("href") item.set_callback(video_list, url=url) yield item # Add the video items here so that show at the end of the listing bold_text = bold(plugin.localize(VIDEO_OF_THE_DAY)) yield Listitem.from_dict(play_video, bold_text, params={"url": "/index.html"}) yield Listitem.from_dict(party_play, plugin.localize(PARTY_MODE), params={"url": "/randomizer.php"})
def root(plugin, content_type="video"): """ :param Route plugin: The plugin parent object. :param str content_type: The type of content been listed e.g. video, music. This is passed in from kodi and we have no use for it as of yet. """ yield Listitem.recent(video_list, url="newvideos.html") yield Listitem.from_dict(top_videos, bold(plugin.localize(TOP_VIDEOS))) yield Listitem.from_dict(watching_now, bold(plugin.localize(WATCHING_NOW))) yield Listitem.search(search_videos) # Fetch HTML Source url = url_constructor("/browse.html") resp = urlquick.get(url) root_elem = resp.parse("div", attrs={"id": "primary"}) for elem in root_elem.iterfind("ul/li"): img = elem.find(".//img") item = Listitem() # The image tag contains both the image url and title item.label = img.get("alt") item.art["thumb"] = img.get("src") url = elem.find("div/a").get("href") item.set_callback(video_list, url=url) yield item # Add the video items here so that show at the end of the listing bold_text = bold(plugin.localize(VIDEO_OF_THE_DAY)) yield Listitem.from_dict(play_video, bold_text, params={"url": "/index.html"}) yield Listitem.from_dict(party_play, plugin.localize(PARTY_MODE), params={"url": "/randomizer.php"})
def last_added(plugin): """:param Route plugin: The plugin parent object.""" html = urlquick.get(url_constructor('/news')) document = html.parse('div', attrs={'class': 'app-news'}) for block in document.iterfind('.//div[@class="row app-news-block"]'): date = block.find('.//div[@class="app-news-date"]/strong').text for element in block.iterfind('.//div[@class="app-news-list-item"]'): item = Listitem() link = element.find('.//a') if link is None: continue title = link.text subtitle = element.find('.//span/small') subtitle = subtitle.text if subtitle is not None else '' genres = link.get('title') badges = map(__parse_badges, element.findall('.//span')) badges = ' '.join(filter(None, badges)) href = link.get('href') if (href.startswith('/show')): show_id = href.split('/')[2] item.art['thumb'] = __get_poster_url(show_id) item.set_callback(show_page, show_id=show_id) elif (href.startswith('/selection')): item.set_callback(tvshow_selection, href) else: continue label = filter(None, [date[:2], bold(title), badges, subtitle]) plot = filter(None, [ '[CR]'.join(filter(None, [bold(title), badges])), genres, subtitle ]) item.label = __replace_html_codes(' '.join(label)) item.info['plot'] = '[CR][CR]'.join(plot) # # Date # date = elem.find(".//time") # if date is not None: # date = date.get("datetime").split("T", 1)[0] # item.info.date(date, "%Y-%m-%d") # 2018-10-19 # # Video url # url_tag = elem.find(".//a[@class='ellipsis']") # url = url_tag.get("href") # item.context.related(video_list, url='url', filter_mode=1) yield item
def search(cls, callback, *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: 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. :raises ValueError: If the given "callback" function does not have a ``search_query`` parameter. """ # Check that callback function has required parameter(search_query) if "search_query" not in callback.route.arg_names(): raise ValueError("callback function is missing required argument: 'search_query'") if args: # Convert positional arguments to keyword arguments callback.route.args_to_kwargs(args, kwargs) item = cls() item.label = bold(Script.localize(SEARCH)) item.art.global_thumb("search.png") item.info["plot"] = Script.localize(SEARCH_PLOT) item.set_callback(SavedSearches, _route=callback.route.path, first_load=True, **kwargs) return item
def test_bold_uni(self): test_string = u"text" ret = utils.bold(test_string) self.assertEqual("[B]text[/B]", ret, msg="Text was not bolded") self.assertIsInstance(ret, type(test_string), msg="Text type was unexpectedly converted")
def youtube(cls, content_id, label=None, enable_playlists=True): """ Constructor to add a "YouTube channel" to add-on. This listitem will list all videos from a "YouTube", channel or playlist. All videos will have a "Related Videos" option via the context menu. If ``content_id`` is a channel ID and ``enable_playlists`` is ``True``, then a link to the "channel playlists" will also be added to the list of videos. :param str content_id: Channel ID or playlist ID, of video content. :param str label: [opt] Listitem Label. (default => "All Videos"). :param bool enable_playlists: [opt] Set to ``False`` to disable linking to channel playlists. (default => ``True``) :example: >>> item = Listitem() >>> item.youtube("UC4QZ_LsYcvcq7qOsOhpAX4A") """ # Youtube exists, Creating listitem link item = cls() item.label = label if label else bold(Script.localize(ALLVIDEOS)) item.art.global_thumb("videos.png") item.params["contentid"] = content_id item.params["enable_playlists"] = False if content_id.startswith("PL") else enable_playlists item.set_callback(YTPlaylist) return item
def __get_tvshows_by_category(category_id, page): items = [] html = urlquick.get( url_constructor('/show?category={}&sortby=a&page={}'.format( category_id, page))) document = None try: document = html.parse('div', attrs={'id': 'shows'}) except Exception as e: pass if document is not None: for show in document.iterfind('.//div[@class="show"]'): title = ''.join( show.find('.//p[@class="show-title"]').itertext()).strip() link = show.find('.//a') href = link.get('href') show_id = href.split('/')[2] img = show.find('.//img[@class="poster poster-lazy"]') genres = img.get('title') item = Listitem() item.label = title item.info['plot'] = '[CR][CR]'.join( filter(None, [bold(title), genres])) item.art['thumb'] = __get_poster_url(show_id) item.set_callback(show_page, show_id=show_id) items.append(item) return items
def __get_episode_info(episode_id): response = urlquick.get( url_constructor( '/show/episode/episode.json?episode={}'.format(episode_id)), headers={ 'X-Requested-With': 'XMLHttpRequest', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:74.0) Gecko/20100101 Firefox/74.0' }).json() label = response['fullname'] title = label voice = response['voice'] if response['name'] is not None: label += __replace_html_codes(' ' + bold(response['name'])) duration = response['duration'] subtitles = url_constructor( response['subtitles']) if response['subtitles'] else None hd = response['video']['files']['HD']['url'] sd = response['video']['files']['SD']['url'] url = hd if hd is not None else sd quality = hd is not None # 0 - sd, 1 - hd return (label, url, quality, filter(None, [subtitles]), duration, __format_join('[CR][CR]', [title, response['name'], voice]))
def search(cls, callback, *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: 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. :raises ValueError: If the given "callback" function does not have a ``search_query`` parameter. """ # Check that callback function has required parameter(search_query) if "search_query" not in callback.route.arg_names(): raise ValueError( "callback function is missing required argument: 'search_query'" ) if args: # Convert positional arguments to keyword arguments callback.route.args_to_kwargs(args, kwargs) item = cls() item.label = bold(Script.localize(SEARCH)) item.art.global_thumb("search.png") item.info["plot"] = Script.localize(SEARCH_PLOT) item.set_callback(SavedSearches, route=callback.route.path, first_load=True, **kwargs) return item
def next_page(cls, *args, **kwargs): """ Constructor for adding link to "Next Page" of content. By default the current running "callback" will be called with all of the parameters that are given here. You can specify which "callback" will be called by setting a keyword only argument called 'callback'. :param args: "Positional" arguments that will be passed to the callback. :param kwargs: "Keyword" arguments that will be passed to the callback. :example: >>> item = Listitem() >>> item.next_page(url="http://example.com/videos?page2") """ # Current running callback callback = kwargs.pop( "callback") if "callback" in kwargs else dispatcher.get_route( ).callback # Add support params to callback params kwargs[ "_updatelisting_"] = True if u"_nextpagecount_" in dispatcher.params else False kwargs["_title_"] = dispatcher.params.get(u"_title_", u"") kwargs["_nextpagecount_"] = dispatcher.params.get( u"_nextpagecount_", 1) + 1 # Create listitem instance item = cls() label = u"%s %i" % (Script.localize(NEXT_PAGE), kwargs["_nextpagecount_"]) item.info["plot"] = Script.localize(NEXT_PAGE_PLOT) item.label = bold(label) item.art.global_thumb("next.png") item.set_callback(callback, *args, **kwargs) return item
def search(cls, callback, *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(Script.localize(SEARCH)) item.art.global_thumb("search.png") item.info["plot"] = Script.localize(SEARCH_PLOT) item.set_callback(Route.ref("/codequick/search:saved_searches"), *args, **kwargs) return item
def youtube(cls, content_id, label=None, enable_playlists=True): """ Constructor to add a "YouTube channel" to add-on. This listitem will list all videos from a "YouTube", channel or playlist. All videos will have a "Related Videos" option via the context menu. If ``content_id`` is a channel ID and ``enable_playlists`` is ``True``, then a link to the "channel playlists" will also be added to the list of videos. :param str content_id: Channel ID or playlist ID, of video content. :param str label: [opt] Listitem Label. (default => "All Videos"). :param bool enable_playlists: [opt] Set to ``False`` to disable linking to channel playlists. (default => ``True``) :example: >>> item = Listitem() >>> item.youtube("UC4QZ_LsYcvcq7qOsOhpAX4A") """ # Youtube exists, Creating listitem link item = cls() item.label = label if label else bold(Script.localize(ALLVIDEOS)) item.art.global_thumb("videos.png") item.params["contentid"] = content_id item.params["enable_playlists"] = False if content_id.startswith( "PL") else enable_playlists item.set_callback(Route.ref("/codequick/youtube:playlist")) return item
def next_page(cls, *args, **kwargs): """ Constructor for adding link to "Next Page" of content. The current running "callback" will be called with all of the parameters that are given here. You can also specify which "callback" will be called by setting a keywork only argument called 'callback'. :param args: "Positional" arguments that will be passed to the callback. :param kwargs: "Keyword" arguments that will be passed to the callback. :example: >>> item = Listitem() >>> item.next_page(url="http://example.com/videos?page2") """ # Current running callback callback = dispatcher.get_route().callback callback = kwargs.pop("callback", callback) # Add support params to callback params kwargs["_updatelisting_"] = True if u"_nextpagecount_" in dispatcher.params else False kwargs["_title_"] = dispatcher.params.get(u"_title_", u"") kwargs["_nextpagecount_"] = dispatcher.params.get(u"_nextpagecount_", 1) + 1 # Create listitem instance item = cls() label = u"%s %i" % (Script.localize(NEXT_PAGE), kwargs["_nextpagecount_"]) item.info["plot"] = Script.localize(NEXT_PAGE_PLOT) item.label = bold(label) item.art.global_thumb("next.png") item.set_callback(callback, *args, **kwargs) return item
def root(plugin, content_type="video"): """ :param Route plugin: The plugin parent object. :param str content_type: The type of content being listed e.g. video, music. This is passed in from kodi and we have no use for it as of yet. """ yield Listitem.recent(video_list, url="/newvideos.html") yield Listitem.from_dict(top_videos, bold(plugin.localize(TOP_VIDEOS))) yield Listitem.from_dict(video_list, bold(plugin.localize(FEATURED)), params={ "url": "/index.html", "filter_mode": 2 }) yield Listitem.search(search_videos) # List Categories resp = urlquick.get(url_constructor("/browse.html")) root_elem = resp.parse( "ul", attrs={"class": "pm-ul-browse-categories list-unstyled thumbnails"}) for elem in root_elem.iterfind("li/div"): url_tag = elem.find("a") item = Listitem() item.label = url_tag.find("h3").text item.art["thumb"] = url_tag.find(".//img").get("src") url = url_tag.get("href") # Add Context menu item to sort by Views, Ratings and/or Title for sort in ("views", "rating", "title"): sort_url = url.replace("date.html", "{}.html".format(sort)) item.context.container(video_list, "By {}".format(sort), url=sort_url) item.set_callback(video_list, url=url) yield item # Video of the day yield Listitem.from_dict(party_play, plugin.localize(PARTY_MODE), params={"url": "/index.html"})
def root(plugin): headers = get_headers() if EMAIL and PASSWORD: profiles_data = urlquick.get(PROFILES_URL, headers=headers, max_age=0).json() pin = profiles_data['pinCode'] else: pin = None avatar_k = urlquick.get(AVATAR_URL + 'kidsDefault').json()['avatars'][0]['url'] id_k = ''.join(choice('0123456789abcdef-') for n in range(36)).encode('utf-8') avatar_a = urlquick.get(AVATAR_URL + 'adultDefault').json()['avatars'][0]['url'] id_a = ''.join(choice('0123456789abcdef-') for n in range(36)).encode('utf-8') profiles_data = { 'profiles': [{ 'type': 'ADULT', 'default': True, 'id': id_a, 'name': plugin.localize(30302), "avatar": { "url": formatimg(avatar_a, 'icon') } }, { 'type': 'KID', 'default': True, 'name': plugin.localize(30301), 'id': id_k, "avatar": { "url": formatimg(avatar_k, 'icon') } }] } for profile in profiles_data['profiles']: profile_type = profile['type'] if MODE_KIDS and profile_type != 'KID' and (not EMAIL or not PASSWORD): continue profile_id = profile['id'] profile_name = profile['name'].title() is_master = profile['default'] avatar = formatimg(profile['avatar']['url'], 'icon') yield Listitem.from_dict(sub_menu, bold(profile_name), art={"thumb": avatar}, params={ 'profile_id': profile_id, 'profile_type': profile_type, 'pin': pin, 'is_master': is_master })
def root(plugin): """:type plugin: Route""" # Set context parameters based on default view setting if plugin.setting.get_int("defaultview") == 0: context_label = plugin.localize(LIST_AUDIO) context_type = "segment" item_type = "video" else: context_label = plugin.localize(LIST_VIDEO) context_type = "video" item_type = "segment" # Fetch HTML Source url = "https://www.sciencefriday.com/explore/" html = urlquick.get(url) # Parse for the content root_elem = html.parse("form", attrs={"class": "searchandfilter"}) sfid = root_elem.get("data-sf-form-id") # Add Youtube & Recent Content yield Listitem.youtube("UCDjGU4DP3b-eGxrsipCvoVQ") # Add Recent Videos link yield Listitem.from_dict(content_lister, bold(plugin.localize(RECENT_VIDEOS)), params={"sfid": sfid, "ctype": "video"}) # Add Recent Audio link yield Listitem.from_dict(content_lister, bold(plugin.localize(RECENT_AUDIO)), params={"sfid": sfid, "ctype": "segment"}) # List all topics for elem in root_elem.iterfind(".//option[@data-sf-cr]"): item = Listitem() item.label = elem.text # Add context item to link to the opposite content type. e.g. audio if video is default item.context.container(content_lister, context_label, topic=elem.attrib["value"], sfid=sfid, ctype=context_type) item.set_callback(content_lister, topic=elem.attrib["value"], ctype=item_type, sfid=sfid) yield item
def recent(cls, callback, *args, **kwargs): """ Constructor for adding "Recent Videos" folder. This is a convenience method that creates the listitem with "name", "thumbnail" and "plot", already preset. :param Callback callback: The "callback" function. :param args: "Positional" arguments that will be passed to the callback. :param kwargs: "Keyword" arguments that will be passed to the callback. """ # Create listitem instance item = cls() item.label = bold(Script.localize(RECENT_VIDEOS)) item.info["plot"] = Script.localize(RECENT_VIDEOS_PLOT) item.art.global_thumb("recent.png") item.set_callback(callback, *args, **kwargs) return item
def recent(cls, callback, *args, **kwargs): """ Constructor for adding "Recent Videos" folder. This is a convenience method that creates the listitem with "name", "thumbnail" and "plot", already preset. :param callback: The "callback" function. :param args: "Positional" arguments that will be passed to the callback. :param kwargs: "Keyword" arguments that will be passed to the callback. """ # Create listitem instance item = cls() item.label = bold(Script.localize(RECENT_VIDEOS)) item.info["plot"] = Script.localize(RECENT_VIDEOS_PLOT) item.art.global_thumb("recent.png") item.set_callback(callback, *args, **kwargs) return item
def __parse_badges(element): element_class = element.get('class') result = None if 'label' in element_class: result = element.text if not result: span = element.find('.//span') if span is not None: result = span.get('title') color_code = 'FFee98fb' # light purple if result in ['Топ', 'Важно']: color_code = 'FFe53935' # red elif result == 'Подборка': color_code = 'FFff9800' # orange elif result == 'Новое': color_code = 'FF5cb85c' # green elif result in ['Обновлено', 'Финал']: color_code = 'FF5bc0de' # blue return None if result is None else bold(color(result, color_code))
def tvshow_selection(plugin, url): html = urlquick.get(url_constructor(url)) document = html.parse('div', attrs={'class': 'container main-container'}) for tvshow in document.iterfind('.//div[@class="row selection-show"]'): link = tvshow.find('a') href = link.get('href') show_id = href.split('/')[2] title = tvshow.find('div//a').text title_original = tvshow.find('div//small') if title_original is not None: title_original = title_original.text description = tvshow.find('div/p').text.strip() item = Listitem() item.label = title item.art['thumb'] = __get_poster_url(show_id) item.info['plot'] = __format_join('[CR][CR]', [ __format_join('[CR]', [bold(title), title_original]), description ]) item.set_callback(show_page, show_id=show_id) yield item
def playlists(plugin, channel_id, show_all=True, pagetoken=None, loop=False): """ List all playlist for giving channel :param Route plugin: Tools related to Route callbacks. :param str channel_id: Channel id to list playlists for. :param bool show_all: [opt] Add link to all of the channels videos if True. (default => True) :param str pagetoken: [opt] The token for the next page of results. :param bool loop: [opt] Return all the playlist for channel. (Default => False) :returns: A generator of listitems. :rtype: :class:`types.GeneratorType` """ gdata = APIControl() # Make sure that we have a valid channel id if not channel_id.startswith("UC"): raise ValueError("channel_id is not valid: %s" % channel_id) # Fetch fanart image for channel fanart = gdata.db.cur.execute( "SELECT fanart FROM channels WHERE channel_id = ?", (channel_id, )).fetchone() if fanart: # pragma: no branch fanart = fanart[0] # Fetch channel playlists feed feed = gdata.api.playlists(channel_id, pagetoken, loop) # Add next Page entry if pagetoken is found if u"nextPageToken" in feed: # pragma: no branch yield Listitem.next_page(channel_id=channel_id, show_all=False, pagetoken=feed[u"nextPageToken"]) # Display a link for listing all channel videos # This is usefull when the root of a addon is the playlist directory if show_all: title = bold(plugin.localize(ALLVIDEOS)) yield Listitem.youtube(channel_id, title, enable_playlists=False) # Loop Entries for playlist_item in feed[u"items"]: # Create listitem object item = Listitem() # Check if there is actualy items in the playlist before listing item_count = playlist_item[u"contentDetails"][u"itemCount"] if item_count == 0: # pragma: no cover continue # Fetch video snippet snippet = playlist_item[u"snippet"] # Set label item.label = u"%s (%s)" % (snippet[u"localized"][u"title"], item_count) # Fetch Image Url item.art["thumb"] = snippet[u"thumbnails"][u"medium"][u"url"] # Set Fanart item.art["fanart"] = fanart # Fetch Possible Plot and Check if Available item.info["plot"] = snippet[u"localized"][u"description"] # Add InfoLabels and Data to Processed List item.set_callback(playlist, contentid=playlist_item[u"id"], enable_playlists=False) yield item # Close db gdata.close()
def content_lister(plugin, sfid, ctype, topic=None, page_count=1): """ :type plugin: Route :type sfid: unicode :type ctype: unicode :type topic: unicode :type page_count: int """ # Add link to Alternitve Listing if page_count == 1 and topic: params = {"_updatelisting_": True, "sfid": sfid, "topic": topic, "ctype": u"segment" if ctype == u"video" else u"video"} label = bold(plugin.localize(LIST_AUDIO) if ctype == u"video" else plugin.localize(LIST_VIDEO)) item_dict = {"label": label, "callback": content_lister, "params": params} yield Listitem.from_dict(**item_dict) # Create content url if topic: url = "https://www.sciencefriday.com/wp-admin/admin-ajax.php?action=get_results&paged=%(next)s&" \ "sfid=%(sfid)s&post_types=%(ctype)s&_sft_topic=%(topic)s" % \ {"sfid": sfid, "ctype": ctype, "topic": topic, "next": page_count} else: url = "https://www.sciencefriday.com/wp-admin/admin-ajax.php?action=get_results&paged=%(next)s&" \ "sfid=%(sfid)s&post_types=%(ctype)s" % \ {"sfid": sfid, "ctype": ctype, "next": page_count} # Fetch & parse HTML Source ishd = bool(plugin.setting.get_int("video_quality", addon_id="script.module.youtube.dl")) root_elem = urlquick.get(url).parse() # Fetch next page next_url = root_elem.find(".//a[@rel='next']") if next_url is not None: # pragma: no branch yield Listitem.next_page(sfid=sfid, ctype=ctype, page_count=page_count+1) # Parse the elements for element in root_elem.iterfind(".//article"): tag_a = element.find(".//a[@rel='bookmark']") item = Listitem() item.label = tag_a.text item.stream.hd(ishd) # Fetch plot & duration tag_p = element.findall(".//p") if tag_p and tag_p[0].get("class") == "run-time": item.info["duration"] = tag_p[0].text item.info["plot"] = tag_p[1].text elif tag_p: # pragma: no branch item.info["plot"] = tag_p[0].text # Fetch image if exists img = element.find(".//img[@data-src]") if img is not None: item.art["thumb"] = img.get("data-src") # Fetch audio/video url tag_audio = element.find(".//a[@data-audio]") if tag_audio is not None: audio_url = tag_audio.get("data-audio") item.set_callback(audio_url) else: item.set_callback(play_video, url=tag_a.get("href")) yield item
def show_page(plugin, show_id): html = urlquick.get(url_constructor('/show/{}'.format(show_id))) document = html.parse('div', attrs={'class': 'container main-container'}) title = document.find('.//div[@id="h-show-title"]') if title is not None: all_seasons_item = Listitem() all_seasons_item.art['thumb'] = __get_poster_url(show_id) title = bold(title.text) title_original = document.find( './/div[@class="app-show-header-title-original"]').text all_seasons_item.label = __replace_html_codes(' '.join( [title, 'Все сезоны'])) years = ''.join( document.find('.//div[@class="app-show-header-years"]').itertext()) genres = filter( None, map(__clear_tvshow_tags, document.findall('.//ul[@class="app-show-tags"]/li/a'))) country = document.find( './/ul[@class="app-show-tags"]/li/a[@class="app-show-tags-flag"]') country = country.text if country is not None else 'un' description = __replace_html_codes( document.find('.//p[@class="app-show-description"]').text) seasons = [] for season_block in document.iterfind( './/section[@class="app-show-seasons-section-light hidden"]'): season = {'title': '', 'episodes': []} season['title'] = season_block.find('.//h3').text for link in season_block.iterfind('.//div/ul/li/a'): episode_id = link.get('id')[31:] season['episodes'].append(episode_id) seasons.append(season) # Script.log(season_number, lvl=Script.ERROR) # Script.log(episode_number, lvl=Script.ERROR) plot = [__format_join('[CR]', [title, title_original]), description] all_seasons_item.info['plot'] = '[CR][CR]'.join(plot) episodes_ids = [] seasons_items = [] for season in seasons: item = Listitem() episodes_count = len(season['episodes']) item.label = __replace_html_codes(' '.join( [bold(season['title']), '({})'.format(episodes_count)])) item.art['thumb'] = __get_poster_url(show_id) plot = [ title, season['title'], 'Эпизодов: {}'.format(episodes_count) ] item.info['plot'] = '[CR][CR]'.join(plot) item.set_callback(tvshow_episodes, episodes_ids=season['episodes'], show_id=show_id) episodes_ids.extend(season['episodes']) seasons_items.append(item) all_seasons_item.set_callback(tvshow_episodes, episodes_ids=episodes_ids, show_id=show_id) yield all_seasons_item mix_playlist = episodes_ids[:] random.shuffle(mix_playlist) yield Listitem.from_dict( play_episodes_mix, 'Микс', art={'thumb': __get_poster_url(show_id)}, info={'plot': 'Воспроизвести в случайном порядке'}, params={'episodes_ids': mix_playlist}) for item in seasons_items: yield item
def root(plugin, content_type="video"): yield Listitem.search(search) yield Listitem.from_dict(last_added, bold('Последние поступления')) categories = __get_categories() for category in categories: yield category
def run(self, channel_id, show_all=True, pagetoken=None, loop=False): """ List all playlist for giving channel :param str channel_id: Channel id to list playlists for. :param bool show_all: [opt] Add link to all of the channels videos if True. (default => True) :param str pagetoken: [opt] The token for the next page of results. :param bool loop: [opt] Return all the playlist for channel. (Default => False) :returns: A generator of listitems. :rtype: :class:`types.GeneratorType` """ # Make sure that we have a valid channel id if not channel_id.startswith("UC"): raise ValueError("channel_id is not valid: %s" % channel_id) # Fetch fanart image for channel fanart = self.db.cur.execute("SELECT fanart FROM channels WHERE channel_id = ?", (channel_id,)).fetchone() if fanart: # pragma: no branch fanart = fanart[0] # Fetch channel playlists feed feed = self.api.playlists(channel_id, pagetoken, loop) # Add next Page entry if pagetoken is found if u"nextPageToken" in feed: # pragma: no branch yield Listitem.next_page(channel_id=channel_id, show_all=False, pagetoken=feed[u"nextPageToken"]) # Display a link for listing all channel videos # This is usefull when the root of a addon is the playlist directory if show_all: title = bold(self.localize(ALLVIDEOS)) yield Listitem.youtube(channel_id, title, enable_playlists=False) # Loop Entries for playlist_item in feed[u"items"]: # Create listitem object item = Listitem() # Check if there is actualy items in the playlist before listing item_count = playlist_item[u"contentDetails"][u"itemCount"] if item_count == 0: # pragma: no cover continue # Fetch video snippet snippet = playlist_item[u"snippet"] # Set label item.label = u"%s (%s)" % (snippet[u"localized"][u"title"], item_count) # Fetch Image Url item.art["thumb"] = snippet[u"thumbnails"][u"medium"][u"url"] # Set Fanart item.art["fanart"] = fanart # Fetch Possible Plot and Check if Available item.info["plot"] = snippet[u"localized"][u"description"] # Add InfoLabels and Data to Processed List item.set_callback(Playlist, contentid=playlist_item[u"id"], enable_playlists=False) yield item
def sub_menu(plugin, profile_id, profile_type, is_master, pin): if profile_type == 'KID': plugin.log('Creating Kids Menu', lvl=plugin.WARNING) # get kids user id yield Listitem.from_dict(LIVE_TV, bold(plugin.localize(30101)), params={ 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.from_dict(BROWSE_TVSHOWS, bold(plugin.localize(30102)), params={ "genreId": "", "productSubType": "SERIES", "page": 0, 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.from_dict(BROWSE_TVSHOWS, bold(plugin.localize(30103)), params={ "genreId": "", "productSubType": "PROGRAM", "page": 0, 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.from_dict(BROWSE_MOVIES, bold(plugin.localize(30104)), params={ 'genreId': '', 'page': 0, 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.search(SEARCH_CONTENT, profile_id=profile_id, profile_type=profile_type, is_master=is_master) else: if MODE_KIDS: user_input = keyboard("Enter your PIN Code", "", True) if user_input != pin: plugin.notify(plugin.localize(30202), plugin.localize(30201), display_time=5000, sound=True) yield False return plugin.log('Creating Main Menu', lvl=plugin.WARNING) yield Listitem.from_dict(LIVE_TV, bold(plugin.localize(30101)), params={ 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.from_dict(CATEGORIES, bold(plugin.localize(30102)), params={ "productSubType": "SERIES", 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.from_dict(CATEGORIES, bold(plugin.localize(30103)), params={ "productSubType": "PROGRAM", 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.from_dict(CATEGORIES_M, bold(plugin.localize(30104)), params={ 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) if EMAIL and PASSWORD: yield Listitem.from_dict(MY_LIST, bold(plugin.localize(30105)), params={ 'profile_id': profile_id, 'profile_type': profile_type, 'is_master': is_master }) yield Listitem.search(SEARCH_CONTENT, profile_id=profile_id, profile_type=profile_type, is_master=is_master)