mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-07 12:05:35 +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
|
# Other
|
||||||
Video
|
Video
|
||||||
|
note.txt
|
||||||
list_proxy.txt
|
list_proxy.txt
|
||||||
note
|
config.json
|
@ -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:
|
||||||
"""
|
"""
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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"
|
||||||
|
@ -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))
|
@ -9,3 +9,4 @@ psutil
|
|||||||
unidecode
|
unidecode
|
||||||
fake-useragent
|
fake-useragent
|
||||||
qbittorrent-api
|
qbittorrent-api
|
||||||
|
python-qbittorrent
|
Loading…
x
Reference in New Issue
Block a user