From ca5120e5cb1419281ce5cf78b5ee7c163ef11987 Mon Sep 17 00:00:00 2001 From: eracknaphobia Date: Fri, 13 Oct 2023 19:23:13 -0400 Subject: [PATCH] [plugin.video.crackle] 2023.10.11+matrix.1 (#4403) --- plugin.video.crackle/README.md | 6 ++ plugin.video.crackle/addon.xml | 5 +- plugin.video.crackle/main.py | 11 ++- .../resource.language.en_gb/strings.po | 12 +++ plugin.video.crackle/resources/lib/globals.py | 83 +++++++++++++------ plugin.video.crackle/resources/settings.xml | 2 +- 6 files changed, 87 insertions(+), 32 deletions(-) create mode 100644 plugin.video.crackle/README.md diff --git a/plugin.video.crackle/README.md b/plugin.video.crackle/README.md new file mode 100644 index 0000000000..03552ea90b --- /dev/null +++ b/plugin.video.crackle/README.md @@ -0,0 +1,6 @@ +# plugin.video.crackle +[![GitHub release](https://img.shields.io/github/release/eracknaphobia/plugin.video.crackle.svg)](https://github.com/eracknaphobia/plugin.video.crackle/releases) +![License](https://img.shields.io/badge/license-GPL%20(%3E%3D%202)-orange) +[![Contributors](https://img.shields.io/github/contributors/eracknaphobia/plugin.video.crackle.svg)](https://github.com/eracknaphobia/plugin.video.crackle/graphs/contributors) + +Watch Crackle thru Kodi diff --git a/plugin.video.crackle/addon.xml b/plugin.video.crackle/addon.xml index 050bbb4ce2..4ec65c1249 100644 --- a/plugin.video.crackle/addon.xml +++ b/plugin.video.crackle/addon.xml @@ -1,5 +1,5 @@ - + @@ -14,7 +14,8 @@ Crackle delivers popular, award-winning TV, movies and originals. With no limit to how much you can watch across all your devices, you can binge all you want, wherever you want. Crackle is a video streaming distributor of original web shows, Hollywood movies, and TV shows. Founded in the early 2000s as Grouper, and rebranded in 2007, Crackle is owned by Sony Pictures Entertainment. - - Sort tv shows by episode + - Add Search Feature + - Switch Menu to localized strings en all diff --git a/plugin.video.crackle/main.py b/plugin.video.crackle/main.py index eaeb946dd3..0597fa08da 100644 --- a/plugin.video.crackle/main.py +++ b/plugin.video.crackle/main.py @@ -41,5 +41,12 @@ if stream_type == "movies": media_id = get_movie_id(media_id) get_stream(media_id) - -xbmcplugin.endOfDirectory(addon_handle) \ No newline at end of file +elif mode == 104: + dialog = xbmcgui.Dialog() + search_phrase = dialog.input('Search Text', type=xbmcgui.INPUT_ALPHANUM) + if search_phrase != "": + search(search_phrase) + xbmcplugin.endOfDirectory(addon_handle, cacheToDisc=True) + +if mode != 104: + xbmcplugin.endOfDirectory(addon_handle) \ No newline at end of file diff --git a/plugin.video.crackle/resources/language/resource.language.en_gb/strings.po b/plugin.video.crackle/resources/language/resource.language.en_gb/strings.po index f9cd354cd8..7fef6e3b8a 100644 --- a/plugin.video.crackle/resources/language/resource.language.en_gb/strings.po +++ b/plugin.video.crackle/resources/language/resource.language.en_gb/strings.po @@ -19,3 +19,15 @@ msgstr "" msgctxt "#30000" msgid "Crackle" msgstr "" + +msgctxt "#30001" +msgid "Movies" +msgstr "" + +msgctxt "#30002" +msgid "TV Shows" +msgstr "" + +msgctxt "#30003" +msgid "Search" +msgstr "" \ No newline at end of file diff --git a/plugin.video.crackle/resources/lib/globals.py b/plugin.video.crackle/resources/lib/globals.py index 90251f07dc..d56d713347 100644 --- a/plugin.video.crackle/resources/lib/globals.py +++ b/plugin.video.crackle/resources/lib/globals.py @@ -10,7 +10,6 @@ addon_url = sys.argv[0] addon_handle = int(sys.argv[1]) ADDON = xbmcaddon.Addon() -KODI_VERSION = float(re.findall(r'\d{2}\.\d{1}', xbmc.getInfoLabel("System.BuildVersion"))[0]) ROOTDIR = ADDON.getAddonInfo('path') FANART = os.path.join(ROOTDIR,"resources","media","fanart.jpg") ICON = os.path.join(ROOTDIR,"resources","media","icon.png") @@ -19,24 +18,21 @@ # Addon Settings LOCAL_STRING = ADDON.getLocalizedString UA_CRACKLE = 'Crackle/7.60 CFNetwork/808.3 Darwin/16.3.0' -UA_WEB = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0' +UA_WEB = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36' UA_ANDROID = 'Android 4.1.1; E270BSA; Crackle 4.4.5.0' PARTNER_KEY = 'Vk5aUUdYV0ZIVFBNR1ZWVg==' PARTNER_ID = '77' BASE_URL = 'https://androidtv-api-us.crackle.com/Service.svc' +WEB_KEY = '5FE67CCA-069A-42C6-A20F-4B47A8054D46' def main_menu(): - add_dir('Movies', 'movies', 99, ICON) - add_dir('TV', 'shows', 99, ICON) - + add_dir(LOCAL_STRING(30001), 'movies', 99, ICON) + add_dir(LOCAL_STRING(30002), 'shows', 99, ICON) + add_dir(LOCAL_STRING(30003), 'search', 104, ICON) def list_movies(genre_id): - url = '/browse/movies/full/%s/alpha-asc/US?format=json' % genre_id - # url = '/browse/movies/full/all/alpha-asc/US' - # url += '?pageSize=500' - # url += '&pageNumber=1' - # url += '&format=json' + url = f"/browse/movies/full/{genre_id}/alpha-asc/US?format=json" json_source = json_request(url) for movie in json_source['Entries']: @@ -61,7 +57,7 @@ def list_movies(genre_id): def list_genre(id): - url = '/genres/%s/all/US?format=json' % id + url = f"/genres/{id}/all/US?format=json" json_source = json_request(url) for genre in json_source['Items']: title = genre['Name'] @@ -74,10 +70,7 @@ def list_genre(id): def list_shows(genre_id): - url = '/browse/shows/full/%s/alpha-asc/US/1000/1?format=json' % genre_id - # url += '?pageSize=500' - # url += '&pageNumber=1' - # url += '&format=json' + url = f"/browse/shows/full/{genre_id}/alpha-asc/US/1000/1?format=json" json_source = json_request(url) for show in json_source['Entries']: @@ -104,7 +97,7 @@ def list_shows(genre_id): def get_episodes(channel): - url = '/channel/'+channel+'/playlists/all/US?format=json' + url = f"/channel/{channel}/playlists/all/US?format=json" json_source = json_request(url) for episode in json_source['Playlists'][0]['Items']: @@ -132,14 +125,14 @@ def get_episodes(channel): def get_movie_id(channel): - url = '/channel/'+str(channel)+'/playlists/all/US?format=json' + url = f"/channel/{channel}/playlists/all/US?format=json" json_source = json_request(url) return str(json_source['Playlists'][0]['Items'][0]['MediaInfo']['Id']) def get_stream(id): - url = '/details/media/%s/US?format=json' % id + url = f"/details/media/{id}/US?format=json" json_source = json_request(url) stream_url = '' stream_480_url = '' @@ -151,19 +144,16 @@ def get_stream(id): headers = 'User-Agent='+UA_WEB listitem = xbmcgui.ListItem() - lic_url = 'https://license-wv.crackle.com/raw/license/widevine/%s/us' % id - license_key = '%s|%s&Content-Type=application/octet-stream|R{SSM}|' % (lic_url,headers) + lic_url = f"https://license-wv.crackle.com/raw/license/widevine/{id}/us" + license_key = f"{lic_url}|{headers}&Content-Type=application/octet-stream|R{{SSM}}|" if 'mpd' in stream_url: is_helper = inputstreamhelper.Helper('mpd', drm='widevine') if not is_helper.check_inputstream(): sys.exit() listitem.setPath(stream_url) - if KODI_VERSION >= 19: - listitem.setProperty('inputstream', 'inputstream.adaptive') - else: - listitem.setProperty('inputstreamaddon', 'inputstream.adaptive') + listitem.setProperty('inputstream', 'inputstream.adaptive') listitem.setProperty('inputstream.adaptive.manifest_type', 'mpd') - listitem.setProperty('inputstream.adaptive.stream_headers', 'User-Agent=%s' % UA_WEB) + listitem.setProperty('inputstream.adaptive.stream_headers', f"User-Agent={UA_WEB}") listitem.setProperty('inputstream.adaptive.license_type', 'com.widevine.alpha') listitem.setProperty('inputstream.adaptive.license_key', license_key) listitem.setMimeType('application/dash+xml') @@ -174,6 +164,45 @@ def get_stream(id): xbmcplugin.setResolvedUrl(addon_handle, True, listitem) +def search(search_phrase): + url = f"https://prod-api.crackle.com/contentdiscovery/search/{search_phrase}" \ + "?useFuzzyMatching=false" \ + "&enforcemediaRights=true" \ + "&pageNumber=1&pageSize=20" \ + "&contentType=Channels" \ + "&searchFields=Title%2CCast" + headers = { + 'User-Agent': UA_WEB, + 'X-Crackle-Platform': WEB_KEY, + } + + r = requests.get(url, headers=headers) + xbmc.log(r.text) + for item in r.json()['data']['items']: + metadata = item['metadata'][0] + title = metadata['title'] + url = str(item['externalId']) + icon = get_image(item['assets']['images'], 220, 330) + fanart = get_image(item['assets']['images'], 1920, 1080) + info = {'plot': metadata['longDescription'], + 'title':title, + 'originaltitle':title, + } + + if item['type'] == 'Movie': + add_stream(title,url,'movies',icon,fanart,info) + else: + add_dir(title, url, 102, icon, fanart, info, content_type='tvshows') + +def get_image(images, width, height): + img = ICON + for image in images: + if image['width'] == width and image['height'] == height: + img = image['url'] + break + + return img + def json_request(url): url = BASE_URL + url @@ -198,7 +227,7 @@ def calc_hmac(src): def get_auth(url): timestamp = strftime('%Y%m%d%H%M', gmtime()) # encoded_url = str(calc_hmac(url+"|"+timestamp)).upper() + "|" + timestamp + "|" + PARTNER_ID - encoded_url = '%s|%s|%s|1' % (calc_hmac(url + "|" + timestamp).upper(), timestamp, PARTNER_ID) + encoded_url = f"{calc_hmac(f'{url}|{timestamp}').upper()}|{timestamp}|{PARTNER_ID}|1" return encoded_url @@ -220,7 +249,7 @@ def add_stream(name, id, stream_type, icon, fanart, info=None): def add_dir(name, id, mode, icon, fanart=None, info=None, genre_id=None, content_type='videos'): ok = True u = addon_url+"?id="+urllib.quote_plus(id)+"&mode="+str(mode) - if genre_id is not None: u += "&genre_id=%s" % genre_id + if genre_id is not None: u += f"&genre_id={genre_id}" listitem=xbmcgui.ListItem(name) if fanart is None: fanart = FANART listitem.setArt({'icon': icon, 'thumb': icon, 'poster': icon, 'fanart': fanart}) diff --git a/plugin.video.crackle/resources/settings.xml b/plugin.video.crackle/resources/settings.xml index 0da8c36f72..6e5091fcf3 100644 --- a/plugin.video.crackle/resources/settings.xml +++ b/plugin.video.crackle/resources/settings.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file