- Fix join multiple ep animeunity

- Add _failed to file with missing ts files.
- Fix requirement
This commit is contained in:
Lovi-0 2024-06-25 22:39:57 +02:00
parent 2b4d355d17
commit e34bce85ed
9 changed files with 75 additions and 37 deletions

3
.gitignore vendored
View File

@ -57,5 +57,6 @@ venv.bak/
# Other # Other
Video Video
note.txt
list_proxy.txt list_proxy.txt
note config.json

View File

@ -34,17 +34,22 @@ class EpisodeManager:
episode = Episode(episode_data) episode = Episode(episode_data)
self.episodes.append(episode) self.episodes.append(episode)
def get_episode_by_index(self, index: int) -> Episode: def find_episode_by_id(self, episode_id: int) -> Episode:
""" """
Get an episode by its index. Get an episode by its id.
Args: Args:
- index (int): Index of the episode to retrieve. - episode_id (int): Index of the episode to retrieve.
Returns: Returns:
Episode: The episode object. Episode: The episode object.
""" """
return self.episodes[index]
for episode in self.episodes:
if episode.id == episode_id:
return episode
return None
def get_length(self) -> int: def get_length(self) -> int:
""" """

View File

@ -62,7 +62,7 @@ class VideoSource:
""" """
try: try:
response = httpx.get(f"https://www.{self.base_name}.{self.domain}/info_api/{self.media_id}/") response = httpx.get(f"https://www.{self.base_name}.{self.domain}/info_api/{self.media_id}/", headers=self.headers)
response.raise_for_status() response.raise_for_status()
# Parse JSON response and return episode count # Parse JSON response and return episode count
@ -89,7 +89,7 @@ class VideoSource:
"end_range": index_ep + 1 "end_range": index_ep + 1
} }
response = httpx.get(f"https://www.{self.base_name}.{self.domain}/info_api/{self.media_id}/{index_ep}", params = params) response = httpx.get(f"https://www.{self.base_name}.{self.domain}/info_api/{self.media_id}/{index_ep}", headers=self.headers, params=params, timeout=5)
response.raise_for_status() response.raise_for_status()
# Return information about the episode # Return information about the episode
@ -112,7 +112,7 @@ class VideoSource:
""" """
try: try:
response = httpx.get(f"https://www.{self.base_name}.{self.domain}/embed-url/{episode_id}") response = httpx.get(f"https://www.{self.base_name}.{self.domain}/embed-url/{episode_id}", headers=self.headers)
response.raise_for_status() response.raise_for_status()
# Extract and clean embed URL # Extract and clean embed URL

View File

@ -32,6 +32,8 @@ def download_episode(index_select: int):
# Get information about the selected episode # Get information about the selected episode
obj_episode = video_source.get_info_episode(index_select) obj_episode = video_source.get_info_episode(index_select)
if obj_episode is not None:
start_message() start_message()
console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n") console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n")
@ -43,7 +45,7 @@ def download_episode(index_select: int):
# Create output path # Create output path
mp4_path = None mp4_path = None
mp4_name = f"{index_select + 1}.mp4" mp4_name = f"{obj_episode.number}.mp4"
if video_source.is_series: if video_source.is_series:
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, video_source.series_name) mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, video_source.series_name)
else: else:
@ -55,6 +57,9 @@ def download_episode(index_select: int):
output_filename = os.path.join(mp4_path, mp4_name) output_filename = os.path.join(mp4_path, mp4_name)
).start() ).start()
else:
logging.error(f"Skip index: {index_select} cant find info with api.")
def donwload_series(tv_id: int, tv_name: str): def donwload_series(tv_id: int, tv_name: str):
""" """

View File

@ -158,6 +158,7 @@ class HLS_Downloader():
# Create an instance of the M3U8_Parser class # Create an instance of the M3U8_Parser class
obj_parse = M3U8_Parser() obj_parse = M3U8_Parser()
self.main_obj_parser = obj_parse
# Extract information about the M3U8 playlist # Extract information about the M3U8 playlist
obj_parse.parse_data( obj_parse.parse_data(
@ -227,7 +228,6 @@ class HLS_Downloader():
if self.codec is not None: if self.codec is not None:
console.print(f"[cyan]Codec [white]=> ([green]'v'[white]: [yellow]{self.codec.video_codec_name}[white] ([green]b[white]: [yellow]{self.codec.video_bitrate // 1000}k[white]), [green]'a'[white]: [yellow]{self.codec.audio_codec_name}[white] ([green]b[white]: [yellow]{self.codec.audio_bitrate // 1000}k[white]))") console.print(f"[cyan]Codec [white]=> ([green]'v'[white]: [yellow]{self.codec.video_codec_name}[white] ([green]b[white]: [yellow]{self.codec.video_bitrate // 1000}k[white]), [green]'a'[white]: [yellow]{self.codec.audio_codec_name}[white] ([green]b[white]: [yellow]{self.codec.audio_bitrate // 1000}k[white]))")
def __donwload_video__(self): def __donwload_video__(self):
""" """
Downloads and manages video segments. Downloads and manages video segments.
@ -254,8 +254,11 @@ class HLS_Downloader():
video_m3u8.get_info() video_m3u8.get_info()
# Download the video segments # Download the video segments
video_m3u8.download_streams(f"{Colors.MAGENTA}video")
self.expected_real_time = video_m3u8.expected_real_time self.expected_real_time = video_m3u8.expected_real_time
list_available_resolution_size = self.main_obj_parser._video.get_list_resolution_and_size(video_m3u8.expected_real_time_s)
#console.print(f"[cyan]Estimate size [white]=> [red]{sorted(list_available_resolution_size, reverse=True)}")
video_m3u8.download_streams(f"{Colors.MAGENTA}video")
# Get time of output file # Get time of output file
print_duration_table(os.path.join(full_path_video, "0.ts")) print_duration_table(os.path.join(full_path_video, "0.ts"))
@ -496,7 +499,10 @@ class HLS_Downloader():
)) ))
# Delete all files except the output file # Delete all files except the output file
if not missing_ts:
delete_files_except_one(self.base_path, os.path.basename(self.output_filename)) delete_files_except_one(self.base_path, os.path.basename(self.output_filename))
else:
delete_files_except_one(self.base_path, os.path.basename(self.output_filename.replace(".mp4", "_failed.mp4")))
# Remove the base folder # Remove the base folder
if REMOVE_SEGMENTS_FOLDER: if REMOVE_SEGMENTS_FOLDER:

View File

@ -127,6 +127,7 @@ class M3U8_Segments:
#console.log(f"[red]Expected duration after download: {m3u8_parser.get_duration()}") #console.log(f"[red]Expected duration after download: {m3u8_parser.get_duration()}")
#console.log(f"[red]There is key: [yellow]{m3u8_parser.keys is not None}") #console.log(f"[red]There is key: [yellow]{m3u8_parser.keys is not None}")
self.expected_real_time = m3u8_parser.get_duration(return_string=False) self.expected_real_time = m3u8_parser.get_duration(return_string=False)
self.expected_real_time_s = m3u8_parser.duration
# Check if there is an encryption key in the playlis # Check if there is an encryption key in the playlis
if m3u8_parser.keys is not None: if m3u8_parser.keys is not None:

View File

@ -6,6 +6,7 @@ import logging
# Internal utilities # Internal utilities
from m3u8 import loads from m3u8 import loads
from Src.Util.os import format_file_size
# External libraries # External libraries
@ -229,6 +230,24 @@ class M3U8_Video:
""" """
return [video['resolution'] for video in self.video_playlist] return [video['resolution'] for video in self.video_playlist]
def get_list_resolution_and_size(self, duration):
"""
Retrieve a list of resolutions and size from the video playlist.
Args:
- duration (int): Total duration of the video in 's'.
Returns:
list: A list of resolutions extracted from the video playlist.
"""
result = []
for video in self.video_playlist:
video_size = format_file_size((video['bandwidth'] * duration) / 8)
result.append((video_size))
return result
class M3U8_Audio: class M3U8_Audio:
def __init__(self, audio_playlist) -> None: def __init__(self, audio_playlist) -> None:
@ -474,7 +493,8 @@ class M3U8_Parser:
self.video_playlist.append({ self.video_playlist.append({
"uri": playlist.uri, "uri": playlist.uri,
"resolution": playlist.stream_info.resolution "resolution": playlist.stream_info.resolution,
"bandwidth": playlist.stream_info.bandwidth
}) })
if there_is_codec: if there_is_codec:
@ -485,7 +505,8 @@ class M3U8_Parser:
self.video_playlist.append({ self.video_playlist.append({
"uri": playlist.uri, "uri": playlist.uri,
"resolution": M3U8_Parser.extract_resolution(playlist.uri) "resolution": M3U8_Parser.extract_resolution(playlist.uri),
"bandwidth": playlist.stream_info.bandwidth
}) })
if there_is_codec: if there_is_codec:
@ -609,7 +630,6 @@ class M3U8_Parser:
minutes, seconds = divmod(remainder, 60) minutes, seconds = divmod(remainder, 60)
# Format the duration string with colors # Format the duration string with colors
if return_string: if return_string:
return f"[yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s" return f"[yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s"

View File

@ -14,7 +14,6 @@ def read_file(file_path):
# Import # Import
from Src.Lib.M3U8.parser import M3U8
from Src.Lib.M3U8 import M3U8_Parser from Src.Lib.M3U8 import M3U8_Parser
@ -31,5 +30,5 @@ playlist = read_file(os.path.join(base_path_file, "playlist.m3u8"))
# Test class # Test class
obj_m3u8_parser.parse_data("http", index_audio) obj_m3u8_parser.parse_data("", playlist)
print(f"Duration : {obj_m3u8_parser.get_duration()}") print(obj_m3u8_parser._video.get_list_resolution_and_size(50000))

View File

@ -9,3 +9,4 @@ psutil
unidecode unidecode
fake-useragent fake-useragent
qbittorrent-api qbittorrent-api
python-qbittorrent