Improve site SC

This commit is contained in:
Lovi 2024-12-08 19:00:37 +01:00
parent f5ad9b7187
commit 0bedb1bf05
7 changed files with 149 additions and 87 deletions

View File

@ -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!
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=UXTWMT8P6HE2C)
# Contributing

View File

@ -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.
@ -30,7 +35,19 @@ class EpisodeManager:
episode = Episode(episode_data)
self.episodes.append(episode)
def get_length(self) -> int:
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 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')
self.type: str = season_data.get('type')
self.seasons_count: int = season_data.get('seasons_count')
self.episodes: EpisodeManager = EpisodeManager()
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)})"
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:

View File

@ -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):

View File

@ -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')

View File

@ -42,7 +42,7 @@ 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()
@ -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,

View File

@ -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', [])
json_response = response.json().get('props')
# Add each season to the season manager
for dict_season in json_response:
self.obj_season_manager.add_season(dict_season)
# 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}")

View File

@ -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": ""