diff --git a/animeworld.py b/animeworld.py index be03224..657045b 100644 --- a/animeworld.py +++ b/animeworld.py @@ -5,16 +5,16 @@ import json from info import get_info_kitsu import config AW_DOMAIN = config.AW_DOMAIN -def get_mp4(anime_url,ismovie,episode): - response = requests.get(anime_url) +async def get_mp4(anime_url,ismovie,episode,client): + response = await client.get(anime_url,follow_redirects=True) soup = BeautifulSoup(response.text,'lxml') episode_page = soup.find('a', {'data-episode-num':episode }) episode_page = f'https://animeworld.{AW_DOMAIN}{episode_page["href"]}' - response = requests.get(episode_page) + response = await client.get(episode_page,follow_redirects=True) soup = BeautifulSoup(response.text,'lxml') a_tag = soup.find('a', {'id': 'alternativeDownloadLink', 'class': 'm-1 btn btn-sm btn-primary'}) url = a_tag['href'] - response = requests.head(url) + response = await client.head(url) if response.status_code == 404: url = None return url @@ -25,7 +25,7 @@ def get_mp4(anime_url,ismovie,episode): -def search(showname,date,ismovie,episode): +async def search(showname,date,ismovie,episode,client): cookies = { 'sessionId': 's%3AtGSRfYcsIoaeV0nqFJgN69Zxixb_-uJU.fcNz%2FsJBiiP8v8TwthMN9%2FmynWFciI5gezZuz8CltyQ', } @@ -53,7 +53,7 @@ def search(showname,date,ismovie,episode): 'keyword': showname, } - response = requests.post(f'https://www.animeworld.{AW_DOMAIN}/api/search/v2', params=params, cookies=cookies, headers=headers) + response = await client.post(f'https://www.animeworld.{AW_DOMAIN}/api/search/v2', params=params, cookies=cookies, headers=headers,follow_redirects=True) months = { "Gennaio": "January", "Febbraio": "February", "Marzo": "March", "Aprile": "April", "Maggio": "May", "Giugno": "June", @@ -72,14 +72,14 @@ def search(showname,date,ismovie,episode): identifier = anime["identifier"] link = anime["link"] anime_url = f'https://animeworld.{AW_DOMAIN}/play/{link}.{identifier}' - final_url = get_mp4(anime_url,ismovie,episode) + final_url = await get_mp4(anime_url,ismovie,episode,client) final_urls.append(final_url) break showname = showname + " (ITA)" params = { 'keyword': showname, } - response = requests.post(f'https://www.animeworld.{AW_DOMAIN}/api/search/v2', params=params, cookies=cookies, headers=headers) + response = await client.post(f'https://www.animeworld.{AW_DOMAIN}/api/search/v2', params=params, cookies=cookies, headers=headers, follow_redirects=True) data = json.loads(response.text) for anime in data["animes"]: release_date = anime["release"] @@ -91,17 +91,18 @@ def search(showname,date,ismovie,episode): identifier = anime["identifier"] link = anime["link"] anime_url = f'https://animeworld.{AW_DOMAIN}/play/{link}.{identifier}' - final_url = get_mp4(anime_url,ismovie,episode) + final_url = await get_mp4(anime_url,ismovie,episode,client) final_urls.append(final_url) break return final_urls -def animeworld(id): + +async def animeworld(id,client): try: kitsu_id = id.split(":")[1] episode = id.split(":")[2] ismovie = 1 if len(id.split(":")) == 2 else 0 - showname,date = get_info_kitsu(kitsu_id) - final_urls = search(showname,date,ismovie,episode) + showname,date = await get_info_kitsu(kitsu_id,client) + final_urls = await search(showname,date,ismovie,episode,client) print(final_urls) return final_urls except: diff --git a/config.json b/config.json index ebe979d..5961dd0 100644 --- a/config.json +++ b/config.json @@ -2,15 +2,15 @@ "Siti": { "StreamingCommunity": { "enabled": "1", - "domain": "photos", + "domain": "buzz", "fast_search": "0" }, "Filmpertutti": { "enabled": "0", - "domain": "makeup" + "domain": "diy" }, "Tuttifilm":{ - "enabled": "1", + "enabled": "0", "domain": "bond", "fast_search": "0" }, diff --git a/convert.py b/convert.py index cb213b9..8581a5f 100644 --- a/convert.py +++ b/convert.py @@ -5,8 +5,8 @@ import config env_vars = load_env() TMDB_KEY = env_vars.get('TMDB_KEY') -def get_TMDb_id_from_IMDb_id(imdb_id): - response = requests.get(f'https://api.themoviedb.org/3/find/{imdb_id}', +async def get_TMDb_id_from_IMDb_id(imdb_id,client): + response = await client.get(f'https://api.themoviedb.org/3/find/{imdb_id}', params={'external_source': 'imdb_id', 'api_key': f'{TMDB_KEY}'}) tmbda = response.json() if tmbda['movie_results']: diff --git a/cool.py b/cool.py index 491b60a..3e8e5de 100644 --- a/cool.py +++ b/cool.py @@ -5,12 +5,12 @@ from convert import get_TMDb_id_from_IMDb_id from loadenv import load_env env_vars = load_env() MYSTERIUS_KEY = env_vars.get('MYSTERIUS_KEY') -def get_links(slug,season,episode,ismovie): +async def get_links(slug,season,episode,ismovie,client): try: headers = { "x-api-key": MYSTERIUS_KEY } - response = requests.get("https://mammamia-urlo-ulala12431.hf.space/api/cookie", headers=headers) + response = await client.get("https://mammamia-urlo-ulala12431.hf.space/api/cookie", headers=headers) Auths = response.json() Bearer = Auths.get('cookie') ap_session = Auths.get('auth') @@ -27,16 +27,15 @@ def get_links(slug,season,episode,ismovie): } if ismovie == 1: - response = requests.get(f'https://altadefinizione-originale.com/api/post/urls/stream/{slug}',cookies=cookies,headers=headers) + response = await client.get(f'https://altadefinizione-originale.com/api/post/urls/stream/{slug}',cookies=cookies,headers=headers) elif ismovie == 0: print("HERE SEASON",season) print("HERE EPISODE",episode) request_url =f'https://altadefinizione-originale.com/api/post/urls/stream/{slug}/{season}/{episode}' print(request_url) - response = requests.get(request_url,cookies=cookies,headers=headers) + response = await client.get(request_url,cookies=cookies,headers=headers) try: video_data = response.json() # Assuming this is the JSON response containing video streams - if 'streams' not in video_data: print("Invalid JSON format: 'streams' key not found or incorrect structure") return None @@ -79,10 +78,10 @@ def get_links(slug,season,episode,ismovie): -def search_imdb(showname,tmdba): +async def search_imdb(showname,tmdba,client): tmdba = str(tmdba) query = f'https://altadefinizione-originale.com/api/search?search={showname}&page=1' - response = requests.get(query) + response = await client.get(query,follow_redirects=True) if response.status_code == 200: data = response.json() if 'data' in data: @@ -108,7 +107,7 @@ def parse_links(resolution_links): print("Failed to fetch video links") -def cool(imdb): +async def cool(imdb,client): try: type = "Cool" general = is_movie(imdb) @@ -120,19 +119,19 @@ def cool(imdb): if "tt" in imdb: #Get showname - tmdba = get_TMDb_id_from_IMDb_id(imdb_id) + tmdba = await get_TMDb_id_from_IMDb_id(imdb_id,client) else: tmdba = imdb_id.replace("tmdb:","") showname = get_info_tmdb(tmdba,ismovie,type) - slug = search_imdb(showname,tmdba) + slug = await search_imdb(showname,tmdba,client) print(ismovie) if ismovie == 1: season = None episode = None - resolution_links = get_links(slug,episode,season,ismovie) + resolution_links = await get_links(slug,episode,season,ismovie,client) results = parse_links(resolution_links) return results elif ismovie == 0: @@ -142,5 +141,5 @@ def cool(imdb): results = parse_links(resolution_links) return results except Exception as e: - print("Cool Error") + print("Cool Error",e) return None \ No newline at end of file diff --git a/filmpertutti.py b/filmpertutti.py index f952663..65e0e44 100644 --- a/filmpertutti.py +++ b/filmpertutti.py @@ -26,13 +26,13 @@ month_mapping = { 'Sep': 'Settembre', 'Oct': 'Ottobre', 'Nov': 'Novembre', 'Dec': 'Dicembre' } -def search(query,date): - response = requests.get(query).json() +async def search(query,date,client): + response = await client.get(query).json() #Get link tid of every item and then open the link to see if the date = date for json in response: link = json['link'] tid = json['id'] - series_response = requests.get(link, headers=headers) + series_response = await client.get(link, headers=headers, follow_redirects=True) series_soup = BeautifulSoup(series_response.text, 'lxml') release_span = series_soup.find('span', class_='released') if release_span: @@ -61,22 +61,22 @@ def get_film(url): tlink = url + "?show_video=true" return tlink -def get_real_link(tlink): +async def get_real_link(tlink,client): #Some basic code to get the mixdrop link - page = requests.get(tlink, headers=headers) - soup = BeautifulSoup(page.content, features="lxml",parse_only=SoupStrainer('iframe')) + page = await client.get(tlink, headers=headers, follow_redirects=True) + soup = BeautifulSoup(page.content(), features="lxml",parse_only=SoupStrainer('iframe')) iframe_src = soup.find('iframe')['src'] - iframe_page = requests.get(iframe_src, headers=headers) - iframe_soup = BeautifulSoup(iframe_page.content, features="lxml") + iframe_page = await client.get(iframe_src, headers=headers, follow_redirects=True) + iframe_soup = BeautifulSoup(iframe_page.content(), features="lxml") mega_button = iframe_soup.find('div', attrs={'class': 'megaButton', 'rel': 'nofollow'}, string='MIXDROP') if mega_button: real_link = mega_button.get('meta-link') return real_link -def get_true_link(real_link): - response = requests.get(real_link, headers=headers) +async def get_true_link(real_link,client): + response = await client.get(real_link, headers=headers, follow_redirects=True) [s1, s2] = re.search(r"\}\('(.+)',.+,'(.+)'\.split", response.text).group(1, 2) schema = s1.split(";")[2][5:-1] terms = s2.split("|") @@ -89,7 +89,7 @@ def get_true_link(real_link): s += d[c] if c in d else c return s -def filmpertutti(imdb): +async def filmpertutti(imdb,client): general = is_movie(imdb) ismovie = general[0] imdb_id = general[1] @@ -100,10 +100,10 @@ def filmpertutti(imdb): if "tt" in imdb: if ismovie == 0: #Get showname and date - showname,date = get_info_imdb(imdb_id,ismovie,type) + showname,date = await get_info_imdb(imdb_id,ismovie,type,client) else: #THIS IS needed cause the only way to get all releases dates is by giving a tmdb ID not a IMDB - tmdba = get_TMDb_id_from_IMDb_id(imdb_id) + tmdba = await get_TMDb_id_from_IMDb_id(imdb_id,client) showname,date = get_info_tmdb(tmdba,ismovie,type) elif "tmdb" in imdb: @@ -114,23 +114,23 @@ def filmpertutti(imdb): #Build the query query = f'https://filmpertutti.{FT_DOMAIN}/wp-json/wp/v2/posts?search={showname}&page=1&_fields=link,id' try: - url,tid = search(query,date) + url,tid = await search(query,date,client) except: print("No results found") return None if ismovie == 0: - episode_link = get_episode_link(season,episode,tid,url) + episode_link = get_episode_link(season,episode,tid,url) #Let's get mixdrop link - real_link = get_real_link(episode_link) + real_link = await get_real_link(episode_link,client) #let's get delivery link, streaming link - streaming_link = get_true_link(real_link) + streaming_link = await get_true_link(real_link,client) print(streaming_link) return streaming_link elif ismovie == 1: film_link = get_film(url) #Let's get mixdrop link - real_link = get_real_link(film_link) + real_link = await get_real_link(film_link,client) #let's get delivery link, streaming link - streaming_link = get_true_link(real_link) + streaming_link = await get_true_link(real_link,client) print(streaming_link) return streaming_link \ No newline at end of file diff --git a/info.py b/info.py index 61161ad..352fb89 100644 --- a/info.py +++ b/info.py @@ -85,9 +85,9 @@ def get_info_tmdb(tmbda,ismovie,type): print("Real date",date) return showname,date -def get_info_imdb(imdb_id, ismovie, type): +async def get_info_imdb(imdb_id, ismovie, type,client): - resp = requests.get(f'https://api.themoviedb.org/3/find/{imdb_id}?api_key={TMDB_KEY}&language=it&external_source=imdb_id') + resp = await client.get(f'https://api.themoviedb.org/3/find/{imdb_id}?api_key={TMDB_KEY}&language=it&external_source=imdb_id') data = resp.json() if ismovie == 0: showname = data['tv_results'][0]['name'] @@ -120,9 +120,9 @@ def get_info_imdb(imdb_id, ismovie, type): elif type == "Cool": return showname -def get_info_kitsu(kitsu_id): +async def get_info_kitsu(kitsu_id,client): api_url = f'https://kitsu.io/api/edge/anime/{kitsu_id}' - response = requests.get(api_url) + response = await client.get(api_url) data = json.loads(response.text) showname = data['data']['attributes']['canonicalTitle'] date = data['data']['attributes']['startDate'] diff --git a/lordchannel.py b/lordchannel.py index 34ee478..09eb5df 100644 --- a/lordchannel.py +++ b/lordchannel.py @@ -10,17 +10,17 @@ import config import re import json LC_DOMAIN = config.LC_DOMAIN -def search(showname,date,season,episode,ismovie): +async def search(showname,date,season,episode,ismovie,client): cookies = { 'csrftoken': '7lvc502CZe8Zbx7iSX1xkZOBA1NbDxJZ', } headers = { - 'authority': 'lordchannel.com', + 'authority': f'lordchannel.{LC_DOMAIN}', 'accept': '*/*', 'accept-language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7', # 'cookie': 'csrftoken=7lvc502CZe8Zbx7iSX1xkZOBA1NbDxJZ', - 'referer': 'https://lordchannel.com/anime/anime-ita/', + 'referer': f'https://lordchannel.{LC_DOMAIN}/anime/anime-ita/', 'sec-ch-ua': '"Not-A.Brand";v="99", "Chromium";v="124"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Android"', @@ -36,14 +36,14 @@ def search(showname,date,season,episode,ismovie): '_': '1724421723999', } - response = requests.get('https://lordchannel.com/live_search/', params=params, cookies=cookies, headers=headers) + response = await client.get(f'https://lordchannel.{LC_DOMAIN}/live_search/', params=params, cookies=cookies, headers=headers, follow_redirects=True) data = json.loads(response.text) for entry in data['data']: if entry is not None: # check if the a_tag exists href = entry['url'] quality = entry['qualit\u00e0_video'] link = f'https://lordchannel.{LC_DOMAIN}{href}' - response = requests.get(link) + response = await client.get(link, follow_redirects=True) soup2 = BeautifulSoup(response.text,'lxml') li_tag = soup2.select_one("ul.card__meta li:nth-of-type(2)") if li_tag is not None: # check if the li_tag exists @@ -63,8 +63,8 @@ def search(showname,date,season,episode,ismovie): print("Sadly date are not equals") continue -def get_m3u8(video_url): - response = requests.get(video_url) +async def get_m3u8(video_url,client): + response = await client.get(video_url, follow_redirects=True) pattern = r'const videoData = \[(.*?)\];' match = re.search(pattern, response.text) @@ -73,7 +73,7 @@ def get_m3u8(video_url): url = video_data[0] return url -def lordchannel(imdb): +async def lordchannel(imdb,client): try: general = is_movie(imdb) ismovie = general[0] @@ -83,19 +83,19 @@ def lordchannel(imdb): season = int(general[2]) episode = int(general[3]) if "tt" in imdb: - tmdba = get_TMDb_id_from_IMDb_id(imdb_id) + tmdba = await get_TMDb_id_from_IMDb_id(imdb_id,client) else: tmdba = imdb_id else: season = None episode = None if "tt" in imdb: - tmdba = get_TMDb_id_from_IMDb_id(imdb_id) + tmdba = await get_TMDb_id_from_IMDb_id(imdb_id,client) else: tmdba = imdb_id showname,date = get_info_tmdb(tmdba,ismovie,type) - video_url,quality = search(showname,date,season,episode,ismovie) - url = get_m3u8(video_url) + video_url,quality = await search(showname,date,season,episode,ismovie,client) + url = await get_m3u8(video_url,client) url = url.replace('"','') print(url) return url,quality diff --git a/okru.py b/okru.py index ae942b0..8969029 100644 --- a/okru.py +++ b/okru.py @@ -5,10 +5,10 @@ from dictionaries import okru -def okru_get_url(id): +async def okru_get_url(id,client): embed_link = okru[id] print(embed_link) - response = requests.get(embed_link) + response = await client.get(embed_link, follow_redirects=True) soup = BeautifulSoup(response.text, 'lxml') div = soup.find('div', {'data-module': 'OKVideo'}) data_options = div.get('data-options') diff --git a/run.py b/run.py index 3bacdef..e7ebd31 100644 --- a/run.py +++ b/run.py @@ -104,80 +104,81 @@ def addon_meta(type, id): } return respond_with({"meta": meta}) - abort(404) + raise HTTPException(status_code=404) @app.get('/stream/{type}/{id}.json') -def addon_stream(type, id): +async def addon_stream(type, id): if type not in MANIFEST['types']: raise HTTPException(status_code=404) streams = {'streams': []} - if type == "tv": - for channel in STREAM["channels"]: - if channel["id"] == id: - streams['streams'].append({ - 'title': channel['name'], - 'url': channel['url'] - }) - if id in okru: - channel_url = okru_get_url(id) + async with httpx.AsyncClient() as client: + if type == "tv": + for channel in STREAM["channels"]: + if channel["id"] == id: streams['streams'].append({ - 'title': channel['name'] + "OKRU", - 'url': channel_url - }) - if not streams['streams']: - raise HTTPException(status_code=404) - return respond_with(streams) - else: - logging.debug(f"Handling movie or series: {id}") - if "kitsu" in id: - if ANIMEWORLD == "1": - animeworld_urls = animeworld(id) - print(animeworld_urls) - if animeworld_urls: - i = 0 - for url in animeworld_urls: - if url: - if i == 0: - title = "Original" - elif i == 1: - title = "Italian" - streams['streams'].append({'title': f'{HF}Animeworld {title}', 'url': url}) - i+=1 + 'title': channel['name'], + 'url': channel['url'] + }) + if id in okru: + channel_url = await okru_get_url(id,client) + streams['streams'].append({ + 'title': channel['name'] + "OKRU", + 'url': channel_url + }) + if not streams['streams']: + raise HTTPException(status_code=404) + return respond_with(streams) else: - if MYSTERIUS == "1": - results = cool(id) - if results: - for resolution, link in results.items(): - streams['streams'].append({'title': f'{HF}Mysterious {resolution}', 'url': link}) - if STREAMINGCOMMUNITY == "1": - url_streaming_community,url_720_streaming_community,quality_sc = streaming_community(id) - if url_streaming_community is not None: - if quality_sc == "1080": - streams['streams'].append({'title': f'{HF}StreamingCommunity 1080p Max', 'url': url_streaming_community}) - streams['streams'].append({'title': f'{HF}StreamingCommunity 720p Max', 'url': url_720_streaming_community}) - else: - streams['streams'].append({'title': f'{HF}StreamingCommunity 720p Max', 'url': url_streaming_community}) - if LORDCHANNEL == "1": - url_lordchannel,quality_lordchannel =lordchannel(id) - if quality_lordchannel == "FULL HD" and url_lordchannel != None: - streams['streams'].append({'title': f'{HF}LordChannel 1080p', 'url': url_lordchannel}) - elif url_lordchannel != None: - streams['streams'].append({'title': f'{HF}LordChannel 720p', 'url': url_lordchannel}) - if FILMPERTUTTI == "1": - url_filmpertutti = filmpertutti(id) - if url_filmpertutti is not None: - streams['streams'].append({'title': 'Filmpertutti', 'url': url_filmpertutti}) - if TUTTIFILM == "1": - url_tuttifilm = tantifilm(id) - if url_tuttifilm: - if not isinstance(url_tuttifilm, str): - for title, url in url_tuttifilm.items(): - streams['streams'].append({'title': f'{HF}Tantifilm {title}', 'url': url, 'behaviorHints': {'proxyHeaders': {"request": {"Referer": "https://d000d.com/"}}, 'notWebReady': True}}) - if STREAMINGWATCH == "1": - url_streamingwatch = streamingwatch(id) - if url_streamingwatch: - streams['streams'].append({'title': f'{HF}StreamingWatch 720p', 'url': url_streamingwatch}) + logging.debug(f"Handling movie or series: {id}") + if "kitsu" in id: + if ANIMEWORLD == "1": + animeworld_urls = await animeworld(id,client) + print(animeworld_urls) + if animeworld_urls: + i = 0 + for url in animeworld_urls: + if url: + if i == 0: + title = "Original" + elif i == 1: + title = "Italian" + streams['streams'].append({'title': f'{HF}Animeworld {title}', 'url': url}) + i+=1 + else: + if MYSTERIUS == "1": + results = await cool(id,client) + if results: + for resolution, link in results.items(): + streams['streams'].append({'title': f'{HF}Mysterious {resolution}', 'url': link}) + if STREAMINGCOMMUNITY == "1": + url_streaming_community,url_720_streaming_community,quality_sc = await streaming_community(id,client) + if url_streaming_community is not None: + if quality_sc == "1080": + streams['streams'].append({'title': f'{HF}StreamingCommunity 1080p Max', 'url': url_streaming_community}) + streams['streams'].append({'title': f'{HF}StreamingCommunity 720p Max', 'url': url_720_streaming_community}) + else: + streams['streams'].append({'title': f'{HF}StreamingCommunity 720p Max', 'url': url_streaming_community}) + if LORDCHANNEL == "1": + url_lordchannel,quality_lordchannel = await lordchannel(id,client) + if quality_lordchannel == "FULL HD" and url_lordchannel != None: + streams['streams'].append({'title': f'{HF}LordChannel 1080p', 'url': url_lordchannel}) + elif url_lordchannel != None: + streams['streams'].append({'title': f'{HF}LordChannel 720p', 'url': url_lordchannel}) + if FILMPERTUTTI == "1": + url_filmpertutti = await filmpertutti(id,client) + if url_filmpertutti is not None: + streams['streams'].append({'title': 'Filmpertutti', 'url': url_filmpertutti}) + if TUTTIFILM == "1": + url_tuttifilm = await tantifilm(id,client) + if url_tuttifilm: + if not isinstance(url_tuttifilm, str): + for title, url in url_tuttifilm.items(): + streams['streams'].append({'title': f'{HF}Tantifilm {title}', 'url': url, 'behaviorHints': {'proxyHeaders': {"request": {"Referer": "https://d000d.com/"}}, 'notWebReady': True}}) + if STREAMINGWATCH == "1": + url_streamingwatch = await streamingwatch(id,client) + if url_streamingwatch: + streams['streams'].append({'title': f'{HF}StreamingWatch 720p', 'url': url_streamingwatch}) if not streams['streams']: raise HTTPException(status_code=404) diff --git a/streamingcommunity.py b/streamingcommunity.py index e65d6e8..dee65ae 100644 --- a/streamingcommunity.py +++ b/streamingcommunity.py @@ -1,5 +1,4 @@ from tmdbv3api import TMDb, Movie, TV -import requests import logging from bs4 import BeautifulSoup,SoupStrainer from datetime import datetime @@ -21,13 +20,13 @@ headers = { } #GET VERSION OF STREAMING COMMUNITY: -def get_version(): +async def get_version(client): #Extract the version from the main page of the site try: base_url = f'https://streamingcommunity.{SC_DOMAIN}/richiedi-un-titolo' - response = requests.get(base_url, headers=headers) + response = await client.get(base_url, headers=headers, follow_redirects=True) #Soup the response soup = BeautifulSoup(response.text, "lxml") @@ -39,9 +38,11 @@ def get_version(): version = "65e52dcf34d64173542cd2dc6b8bb75b" return version -def search(query,date,ismovie): +async def search(query,date,ismovie, client): #Do a request to get the ID of serie/move and it's slug in the URL - response = requests.get(query).json() + response = await client.get(query, follow_redirects=True) + response = response.json() + for item in response['data']: tid = item['id'] slug = item['slug'] @@ -54,8 +55,7 @@ def search(query,date,ismovie): #Added a Check to see if the result is what it is supposed to be if SC_FAST_SEARCH == "0": if ismovie == 0: - # - response = requests.get ( f'https://streamingcommunity.boston/titles/{tid}-{slug}') + response = await client.get ( f'https://streamingcommunity.{SC_DOMAIN}/titles/{tid}-{slug}', follow_redirects=True) pattern = r'