- 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
Video
note.txt
list_proxy.txt
note
config.json

View File

@ -34,17 +34,22 @@ class EpisodeManager:
episode = Episode(episode_data)
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:
- index (int): Index of the episode to retrieve.
- episode_id (int): Index of the episode to retrieve.
Returns:
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:
"""

View File

@ -62,7 +62,7 @@ class VideoSource:
"""
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()
# Parse JSON response and return episode count
@ -89,7 +89,7 @@ class VideoSource:
"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()
# Return information about the episode
@ -112,7 +112,7 @@ class VideoSource:
"""
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()
# Extract and clean embed URL

View File

@ -32,28 +32,33 @@ def download_episode(index_select: int):
# Get information about the selected episode
obj_episode = video_source.get_info_episode(index_select)
start_message()
console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n")
if obj_episode is not None:
# Get the embed URL for the episode
embed_url = video_source.get_embed(obj_episode.id)
start_message()
console.print(f"[yellow]Download: [red]EP_{obj_episode.number} \n")
# Parse parameter in embed text
video_source.parse_script(embed_url)
# Get the embed URL for the episode
embed_url = video_source.get_embed(obj_episode.id)
# Parse parameter in embed text
video_source.parse_script(embed_url)
# Create output path
mp4_path = None
mp4_name = f"{obj_episode.number}.mp4"
if video_source.is_series:
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, video_source.series_name)
else:
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, video_source.series_name)
# Start downloading
HLS_Downloader(
m3u8_playlist = video_source.get_playlist(),
output_filename = os.path.join(mp4_path, mp4_name)
).start()
# Create output path
mp4_path = None
mp4_name = f"{index_select + 1}.mp4"
if video_source.is_series:
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, video_source.series_name)
else:
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, MOVIE_FOLDER, video_source.series_name)
# Start downloading
HLS_Downloader(
m3u8_playlist = video_source.get_playlist(),
output_filename = os.path.join(mp4_path, mp4_name)
).start()
logging.error(f"Skip index: {index_select} cant find info with api.")
def donwload_series(tv_id: int, tv_name: str):

View File

@ -88,7 +88,7 @@ class HLS_Downloader():
# For missing output_filename
folder, base_name = os.path.split(self.output_filename) # Split file_folder output
base_name = reduce_base_name(remove_special_characters(base_name)) # Remove special char
base_name = reduce_base_name(remove_special_characters(base_name)) # Remove special char
create_folder(folder) # Create folder and check if exist
if not can_create_file(base_name): # Check if folder file name can be create
logging.error("Invalid mp4 name.")
@ -158,6 +158,7 @@ class HLS_Downloader():
# Create an instance of the M3U8_Parser class
obj_parse = M3U8_Parser()
self.main_obj_parser = obj_parse
# Extract information about the M3U8 playlist
obj_parse.parse_data(
@ -227,7 +228,6 @@ class HLS_Downloader():
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]))")
def __donwload_video__(self):
"""
Downloads and manages video segments.
@ -254,9 +254,12 @@ class HLS_Downloader():
video_m3u8.get_info()
# Download the video segments
video_m3u8.download_streams(f"{Colors.MAGENTA}video")
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
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_files_except_one(self.base_path, os.path.basename(self.output_filename))
if not missing_ts:
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
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]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_s = m3u8_parser.duration
# Check if there is an encryption key in the playlis
if m3u8_parser.keys is not None:

View File

@ -6,6 +6,7 @@ import logging
# Internal utilities
from m3u8 import loads
from Src.Util.os import format_file_size
# External libraries
@ -228,6 +229,24 @@ class M3U8_Video:
list: A list of resolutions extracted from the 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:
@ -474,7 +493,8 @@ class M3U8_Parser:
self.video_playlist.append({
"uri": playlist.uri,
"resolution": playlist.stream_info.resolution
"resolution": playlist.stream_info.resolution,
"bandwidth": playlist.stream_info.bandwidth
})
if there_is_codec:
@ -485,7 +505,8 @@ class M3U8_Parser:
self.video_playlist.append({
"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:
@ -609,7 +630,6 @@ class M3U8_Parser:
minutes, seconds = divmod(remainder, 60)
# Format the duration string with colors
if return_string:
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
from Src.Lib.M3U8.parser import M3U8
from Src.Lib.M3U8 import M3U8_Parser
@ -31,5 +30,5 @@ playlist = read_file(os.path.join(base_path_file, "playlist.m3u8"))
# Test class
obj_m3u8_parser.parse_data("http", index_audio)
print(f"Duration : {obj_m3u8_parser.get_duration()}")
obj_m3u8_parser.parse_data("", playlist)
print(obj_m3u8_parser._video.get_list_resolution_and_size(50000))

View File

@ -8,4 +8,5 @@ m3u8
psutil
unidecode
fake-useragent
qbittorrent-api
qbittorrent-api
python-qbittorrent