mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-06-05 02:55:25 +00:00
v2.3.0
This commit is contained in:
parent
b40d202255
commit
d03ece1cf2
16
README.md
16
README.md
@ -214,12 +214,14 @@ The configuration file is divided into several main sections:
|
||||
"movie_folder_name": "Movie",
|
||||
"serie_folder_name": "TV",
|
||||
"map_episode_name": "%(tv_name)_S%(season)E%(episode)_%(episode_name)",
|
||||
"add_siteName": false,
|
||||
"disable_searchDomain": false,
|
||||
"not_close": false
|
||||
}
|
||||
```
|
||||
|
||||
- `root_path`: Directory where all videos will be saved
|
||||
|
||||
|
||||
### Path examples:
|
||||
* Windows: `C:\\MyLibrary\\Folder` or `\\\\MyServer\\MyLibrary` (if you want to use a network folder)
|
||||
* Linux/MacOS: `Desktop/MyLibrary/Folder`
|
||||
@ -241,7 +243,10 @@ The configuration file is divided into several main sections:
|
||||
* `%(episode_name)` : Is the name of the episode
|
||||
`<br/><br/>`
|
||||
|
||||
- `not_close`: If true, continues running after downloading
|
||||
- `add_siteName`: If set to true, appends the site_name to the root path before the movie and serie folders.
|
||||
- `disable_searchDomain`: If set to true, disables the search for a new domain for all sites.
|
||||
- `not_close`: If set to true, keeps the program running after the download is complete.
|
||||
|
||||
|
||||
### qBittorrent Configuration
|
||||
|
||||
@ -258,7 +263,6 @@ The configuration file is divided into several main sections:
|
||||
|
||||
To enable qBittorrent integration, follow the setup guide [here](https://github.com/lgallard/qBittorrent-Controller/wiki/How-to-enable-the-qBittorrent-Web-UI).
|
||||
|
||||
<br>
|
||||
|
||||
## REQUESTS Settings
|
||||
|
||||
@ -272,7 +276,6 @@ The configuration file is divided into several main sections:
|
||||
- `timeout`: Maximum timeout (in seconds) for each request
|
||||
- `max_retry`: Number of retry attempts per segment during M3U8 index download
|
||||
|
||||
<br>
|
||||
|
||||
## M3U8_DOWNLOAD Settings
|
||||
|
||||
@ -293,10 +296,9 @@ The configuration file is divided into several main sections:
|
||||
- `cleanup_tmp_folder`: Remove temporary .ts files after download
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Set `tqdm_use_large_bar` to `false` when using Termux or terminals with limited width to prevent display issues
|
||||
> Set `tqdm_use_large_bar` to `false` when using Termux or terminals with limited width to prevent network monitoring issues
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
### Language Settings
|
||||
|
||||
@ -345,7 +347,6 @@ forced-ita hin - Hindi pol - Polish tur - Turkish
|
||||
- `force_resolution`: Force specific resolution (-1 for best available, or specify 1080, 720, 360)
|
||||
- `get_only_link`: Return M3U8 playlist/index URL instead of downloading
|
||||
|
||||
<br>
|
||||
|
||||
# COMMAND
|
||||
|
||||
@ -361,7 +362,6 @@ forced-ita hin - Hindi pol - Polish tur - Turkish
|
||||
- Enter a season number followed by `-*` to download from that season to the end.
|
||||
* **Example:** `3-*` will download from *Season 3* to the final season.
|
||||
|
||||
<br>
|
||||
|
||||
# Docker
|
||||
|
||||
|
@ -5,20 +5,14 @@ from typing import Dict, Any, List, Union
|
||||
|
||||
class Episode:
|
||||
def __init__(self, data: Dict[str, Any]):
|
||||
self.images = None
|
||||
self.data = data
|
||||
|
||||
self.id: int = data.get('id')
|
||||
self.scws_id: int = data.get('scws_id')
|
||||
self.number: int = data.get('number')
|
||||
self.name: str = data.get('name')
|
||||
self.plot: str = data.get('plot')
|
||||
self.duration: int = data.get('duration')
|
||||
|
||||
def collect_image(self, SITE_NAME, domain):
|
||||
self.image = None
|
||||
if len(self.data.get('images')) > 0:
|
||||
self.image = f"https://cdn.{SITE_NAME}.{domain}/images/{self.data.get('images')[0]['filename']}"
|
||||
self.id: int = data.get('id', 0)
|
||||
self.scws_id: int = data.get('scws_id', 0)
|
||||
self.number: int = data.get('number', 1)
|
||||
self.name: str = data.get('name', '')
|
||||
self.plot: str = data.get('plot', '')
|
||||
self.duration: int = data.get('duration', 0)
|
||||
|
||||
def __str__(self):
|
||||
return f"Episode(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', duration={self.duration} sec)"
|
||||
@ -73,24 +67,19 @@ class EpisodeManager:
|
||||
|
||||
class Season:
|
||||
def __init__(self, season_data: Dict[str, Union[int, str, None]]):
|
||||
self.images = {}
|
||||
self.season_data = season_data
|
||||
|
||||
self.id: int = season_data.get('id')
|
||||
self.scws_id: int = season_data.get('scws_id')
|
||||
self.imdb_id: int = season_data.get('imdb_id')
|
||||
self.number: int = season_data.get('number')
|
||||
self.name: str = season_data.get('name')
|
||||
self.slug: str = season_data.get('slug')
|
||||
self.plot: str = season_data.get('plot')
|
||||
self.type: str = season_data.get('type')
|
||||
self.seasons_count: int = season_data.get('seasons_count')
|
||||
self.id: int = season_data.get('id', 0)
|
||||
self.scws_id: int = season_data.get('scws_id', 0)
|
||||
self.imdb_id: int = season_data.get('imdb_id', 0)
|
||||
self.number: int = season_data.get('number', 0)
|
||||
self.name: str = season_data.get('name', '')
|
||||
self.slug: str = season_data.get('slug', '')
|
||||
self.plot: str = season_data.get('plot', '')
|
||||
self.type: str = season_data.get('type', '')
|
||||
self.seasons_count: int = season_data.get('seasons_count', 0)
|
||||
self.episodes: EpisodeManager = EpisodeManager()
|
||||
|
||||
def collect_images(self, SITE_NAME, domain):
|
||||
for dict_image in self.season_data.get('images'):
|
||||
self.images[dict_image.get('type')] = f"https://cdn.{SITE_NAME}.{domain}/images/{dict_image.get('filename')}"
|
||||
|
||||
|
||||
class Stream:
|
||||
def __init__(self, name: str, url: str, active: bool):
|
||||
|
@ -19,9 +19,11 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def title_search(word_to_search: str) -> int:
|
||||
@ -38,8 +40,10 @@ def title_search(word_to_search: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Find new domain if prev dont work
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
# Construct the full site URL and load the search page
|
||||
try:
|
||||
|
@ -21,7 +21,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||
|
||||
|
||||
# Config
|
||||
from .costant import ROOT_PATH, DOMAIN_NOW, SITE_NAME, MOVIE_FOLDER
|
||||
from .costant import DOMAIN_NOW, SITE_NAME, MOVIE_FOLDER
|
||||
|
||||
|
||||
def download_title(select_title: MediaItem):
|
||||
@ -39,7 +39,7 @@ def download_title(select_title: MediaItem):
|
||||
# Define output path
|
||||
title_name = os_manager.get_sanitize_file(select_title.name)
|
||||
mp4_path = os_manager.get_sanitize_path(
|
||||
os.path.join(ROOT_PATH, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
os.path.join(MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
)
|
||||
|
||||
# Create output folder
|
||||
|
@ -11,5 +11,9 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
@ -22,7 +22,7 @@ from StreamingCommunity.Api.Player.supervideo import VideoSource
|
||||
|
||||
|
||||
# Config
|
||||
from .costant import ROOT_PATH, MOVIE_FOLDER
|
||||
from .costant import MOVIE_FOLDER
|
||||
|
||||
|
||||
def download_film(select_title: MediaItem) -> str:
|
||||
@ -47,7 +47,7 @@ def download_film(select_title: MediaItem) -> str:
|
||||
# Define output path
|
||||
title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
|
||||
mp4_path = os_manager.get_sanitize_path(
|
||||
os.path.join(ROOT_PATH, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
os.path.join(MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
)
|
||||
|
||||
# Get m3u8 master playlist
|
||||
|
@ -19,9 +19,11 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def title_search(title_search: str) -> int:
|
||||
@ -38,9 +40,11 @@ def title_search(title_search: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Find new domain if prev dont work
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
# Send request to search for title
|
||||
client = httpx.Client()
|
||||
|
||||
|
@ -11,5 +11,9 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
@ -23,7 +23,7 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSourceAnime
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER, MOVIE_FOLDER
|
||||
from .costant import SITE_NAME, SERIES_FOLDER, MOVIE_FOLDER
|
||||
|
||||
|
||||
|
||||
@ -54,11 +54,11 @@ def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_so
|
||||
|
||||
if scrape_serie.is_series:
|
||||
mp4_path = os_manager.get_sanitize_path(
|
||||
os.path.join(ROOT_PATH, SERIES_FOLDER, scrape_serie.series_name)
|
||||
os.path.join(SERIES_FOLDER, scrape_serie.series_name)
|
||||
)
|
||||
else:
|
||||
mp4_path = os_manager.get_sanitize_path(
|
||||
os.path.join(ROOT_PATH, MOVIE_FOLDER, scrape_serie.series_name)
|
||||
os.path.join(MOVIE_FOLDER, scrape_serie.series_name)
|
||||
)
|
||||
|
||||
# Create output folder
|
||||
|
@ -21,10 +21,11 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def get_token(site_name: str, domain: str) -> dict:
|
||||
@ -40,7 +41,10 @@ def get_token(site_name: str, domain: str) -> dict:
|
||||
"""
|
||||
|
||||
# Send a GET request to the specified URL composed of the site name and domain
|
||||
response = httpx.get(f"https://www.{site_name}.{domain}")
|
||||
response = httpx.get(
|
||||
url=f"https://www.{site_name}.{domain}",
|
||||
timeout=max_timeout
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
# Initialize variables to store CSRF token
|
||||
@ -103,8 +107,10 @@ def title_search(title: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Get token and session value from configuration
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://www.{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://www.{SITE_NAME}")
|
||||
|
||||
data = get_token(SITE_NAME, domain_to_use)
|
||||
|
||||
|
@ -11,5 +11,9 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
@ -21,7 +21,7 @@ from StreamingCommunity.Api.Player.maxstream import VideoSource
|
||||
|
||||
|
||||
# Config
|
||||
from .costant import ROOT_PATH, MOVIE_FOLDER
|
||||
from .costant import MOVIE_FOLDER
|
||||
|
||||
|
||||
def download_film(select_title: MediaItem) -> str:
|
||||
@ -46,7 +46,7 @@ def download_film(select_title: MediaItem) -> str:
|
||||
# Define output path
|
||||
title_name = os_manager.get_sanitize_file(select_title.name) +".mp4"
|
||||
mp4_path = os_manager.get_sanitize_path(
|
||||
os.path.join(ROOT_PATH, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
os.path.join(MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
)
|
||||
|
||||
# Get m3u8 master playlist
|
||||
|
@ -18,9 +18,11 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def title_search(word_to_search: str) -> int:
|
||||
@ -37,8 +39,10 @@ def title_search(word_to_search: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Find new domain if prev dont work
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
response = httpx.get(
|
||||
url=f"https://{SITE_NAME}.{domain_to_use}/?s={word_to_search}",
|
||||
|
@ -12,5 +12,9 @@ ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
COOKIE = config_manager.get_dict('SITE', SITE_NAME)['extra']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
@ -24,7 +24,7 @@ from StreamingCommunity.Api.Player.ddl import VideoSource
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import ROOT_PATH, SERIES_FOLDER
|
||||
from .costant import SERIES_FOLDER
|
||||
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo,
|
||||
title_name = os_manager.get_sanitize_file(
|
||||
f"{map_episode_title(scape_info_serie.tv_name, None, index_episode_selected, obj_episode.get('name'))}.mp4"
|
||||
)
|
||||
mp4_path = os.path.join(ROOT_PATH, SERIES_FOLDER, scape_info_serie.tv_name)
|
||||
mp4_path = os.path.join(SERIES_FOLDER, scape_info_serie.tv_name)
|
||||
|
||||
# Create output folder
|
||||
os_manager.create_path(mp4_path)
|
||||
|
@ -22,9 +22,11 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def title_search(word_to_search: str) -> int:
|
||||
@ -41,8 +43,10 @@ def title_search(word_to_search: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Find new domain if prev dont work
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
# Send request to search for titles
|
||||
try:
|
||||
|
@ -11,5 +11,9 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
# Internal utilities
|
||||
@ -24,7 +23,7 @@ from StreamingCommunity.Api.Player.supervideo import VideoSource
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import ROOT_PATH, SERIES_FOLDER
|
||||
from .costant import SERIES_FOLDER
|
||||
|
||||
|
||||
|
||||
@ -50,7 +49,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scap
|
||||
|
||||
# Define filename and path for the downloaded video
|
||||
mp4_name = f"{map_episode_title(scape_info_serie.tv_name, index_season_selected, index_episode_selected, obj_episode.get('name'))}.mp4"
|
||||
mp4_path = os.path.join(ROOT_PATH, SERIES_FOLDER, scape_info_serie.tv_name, f"S{index_season_selected}")
|
||||
mp4_path = os.path.join(SERIES_FOLDER, scape_info_serie.tv_name, f"S{index_season_selected}")
|
||||
|
||||
# Setup video source
|
||||
video_source = VideoSource(obj_episode.get('url'))
|
||||
|
@ -19,9 +19,11 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def title_search(word_to_search: str) -> int:
|
||||
@ -38,8 +40,10 @@ def title_search(word_to_search: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Find new domain if prev dont work
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
# Send request to search for titles
|
||||
try:
|
||||
|
@ -11,5 +11,9 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
@ -2,6 +2,7 @@
|
||||
|
||||
|
||||
# Internal utilities
|
||||
from StreamingCommunity.Util._jsonConfig import config_manager
|
||||
from StreamingCommunity.Util.table import TVShowManager
|
||||
|
||||
|
||||
@ -13,9 +14,11 @@ from .util.ilCorsarScraper import IlCorsaroNeroScraper
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
async def title_search(word_to_search: str) -> int:
|
||||
@ -32,7 +35,10 @@ async def title_search(word_to_search: str) -> int:
|
||||
table_show_manager.clear()
|
||||
|
||||
# Find new domain if prev dont work
|
||||
domain_to_use, _ = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
# Create scraper and collect result
|
||||
print("\n")
|
||||
|
@ -15,7 +15,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
||||
|
||||
|
||||
# Config
|
||||
from .costant import ROOT_PATH, MOVIE_FOLDER
|
||||
from .costant import MOVIE_FOLDER
|
||||
|
||||
|
||||
def download_title(select_title: MediaItem):
|
||||
@ -27,13 +27,13 @@ def download_title(select_title: MediaItem):
|
||||
"""
|
||||
|
||||
start_message()
|
||||
console.print(f"[yellow]Download: [red]{select_title.name} \n")
|
||||
console.print(f"[yellow]Download: [red]{select_title.name} \n")
|
||||
print()
|
||||
|
||||
# Define output path
|
||||
title_name = os_manager.get_sanitize_file(select_title.name)
|
||||
mp4_path = os_manager.get_sanitize_path(
|
||||
os.path.join(ROOT_PATH, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
os.path.join(MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
)
|
||||
|
||||
# Create output folder
|
||||
|
@ -11,5 +11,9 @@ SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
@ -33,7 +33,7 @@ from StreamingCommunity.Lib.TMBD import Json_film
|
||||
|
||||
|
||||
# Config
|
||||
from .costant import ROOT_PATH, SITE_NAME, DOMAIN_NOW, MOVIE_FOLDER
|
||||
from .costant import SITE_NAME, DOMAIN_NOW, MOVIE_FOLDER
|
||||
|
||||
|
||||
def download_film(movie_details: Json_film) -> str:
|
||||
@ -75,7 +75,7 @@ def download_film(movie_details: Json_film) -> str:
|
||||
|
||||
# Define output path
|
||||
title_name = os_manager.get_sanitize_file(movie_details.title) + ".mp4"
|
||||
mp4_path = os.path.join(ROOT_PATH, MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
mp4_path = os.path.join(MOVIE_FOLDER, title_name.replace(".mp4", ""))
|
||||
|
||||
# Get m3u8 master playlist
|
||||
master_playlist = video_source.get_playlist()
|
||||
|
@ -9,7 +9,11 @@ from StreamingCommunity.Util._jsonConfig import config_manager
|
||||
|
||||
SITE_NAME = os.path.basename(os.path.dirname(os.path.abspath(__file__)))
|
||||
ROOT_PATH = config_manager.get('DEFAULT', 'root_path')
|
||||
DOMAIN_NOW = config_manager.get('SITE', SITE_NAME)
|
||||
DOMAIN_NOW = config_manager.get_dict('SITE', SITE_NAME)['domain']
|
||||
|
||||
SERIES_FOLDER = config_manager.get('DEFAULT', 'serie_folder_name')
|
||||
MOVIE_FOLDER = config_manager.get('DEFAULT', 'movie_folder_name')
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, config_manager.get('DEFAULT', 'movie_folder_name'))
|
||||
|
||||
if config_manager.get_bool("DEFAULT", "add_siteName"):
|
||||
SERIES_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'serie_folder_name'))
|
||||
MOVIE_FOLDER = os.path.join(ROOT_PATH, SITE_NAME, config_manager.get('DEFAULT', 'movie_folder_name'))
|
@ -22,7 +22,7 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import ROOT_PATH, SITE_NAME, MOVIE_FOLDER
|
||||
from .costant import SITE_NAME, MOVIE_FOLDER
|
||||
|
||||
|
||||
def download_film(select_title: MediaItem) -> str:
|
||||
@ -51,8 +51,8 @@ def download_film(select_title: MediaItem) -> str:
|
||||
master_playlist = video_source.get_playlist()
|
||||
|
||||
# Define the filename and path for the downloaded film
|
||||
title_name = os_manager.get_sanitize_file(select_title.slug) + ".mp4"
|
||||
mp4_path = os.path.join(ROOT_PATH, MOVIE_FOLDER, select_title.slug)
|
||||
title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
|
||||
mp4_path = os.path.join(MOVIE_FOLDER, select_title.name)
|
||||
|
||||
# Download the film using the m3u8 playlist, and output filename
|
||||
r_proc = HLS_Downloader(
|
||||
|
@ -24,7 +24,7 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
||||
|
||||
|
||||
# Variable
|
||||
from .costant import ROOT_PATH, SITE_NAME, SERIES_FOLDER
|
||||
from .costant import SITE_NAME, SERIES_FOLDER
|
||||
|
||||
|
||||
|
||||
@ -48,7 +48,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
|
||||
|
||||
# Define filename and path for the downloaded video
|
||||
mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
|
||||
mp4_path = os.path.join(ROOT_PATH, SERIES_FOLDER, scrape_serie.series_name, f"S{index_season_selected}")
|
||||
mp4_path = os.path.join(SERIES_FOLDER, scrape_serie.series_name, f"S{index_season_selected}")
|
||||
|
||||
# Retrieve scws and if available master playlist
|
||||
video_source.get_iframe(obj_episode.id)
|
||||
|
@ -26,30 +26,36 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
||||
|
||||
|
||||
# Config
|
||||
from .costant import SITE_NAME
|
||||
from .costant import SITE_NAME, DOMAIN_NOW
|
||||
|
||||
|
||||
# Variable
|
||||
media_search_manager = MediaManager()
|
||||
table_show_manager = TVShowManager()
|
||||
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
||||
disable_searchDomain = config_manager.get_bool("DEFAULT", "disable_searchDomain")
|
||||
|
||||
|
||||
def get_version(text: str):
|
||||
def get_version(domain: str):
|
||||
"""
|
||||
Extracts the version from the HTML text of a webpage.
|
||||
|
||||
Parameters:
|
||||
- text (str): The HTML text of the webpage.
|
||||
- domain (str): The domain of the site.
|
||||
|
||||
Returns:
|
||||
str: The version extracted from the webpage.
|
||||
list: Top 10 titles headlines for today.
|
||||
"""
|
||||
try:
|
||||
response = httpx.get(
|
||||
url=f"https://{SITE_NAME}.{domain}/",
|
||||
headers={'User-Agent': get_headers()},
|
||||
timeout=max_timeout
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
# Parse request to site
|
||||
soup = BeautifulSoup(text, "html.parser")
|
||||
soup = BeautifulSoup(response.text, "html.parser")
|
||||
|
||||
# Extract version
|
||||
version = json.loads(soup.find("div", {"id": "app"}).get("data-page"))['version']
|
||||
@ -72,22 +78,13 @@ def get_version_and_domain():
|
||||
"""
|
||||
|
||||
# Find new domain if prev dont work
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
domain_to_use = DOMAIN_NOW
|
||||
|
||||
# Extract version from the response
|
||||
try:
|
||||
version = get_version(
|
||||
httpx.get(
|
||||
url=base_url,
|
||||
headers={'User-Agent': get_headers()},
|
||||
timeout=max_timeout
|
||||
).text
|
||||
)
|
||||
if not disable_searchDomain:
|
||||
domain_to_use, base_url = search_domain(SITE_NAME, f"https://{SITE_NAME}")
|
||||
|
||||
version = get_version(domain_to_use)
|
||||
|
||||
except:
|
||||
console.print("[green]Auto generate version ...")
|
||||
version = secrets.token_hex(32 // 2)
|
||||
|
||||
return version, domain_to_use
|
||||
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
# 01.03.24
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
|
||||
# External libraries
|
||||
import httpx
|
||||
from bs4 import BeautifulSoup
|
||||
|
||||
|
||||
# Internal utilities
|
||||
@ -56,33 +58,33 @@ class ScrapeSerie:
|
||||
Raises:
|
||||
Exception: If there's an error fetching season information
|
||||
"""
|
||||
self.headers = {
|
||||
'user-agent': get_headers(),
|
||||
'x-inertia': 'true',
|
||||
'x-inertia-version': self.version,
|
||||
}
|
||||
|
||||
try:
|
||||
|
||||
response = httpx.get(
|
||||
url=f"https://{self.base_name}.{self.domain}/titles/{self.media_id}-{self.series_name}",
|
||||
headers=self.headers,
|
||||
url=f"https://{self.base_name}.{self.domain}/titles/{self.media_id}-{self.series_name}",
|
||||
headers=self.headers,
|
||||
timeout=max_timeout
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
# Extract seasons from JSON response
|
||||
json_response = response.json().get('props')
|
||||
soup = BeautifulSoup(response.text, "html.parser")
|
||||
json_response = json.loads(soup.find("div", {"id": "app"}).get("data-page"))
|
||||
|
||||
"""
|
||||
response = httpx.post(
|
||||
url=f'https://{self.base_name}.{self.domain}/api/titles/preview/{self.media_id}',
|
||||
headers={'User-Agent': get_headers()}
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
# Extract seasons from JSON response
|
||||
json_response = response.json()
|
||||
"""
|
||||
|
||||
# Collect info about season
|
||||
self.season_manager = Season(json_response.get('title'))
|
||||
self.season_manager.collect_images(self.base_name, self.domain)
|
||||
self.season_manager = Season(json_response.get("props").get("title"))
|
||||
|
||||
# Collect first episode info
|
||||
for i, ep in enumerate(json_response.get('loadedSeason').get('episodes')):
|
||||
self.season_manager.episodes.add(ep)
|
||||
self.season_manager.episodes.get(i).collect_image(self.base_name, self.domain)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error collecting season info: {e}")
|
||||
raise
|
||||
@ -97,16 +99,14 @@ class ScrapeSerie:
|
||||
Raises:
|
||||
Exception: If there's an error fetching episode information
|
||||
"""
|
||||
self.headers = {
|
||||
'user-agent': get_headers(),
|
||||
'x-inertia': 'true',
|
||||
'x-inertia-version': self.version,
|
||||
}
|
||||
|
||||
try:
|
||||
response = httpx.get(
|
||||
url=f'https://{self.base_name}.{self.domain}/titles/{self.media_id}-{self.series_name}/stagione-{number_season}',
|
||||
headers=self.headers,
|
||||
headers={
|
||||
'User-Agent': get_headers(),
|
||||
'x-inertia': 'true',
|
||||
'x-inertia-version': self.version,
|
||||
},
|
||||
timeout=max_timeout
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
@ -104,14 +104,15 @@ class HttpClient:
|
||||
response = httpx.get(
|
||||
url=url,
|
||||
headers=self.headers,
|
||||
timeout=max_timeout
|
||||
timeout=max_timeout,
|
||||
follow_redirects=True
|
||||
)
|
||||
|
||||
response.raise_for_status()
|
||||
return response.text
|
||||
|
||||
except Exception as e:
|
||||
logging.info(f"Request to {url} failed with error: {e}")
|
||||
console.print(f"Request to {url} failed with error: {e}")
|
||||
return 404
|
||||
|
||||
def get_content(self, url):
|
||||
|
@ -194,23 +194,28 @@ class M3U8_Segments:
|
||||
"""
|
||||
if self.is_index_url:
|
||||
|
||||
# Send a GET request to retrieve the index M3U8 file
|
||||
response = httpx.get(
|
||||
self.url,
|
||||
headers={'User-Agent': get_headers()},
|
||||
timeout=max_timeout
|
||||
)
|
||||
response.raise_for_status()
|
||||
try:
|
||||
|
||||
# Save the M3U8 file to the temporary folder
|
||||
path_m3u8_file = os.path.join(self.tmp_folder, "playlist.m3u8")
|
||||
open(path_m3u8_file, "w+").write(response.text)
|
||||
# Send a GET request to retrieve the index M3U8 file
|
||||
response = httpx.get(
|
||||
self.url,
|
||||
headers={'User-Agent': get_headers()},
|
||||
timeout=max_timeout,
|
||||
follow_redirects=True
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
# Parse the text from the M3U8 index file
|
||||
self.parse_data(response.text)
|
||||
# Save the M3U8 file to the temporary folder
|
||||
path_m3u8_file = os.path.join(self.tmp_folder, "playlist.m3u8")
|
||||
open(path_m3u8_file, "w+").write(response.text)
|
||||
|
||||
# Parse the text from the M3U8 index file
|
||||
self.parse_data(response.text)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error during M3U8 index request: {e}")
|
||||
|
||||
else:
|
||||
|
||||
# Parser data of content of index pass in input to class
|
||||
self.parse_data(self.url)
|
||||
|
||||
@ -385,7 +390,7 @@ class M3U8_Segments:
|
||||
buffer[index] = segment_content
|
||||
|
||||
except queue.Empty:
|
||||
self.current_timeout = min(self.max_timeout, self.current_timeout * 1.5)
|
||||
self.current_timeout = min(self.max_timeout, self.current_timeout * 1.25)
|
||||
|
||||
if self.stop_event.is_set():
|
||||
break
|
||||
@ -546,7 +551,7 @@ class M3U8_Segments:
|
||||
raise Exception("Output file is empty")
|
||||
|
||||
# Display additional
|
||||
if self.info_nRetry >= len(self.segments) * (1/3.33):
|
||||
if self.info_nRetry >= len(self.segments) * 0.3:
|
||||
|
||||
# Get expected time
|
||||
ex_hours, ex_minutes, ex_seconds = format_duration(self.expected_real_time_s)
|
||||
|
@ -1,5 +1,5 @@
|
||||
__title__ = 'StreamingCommunity'
|
||||
__version__ = '2.2.0'
|
||||
__version__ = '2.3.0'
|
||||
__author__ = 'Lovi-0'
|
||||
__description__ = 'A command-line program to download film'
|
||||
__copyright__ = 'Copyright 2024'
|
||||
|
@ -15,6 +15,8 @@
|
||||
"user": "admin",
|
||||
"pass": "adminadmin"
|
||||
},
|
||||
"add_siteName": true,
|
||||
"disable_searchDomain": true,
|
||||
"not_close": false
|
||||
},
|
||||
"REQUESTS": {
|
||||
@ -24,7 +26,7 @@
|
||||
"proxy_start_max": 0.5
|
||||
},
|
||||
"M3U8_DOWNLOAD": {
|
||||
"tqdm_delay": 0.01,
|
||||
"tqdm_delay": 0.12,
|
||||
"tqdm_use_large_bar": true,
|
||||
"default_video_workser": 12,
|
||||
"default_audio_workser": 12,
|
||||
|
Loading…
x
Reference in New Issue
Block a user