mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-06 19:45:24 +00:00
Add some hls improvement. (#254)
* Fix episode anime * Fix interrupt immediately * Add resolution best or worst
This commit is contained in:
parent
959adbab22
commit
5a36e78b45
17
README.md
17
README.md
@ -425,12 +425,25 @@ You can download VLC Media Player from the [official website](https://www.videol
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"force_resolution": -1,
|
"force_resolution": "1080p",
|
||||||
"get_only_link": false
|
"get_only_link": false
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- `force_resolution`: Force specific resolution (-1 for best available, or specify 1080, 720, 360)
|
- `force_resolution`: Choose the video resolution for downloading:
|
||||||
|
* `"Best"`: Highest available resolution
|
||||||
|
* `"Worst"`: Lowest available resolution
|
||||||
|
* `"720p"`: Force 720p resolution
|
||||||
|
* Or specify one of these resolutions:
|
||||||
|
- 1080p (1920x1080)
|
||||||
|
- 720p (1280x720)
|
||||||
|
- 480p (640x480)
|
||||||
|
- 360p (640x360)
|
||||||
|
- 320p (480x320)
|
||||||
|
- 240p (426x240)
|
||||||
|
- 240p (320x240)
|
||||||
|
- 144p (256x144)
|
||||||
|
|
||||||
- `get_only_link`: Return M3U8 playlist/index URL instead of downloading
|
- `get_only_link`: Return M3U8 playlist/index URL instead of downloading
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bo
|
|||||||
|
|
||||||
# Logic class
|
# Logic class
|
||||||
from .util.ScrapeSerie import ScrapeSerieAnime
|
from .util.ScrapeSerie import ScrapeSerieAnime
|
||||||
from StreamingCommunity.Api.Template.Util import manage_selection
|
from StreamingCommunity.Api.Template.Util import manage_selection, dynamic_format_number
|
||||||
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||||
|
|
||||||
|
|
||||||
@ -64,8 +64,7 @@ def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_so
|
|||||||
video_source.get_embed(obj_episode.id)
|
video_source.get_embed(obj_episode.id)
|
||||||
|
|
||||||
# Create output path
|
# Create output path
|
||||||
title_name = f"{obj_episode.number}.mp4"
|
title_name = f"{scrape_serie.series_name}_EP_{dynamic_format_number(int(obj_episode.number))}.mp4"
|
||||||
title_name = f"{scrape_serie.series_name}_EP_{obj_episode.number}.mp4"
|
|
||||||
|
|
||||||
if scrape_serie.is_series:
|
if scrape_serie.is_series:
|
||||||
mp4_path = os_manager.get_sanitize_path(os.path.join(ANIME_FOLDER, scrape_serie.series_name))
|
mp4_path = os_manager.get_sanitize_path(os.path.join(ANIME_FOLDER, scrape_serie.series_name))
|
||||||
|
@ -43,7 +43,7 @@ DOWNLOAD_SPECIFIC_SUBTITLE = config_manager.get_list('M3U8_DOWNLOAD', 'specific_
|
|||||||
MERGE_AUDIO = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_audio')
|
MERGE_AUDIO = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_audio')
|
||||||
MERGE_SUBTITLE = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_subs')
|
MERGE_SUBTITLE = config_manager.get_bool('M3U8_DOWNLOAD', 'merge_subs')
|
||||||
CLEANUP_TMP = config_manager.get_bool('M3U8_DOWNLOAD', 'cleanup_tmp_folder')
|
CLEANUP_TMP = config_manager.get_bool('M3U8_DOWNLOAD', 'cleanup_tmp_folder')
|
||||||
FILTER_CUSTOM_REOLUTION = config_manager.get_int('M3U8_PARSER', 'force_resolution')
|
FILTER_CUSTOM_REOLUTION = config_manager.get('M3U8_PARSER', 'force_resolution')
|
||||||
GET_ONLY_LINK = config_manager.get_bool('M3U8_PARSER', 'get_only_link')
|
GET_ONLY_LINK = config_manager.get_bool('M3U8_PARSER', 'get_only_link')
|
||||||
RETRY_LIMIT = config_manager.get_int('REQUESTS', 'max_retry')
|
RETRY_LIMIT = config_manager.get_int('REQUESTS', 'max_retry')
|
||||||
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
||||||
@ -164,10 +164,12 @@ class M3U8Manager:
|
|||||||
self.sub_streams = []
|
self.sub_streams = []
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if FILTER_CUSTOM_REOLUTION != -1:
|
if str(FILTER_CUSTOM_REOLUTION).lower().strip() == "best":
|
||||||
self.video_url, self.video_res = self.parser._video.get_custom_uri(y_resolution=FILTER_CUSTOM_REOLUTION)
|
|
||||||
else:
|
|
||||||
self.video_url, self.video_res = self.parser._video.get_best_uri()
|
self.video_url, self.video_res = self.parser._video.get_best_uri()
|
||||||
|
elif str(FILTER_CUSTOM_REOLUTION).lower().strip() == "worst":
|
||||||
|
self.video_url, self.video_res = self.parser._video.get_worst_uri()
|
||||||
|
elif "p" in str(FILTER_CUSTOM_REOLUTION).lower().strip():
|
||||||
|
self.video_url, self.video_res = self.parser._video.get_custom_uri(int(str(FILTER_CUSTOM_REOLUTION).strip().replace("p", "")))
|
||||||
|
|
||||||
self.audio_streams = []
|
self.audio_streams = []
|
||||||
if ENABLE_AUDIO:
|
if ENABLE_AUDIO:
|
||||||
@ -184,17 +186,12 @@ class M3U8Manager:
|
|||||||
]
|
]
|
||||||
|
|
||||||
def log_selection(self):
|
def log_selection(self):
|
||||||
if FILTER_CUSTOM_REOLUTION == -1:
|
|
||||||
set_resolution = "Best"
|
|
||||||
else:
|
|
||||||
set_resolution = f"{FILTER_CUSTOM_REOLUTION}p"
|
|
||||||
|
|
||||||
tuple_available_resolution = self.parser._video.get_list_resolution()
|
tuple_available_resolution = self.parser._video.get_list_resolution()
|
||||||
list_available_resolution = [f"{r[0]}x{r[1]}" for r in tuple_available_resolution]
|
list_available_resolution = [f"{r[0]}x{r[1]}" for r in tuple_available_resolution]
|
||||||
|
|
||||||
console.print(
|
console.print(
|
||||||
f"[cyan bold]Video →[/cyan bold] [green]Available:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | "
|
f"[cyan bold]Video →[/cyan bold] [green]Available:[/green] [purple]{', '.join(list_available_resolution)}[/purple] | "
|
||||||
f"[red]Set:[/red] [purple]{set_resolution}[/purple] | "
|
f"[red]Set:[/red] [purple]{FILTER_CUSTOM_REOLUTION}[/purple] | "
|
||||||
f"[yellow]Downloadable:[/yellow] [purple]{self.video_res[0]}x{self.video_res[1]}[/purple]"
|
f"[yellow]Downloadable:[/yellow] [purple]{self.video_res[0]}x{self.video_res[1]}[/purple]"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ PROXY_START_MAX = config_manager.get_float('REQUESTS', 'proxy_start_max')
|
|||||||
DEFAULT_VIDEO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_video_workser')
|
DEFAULT_VIDEO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_video_workser')
|
||||||
DEFAULT_AUDIO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_audio_workser')
|
DEFAULT_AUDIO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_audio_workser')
|
||||||
MAX_TIMEOOUT = config_manager.get_int("REQUESTS", "timeout")
|
MAX_TIMEOOUT = config_manager.get_int("REQUESTS", "timeout")
|
||||||
|
MAX_INTERRUPT_COUNT = 3
|
||||||
SEGMENT_MAX_TIMEOUT = config_manager.get_int("M3U8_DOWNLOAD", "segment_timeout")
|
SEGMENT_MAX_TIMEOUT = config_manager.get_int("M3U8_DOWNLOAD", "segment_timeout")
|
||||||
|
|
||||||
|
|
||||||
@ -83,6 +84,9 @@ class M3U8_Segments:
|
|||||||
# Stopping
|
# Stopping
|
||||||
self.interrupt_flag = threading.Event()
|
self.interrupt_flag = threading.Event()
|
||||||
self.download_interrupted = False
|
self.download_interrupted = False
|
||||||
|
self.interrupt_count = 0
|
||||||
|
self.force_stop = False
|
||||||
|
self.interrupt_lock = threading.Lock()
|
||||||
|
|
||||||
# OTHER INFO
|
# OTHER INFO
|
||||||
self.info_maxRetry = 0
|
self.info_maxRetry = 0
|
||||||
@ -157,12 +161,24 @@ class M3U8_Segments:
|
|||||||
Set up a signal handler for graceful interruption.
|
Set up a signal handler for graceful interruption.
|
||||||
"""
|
"""
|
||||||
def interrupt_handler(signum, frame):
|
def interrupt_handler(signum, frame):
|
||||||
if not self.interrupt_flag.is_set():
|
with self.interrupt_lock:
|
||||||
console.print("\n[red]- Stopping download gracefully...")
|
self.interrupt_count += 1
|
||||||
#self.interrupt_flag.set() IN MODO DA NON TERMINARE SUBITO
|
if self.interrupt_count >= MAX_INTERRUPT_COUNT:
|
||||||
self.download_interrupted = True
|
self.force_stop = True
|
||||||
#self.stop_event.set() IN MODO DA NON TERMINARE SUBITO
|
|
||||||
|
if self.force_stop:
|
||||||
|
console.print("\n[red]Force stop triggered! Exiting immediately.")
|
||||||
|
|
||||||
|
else:
|
||||||
|
if not self.interrupt_flag.is_set():
|
||||||
|
remaining = MAX_INTERRUPT_COUNT - self.interrupt_count
|
||||||
|
console.print(f"\n[red]- Stopping gracefully... (Ctrl+C {remaining}x to force)")
|
||||||
|
self.download_interrupted = True
|
||||||
|
|
||||||
|
if remaining == 1:
|
||||||
|
self.interrupt_flag.set()
|
||||||
|
|
||||||
|
|
||||||
if threading.current_thread() is threading.main_thread():
|
if threading.current_thread() is threading.main_thread():
|
||||||
signal.signal(signal.SIGINT, interrupt_handler)
|
signal.signal(signal.SIGINT, interrupt_handler)
|
||||||
else:
|
else:
|
||||||
@ -430,8 +446,8 @@ class M3U8_Segments:
|
|||||||
writer_thread.join(timeout=30)
|
writer_thread.join(timeout=30)
|
||||||
progress_bar.close()
|
progress_bar.close()
|
||||||
|
|
||||||
if self.download_interrupted:
|
#if self.download_interrupted:
|
||||||
console.print("\n[red]Download terminated by user")
|
# console.print("\n[red]Download terminated by user")
|
||||||
|
|
||||||
if self.info_nFailed > 0:
|
if self.info_nFailed > 0:
|
||||||
self._display_error_summary()
|
self._display_error_summary()
|
||||||
|
@ -119,8 +119,8 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|||||||
bar_format=f"{Colors.YELLOW}[MP4]{Colors.WHITE}: "
|
bar_format=f"{Colors.YELLOW}[MP4]{Colors.WHITE}: "
|
||||||
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
||||||
f"{Colors.YELLOW}{{n_fmt}}{Colors.WHITE} / {Colors.RED}{{total_fmt}} {Colors.WHITE}] "
|
f"{Colors.YELLOW}{{n_fmt}}{Colors.WHITE} / {Colors.RED}{{total_fmt}} {Colors.WHITE}] "
|
||||||
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}} {Colors.WHITE}| "
|
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{Colors.WHITE}, "
|
||||||
f"{Colors.YELLOW}{{rate_fmt}}{{postfix}} {Colors.WHITE}]",
|
f"{Colors.YELLOW}{{rate_fmt}}{{postfix}} ",
|
||||||
unit='iB',
|
unit='iB',
|
||||||
unit_scale=True,
|
unit_scale=True,
|
||||||
desc='Downloading',
|
desc='Downloading',
|
||||||
|
@ -39,12 +39,17 @@ CODEC_MAPPINGS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RESOLUTIONS = [
|
RESOLUTIONS = [
|
||||||
(7680, 4320),
|
(7680, 4320), # 8K
|
||||||
(3840, 2160),
|
(3840, 2160), # 4K
|
||||||
(2560, 1440),
|
(2560, 1440), # 1440p
|
||||||
(1920, 1080),
|
(1920, 1080), # 1080p
|
||||||
(1280, 720),
|
(1280, 720), # 720p
|
||||||
(640, 480)
|
(640, 480), # VGA
|
||||||
|
(640, 360), # 360p
|
||||||
|
(480, 320), # HVGA
|
||||||
|
(426, 240), # 240p
|
||||||
|
(320, 240), # QVGA
|
||||||
|
(256, 144), # 144p
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
"default_preset": "ultrafast"
|
"default_preset": "ultrafast"
|
||||||
},
|
},
|
||||||
"M3U8_PARSER": {
|
"M3U8_PARSER": {
|
||||||
"force_resolution": -1,
|
"force_resolution": "Best",
|
||||||
"get_only_link": false
|
"get_only_link": false
|
||||||
},
|
},
|
||||||
"SITE": {
|
"SITE": {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user