diff --git a/Src/Api/film.py b/Src/Api/film.py index 6de8a3b..04b54c5 100644 --- a/Src/Api/film.py +++ b/Src/Api/film.py @@ -10,6 +10,7 @@ from Src.Lib.FFmpeg.my_m3u8 import download_m3u8 import requests, os, re, json, sys, binascii from bs4 import BeautifulSoup + # [func] def get_iframe(id_title, domain): req = requests.get(url = f"https://streamingcommunity.{domain}/iframe/{id_title}", headers = { @@ -29,7 +30,8 @@ def get_iframe(id_title, domain): else: console.log(f"[red]Error: {req.status_code}") sys.exit(0) - + + def select_quality(json_win_param): if json_win_param['token1080p']: @@ -41,6 +43,7 @@ def select_quality(json_win_param): else: return "360p" + def parse_content(embed_content): # Parse parameter from req embed content @@ -53,10 +56,12 @@ def parse_content(embed_content): json_win_param = json_win_param.replace(",}", "}").replace("'", '"') return json.loads(json_win_video), json.loads(json_win_param), select_quality(json.loads(json_win_param)) + def get_m3u8_url(json_win_video, json_win_param, render_quality): token_render = f"token{render_quality}" return f"https://vixcloud.co/playlist/{json_win_video['id']}?type=video&rendition={render_quality}&token={json_win_param[token_render]}&expires={json_win_param['expires']}" + def get_m3u8_key(json_win_video, json_win_param, title_name, token_render): response = requests.get('https://vixcloud.co/storage/enc.key', headers={ 'referer': f'https://vixcloud.co/embed/{json_win_video["id"]}?token={json_win_param[token_render]}&title={title_name}&referer=1&expires={json_win_param["expires"]}', @@ -68,6 +73,7 @@ def get_m3u8_key(json_win_video, json_win_param, title_name, token_render): console.log(f"[red]Error: {response.status_code}") sys.exit(0) + def get_m3u8_audio(json_win_video, json_win_param, title_name, token_render): req = requests.get(f'https://vixcloud.co/playlist/{json_win_video["id"]}', params={'token': json_win_param['token'], 'expires': json_win_param["expires"] }, headers={ 'referer': f'https://vixcloud.co/embed/{json_win_video["id"]}?token={json_win_param[token_render]}&title={title_name}&referer=1&expires={json_win_param["expires"]}' @@ -101,7 +107,7 @@ def main_dw_film(id_film, title_name, domain): m3u8_url_audio = get_m3u8_audio(json_win_video, json_win_param, title_name, token_render) - if m3u8_url_audio != None: + if m3u8_url_audio is not None: console.print("[blue]Using m3u8 audio => [red]True") - - download_m3u8(m3u8_index=m3u8_url, m3u8_audio=m3u8_url_audio, m3u8_subtitle=m3u8_url, key=m3u8_key, output_filename=mp4_path) + subtitle_path = os.path.join(config['root_path'], config['series_folder_name'], mp4_name) + download_m3u8(m3u8_index=m3u8_url, m3u8_audio=m3u8_url_audio, m3u8_subtitle=m3u8_url, key=m3u8_key, output_filename=mp4_path, subtitle_folder=subtitle_path, content_name=mp4_name) diff --git a/Src/Api/tv.py b/Src/Api/tv.py index f115fd2..e24963e 100644 --- a/Src/Api/tv.py +++ b/Src/Api/tv.py @@ -17,6 +17,7 @@ def get_token(id_tv, domain): session.get(f"https://streamingcommunity.{domain}/watch/{id_tv}") return session.cookies['XSRF-TOKEN'] + def get_info_tv(id_film, title_name, site_version, domain): req = requests.get(f"https://streamingcommunity.{domain}/titles/{id_film}-{title_name}", headers={ @@ -31,6 +32,7 @@ def get_info_tv(id_film, title_name, site_version, domain): console.log(f"[red]Error: {req.status_code}") sys.exit(0) + def get_info_season(tv_id, tv_name, domain, version, token, n_stagione): req = requests.get(f'https://streamingcommunity.{domain}/titles/{tv_id}-{tv_name}/stagione-{n_stagione}', headers={ 'authority': f'streamingcommunity.{domain}', 'referer': f'https://streamingcommunity.broker/titles/{tv_id}-{tv_name}', @@ -43,6 +45,7 @@ def get_info_season(tv_id, tv_name, domain, version, token, n_stagione): console.log(f"[red]Error: {req.status_code}") sys.exit(0) + def get_iframe(tv_id, ep_id, domain, token): req = requests.get(f'https://streamingcommunity.{domain}/iframe/{tv_id}', params={'episode_id': ep_id, 'next_episode': '1'}, cookies={'XSRF-TOKEN': token}, headers={ 'referer': f'https://streamingcommunity.{domain}/watch/{tv_id}?e={ep_id}', @@ -86,14 +89,17 @@ def parse_content(embed_content): json_win_param = json_win_param.replace(",}", "}").replace("'", '"') return json.loads(json_win_video), json.loads(json_win_param), select_quality(json.loads(json_win_param)) + def get_playlist(json_win_video, json_win_param, render_quality): token_render = f"token{render_quality}" return f"https://vixcloud.co/playlist/{json_win_video['id']}?token={json_win_param['token']}&{token_render}={json_win_param[token_render]}&expires={json_win_param['expires']}" + def get_m3u8_url(json_win_video, json_win_param, render_quality): token_render = f"token{render_quality}" return f"https://vixcloud.co/playlist/{json_win_video['id']}?type=video&rendition={render_quality}&token={json_win_param[token_render]}&expires={json_win_param['expires']}" + def get_m3u8_key_ep(json_win_video, json_win_param, tv_name, n_stagione, n_ep, ep_title, token_render): response = requests.get('https://vixcloud.co/storage/enc.key', headers={ 'referer': f'https://vixcloud.co/embed/{json_win_video["id"]}?token={json_win_param[token_render]}&title={tv_name}&referer=1&expires={json_win_param["expires"]}&description=S{n_stagione}%3AE{n_ep}+{ep_title}&nextEpisode=1', @@ -124,7 +130,7 @@ def get_m3u8_playlist(json_win_video, json_win_param, tv_name, n_stagione, n_ep, # [func \ main] def dw_single_ep(tv_id, eps, index_ep_select, domain, token, tv_name, season_select): - enccoded_name = urllib.parse.quote(eps[index_ep_select]['name']) + encoded_name = urllib.parse.quote(eps[index_ep_select]['name']) console.print(f"[green]Downloading episode: [blue]{eps[index_ep_select]['n']} [green]=> [purple]{eps[index_ep_select]['name']}") embed_content = get_iframe(tv_id, eps[index_ep_select]['id'], domain, token) @@ -135,20 +141,23 @@ def dw_single_ep(tv_id, eps, index_ep_select, domain, token, tv_name, season_sel m3u8_playlist = get_playlist(json_win_video, json_win_param, render_quality) m3u8_url = get_m3u8_url(json_win_video, json_win_param, render_quality) - m3u8_key = get_m3u8_key_ep(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, enccoded_name, token_render) + m3u8_key = get_m3u8_key_ep(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, encoded_name, token_render) mp4_name = f"{tv_name.replace('+', '_')}_S{str(season_select).zfill(2)}E{str(index_ep_select+1).zfill(2)}" mp4_format = f"{mp4_name}.mp4" season = mp4_name.rsplit("E", 1)[0] mp4_path = os.path.join(config['root_path'], config['series_folder_name'], tv_name, season, mp4_format) - m3u8_url_audio = get_m3u8_playlist(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, enccoded_name, token_render) + m3u8_url_audio = get_m3u8_playlist(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, encoded_name, token_render) - if m3u8_url_audio != None: + if m3u8_url_audio is not None: console.print("[blue]Using m3u8 audio => [red]True") + # Movie_Name.[Language_Code].vtt + # Movie_Name.[Language_Code].forced.vtt + subtitle_path = os.path.join(config['root_path'], config['series_folder_name'], mp4_name, season) + download_m3u8(m3u8_index=m3u8_url, m3u8_audio=m3u8_url_audio, m3u8_subtitle=m3u8_playlist, key=m3u8_key, output_filename=mp4_path, subtitle_folder=subtitle_path, content_name=mp4_name) + - download_m3u8(m3u8_index=m3u8_url, m3u8_audio=m3u8_url_audio, m3u8_subtitle=m3u8_playlist, key=m3u8_key, output_filename=mp4_path) - def main_dw_tv(tv_id, tv_name, version, domain): token = get_token(tv_id, domain) diff --git a/Src/Lib/FFmpeg/my_m3u8.py b/Src/Lib/FFmpeg/my_m3u8.py index b91ee35..fb81f83 100644 --- a/Src/Lib/FFmpeg/my_m3u8.py +++ b/Src/Lib/FFmpeg/my_m3u8.py @@ -66,7 +66,7 @@ class M3U8_Parser: }) for key in m3u8_obj.keys: - if key != None: + if key is not None: self.keys = ({ "method": key.method, "uri": key.uri, @@ -91,7 +91,6 @@ class M3U8_Parser: "uri": media.uri }) - for segment in m3u8_obj.segments: if "vtt" not in segment.uri: self.segments.append(segment.uri) @@ -111,10 +110,10 @@ class M3U8_Parser: print("No video playlist found") return None - def download_subtitle(self): + def download_subtitle(self, subtitle_path, content_name): """Download all subtitle if present""" - path = os.path.join(config['root_path'], "Film o Serie", "nome film o stagione serie") + path = subtitle_path if self.subtitle_playlist: for sub_info in self.subtitle_playlist: @@ -130,9 +129,12 @@ class M3U8_Parser: sub_parse = M3U8_Parser() sub_parse.parse_data(req_sub_content.text) url_subtitle = sub_parse.subtitle[0] + + # Subtitles convention: # Movie_Name.[Language_Code].vtt - # Movie_Name.[Language_Code].forced.vtt - open(os.path.join(path, "nome film o serie" ,f".{name_language}" + "se conteneva forced: .forced" + ".vtt"), "wb").write(requests.get(url_subtitle).content) + # Movie_Name.[Language_Code].forced.vtt # If forced + # Implementare "forced" + open(os.path.join(path, content_name + f".{name_language}" + ".vtt"), "wb").write(requests.get(url_subtitle).content) else: console.log("[red]No subtitle found") @@ -143,7 +145,7 @@ class M3U8_Parser: if self.audio_ts: console.log(f"[cyan]Found {len(self.audio_ts)}, playlist with audio") - if language_name != None: + if language_name is not None: for obj_audio in self.audio_ts: if obj_audio.get("name") == language_name: return obj_audio.get("uri") @@ -152,12 +154,13 @@ class M3U8_Parser: else: console.log("[red]Couldn't find any playlist with audio") - + + class M3U8_Segments: def __init__(self, url, key=None): self.url = url self.key = key - if key != None: + if key is not None: self.decription = Decryption(key) self.temp_folder = os.path.join("tmp", "segments") @@ -173,7 +176,7 @@ class M3U8_Segments: m3u8_parser.parse_data(m3u8_content) # Add decryption iv if present - if self.key != None and m3u8_parser.keys: + if self.key is not None and m3u8_parser.keys: self.decription.parse_key(m3u8_parser.keys.get("iv")) # Add all segments @@ -186,7 +189,7 @@ class M3U8_Segments: if response.ok: self.parse_data(response.text) - #console.log(f"[red]Ts segments find [white]=> [yellow]{len(self.segments)}") + # console.log(f"[red]Ts segments find [white]=> [yellow]{len(self.segments)}") if len(self.segments) == 0: console.log("[red]Couldn't find any segments to download, retry") @@ -215,20 +218,19 @@ class M3U8_Segments: if response.status_code == 200: return response.content else: - #print(f"Failed to fetch {ts_url}: {response.status_code}") + # print(f"Failed to fetch {ts_url}: {response.status_code}") failed_segments.append(str(url_number)) return None except Exception as e: - #print(f"Failed to fetch {ts_url}: {str(e)}") + # print(f"Failed to fetch {ts_url}: {str(e)}") failed_segments.append(str(url_number)) return None else: - #print("Skip ", ts_url, " arr ", failed_segments) + # print("Skip ", ts_url, " arr ", failed_segments) return None - def save_ts(self, index, progress_counter, quit_event): """Save ts file and decrypt if there is iv present in decryption class""" @@ -249,7 +251,7 @@ class M3U8_Segments: progress_counter.update(1) def download_ts(self): - """Loop to donwload all segment of playlist m3u8 and break it if there is no progress""" + """Loop to download all segment of playlist m3u8 and break it if there is no progress""" progress_counter = tqdm(total=len(self.segments), unit="bytes", desc="[yellow]Download") @@ -313,6 +315,7 @@ class M3U8_Segments: file_list_path = os.path.join(current_dir, 'file_list.txt') ts_files = [f for f in os.listdir(self.temp_folder) if f.endswith(".ts")] + def extract_number(file_name): return int(''.join(filter(str.isdigit, file_name))) ts_files.sort(key=extract_number) @@ -321,7 +324,6 @@ class M3U8_Segments: console.log("[red]Couldn't find any segments to join, retry") sys.exit(0) - with open(file_list_path, 'w') as f: for ts_file in ts_files: relative_path = os.path.relpath(os.path.join(self.temp_folder, ts_file), current_dir) @@ -338,6 +340,7 @@ class M3U8_Segments: os.remove(file_list_path) shutil.rmtree("tmp", ignore_errors=True) + class M3U8_Downloader: def __init__(self, m3u8_url, m3u8_audio = None, key=None, output_filename="output.mp4"): self.m3u8_url = m3u8_url @@ -355,7 +358,7 @@ class M3U8_Downloader: print_duration_table(self.video_path) print("\n") - if self.m3u8_audio != None: + if self.m3u8_audio is not None: audio_m3u8 = M3U8_Segments(self.m3u8_audio, self.key) console.log("[green]Downloading audio ts") audio_m3u8.get_info() @@ -407,6 +410,7 @@ def df_make_req(url): console.log(f"[red]Wrong url, error: {response.status_code}") sys.exit(0) + def download_subtitle(url, name_language): """Make req to vtt url and save to video subtitle folder""" @@ -416,12 +420,13 @@ def download_subtitle(url, name_language): console.log(f"[green]Downloading subtitle: [red]{name_language}") open(os.path.join(path, name_language + ".vtt"), "wb").write(requests.get(url).content) -def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_subtitle=None, key=None, output_filename=os.path.join("videos", "output.mp4"), log=False): + +def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_subtitle=None, key=None, output_filename=os.path.join("videos", "output.mp4"), log=False, subtitle_folder="subtitles", content_name=""): # Get byte of key key = bytes.fromhex(key) if key is not None else key - if m3u8_playlist != None: + if m3u8_playlist is not None: console.log(f"[green]Downloading m3u8 from playlist") # Parse m3u8 playlist @@ -433,15 +438,13 @@ def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_s else: parse_class_m3u8.parse_data(m3u8_playlist) - # Get italian language if present as default if DOWNLOAD_DEFAULT_LANGUAGE: m3u8_audio = parse_class_m3u8.get_track_audio("Italian") console.log(f"[green]Selected language => [purple]{m3u8_audio}") - # Get best quality - if m3u8_index == None: + if m3u8_index is None: m3u8_index = parse_class_m3u8.get_best_quality() if "https" in m3u8_index: if log: console.log(f"[green]Selected m3u8 index => [purple]{m3u8_index}") @@ -449,12 +452,11 @@ def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_s console.log("[red]Couldn't find a valid m3u8 index") sys.exit(0) - # Download subtitle if present ( normally in m3u8 playlist ) if DOWNLOAD_SUB: - parse_class_m3u8.download_subtitle() + parse_class_m3u8.download_subtitle(subtitle_path=subtitle_folder, content_name=content_name) - if m3u8_subtitle != None: + if m3u8_subtitle is not None: parse_class_m3u8_sub = M3U8_Parser() @@ -466,8 +468,7 @@ def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_s # Download subtitle if present ( normally in m3u8 playlist ) if DOWNLOAD_SUB: - parse_class_m3u8_sub.download_subtitle() - + parse_class_m3u8_sub.download_subtitle(subtitle_path=subtitle_folder, content_name=content_name) # Download m3u8 index, with segments # os.makedirs("videos", exist_ok=True) @@ -476,4 +477,4 @@ def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_s if log: console.log(f"[green]Download m3u8 from index [white]=> [purple]{m3u8_index}") - M3U8_Downloader(m3u8_index, m3u8_audio, key=key, output_filename=output_filename).start() \ No newline at end of file + M3U8_Downloader(m3u8_index, m3u8_audio, key=key, output_filename=output_filename).start()