def getVideos(self): # # Init # # Create a list for our items. listing = [] # # Get HTML page # response = requests.get(self.video_list_page_url, headers=HEADERS) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source", html_source) try: json_data = json.loads(html_source) # for item in json_data['data']: # log("attribute1", item['canonical_links']['self']) # log("attribute2", item['attributes']['title']) # exit(1) except (ValueError, KeyError, TypeError): xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30109)) exit(1) for item in json_data['data']: season_title = item['attributes']['title'] # the season url should something like this: # https://svod-be.roosterteeth.com/api/v1/seasons/let-s-play-2018/episodes serie_url_last_part = item['links']['episodes'] serie_url = ROOSTERTEETH_BASE_URL + serie_url_last_part # serie_url should now looks something like this: https://svod-be.roosterteeth.com/api/v1/seasons/gameplay-2019/episodes?order=desc # let's alter the selection criteria a bit pos_of_questionmark = serie_url.find("?") if pos_of_questionmark >= 0: serie_url = serie_url[0:pos_of_questionmark] serie_url = serie_url + ROOSTERTEETH_PAGE_URL_PART + ROOSTERTEETH_ORDER_URL_PART # log("serie_url", serie_url) thumb = self.thumbnail_url title = season_title url = serie_url thumbnail_url = thumb # Add to list... list_item = xbmcgui.ListItem(title) list_item.setArt({ 'thumb': thumbnail_url, 'icon': thumbnail_url, 'fanart': os.path.join(RESOURCES_PATH, 'fanart-blur.jpg') }) list_item.setProperty('IsPlayable', 'false') # let's remove any non-ascii characters from the title, to prevent errors with urllib.parse.parse_qs # of the parameters title = title.encode('ascii', 'ignore') parameters = { "action": "list-episodes", "url": url, "title": title, "show_serie_name": "False", "next_page_possible": "True" } plugin_url_with_parms = self.plugin_url + '?' + urllib.parse.urlencode( parameters) is_folder = True # Add refresh option to context menu list_item.addContextMenuItems([('Refresh', 'Container.Refresh')]) # Add our item to the listing as a 3-element tuple. listing.append((plugin_url_with_parms, list_item, is_folder)) # Add our listing to Kodi. # Large lists and/or slower systems benefit from adding all items at once via addDirectoryItems # instead of adding one by ove via addDirectoryItem. xbmcplugin.addDirectoryItems(self.plugin_handle, listing, len(listing)) # Set initial sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_DATEADDED) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)
def __init__(self): # Get the command line arguments # Get the plugin url in plugin:// notation self.plugin_url = sys.argv[0] # Get the plugin handle as an integer number self.plugin_handle = int(sys.argv[1]) # # Roosterteeth Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30301), "url": ROOSTERTEETHRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30301)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Roosterteeth Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30302), "url": ROOSTERTEETHSHOWSURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30302)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Achievement Hunter Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30303), "url": ACHIEVEMENTHUNTERRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30303)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Achievement Hunter Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30304), "url": ACHIEVEMENTHUNTERSHOWSURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30304)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Fun Haus Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30305), "url": FUNHAUSRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30305)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Fun Haus Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30306), "url": FUNHAUSSHOWURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30306)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Screw Attack Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30307), "url": SCREWATTACKRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30307)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Screw Attack Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30308), "url": SCREWATTACKSHOWSURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30308)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # The Know Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30311), "url": THEKNOWRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30311)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # The Know Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30312), "url": THEKNOWSHOWSURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30312)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Game Attack Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30309), "url": GAMEATTACKRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30309)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Game Attack Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30310), "url": GAMEATTACKSHOWSURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30310)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Cow Chop Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30313), "url": COWCHOPRECENTLYADDEDURL, "next_page_possible": "True" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30313)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Cow Chop Shows # parameters = { "action": "list-shows", "plugin_category": LANGUAGE(30314), "url": COWCHOPSHOWSURL, "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30314)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # Disable sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_NONE) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)
def playVideo(self): # # Init # dialog_wait = xbmcgui.DialogProgress() # # Get current list item details... # title = xbmc.getInfoLabel("listitem.Title") # thumbnail_url = xbmc.getInfoImage("list_item.Thumb") studio = xbmc.getInfoLabel("list_item.Studio") mediatype = xbmc.getInfoLabel("list_item.Mediatype") # plot = xbmc.getInfoLabel("list_item.Plot") # genre = xbmc.getInfoLabel("list_item.Genre") session = '' try: # requests is sooooo nice, respect! session = requests.Session() if self.is_sponsor_only == "True": must_login_sponsored_user = True video_is_not_yet_available = False else: # try and get the non-sponsored video without being logged in # get the page that contains the video response = session.get(self.url, headers=HEADERS) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source without authorization", html_source) # sometimes a non-sponsor video is not available. However this video will (!) be available for a sponsor # after logging in. One of the perks of being a sponsor, i reckon. This is what you get back in that # case: {"access":false,"message":"not yet available"} if html_source.find("not yet available") >= 0: # let's try and get this non-sponsored video after login in the sponsored user then must_login_sponsored_user = True video_is_not_yet_available = True else: must_login_sponsored_user = False video_is_not_yet_available = False #log("must_login_sponsored_user", must_login_sponsored_user) # login if needed if must_login_sponsored_user: # is the sponsor switch in the settings of this addon turned on? if self.IS_SPONSOR == 'true': # is it a sponsored video or not? if self.is_sponsor_only == "True": log("logging in with user for this sponsored video", self.url) else: log("logging in with user for this non-sponsored video", self.url) # let's try and get authorization try: # we need a NEW (!!!) session session = requests.Session() # set the needed authorization-data payload = {"client_id": KODI_ROOSTERTEETH_ADDON_CLIENT_ID, "grant_type": "password", "password": SETTINGS.getSetting('password'), "scope": "user public", "username": SETTINGS.getSetting('username')} # post the payload to the authorization url, to actually get an access token (oauth) back response = session.post(ROOSTERTEETH_AUTHORIZATION_URL, data=payload) log('post login page response, status_code:', response.status_code) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source getting authorization", html_source) # check that the login was technically ok (status_code 200). # This in itself does NOT mean that the username/password were correct. if response.status_code == 200: pass # {"access_token":"eyJ0eXAiOiJKV1QiLCJ<SOMETHINGSOMETHING>","token_type":"bearer","expires_ # check that we get back an access_token (oauth) # for some reason html_source can't be loaded in json, so we have to do it the hard way :( start_pos_access_token_url = html_source.find('"access_token":"') if start_pos_access_token_url >= 0: log('login was successful!', 'login was successful!') start_pos_access_token_url = start_pos_access_token_url + len('"access_token":"') end_pos_access_token = html_source.find('"', start_pos_access_token_url) access_token = html_source[start_pos_access_token_url:end_pos_access_token] # log("access_token", access_token) # let's make a new header dictionary headers_with_access_token = HEADERS # add the access token to the dictionary # see https://stackoverflow.com/questions/29931671/making-an-api-call-in-python-with-an-api-that-requires-a-bearer-token # this is some specific magic for setting the authorization in the header headers_with_access_token['Authorization'] = "Bearer " + access_token # log("headers_with_access_token", headers_with_access_token) # let's try getting the page with the received access_code response = session.get(self.url, headers=headers_with_access_token) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source with authorization", html_source) else: log('login was NOT successful!', 'login was NOT successful!') try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30101), LANGUAGE(30102), LANGUAGE(30103)) exit(1) else: try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30104) % (convertToUnicodeString(response.status_code))) exit(1) except urllib.error.HTTPError as error: log("HTTPError1", error) try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30106) % (convertToUnicodeString(error))) exit(1) except: exception = sys.exc_info()[0] log("ExceptionError1", exception) try: dialog_wait.close() del dialog_wait except: pass exit(1) else: try: dialog_wait.close() del dialog_wait except: pass if video_is_not_yet_available: xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30110)) else: xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30105)) exit(1) except urllib.error.HTTPError as error: log("HTTPError1", error) try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30106) % (convertToUnicodeString(error))) exit(1) except: exception = sys.exc_info()[0] log("ExceptionError2", exception) try: dialog_wait.close() del dialog_wait except: pass exit(1) video_url = '' no_url_found = True have_valid_url = False # for some reason html_source can't be loaded in json, so we have to do it the hard way :( start_pos_m3u8_url = html_source.find('"url":"') if start_pos_m3u8_url == -1: found_m3u8_url = False else: start_pos_m3u8_url = start_pos_m3u8_url + len('"url":"') end_pos_m3u8_url = html_source.find('"', start_pos_m3u8_url) if end_pos_m3u8_url == -1: found_m3u8_url = False else: m3u8_url = html_source[start_pos_m3u8_url:end_pos_m3u8_url] log("m3u8_url", m3u8_url) found_m3u8_url = True log("found_m3u8_url", found_m3u8_url) if found_m3u8_url: # for some reason u0026 is present in the url, it should have been an ampersand # let's correct that m3u8_url = m3u8_url.replace('u0026', '&') log("corrected m3u8_url", m3u8_url) # get the content of the m3u8 file response = session.get(m3u8_url, headers=HEADERS) if response.status_code == 200: have_valid_url = True video_url = m3u8_url log("video_url", video_url) if self.USE_ADAPTIVE_STREAM == 'true': pass else: html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source m3u8 file", html_source) # determine the wanted video quality if self.PREFERRED_QUALITY == '0': # Very Low quality = VQ240P elif self.PREFERRED_QUALITY == '1': # Low quality = VQ360P elif self.PREFERRED_QUALITY == '2': # Medium quality = VQ480P elif self.PREFERRED_QUALITY == '3': # High Quality quality = VQ720P elif self.PREFERRED_QUALITY == '4': # Very High Quality quality = VQ1080P elif self.PREFERRED_QUALITY == '5': # Ultra High Quality quality = VQ4K else: # Default in case quality is not found quality = VQ720P # log("wanted quality", quality) # an example of the content of a m3u8 file. Not all the resolutions will be there as most videos don't # have an 4k option: # #EXTM3U # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=21589000,RESOLUTION=1280x720,CODECS="avc1.4d001f,mp4a.40.2" # aef4654c-hls_4k-rebuilds-4030.mp4.m3u8 # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=21589000,RESOLUTION=1280x720,CODECS="avc1.4d001f,mp4a.40.2" # aef4654c-hls_1080p-rebuilds-4030.mp4.m3u8 # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=8281000,RESOLUTION=1280x720,CODECS="avc1.4d001f,mp4a.40.2" # aef4654c-hls_720p-rebuilds-4030.mp4.m3u8 # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=6370000,RESOLUTION=854x480,CODECS="avc1.4d001f,mp4a.40.2" # aef4654c-hls_480p-rebuilds-4030.mp4.m3u8 # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=4093000,RESOLUTION=640x360,CODECS="avc1.4d001f,mp4a.40.2" # aef4654c-hls_360p-rebuilds-4030.mp4.m3u8 # #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=2941000,RESOLUTION=426x240,CODECS="avc1.4d001f,mp4a.40.2" # aef4654c-hls_240p-rebuilds-4030.mp4.m3u8 # Let's try and find a video of the desired video quality. # If that can't be found, try to find a video with less than the desired video quality video_url_altered = '' if video_url_altered == '': if quality in [VQ4K]: video_url_altered = self.find_video_quality_url(VQ4K, response, video_url) if video_url_altered == '': if quality in [VQ4K, VQ1080P]: video_url_altered = self.find_video_quality_url(VQ1080P, response, video_url) if video_url_altered == '': if quality in [VQ4K, VQ1080P, VQ720P]: video_url_altered = self.find_video_quality_url(VQ720P, response, video_url) if video_url_altered == '': if quality in [VQ4K, VQ1080P, VQ720P, VQ480P]: video_url_altered = self.find_video_quality_url(VQ480P, response, video_url) if video_url_altered == '': if quality in [VQ4K, VQ1080P, VQ720P, VQ480P, VQ360P]: video_url_altered = self.find_video_quality_url(VQ360P, response, video_url) if video_url_altered == '': if quality in [VQ4K, VQ1080P, VQ720P, VQ480P, VQ360P, VQ240P]: video_url_altered = self.find_video_quality_url(VQ240P, response, video_url) if video_url_altered == '': pass else: log("video_url_altered", video_url_altered) # Find out if the altered m3u8 url exists response = session.get(video_url_altered) log("response.status_code", response.status_code) # if we find a m3u8 file with the altered url, let's use that. # If it is not found, let's use the unaltered url. if response.status_code in [200]: video_url = video_url_altered log("final video_url", video_url) else: have_valid_url = False # Play video... if have_valid_url: list_item = xbmcgui.ListItem(path=video_url) if self.USE_ADAPTIVE_STREAM == 'true': list_item.setProperty('inputstreamaddon', 'inputstream.adaptive') list_item.setProperty('inputstream.adaptive.manifest_type', 'hls') xbmcplugin.setResolvedUrl(self.plugin_handle, True, list_item) # # Alert user # elif no_url_found: xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30107))
def __init__(self): # Get the command line arguments # Get the plugin url in plugin:// notation self.plugin_url = sys.argv[0] # Get the plugin handle as an integer number self.plugin_handle = int(sys.argv[1]) # # Init # # Create a list for our items. listing = [] # # Get HTML page # response = requests.get(ROOSTERTEETH_CHANNELS_URL, headers=HEADERS) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source", html_source) try: json_data = json.loads(html_source) except (ValueError, KeyError, TypeError): xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30109)) exit(1) for item in json_data['data']: thumb = item['included']['images'][0]['attributes']['large'] channel_name = item['attributes']['name'] channel_name_in_url = item['attributes']['slug'] # channel_shows_link = item['links']['shows'] channel_episodes_link = item['links']['episodes'] title = channel_name.title() + ' ' + LANGUAGE(30321) # Add serie recently added episodes url_serie_recently_added_episodes = ROOSTERTEETH_BASE_URL + channel_episodes_link + \ ROOSTERTEETH_PAGE_URL_PART + ROOSTERTEETH_ORDER_URL_PART + \ ROOSTERTEETH_CHANNEL_URL_PART + channel_name_in_url # log("serie recently added episode url", url_serie_recently_added_episodes) thumbnail_url = thumb title = title.encode('ascii', 'ignore') parameters = { "action": "list-episodes", "plugin_category": title, "url": url_serie_recently_added_episodes, "show_serie_name": "True", "next_page_possible": "True" } list_item = xbmcgui.ListItem(title) list_item.setArt({ 'thumb': thumbnail_url, 'icon': thumbnail_url, 'fanart': os.path.join(RESOURCES_PATH, 'fanart-blur.jpg') }) list_item.setProperty('IsPlayable', 'false') url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) is_folder = True xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # Add serie shows title = channel_name.title() + ' ' + LANGUAGE(30302) # let's remove any non-ascii characters from the title, to prevent errors with urllib.parse.parse_qs # of the parameters title = title.encode('ascii', 'ignore') url_serie_shows = ROOSTERTEETH_SERIES_BASE_URL + ROOSTERTEETH_GET_EVERYTHING_IN_ONE_PAGE_URL_PART + \ ROOSTERTEETH_ORDER_URL_PART + ROOSTERTEETH_CHANNEL_URL_PART + channel_name_in_url # log("serie shows url", url_serie_shows) parameters = { "action": "list-series", "plugin_category": title, "url": url_serie_shows, "show_serie_name": "True", "next_page_possible": "True" } list_item = xbmcgui.ListItem(title) list_item.setArt({ 'thumb': thumbnail_url, 'icon': thumbnail_url, 'fanart': os.path.join(RESOURCES_PATH, 'fanart-blur.jpg') }) list_item.setProperty('IsPlayable', 'false') url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) is_folder = True xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # Add Series url_series = ROOSTERTEETH_SERIES_URL + ROOSTERTEETH_GET_EVERYTHING_IN_ONE_PAGE_URL_PART + \ ROOSTERTEETH_ORDER_URL_PART parameters = { "action": "list-series", "plugin_category": LANGUAGE(30302), "url": url_series, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30302)) is_folder = True list_item.setArt( {'fanart': os.path.join(RESOURCES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # Set initial sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_DATEADDED) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)
def getVideos(self): # # Init # # Create a list for our items. listing = [] # # Get HTML page # response = requests.get(self.video_list_page_url, headers=HEADERS) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source", html_source) try: json_data = json.loads(html_source) # for item in json_data['data']: # log("attribute1", item['canonical_links']['self']) # log("attribute2", item['attributes']['title']) # exit(1) except (ValueError, KeyError, TypeError): xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30109)) exit(1) for item in json_data['data']: serie_title = item['attributes']['title'] summary = item['attributes']['summary'] last_episode_golive_at = item['attributes'][ 'last_episode_golive_at'] last_episode_golive_at = last_episode_golive_at[0:10] # this part looks like this f.e.: /series/nature-town serie_url_middle_part = item['canonical_links']['self'] serie_name = serie_url_middle_part.replace('/series/', '') # log("serie_url_middle_part", serie_url_middle_part) # log("serie_name", serie_name) # the serie url should become something like this: # https://svod-be.roosterteeth.com/api/v1/shows/nature-town/seasons?order=desc serie_url = ROOSTERTEETH_SERIES_BASE_URL + '/' + serie_name + '/' + 'seasons' \ + ROOSTERTEETH_GET_EVERYTHING_IN_ONE_PAGE_URL_PART + ROOSTERTEETH_ORDER_URL_PART thumb = item['included']['images'][0]['attributes']['thumb'] title = serie_title url = serie_url thumbnail_url = thumb # Add to list... list_item = xbmcgui.ListItem(title) list_item.setInfo( "video", { "title": title, "mediatype": "video", "plot": summary + '\n' + LANGUAGE(30319) + ' ' + last_episode_golive_at }) list_item.setArt({ 'thumb': thumbnail_url, 'icon': thumbnail_url, 'fanart': os.path.join(RESOURCES_PATH, 'fanart-blur.jpg') }) list_item.setProperty('IsPlayable', 'false') # let's remove any non-ascii characters from the title, to prevent errors with urllib.parse.parse_qs # of the parameters title = title.encode('ascii', 'ignore') parameters = { "action": "list-serie-seasons", "url": url, "title": title, "thumbnail_url": thumbnail_url, "next_page_possible": "False" } plugin_url_with_parms = self.plugin_url + '?' + urllib.parse.urlencode( parameters) is_folder = True # Add refresh option to context menu list_item.addContextMenuItems([('Refresh', 'Container.Refresh')]) # Add our item to the listing as a 3-element tuple. listing.append((plugin_url_with_parms, list_item, is_folder)) # Add our listing to Kodi. # Large lists and/or slower systems benefit from adding all items at once via addDirectoryItems # instead of adding one by ove via addDirectoryItem. xbmcplugin.addDirectoryItems(self.plugin_handle, listing, len(listing)) # Set initial sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_DATEADDED) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)
def getVideos(self): # # Init # # Create a list for our items. listing = [] # # Get HTML page # response = requests.get(self.url, headers=HEADERS) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source", html_source) try: json_data = json.loads(html_source) # for item in json_data['data']: # log("attribute1", item['canonical_links']['self']) # log("attribute2", item['attributes']['title']) # exit(1) except (ValueError, KeyError, TypeError): xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30109)) exit(1) for item in json_data['data']: episode_title = item['attributes']['title'] caption = item['attributes']['caption'] length = item['attributes']['length'] channel_slug = item['attributes']['channel_slug'] # the url should be something like: # https://svod-be.roosterteeth.com/api/v1/episodes/ffc530d0-464d-11e7-a302-065410f210c4/videos" # or even # https://svod-be.roosterteeth.com/api/v1/episodes/lets-play-2011-2/videos technical_episode_url_last_part = item['links']['videos'] technical_episode_url = ROOSTERTEETH_BASE_URL + technical_episode_url_last_part technical_url = technical_episode_url log("technical_url", technical_url) functional_episode_url_middle_part = item['links']['self'] functional_url = ROOSTERTEETH_BASE_URL + functional_episode_url_middle_part + '/videos' log("functional_url", functional_url) thumb = item['included']['images'][0]['attributes']['thumb'] serie_title = item['attributes']['show_title'] is_sponsor_only = item['attributes']['is_sponsors_only'] # let's put some more info in the title of the episode if self.show_serie_name == "True": title = serie_title + ' - ' + episode_title else: title = episode_title if is_sponsor_only: title = SPONSOR_ONLY_VIDEO_TITLE_PREFIX + ' ' + title title = convertToUnicodeString(title) thumbnail_url = thumb plot = caption duration_in_seconds = length studio = channel_slug studio = convertToUnicodeString(studio) studio = studio.replace("-", " ") studio = studio.capitalize() # Add to list... list_item = xbmcgui.ListItem(label=title, thumbnailImage=thumbnail_url) list_item.setInfo( "video", { "title": title, "studio": studio, "mediatype": "video", "plot": plot, "duration": duration_in_seconds }) list_item.setArt({ 'thumb': thumbnail_url, 'icon': thumbnail_url, 'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg') }) list_item.setProperty('IsPlayable', 'true') # let's remove any non-ascii characters from the title, to prevent errors with urllib.parse.parse_qs # of the parameters title = title.encode('ascii', 'ignore') parameters = { "action": "play", "functional_url": functional_url, "technical_url": technical_url, "title": title, "is_sponsor_only": is_sponsor_only, "next_page_possible": "False" } plugin_url_with_parms = self.plugin_url + '?' + urllib.parse.urlencode( parameters) is_folder = False # Add refresh option to context menu list_item.addContextMenuItems([('Refresh', 'Container.Refresh')]) # Add our item to the listing as a 3-element tuple. listing.append((plugin_url_with_parms, list_item, is_folder)) # Add our listing to Kodi. # Large lists and/or slower systems benefit from adding all items at once via addDirectoryItems # instead of adding one by ove via addDirectoryItem. xbmcplugin.addDirectoryItems(self.plugin_handle, listing, len(listing)) # Disable sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_NONE) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)
def __init__(self): # Get the command line arguments # Get the plugin url in plugin:// notation self.plugin_url = sys.argv[0] # Get the plugin handle as an integer number self.plugin_handle = int(sys.argv[1]) # # Roosterteeth Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30301), "url": ROOSTERTEETH_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30301)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Achievement Hunter Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30303), "url": ACHIEVEMENTHUNTER_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30303)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Fun Haus Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30305), "url": FUNHAUS_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30305)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Screw Attack Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30307), "url": SCREWATTACK__RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30307)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Cow Chop Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30309), "url": COWCHOP_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30309)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Sugar Pine 7 Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30311), "url": SUGARPINE7__RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30311)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Game Attack Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30313), "url": GAMEATTACK_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30313)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # The Know Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30315), "url": THEKNOW_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30315)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # JT Music Recently Added Episodes # parameters = { "action": "list-episodes", "plugin_category": LANGUAGE(30317), "url": JTMUSIC_RECENTLY_ADDED_VIDEOS_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30317)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # # Series # parameters = { "action": "list-series", "plugin_category": LANGUAGE(30302), "url": ROOSTERTEETH_SERIES_URL, "show_serie_name": "True", "next_page_possible": "False" } url = self.plugin_url + '?' + urllib.parse.urlencode(parameters) list_item = xbmcgui.ListItem(LANGUAGE(30302)) is_folder = True list_item.setArt( {'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg')}) list_item.setProperty('IsPlayable', 'false') xbmcplugin.addDirectoryItem(handle=self.plugin_handle, url=url, listitem=list_item, isFolder=is_folder) # Disable sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_NONE) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)
def playVideo(self): # # Init # # # Get current list item details... # # title = unicode(xbmc.getInfoLabel("listitem.Title"), "utf-8") thumbnail_url = xbmc.getInfoImage("list_item.Thumb") # studio = unicode(xbmc.getInfoLabel("list_item.Studio"), "utf-8") plot = unicode(xbmc.getInfoLabel("list_item.Plot"), "utf-8") genre = unicode(xbmc.getInfoLabel("list_item.Genre"), "utf-8") # # Show wait dialog while parsing data... # dialog_wait = xbmcgui.DialogProgress() dialog_wait.create(LANGUAGE(30100), self.title) # wait 1 second xbmc.sleep(1000) reply = '' session = '' try: # requests is sooooo nice, respect! session = requests.Session() # get the page that contains the video reply = session.get(self.video_page_url) # is it a sponsored video? if str(reply.text).find('sponsor-only') >= 0 or str(reply.text).find('non-sponsor') >= 0: if self.IS_SPONSOR == 'true': try: # we need a NEW (!!!) session session = requests.Session() # get the LOGIN-page if 'achievementhunter' in reply.url: reply = session.get(LOGINURL_AH) elif 'funhaus' in reply.url: reply = session.get(LOGINURL_FH) elif 'screwattack' in reply.url: reply = session.get(LOGINURL_SA) elif 'gameattack' in reply.url: reply = session.get(LOGINURL_GA) elif 'theknow' in reply.url: reply = session.get(LOGINURL_TK) elif 'cowchop' in reply.url: reply = session.get(LOGINURL_CC) else: reply = session.get(LOGINURL_RT) xbmc.log('get login page request, status_code:' + str(reply.status_code)) # This is part of the LOGIN page, it contains a token!: # # <input name="_token" type="hidden" value="Zu8TRC43VYiTxfn3JnNgiDnTpbQvPv5xWgzFpEYJ"> # <fieldset> # <h3 class="content-title">Log In</h3> # <label for="username">Username</label> # <input name="username" type="text" value="" id="username"> # <label for="password">Password</label> # <input name="password" type="password" value="" id="password"> # <input type="submit" value="Log in"> # </fieldset> # get the token soup = BeautifulSoup(reply.text) video_urls = soup.findAll('input', attrs={'name': re.compile("_token")}, limit=1) token = str(video_urls[0]['value']) # set the needed LOGIN-data payload = {'_token': token, 'username': SETTINGS.getSetting('username'), 'password': SETTINGS.getSetting('password')} # post the LOGIN-page with the LOGIN-data, to actually login this session if 'achievementhunter' in reply.url: reply = session.post(LOGINURL_AH, data=payload) elif 'funhaus' in reply.url: reply = session.post(LOGINURL_FH, data=payload) elif 'screwattack' in reply.url: reply = session.post(LOGINURL_SA, data=payload) elif 'gameattack' in reply.url: reply = session.post(LOGINURL_GA, data=payload) elif 'theknow' in reply.url: reply = session.post(LOGINURL_TK, data=payload) elif 'cowchop' in reply.url: reply = session.post(LOGINURL_CC, data=payload) else: reply = session.post(LOGINURL_RT, data=payload) xbmc.log('post login page response, status_code:' + str(reply.status_code)) # check that the login was technically ok (status_code 200). # This in itself does NOT mean that the username/password were correct. if reply.status_code == 200: pass # check that the username is in the response. If that's the case, the login was ok # and the username and password in settings are ok. if str(reply.text).find(SETTINGS.getSetting('username')) >= 0: dialog_wait.create("Login Success", "Currently looking for videos in '%s'" % self.title) xbmc.log('login was successful!') # let's try getting the page again after a login, hopefully it contains a link to # the video now reply = session.get(self.video_page_url) xbmc.log("[ADDON] %s v%s (%s) debug mode, Loaded %s" % ( ADDON, VERSION, DATE, str(self.video_page_url)), xbmc.LOGDEBUG) else: try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30101), LANGUAGE(30102), LANGUAGE(30103)) exit(1) else: try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30104) % (str(reply.status_code))) exit(1) except urllib2.HTTPError, error: xbmc.log("[ADDON] %s v%s (%s) debug mode, %s = %s" % ( ADDON, VERSION, DATE, "HTTPError", str(error)), xbmc.LOGDEBUG) try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30106) % (str(error))) exit(1) except: exception = sys.exc_info()[0] xbmc.log("[ADDON] %s v%s (%s) debug mode, %s = %s" % ( ADDON, VERSION, DATE, "Exception1:", str(exception)), xbmc.LOGDEBUG) try: dialog_wait.close() del dialog_wait except: pass exit(1)
xbmc.log("[ADDON] %s v%s (%s) debug mode, %s = %s" % ( ADDON, VERSION, DATE, "Exception1:", str(exception)), xbmc.LOGDEBUG) try: dialog_wait.close() del dialog_wait except: pass exit(1) else: try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30105)) exit(1) except urllib2.HTTPError, error: xbmc.log("[ADDON] %s v%s (%s) debug mode, %s = %s" % ( ADDON, VERSION, DATE, "HTTPError", str(error)), xbmc.LOGDEBUG) try: dialog_wait.close() del dialog_wait except: pass xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30106) % (str(error))) exit(1) except: exception = sys.exc_info()[0] xbmc.log("[ADDON] %s v%s (%s) debug mode, %s = %s" % (
def getVideos(self): # # Init # # Create a list for our items. listing = [] # # Get HTML page # response = requests.get(self.video_list_page_url, headers=HEADERS) html_source = response.text html_source = convertToUnicodeString(html_source) # log("html_source", html_source) try: json_data = json.loads(html_source) # for item in json_data['data']: # log("attribute1", item['canonical_links']['self']) # log("attribute2", item['attributes']['title']) # exit(1) except (ValueError, KeyError, TypeError): xbmcgui.Dialog().ok(LANGUAGE(30000), LANGUAGE(30109)) exit(1) for item in json_data['data']: serie_title = item['attributes']['title'] serie_url_middle_part = item['canonical_links']['self'] # the serie url should something like this: # https://svod-be.roosterteeth.com/api/v1/shows/always-open/seasons serie_url = ROOSTERTEETH_SERIES_BASE_URL + serie_url_middle_part + '/seasons' # remove '/series/' from the url serie_url = serie_url.replace('/series/', '/') thumb = item['included']['images'][0]['attributes']['thumb'] title = serie_title url = serie_url thumbnail_url = thumb # Add to list... list_item = xbmcgui.ListItem(label=title, thumbnailImage=thumbnail_url) list_item.setArt({ 'thumb': thumbnail_url, 'icon': thumbnail_url, 'fanart': os.path.join(IMAGES_PATH, 'fanart-blur.jpg') }) list_item.setProperty('IsPlayable', 'false') # let's remove any non-ascii characters from the title, to prevent errors with urllib.parse.parse_qs # of the parameters title = title.encode('ascii', 'ignore') parameters = { "action": "list-serie-seasons", "url": url, "title": title, "thumbnail_url": thumbnail_url, "next_page_possible": "False" } plugin_url_with_parms = self.plugin_url + '?' + urllib.parse.urlencode( parameters) is_folder = True # Add refresh option to context menu list_item.addContextMenuItems([('Refresh', 'Container.Refresh')]) # Add our item to the listing as a 3-element tuple. listing.append((plugin_url_with_parms, list_item, is_folder)) # Add our listing to Kodi. # Large lists and/or slower systems benefit from adding all items at once via addDirectoryItems # instead of adding one by ove via addDirectoryItem. xbmcplugin.addDirectoryItems(self.plugin_handle, listing, len(listing)) # Disable sorting xbmcplugin.addSortMethod(handle=self.plugin_handle, sortMethod=xbmcplugin.SORT_METHOD_NONE) # Finish creating a virtual folder. xbmcplugin.endOfDirectory(self.plugin_handle)