mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-05 02:55:25 +00:00
- Fix join multiple ep animeunity
- Add _failed to file with missing ts files. - Fix requirement
This commit is contained in:
parent
2b4d355d17
commit
e34bce85ed
3
.gitignore
vendored
3
.gitignore
vendored
@ -57,5 +57,6 @@ venv.bak/
|
||||
|
||||
# Other
|
||||
Video
|
||||
note.txt
|
||||
list_proxy.txt
|
||||
note
|
||||
config.json
|
@ -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:
|
||||
"""
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
@ -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))
|
@ -8,4 +8,5 @@ m3u8
|
||||
psutil
|
||||
unidecode
|
||||
fake-useragent
|
||||
qbittorrent-api
|
||||
qbittorrent-api
|
||||
python-qbittorrent
|
Loading…
x
Reference in New Issue
Block a user