Update config.json and film.py to support different audio languages

This commit is contained in:
Fede14 2024-03-05 00:59:45 +01:00
commit a2a32a6f92
5 changed files with 161 additions and 42 deletions

View File

@ -53,7 +53,9 @@ You can change some behaviors by tweaking the configuration file.
"movies_folder_name": "Film", "movies_folder_name": "Film",
"series_folder_name": "Serie", "series_folder_name": "Serie",
"download_subtitles": true, "download_subtitles": true,
"download_default_language": false "download_default_language": true,
"selected_language": "English",
"max_worker": 20
} }
``` ```
#### Options #### Options
@ -63,7 +65,9 @@ You can change some behaviors by tweaking the configuration file.
| movies_folder_name | Film | The folder name where all the movies will be placed. Do not put trailing slash. | downloaded-movies | | movies_folder_name | Film | The folder name where all the movies will be placed. Do not put trailing slash. | downloaded-movies |
| series_folder_name | Serie | The folder name where all the TV Series will be placed. Do not put trailing slash. | mytvseries | | series_folder_name | Serie | The folder name where all the TV Series will be placed. Do not put trailing slash. | mytvseries |
| download_subtitles | true | Whether or not you want all the found subtitles to be downloaded. | false | | download_subtitles | true | Whether or not you want all the found subtitles to be downloaded. | false |
| download_default_language | false | Whether or not you want to download only the default Italian audio language. | true | | download_default_language | true | Whether or not you want to download only the default Italian audio language. | true |
| selected_language | English | If "download_default_language" is False the script will download this language | English |
| max_worker | 20 | How many workers will cooperate to download .ts file (High value may lag your pc) | 20 |
## Tutorial ## Tutorial
For a detailed walkthrough, refer to the [video tutorial](https://www.youtube.com/watch?v=Ok7hQCgxqLg&ab_channel=Nothing) For a detailed walkthrough, refer to the [video tutorial](https://www.youtube.com/watch?v=Ok7hQCgxqLg&ab_channel=Nothing)

View File

@ -81,9 +81,22 @@ def get_m3u8_audio(json_win_video, json_win_param, title_name, token_render):
if req.ok: if req.ok:
m3u8_cont = req.text.split() m3u8_cont = req.text.split()
m3u8_cont_arr = []
for row in m3u8_cont: for row in m3u8_cont:
if "audio" in str(row) and "ita" in str(row): if "audio" in str(row):
return row.split(",")[-1].split('"')[-2] lang=None
default=False
for field in row.split(","):
if "NAME" in field:
lang = field.split('"')[-2]
if "DEFAULT" in field:
default_str = field.split('=')[1]
default = default_str.strip() == "YES"
audioobj={"url": row.split(",")[-1].split('"')[-2], "lang": lang, "default": default}
if audioobj['lang'] is None:
continue
m3u8_cont_arr.append(audioobj)
return m3u8_cont_arr or None
else: else:
console.log(f"[red]Error: {req.status_code}") console.log(f"[red]Error: {req.status_code}")
sys.exit(0) sys.exit(0)

View File

@ -111,17 +111,29 @@ def get_m3u8_key_ep(json_win_video, json_win_param, tv_name, n_stagione, n_ep, e
console.log(f"[red]Error: {response.status_code}") console.log(f"[red]Error: {response.status_code}")
sys.exit(0) sys.exit(0)
def get_m3u8_playlist(json_win_video, json_win_param, tv_name, n_stagione, n_ep, ep_title, token_render): def get_m3u8_audio(json_win_video, json_win_param, tv_name, n_stagione, n_ep, ep_title, 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={ 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={tv_name}&referer=1&expires={json_win_param["expires"]}&description=S{n_stagione}%3AE{n_ep}+{ep_title}&nextEpisode=1' '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'
}) })
if req.ok: if req.ok:
m3u8_cont = req.text.split() m3u8_cont = req.text.split()
m3u8_cont_arr = []
for row in m3u8_cont: for row in m3u8_cont:
if "audio" in str(row) and "ita" in str(row): if "audio" in str(row):
return row.split(",")[-1].split('"')[-2] lang=None
default=False
for field in row.split(","):
if "NAME" in field:
lang = field.split('"')[-2]
if "DEFAULT" in field:
default_str = field.split('=')[1]
default = default_str.strip() == "YES"
audioobj={"url": row.split(",")[-1].split('"')[-2], "lang": lang, "default": default}
if audioobj['lang'] is None:
continue
m3u8_cont_arr.append(audioobj)
return m3u8_cont_arr or None
else: else:
console.log(f"[red]Error: {req.status_code}") console.log(f"[red]Error: {req.status_code}")
sys.exit(0) sys.exit(0)
@ -148,7 +160,7 @@ def dw_single_ep(tv_id, eps, index_ep_select, domain, token, tv_name, season_sel
season = mp4_name.rsplit("E", 1)[0] season = mp4_name.rsplit("E", 1)[0]
mp4_path = os.path.join(config['root_path'], config['series_folder_name'], tv_name, season, mp4_format) 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, encoded_name, token_render) m3u8_url_audio = get_m3u8_audio(json_win_video, json_win_param, tv_name, season_select, index_ep_select+1, encoded_name, token_render)
if m3u8_url_audio is not None: if m3u8_url_audio is not None:
console.print("[blue]Using m3u8 audio => [red]True") console.print("[blue]Using m3u8 audio => [red]True")

View File

@ -20,9 +20,10 @@ warnings.filterwarnings("ignore", category=TqdmExperimentalWarning)
warnings.filterwarnings("ignore", category=UserWarning, module="cryptography") warnings.filterwarnings("ignore", category=UserWarning, module="cryptography")
# Variable # Variable
MAX_WORKER = 20 MAX_WORKER = config['max_worker']
DOWNLOAD_SUB = config['download_subtitles'] DOWNLOAD_SUB = config['download_subtitles']
DOWNLOAD_DEFAULT_LANGUAGE = config['download_default_language'] DOWNLOAD_DEFAULT_LANGUAGE = config['download_default_language'] # True to select default language, False to select language
SELECTED_LANGUAGE = config['selected_language'] # Ex. "English" if DOWNLOAD_DEFAULT_LANGUAGE is False
failed_segments = [] failed_segments = []
@ -118,8 +119,10 @@ class M3U8_Parser:
if self.subtitle_playlist: if self.subtitle_playlist:
for sub_info in self.subtitle_playlist: for sub_info in self.subtitle_playlist:
name_language = sub_info.get("language") name_language = sub_info.get("language")
full_name = sub_info.get("name")
if name_language in ["auto", "ita"]:
if name_language in ["auto"]:
continue continue
os.makedirs(path, exist_ok=True) os.makedirs(path, exist_ok=True)
@ -368,6 +371,13 @@ class M3U8_Downloader:
print("\n") print("\n")
self.join_audio() self.join_audio()
os.renames(f"{self.video_path}.mp4", self.video_path)
# else:
# self.join_subtitle(self.video_path)
if os.path.exists(f"{self.video_path}.mp4"):
os.renames(f"{self.video_path}.mp4", self.video_path)
def join_audio(self): def join_audio(self):
"""Join audio with video and sync it""" """Join audio with video and sync it"""
@ -391,11 +401,76 @@ class M3U8_Downloader:
console.print("[green]Merge completed successfully.") console.print("[green]Merge completed successfully.")
# self.join_subtitle(self.video_path + ".mp4")
except ffmpeg.Error as e: except ffmpeg.Error as e:
print("ffmpeg error:", e) print("ffmpeg error:", e)
os.remove(self.video_path) os.remove(self.video_path)
os.remove(self.audio_path) os.remove(self.audio_path)
#todo: join_subtitle
# def join_subtitle(self, video_path):
# """Join subtitles with video and sync them"""
# subtitle_dir = "videos/subtitle/"
# italian_subtitle_file = "Italian.vtt"
# portuguese_subtitle_file = "Portuguese.vtt"
# italian_subtitle_path = os.path.join(subtitle_dir, italian_subtitle_file)
# portuguese_subtitle_path = os.path.join(subtitle_dir, portuguese_subtitle_file)
# if not os.path.exists(italian_subtitle_path):
# console.log(f"[red]Subtitle file '{italian_subtitle_file}' not found in '{subtitle_dir}'")
# return
# if not os.path.exists(portuguese_subtitle_path):
# console.log(f"[red]Subtitle file '{portuguese_subtitle_file}' not found in '{subtitle_dir}'")
# return
# try:
# video_stream = ffmpeg.input(video_path)
# italian_subtitle_stream = ffmpeg.input(italian_subtitle_path)
# portuguese_subtitle_stream = ffmpeg.input(portuguese_subtitle_path)
# process = (
# ffmpeg.output(
# video_stream,
# italian_subtitle_stream,
# portuguese_subtitle_stream,
# f"{os.path.splitext(video_path)[0]}_subtitled.mp4",
# vcodec="copy",
# acodec="copy",
# scodec="mov_text",
# loglevel='quiet',
# )
# .global_args(
# '-map',
# '0:v:0',
# '-map',
# '1:s:0',
# '-metadata:s:s:0',
# 'language=ita',
# '-map',
# '2:s:0',
# '-metadata:s:s:1',
# 'language=por',
# '-shortest',
# '-strict',
# 'experimental',
# )
# .run()
# )
# console.log("[green]Subtitles merged successfully.")
# except ffmpeg.Error as e:
# print("ffmpeg error:", e)
# os.remove(video_path) # Optionally remove original video if desired
# os.remove(italian_subtitle_path)
# os.remove(portuguese_subtitle_path)
# [ main function ] # [ main function ]
@ -422,41 +497,54 @@ def download_subtitle(url, name_language):
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=""): 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=""):
m3u8_audio_url=None
# Get byte of key # Get byte of key
key = bytes.fromhex(key) if key is not None else key key = bytes.fromhex(key) if key is not None else key
if m3u8_playlist is not None: # if m3u8_playlist is not None:
console.log(f"[green]Downloading m3u8 from playlist") # console.log(f"[green]Downloading m3u8 from playlist")
# Parse m3u8 playlist # # Parse m3u8 playlist
parse_class_m3u8 = M3U8_Parser() # parse_class_m3u8 = M3U8_Parser()
# Parse directly m3u8 content pass if present # # Parse directly m3u8 content pass if present
if "#EXTM3U" not in m3u8_playlist: # if "#EXTM3U" not in m3u8_playlist:
parse_class_m3u8.parse_data(df_make_req(m3u8_playlist)) # parse_class_m3u8.parse_data(df_make_req(m3u8_playlist))
else: # else:
parse_class_m3u8.parse_data(m3u8_playlist) # parse_class_m3u8.parse_data(m3u8_playlist)
# Get italian language if present as default # # Get italian language if present as default
# if DOWNLOAD_DEFAULT_LANGUAGE:
# m3u8_audio = parse_class_m3u8.get_track_audio("English")
# console.log(f"[green]Select language => [purple]{m3u8_audio}")
# # Get best quality
# if m3u8_index == None:
# m3u8_index = parse_class_m3u8.get_best_quality()
# if "https" in m3u8_index:
# if log: console.log(f"[green]Select m3u8 index => [purple]{m3u8_index}")
# else:
# console.log("[red]Cant find a valid m3u8 index")
# sys.exit(0)
# # Download subtitle if present ( normaly in m3u8 playlist )
# if DONWLOAD_SUB:
# parse_class_m3u8.download_subtitle()
if m3u8_audio is not None:
m3u8_audio_obj = None
if DOWNLOAD_DEFAULT_LANGUAGE: if DOWNLOAD_DEFAULT_LANGUAGE:
m3u8_audio = parse_class_m3u8.get_track_audio("Italian") m3u8_audio_obj = next((audioobj for audioobj in m3u8_audio if audioobj.get("default", False)), None) or m3u8_audio[0]
console.log(f"[green]Selected language => [purple]{m3u8_audio}") elif SELECTED_LANGUAGE:
m3u8_audio_obj = next((audioobj for audioobj in m3u8_audio if audioobj["lang"] == SELECTED_LANGUAGE), None)
# Get best quality if m3u8_audio_obj is None:
if m3u8_index is None: console.log("[red]Cant find a valid m3u8 audio")
m3u8_index = parse_class_m3u8.get_best_quality() sys.exit(0)
if "https" in m3u8_index: m3u8_audio_url = m3u8_audio_obj["url"]
if log: console.log(f"[green]Selected m3u8 index => [purple]{m3u8_index}") console.log(f"[green]Select language => [purple]{m3u8_audio_obj['lang']}")
else: if m3u8_subtitle != None:
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(subtitle_path=subtitle_folder, content_name=content_name)
if m3u8_subtitle is not None:
parse_class_m3u8_sub = M3U8_Parser() parse_class_m3u8_sub = M3U8_Parser()
@ -477,4 +565,4 @@ def download_m3u8(m3u8_playlist=None, m3u8_index = None, m3u8_audio=None, m3u8_s
if log: if log:
console.log(f"[green]Download m3u8 from index [white]=> [purple]{m3u8_index}") 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() M3U8_Downloader(m3u8_index, m3u8_audio_url, key=key, output_filename=output_filename).start()

View File

@ -3,5 +3,7 @@
"movies_folder_name": "Film", "movies_folder_name": "Film",
"series_folder_name": "Serie", "series_folder_name": "Serie",
"download_subtitles": true, "download_subtitles": true,
"download_default_language": false "download_default_language": true,
"selected_language": "English",
"max_worker": 20
} }