mirror of
https://github.com/Arrowar/StreamingCommunity.git
synced 2025-07-22 18:10:02 +00:00
Improve site SC
This commit is contained in:
parent
f5ad9b7187
commit
0bedb1bf05
26
README.md
26
README.md
@ -314,6 +314,24 @@ forced-ita hin - Hindi pol - Polish tur - Turkish
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
# COMMAND
|
||||
|
||||
|
||||
- Download a specific season by entering its number.
|
||||
* **Example:** `1` will download *Season 1* only.
|
||||
|
||||
- Use the wildcard `*` to download every available season.
|
||||
* **Example:** `*` will download all seasons in the series.
|
||||
|
||||
- Specify a range of seasons using a hyphen `-`.
|
||||
* **Example:** `1-2` will download *Seasons 1 and 2*.
|
||||
|
||||
- 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
|
||||
|
||||
You can run the script in a docker container, to build the image just run
|
||||
@ -371,7 +389,13 @@ The `run-container` command mounts also the `config.json` file, so any change to
|
||||
|
||||
# To Do
|
||||
|
||||
- Create website API
|
||||
- Create website API -> https://github.com/Lovi-0/StreamingCommunity/tree/test_gui_1
|
||||
|
||||
# SUPPORT
|
||||
|
||||
If you'd like to support this project, consider making a donation!
|
||||
|
||||
[](https://www.paypal.com/donate/?hosted_button_id=UXTWMT8P6HE2C)
|
||||
|
||||
# Contributing
|
||||
|
||||
|
@ -1,17 +1,22 @@
|
||||
# 23.11.24
|
||||
|
||||
import re
|
||||
import logging
|
||||
from typing import Dict, Any, List, Union
|
||||
|
||||
|
||||
class Episode:
|
||||
def __init__(self, data: Dict[str, Any]):
|
||||
self.id: int = data.get('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', '')
|
||||
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 = f"https://cdn.{SITE_NAME}.{domain}/images/{self.data.get('images')[0]['filename']}"
|
||||
|
||||
def __str__(self):
|
||||
return f"Episode(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', duration={self.duration} sec)"
|
||||
@ -20,7 +25,7 @@ class EpisodeManager:
|
||||
def __init__(self):
|
||||
self.episodes: List[Episode] = []
|
||||
|
||||
def add_episode(self, episode_data: Dict[str, Any]):
|
||||
def add(self, episode_data: Dict[str, Any]):
|
||||
"""
|
||||
Add a new episode to the manager.
|
||||
|
||||
@ -29,8 +34,20 @@ class EpisodeManager:
|
||||
"""
|
||||
episode = Episode(episode_data)
|
||||
self.episodes.append(episode)
|
||||
|
||||
def get(self, index: int) -> Episode:
|
||||
"""
|
||||
Retrieve an episode by its index in the episodes list.
|
||||
|
||||
Parameters:
|
||||
- index (int): The zero-based index of the episode to retrieve.
|
||||
|
||||
Returns:
|
||||
Episode: The Episode object at the specified index.
|
||||
"""
|
||||
return self.episodes[index]
|
||||
|
||||
def get_length(self) -> int:
|
||||
def length(self) -> int:
|
||||
"""
|
||||
Get the number of episodes in the manager.
|
||||
|
||||
@ -54,61 +71,23 @@ 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.episodes_count: int = season_data.get('episodes_count')
|
||||
|
||||
def __str__(self):
|
||||
return f"Season(id={self.id}, number={self.number}, name='{self.name}', plot='{self.plot}', episodes_count={self.episodes_count})"
|
||||
|
||||
class SeasonManager:
|
||||
def __init__(self):
|
||||
self.seasons: List[Season] = []
|
||||
|
||||
def add_season(self, season_data: Dict[str, Union[int, str, None]]):
|
||||
"""
|
||||
Add a new season to the manager.
|
||||
|
||||
Parameters:
|
||||
season_data (Dict[str, Union[int, str, None]]): A dictionary containing data for the new season.
|
||||
"""
|
||||
season = Season(season_data)
|
||||
self.seasons.append(season)
|
||||
|
||||
def get(self, index: int) -> Season:
|
||||
"""
|
||||
Get a season item from the list by index.
|
||||
|
||||
Parameters:
|
||||
index (int): The index of the seasons item to retrieve.
|
||||
|
||||
Returns:
|
||||
Season: The media item at the specified index.
|
||||
"""
|
||||
return self.media_list[index]
|
||||
|
||||
def get_length(self) -> int:
|
||||
"""
|
||||
Get the number of seasons in the manager.
|
||||
|
||||
Returns:
|
||||
int: Number of seasons.
|
||||
"""
|
||||
return len(self.seasons)
|
||||
|
||||
def clear(self) -> None:
|
||||
"""
|
||||
This method clears the seasons list.
|
||||
|
||||
Parameters:
|
||||
self: The object instance.
|
||||
"""
|
||||
self.seasons.clear()
|
||||
|
||||
def __str__(self):
|
||||
return f"SeasonManager(num_seasons={len(self.seasons)})"
|
||||
self.type: str = season_data.get('type')
|
||||
self.seasons_count: int = season_data.get('seasons_count')
|
||||
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:
|
||||
|
@ -169,6 +169,56 @@ class VideoSource:
|
||||
# Construct the new URL with updated query parameters
|
||||
return urlunparse(parsed_url._replace(query=query_string))
|
||||
|
||||
def get_mp4(self, url_to_download: str, scws_id: str) -> list:
|
||||
"""
|
||||
Generate download links for the specified resolutions from StreamingCommunity.
|
||||
|
||||
Args:
|
||||
url_to_download (str): URL of the video page.
|
||||
scws_id (str): SCWS ID of the title.
|
||||
|
||||
Returns:
|
||||
list: A list of video download URLs.
|
||||
"""
|
||||
headers = {
|
||||
'referer': url_to_download,
|
||||
'user-agent': get_headers(),
|
||||
}
|
||||
|
||||
# API request to get video details
|
||||
video_api_url = f'https://{self.base_name}.{self.domain}/api/video/{scws_id}'
|
||||
response = httpx.get(video_api_url, headers=headers)
|
||||
|
||||
if response.status_code == 200:
|
||||
response_json = response.json()
|
||||
|
||||
video_tracks = response_json.get('video_tracks', [])
|
||||
track = video_tracks[-1]
|
||||
console.print(f"[cyan]Available resolutions: [red]{[str(track['quality']) for track in video_tracks]}")
|
||||
|
||||
# Request download link generation for each track
|
||||
download_response = httpx.post(
|
||||
url=f'https://{self.base_name}.{self.domain}/api/download/generate_link?scws_id={track["video_id"]}&rendition={track["quality"]}',
|
||||
headers={
|
||||
'referer': url_to_download,
|
||||
'user-agent': get_headers(),
|
||||
'x-xsrf-token': config_manager.get("SITE", self.base_name)['extra']['x-xsrf-token']
|
||||
},
|
||||
cookies={
|
||||
'streamingcommunity_session': config_manager.get("SITE", self.base_name)['extra']['streamingcommunity_session']
|
||||
}
|
||||
)
|
||||
|
||||
if download_response.status_code == 200:
|
||||
return {'url': download_response.text, 'quality': track["quality"]}
|
||||
|
||||
else:
|
||||
logging.error(f"Failed to generate link for resolution {track['quality']} (HTTP {download_response.status_code}).")
|
||||
|
||||
else:
|
||||
logging.error(f"Error fetching video API URL (HTTP {response.status_code}).")
|
||||
return []
|
||||
|
||||
|
||||
class VideoSourceAnime(VideoSource):
|
||||
def __init__(self, site_name: str):
|
||||
@ -221,4 +271,4 @@ class VideoSourceAnime(VideoSource):
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error fetching embed URL: {e}")
|
||||
return None
|
||||
return None
|
@ -10,7 +10,7 @@ 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_dict('SITE', SITE_NAME)['domain']
|
||||
COOKIE = config_manager.get_dict('SITE', SITE_NAME)['cookie']
|
||||
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')
|
||||
|
@ -42,13 +42,13 @@ def download_video(tv_name: str, index_season_selected: int, index_episode_selec
|
||||
start_message()
|
||||
|
||||
# Get info about episode
|
||||
obj_episode = scrape_serie.obj_episode_manager.episodes[index_episode_selected - 1]
|
||||
obj_episode = scrape_serie.episode_manager.get(index_episode_selected - 1)
|
||||
console.print(f"[yellow]Download: [red]{index_season_selected}:{index_episode_selected} {obj_episode.name}")
|
||||
print()
|
||||
|
||||
# Define filename and path for the downloaded video
|
||||
mp4_name = f"{map_episode_title(tv_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
|
||||
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, tv_name, f"S{index_season_selected}")
|
||||
mp4_path = os.path.join(ROOT_PATH, SITE_NAME, SERIES_FOLDER, tv_name, f"S{index_season_selected}")
|
||||
|
||||
# Retrieve scws and if available master playlist
|
||||
video_source.get_iframe(obj_episode.id)
|
||||
@ -84,13 +84,12 @@ def download_episode(tv_name: str, index_season_selected: int, scrape_serie: Scr
|
||||
"""
|
||||
|
||||
# Clean memory of all episodes and get the number of the season
|
||||
scrape_serie.obj_episode_manager.clear()
|
||||
season_number = scrape_serie.obj_season_manager.seasons[index_season_selected - 1].number
|
||||
scrape_serie.episode_manager.clear()
|
||||
|
||||
# Start message and collect information about episodes
|
||||
start_message()
|
||||
scrape_serie.collect_title_season(season_number)
|
||||
episodes_count = scrape_serie.obj_episode_manager.get_length()
|
||||
scrape_serie.collect_info_season(index_season_selected)
|
||||
episodes_count = scrape_serie.episode_manager.length()
|
||||
|
||||
if download_all:
|
||||
|
||||
@ -137,8 +136,8 @@ def download_series(select_season: MediaItem, version: str) -> None:
|
||||
video_source.setup(select_season.id)
|
||||
|
||||
# Collect information about seasons
|
||||
scrape_serie.collect_info_seasons()
|
||||
seasons_count = scrape_serie.obj_season_manager.get_length()
|
||||
scrape_serie.collect_info_title()
|
||||
seasons_count = scrape_serie.season_manager.seasons_count
|
||||
|
||||
# Prompt user for season selection and download episodes
|
||||
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
|
||||
@ -188,7 +187,7 @@ def display_episodes_list(scrape_serie) -> str:
|
||||
table_show_manager.add_column(column_info)
|
||||
|
||||
# Populate the table with episodes information
|
||||
for i, media in enumerate(scrape_serie.obj_episode_manager.episodes):
|
||||
for i, media in enumerate(scrape_serie.episode_manager.episodes):
|
||||
table_show_manager.add_tv_show({
|
||||
'Index': str(media.number),
|
||||
'Name': media.name,
|
||||
|
@ -10,7 +10,7 @@ import httpx
|
||||
# Internal utilities
|
||||
from StreamingCommunity.Util.headers import get_headers
|
||||
from StreamingCommunity.Util._jsonConfig import config_manager
|
||||
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager, EpisodeManager
|
||||
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import Season, EpisodeManager
|
||||
|
||||
|
||||
# Variable
|
||||
@ -46,10 +46,10 @@ class ScrapeSerie:
|
||||
if series_name is not None:
|
||||
self.is_series = True
|
||||
self.series_name = series_name
|
||||
self.obj_season_manager: SeasonManager = SeasonManager()
|
||||
self.obj_episode_manager: EpisodeManager = EpisodeManager()
|
||||
self.season_manager = None
|
||||
self.episode_manager: EpisodeManager = EpisodeManager()
|
||||
|
||||
def collect_info_seasons(self) -> None:
|
||||
def collect_info_title(self) -> None:
|
||||
"""
|
||||
Retrieve season information for a TV series from the streaming site.
|
||||
|
||||
@ -72,17 +72,22 @@ class ScrapeSerie:
|
||||
response.raise_for_status()
|
||||
|
||||
# Extract seasons from JSON response
|
||||
json_response = response.json().get('props', {}).get('title', {}).get('seasons', [])
|
||||
|
||||
# Add each season to the season manager
|
||||
for dict_season in json_response:
|
||||
self.obj_season_manager.add_season(dict_season)
|
||||
json_response = response.json().get('props')
|
||||
|
||||
# Collect info about season
|
||||
self.season_manager = Season(json_response.get('title'))
|
||||
self.season_manager.collect_images(self.base_name, self.domain)
|
||||
|
||||
# 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
|
||||
|
||||
def collect_title_season(self, number_season: int) -> None:
|
||||
def collect_info_season(self, number_season: int) -> None:
|
||||
"""
|
||||
Retrieve episode information for a specific season.
|
||||
|
||||
@ -92,8 +97,13 @@ class ScrapeSerie:
|
||||
Raises:
|
||||
Exception: If there's an error fetching episode information
|
||||
"""
|
||||
try:
|
||||
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,
|
||||
@ -102,11 +112,11 @@ class ScrapeSerie:
|
||||
response.raise_for_status()
|
||||
|
||||
# Extract episodes from JSON response
|
||||
json_response = response.json().get('props', {}).get('loadedSeason', {}).get('episodes', [])
|
||||
json_response = response.json().get('props').get('loadedSeason').get('episodes')
|
||||
|
||||
# Add each episode to the episode manager
|
||||
for dict_episode in json_response:
|
||||
self.obj_episode_manager.add_episode(dict_episode)
|
||||
self.episode_manager.add(dict_episode)
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error collecting title season info: {e}")
|
||||
|
@ -62,7 +62,7 @@
|
||||
},
|
||||
"SITE": {
|
||||
"streamingcommunity": {
|
||||
"domain": "asia"
|
||||
"domain": "family"
|
||||
},
|
||||
"altadefinizione": {
|
||||
"domain": "now"
|
||||
@ -75,7 +75,7 @@
|
||||
},
|
||||
"ddlstreamitaly": {
|
||||
"domain": "co",
|
||||
"cookie": {
|
||||
"extra": {
|
||||
"ips4_device_key": "",
|
||||
"ips4_member_id": "",
|
||||
"ips4_login_key": ""
|
||||
|
Loading…
x
Reference in New Issue
Block a user