StreamingCommunity 3.3.9__py3-none-any.whl → 3.4.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of StreamingCommunity might be problematic. Click here for more details.
- StreamingCommunity/Api/Player/hdplayer.py +0 -5
- StreamingCommunity/Api/Player/mediapolisvod.py +4 -13
- StreamingCommunity/Api/Player/supervideo.py +3 -8
- StreamingCommunity/Api/Player/sweetpixel.py +1 -9
- StreamingCommunity/Api/Player/vixcloud.py +5 -16
- StreamingCommunity/Api/Site/altadefinizione/film.py +4 -16
- StreamingCommunity/Api/Site/altadefinizione/series.py +3 -12
- StreamingCommunity/Api/Site/altadefinizione/site.py +2 -9
- StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +2 -7
- StreamingCommunity/Api/Site/animeunity/site.py +9 -24
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +11 -27
- StreamingCommunity/Api/Site/animeworld/film.py +4 -2
- StreamingCommunity/Api/Site/animeworld/site.py +3 -11
- StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +1 -4
- StreamingCommunity/Api/Site/crunchyroll/film.py +4 -5
- StreamingCommunity/Api/Site/crunchyroll/series.py +5 -17
- StreamingCommunity/Api/Site/crunchyroll/site.py +4 -13
- StreamingCommunity/Api/Site/crunchyroll/util/ScrapeSerie.py +5 -27
- StreamingCommunity/Api/Site/crunchyroll/util/get_license.py +11 -26
- StreamingCommunity/Api/Site/guardaserie/series.py +3 -14
- StreamingCommunity/Api/Site/guardaserie/site.py +4 -12
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +3 -10
- StreamingCommunity/Api/Site/mediasetinfinity/film.py +11 -12
- StreamingCommunity/Api/Site/mediasetinfinity/series.py +4 -15
- StreamingCommunity/Api/Site/mediasetinfinity/site.py +16 -32
- StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +39 -50
- StreamingCommunity/Api/Site/mediasetinfinity/util/fix_mpd.py +3 -3
- StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +7 -25
- StreamingCommunity/Api/Site/raiplay/film.py +6 -8
- StreamingCommunity/Api/Site/raiplay/series.py +5 -20
- StreamingCommunity/Api/Site/raiplay/site.py +45 -47
- StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +91 -55
- StreamingCommunity/Api/Site/raiplay/util/get_license.py +3 -12
- StreamingCommunity/Api/Site/streamingcommunity/film.py +5 -16
- StreamingCommunity/Api/Site/streamingcommunity/series.py +5 -10
- StreamingCommunity/Api/Site/streamingcommunity/site.py +3 -22
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +11 -27
- StreamingCommunity/Api/Site/streamingwatch/__init__.py +1 -0
- StreamingCommunity/Api/Site/streamingwatch/film.py +4 -2
- StreamingCommunity/Api/Site/streamingwatch/series.py +4 -14
- StreamingCommunity/Api/Site/streamingwatch/site.py +4 -18
- StreamingCommunity/Api/Site/streamingwatch/util/ScrapeSerie.py +0 -3
- StreamingCommunity/Api/Template/Util/__init__.py +4 -2
- StreamingCommunity/Api/Template/Util/manage_ep.py +66 -0
- StreamingCommunity/Api/Template/config_loader.py +0 -7
- StreamingCommunity/Lib/Downloader/DASH/decrypt.py +54 -1
- StreamingCommunity/Lib/Downloader/DASH/downloader.py +186 -70
- StreamingCommunity/Lib/Downloader/DASH/parser.py +2 -3
- StreamingCommunity/Lib/Downloader/DASH/segments.py +109 -68
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +100 -82
- StreamingCommunity/Lib/Downloader/HLS/segments.py +40 -28
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +16 -4
- StreamingCommunity/Lib/FFmpeg/capture.py +37 -5
- StreamingCommunity/Lib/FFmpeg/command.py +32 -90
- StreamingCommunity/Lib/M3U8/estimator.py +47 -1
- StreamingCommunity/Lib/TMBD/tmdb.py +2 -4
- StreamingCommunity/TelegramHelp/config.json +0 -1
- StreamingCommunity/Upload/update.py +19 -6
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/config_json.py +28 -21
- StreamingCommunity/Util/http_client.py +28 -0
- StreamingCommunity/Util/os.py +16 -6
- StreamingCommunity/Util/table.py +50 -8
- {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/METADATA +1 -3
- streamingcommunity-3.4.2.dist-info/RECORD +111 -0
- streamingcommunity-3.3.9.dist-info/RECORD +0 -111
- {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/WHEEL +0 -0
- {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/top_level.txt +0 -0
|
@@ -3,19 +3,12 @@
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
# External libraries
|
|
7
|
-
import httpx
|
|
8
|
-
|
|
9
|
-
|
|
10
6
|
# Internal utilities
|
|
11
7
|
from StreamingCommunity.Util.headers import get_headers
|
|
12
|
-
from StreamingCommunity.Util.
|
|
8
|
+
from StreamingCommunity.Util.http_client import create_client
|
|
13
9
|
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
|
|
14
10
|
|
|
15
11
|
|
|
16
|
-
# Variable
|
|
17
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
18
|
-
|
|
19
12
|
|
|
20
13
|
class GetSerieInfo:
|
|
21
14
|
def __init__(self, path_id: str):
|
|
@@ -23,16 +16,17 @@ class GetSerieInfo:
|
|
|
23
16
|
self.base_url = "https://www.raiplay.it"
|
|
24
17
|
self.path_id = path_id
|
|
25
18
|
self.series_name = None
|
|
26
|
-
self.prog_tipology = "film"
|
|
27
19
|
self.prog_description = None
|
|
28
20
|
self.prog_year = None
|
|
29
21
|
self.seasons_manager = SeasonManager()
|
|
22
|
+
self.season_block_mapping = {} # Map season number to block_id
|
|
23
|
+
self.all_seasons_data = [] # Store all seasons before filtering
|
|
30
24
|
|
|
31
25
|
def collect_info_title(self) -> None:
|
|
32
|
-
"""Get series info including seasons."""
|
|
26
|
+
"""Get series info including seasons from all multimedia blocks."""
|
|
33
27
|
try:
|
|
34
28
|
program_url = f"{self.base_url}/{self.path_id}"
|
|
35
|
-
response =
|
|
29
|
+
response = create_client(headers=get_headers()).get(program_url)
|
|
36
30
|
|
|
37
31
|
# If 404, content is not yet available
|
|
38
32
|
if response.status_code == 404:
|
|
@@ -43,76 +37,118 @@ class GetSerieInfo:
|
|
|
43
37
|
json_data = response.json()
|
|
44
38
|
|
|
45
39
|
# Get basic program info
|
|
46
|
-
|
|
47
|
-
self.
|
|
48
|
-
self.
|
|
40
|
+
program_info = json_data.get('program_info', {})
|
|
41
|
+
self.prog_description = program_info.get('vanity', '') or program_info.get('description', '')
|
|
42
|
+
self.prog_year = program_info.get('year', '')
|
|
43
|
+
self.series_name = program_info.get('title', '') or program_info.get('name', '')
|
|
44
|
+
|
|
45
|
+
# Collect all seasons from all multimedia blocks
|
|
46
|
+
self.all_seasons_data = []
|
|
47
|
+
blocks_found = {}
|
|
49
48
|
|
|
50
|
-
# Look for seasons in the 'blocks' property
|
|
51
49
|
for block in json_data.get('blocks', []):
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
50
|
+
block_type = block.get('type', '')
|
|
51
|
+
block_name = block.get('name', 'N/A')
|
|
52
|
+
block_id = block.get('id', '')
|
|
53
|
+
|
|
54
|
+
# Only process multimedia blocks with sets
|
|
55
|
+
if block_type == 'RaiPlay Multimedia Block' and 'sets' in block:
|
|
56
|
+
sets = block.get('sets', [])
|
|
57
|
+
|
|
58
|
+
for season_set in sets:
|
|
59
|
+
episode_size = season_set.get('episode_size', {})
|
|
60
|
+
episode_count = episode_size.get('number', 0)
|
|
61
|
+
|
|
62
|
+
# Only add sets with episodes
|
|
63
|
+
if episode_count > 0:
|
|
64
|
+
self.all_seasons_data.append({
|
|
65
|
+
'season_set': season_set,
|
|
66
|
+
'block_id': block_id,
|
|
67
|
+
'block_name': block_name
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
# Track which blocks we found
|
|
71
|
+
if block_name not in blocks_found:
|
|
72
|
+
blocks_found[block_name] = 0
|
|
73
|
+
blocks_found[block_name] += 1
|
|
74
|
+
|
|
75
|
+
# Add all collected seasons without any filtering (oldest first)
|
|
76
|
+
for season_data in reversed(self.all_seasons_data):
|
|
77
|
+
self._add_season(
|
|
78
|
+
season_data['season_set'],
|
|
79
|
+
season_data['block_id'],
|
|
80
|
+
season_data['block_name']
|
|
81
|
+
)
|
|
72
82
|
|
|
73
83
|
except Exception as e:
|
|
74
84
|
logging.error(f"Unexpected error collecting series info: {e}")
|
|
75
85
|
|
|
76
|
-
def _add_season(self, season_set: dict, block_id: str):
|
|
86
|
+
def _add_season(self, season_set: dict, block_id: str, block_name: str):
|
|
87
|
+
"""Add a season combining set name and block name."""
|
|
88
|
+
set_name = season_set.get('name', '')
|
|
89
|
+
season_number = len(self.seasons_manager.seasons) + 1
|
|
90
|
+
|
|
91
|
+
# Store block_id mapping
|
|
92
|
+
self.season_block_mapping[season_number] = {
|
|
93
|
+
'block_id': block_id,
|
|
94
|
+
'set_id': season_set.get('id', '')
|
|
95
|
+
}
|
|
96
|
+
|
|
77
97
|
self.seasons_manager.add_season({
|
|
78
98
|
'id': season_set.get('id', ''),
|
|
79
|
-
'number':
|
|
80
|
-
'name':
|
|
81
|
-
'
|
|
82
|
-
'
|
|
99
|
+
'number': season_number,
|
|
100
|
+
'name': set_name,
|
|
101
|
+
#'episodes_count': season_set.get('episode_size', {}).get('number', 0),
|
|
102
|
+
'type': block_name
|
|
83
103
|
})
|
|
84
104
|
|
|
85
105
|
def collect_info_season(self, number_season: int) -> None:
|
|
86
|
-
"""Get episodes for a specific season."""
|
|
106
|
+
"""Get episodes for a specific season using episodes.json endpoint."""
|
|
87
107
|
try:
|
|
88
108
|
season = self.seasons_manager.get_season_by_number(number_season)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
109
|
+
block_info = self.season_block_mapping[number_season]
|
|
110
|
+
block_id = block_info['block_id']
|
|
111
|
+
set_id = block_info['set_id']
|
|
112
|
+
|
|
113
|
+
# Build episodes endpoint URL
|
|
114
|
+
base_path = self.path_id.replace('.json', '')
|
|
115
|
+
url = f"{self.base_url}/{base_path}/{block_id}/{set_id}/episodes.json"
|
|
116
|
+
|
|
117
|
+
response = create_client(headers=get_headers()).get(url)
|
|
93
118
|
response.raise_for_status()
|
|
94
119
|
|
|
95
120
|
episodes_data = response.json()
|
|
96
|
-
cards = []
|
|
97
121
|
|
|
98
|
-
#
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
122
|
+
# Navigate nested structure to find cards
|
|
123
|
+
cards = []
|
|
124
|
+
seasons = episodes_data.get('seasons', [])
|
|
125
|
+
if seasons:
|
|
126
|
+
for season_data in seasons:
|
|
127
|
+
episodes = season_data.get('episodes', [])
|
|
128
|
+
for episode in episodes:
|
|
129
|
+
cards.extend(episode.get('cards', []))
|
|
103
130
|
|
|
131
|
+
# Fallback to direct cards if nested structure not found
|
|
104
132
|
if not cards:
|
|
105
133
|
cards = episodes_data.get('cards', [])
|
|
106
134
|
|
|
107
135
|
# Add episodes to season
|
|
108
136
|
for ep in cards:
|
|
137
|
+
video_url = ep.get('video_url', '')
|
|
138
|
+
mpd_id = ''
|
|
139
|
+
if video_url and '=' in video_url:
|
|
140
|
+
mpd_id = video_url.split("=")[1].strip()
|
|
141
|
+
|
|
142
|
+
weblink = ep.get('weblink', '') or ep.get('url', '')
|
|
143
|
+
episode_url = f"{self.base_url}{weblink}" if weblink else ''
|
|
144
|
+
|
|
109
145
|
episode = {
|
|
110
146
|
'id': ep.get('id', ''),
|
|
111
147
|
'number': ep.get('episode', ''),
|
|
112
|
-
'name': ep.get('episode_title', '') or ep.get('toptitle', ''),
|
|
113
|
-
'duration': ep.get('duration', ''),
|
|
114
|
-
'url':
|
|
115
|
-
'mpd_id':
|
|
148
|
+
'name': ep.get('episode_title', '') or ep.get('name', '') or ep.get('toptitle', ''),
|
|
149
|
+
'duration': ep.get('duration', '') or ep.get('duration_in_minutes', ''),
|
|
150
|
+
'url': episode_url,
|
|
151
|
+
'mpd_id': mpd_id
|
|
116
152
|
}
|
|
117
153
|
season.episodes.add(episode)
|
|
118
154
|
|
|
@@ -1,20 +1,11 @@
|
|
|
1
1
|
# 16.03.25
|
|
2
2
|
|
|
3
3
|
|
|
4
|
-
# External library
|
|
5
|
-
import httpx
|
|
6
|
-
|
|
7
|
-
|
|
8
4
|
# Internal utilities
|
|
9
|
-
from StreamingCommunity.Util.
|
|
5
|
+
from StreamingCommunity.Util.http_client import create_client
|
|
10
6
|
from StreamingCommunity.Util.headers import get_headers
|
|
11
7
|
|
|
12
8
|
|
|
13
|
-
# Variable
|
|
14
|
-
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
9
|
def generate_license_url(mpd_id: str):
|
|
19
10
|
"""
|
|
20
11
|
Generates the URL to obtain the Widevine license.
|
|
@@ -29,8 +20,8 @@ def generate_license_url(mpd_id: str):
|
|
|
29
20
|
'cont': mpd_id,
|
|
30
21
|
'output': '62',
|
|
31
22
|
}
|
|
32
|
-
|
|
33
|
-
response =
|
|
23
|
+
|
|
24
|
+
response = create_client(headers=get_headers()).get('https://mediapolisvod.rai.it/relinker/relinkerServlet.htm', params=params)
|
|
34
25
|
response.raise_for_status()
|
|
35
26
|
|
|
36
27
|
# Extract the license URL from the response in two lines
|
|
@@ -9,8 +9,9 @@ from rich.console import Console
|
|
|
9
9
|
|
|
10
10
|
# Internal utilities
|
|
11
11
|
from StreamingCommunity.Util.os import os_manager
|
|
12
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
12
13
|
from StreamingCommunity.Util.message import start_message
|
|
13
|
-
from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession
|
|
14
|
+
from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
# Logic class
|
|
@@ -25,6 +26,7 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
|
|
|
25
26
|
|
|
26
27
|
# Variable
|
|
27
28
|
console = Console()
|
|
29
|
+
extension_output = config_manager.get("M3U8_CONVERSION", "extension")
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
def download_film(select_title: MediaItem) -> str:
|
|
@@ -38,19 +40,6 @@ def download_film(select_title: MediaItem) -> str:
|
|
|
38
40
|
Return:
|
|
39
41
|
- str: output path
|
|
40
42
|
"""
|
|
41
|
-
if site_constant.TELEGRAM_BOT:
|
|
42
|
-
bot = get_bot_instance()
|
|
43
|
-
bot.send_message(f"Download in corso:\n{select_title.name}", None)
|
|
44
|
-
|
|
45
|
-
# Viene usato per lo screen
|
|
46
|
-
console.print(f"## Download: [red]{select_title.name} ##")
|
|
47
|
-
|
|
48
|
-
# Get script_id
|
|
49
|
-
script_id = TelegramSession.get_session()
|
|
50
|
-
if script_id != "unknown":
|
|
51
|
-
TelegramSession.updateScriptId(script_id, select_title.name)
|
|
52
|
-
|
|
53
|
-
# Start message and display film information
|
|
54
43
|
start_message()
|
|
55
44
|
console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
|
|
56
45
|
|
|
@@ -67,8 +56,8 @@ def download_film(select_title: MediaItem) -> str:
|
|
|
67
56
|
return None
|
|
68
57
|
|
|
69
58
|
# Define the filename and path for the downloaded film
|
|
70
|
-
title_name = os_manager.get_sanitize_file(select_title.name) +
|
|
71
|
-
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(
|
|
59
|
+
title_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
|
|
60
|
+
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))
|
|
72
61
|
|
|
73
62
|
# Download the film using the m3u8 playlist, and output filename
|
|
74
63
|
hls_process = HLS_Downloader(
|
|
@@ -21,7 +21,8 @@ from StreamingCommunity.Api.Template.Util import (
|
|
|
21
21
|
map_episode_title,
|
|
22
22
|
validate_selection,
|
|
23
23
|
validate_episode_selection,
|
|
24
|
-
display_episodes_list
|
|
24
|
+
display_episodes_list,
|
|
25
|
+
display_seasons_list
|
|
25
26
|
)
|
|
26
27
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
27
28
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
@@ -166,9 +167,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
166
167
|
if site_constant.TELEGRAM_BOT:
|
|
167
168
|
bot = get_bot_instance()
|
|
168
169
|
|
|
169
|
-
# Prompt user for season selection and download episodes
|
|
170
|
-
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
|
|
171
|
-
|
|
172
170
|
# If season_selection is provided, use it instead of asking for input
|
|
173
171
|
if season_selection is None:
|
|
174
172
|
if site_constant.TELEGRAM_BOT:
|
|
@@ -188,10 +186,8 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
188
186
|
)
|
|
189
187
|
|
|
190
188
|
else:
|
|
191
|
-
index_season_selected =
|
|
192
|
-
|
|
193
|
-
"[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
|
|
194
|
-
)
|
|
189
|
+
index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
|
|
190
|
+
|
|
195
191
|
else:
|
|
196
192
|
index_season_selected = season_selection
|
|
197
193
|
console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
|
|
@@ -211,7 +207,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
211
207
|
|
|
212
208
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
|
213
209
|
download_episode(season_number, scrape_serie, video_source, download_all=True)
|
|
214
|
-
|
|
215
210
|
else:
|
|
216
211
|
download_episode(season_number, scrape_serie, video_source, download_all=False, episode_selection=episode_selection)
|
|
217
212
|
|
|
@@ -221,4 +216,4 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
221
216
|
# Get script_id
|
|
222
217
|
script_id = TelegramSession.get_session()
|
|
223
218
|
if script_id != "unknown":
|
|
224
|
-
TelegramSession.deleteScriptId(script_id)
|
|
219
|
+
TelegramSession.deleteScriptId(script_id)
|
|
@@ -4,14 +4,13 @@ import json
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
# External libraries
|
|
7
|
-
import httpx
|
|
8
7
|
from bs4 import BeautifulSoup
|
|
9
8
|
from rich.console import Console
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
# Internal utilities
|
|
13
|
-
from StreamingCommunity.Util.config_json import config_manager
|
|
14
12
|
from StreamingCommunity.Util.headers import get_userAgent
|
|
13
|
+
from StreamingCommunity.Util.http_client import create_client
|
|
15
14
|
from StreamingCommunity.Util.table import TVShowManager
|
|
16
15
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
17
16
|
|
|
@@ -25,8 +24,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
|
|
25
24
|
console = Console()
|
|
26
25
|
media_search_manager = MediaManager()
|
|
27
26
|
table_show_manager = TVShowManager()
|
|
28
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
29
|
-
ssl_verify = config_manager.get_bool("REQUESTS", "verify")
|
|
30
27
|
|
|
31
28
|
|
|
32
29
|
def title_search(query: str) -> int:
|
|
@@ -46,13 +43,7 @@ def title_search(query: str) -> int:
|
|
|
46
43
|
table_show_manager.clear()
|
|
47
44
|
|
|
48
45
|
try:
|
|
49
|
-
response =
|
|
50
|
-
f"{site_constant.FULL_URL}/it",
|
|
51
|
-
headers={'user-agent': get_userAgent()},
|
|
52
|
-
timeout=max_timeout,
|
|
53
|
-
verify=ssl_verify,
|
|
54
|
-
follow_redirects=True
|
|
55
|
-
)
|
|
46
|
+
response = create_client(headers={'user-agent': get_userAgent()}).get(f"{site_constant.FULL_URL}/it")
|
|
56
47
|
response.raise_for_status()
|
|
57
48
|
|
|
58
49
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
@@ -66,17 +57,7 @@ def title_search(query: str) -> int:
|
|
|
66
57
|
console.print(f"[cyan]Search url: [yellow]{search_url}")
|
|
67
58
|
|
|
68
59
|
try:
|
|
69
|
-
response =
|
|
70
|
-
search_url,
|
|
71
|
-
headers = {
|
|
72
|
-
'referer': site_constant.FULL_URL,
|
|
73
|
-
'user-agent': get_userAgent(),
|
|
74
|
-
'x-inertia': 'true',
|
|
75
|
-
'x-inertia-version': version
|
|
76
|
-
},
|
|
77
|
-
timeout=max_timeout,
|
|
78
|
-
verify=ssl_verify
|
|
79
|
-
)
|
|
60
|
+
response = create_client(headers={'user-agent': get_userAgent(), 'x-inertia': 'true', 'x-inertia-version': version}).get(search_url)
|
|
80
61
|
response.raise_for_status()
|
|
81
62
|
|
|
82
63
|
except Exception as e:
|
|
@@ -5,21 +5,15 @@ import logging
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
# External libraries
|
|
8
|
-
import httpx
|
|
9
8
|
from bs4 import BeautifulSoup
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
# Internal utilities
|
|
13
|
-
from StreamingCommunity.Util.headers import
|
|
14
|
-
from StreamingCommunity.Util.
|
|
12
|
+
from StreamingCommunity.Util.headers import get_headers
|
|
13
|
+
from StreamingCommunity.Util.http_client import create_client
|
|
15
14
|
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
# Variable
|
|
19
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
20
|
-
ssl_verify = config_manager.get_bool("REQUESTS", "verify")
|
|
21
|
-
|
|
22
|
-
|
|
23
17
|
class GetSerieInfo:
|
|
24
18
|
def __init__(self, url, media_id: int = None, series_name: str = None):
|
|
25
19
|
"""
|
|
@@ -31,7 +25,7 @@ class GetSerieInfo:
|
|
|
31
25
|
- series_name (str, optional): Name of the TV series
|
|
32
26
|
"""
|
|
33
27
|
self.is_series = False
|
|
34
|
-
self.headers =
|
|
28
|
+
self.headers = get_headers()
|
|
35
29
|
self.url = url
|
|
36
30
|
self.media_id = media_id
|
|
37
31
|
self.seasons_manager = SeasonManager()
|
|
@@ -48,12 +42,7 @@ class GetSerieInfo:
|
|
|
48
42
|
Exception: If there's an error fetching series information
|
|
49
43
|
"""
|
|
50
44
|
try:
|
|
51
|
-
response =
|
|
52
|
-
url=f"{self.url}/titles/{self.media_id}-{self.series_name}",
|
|
53
|
-
headers=self.headers,
|
|
54
|
-
timeout=max_timeout,
|
|
55
|
-
verify=ssl_verify
|
|
56
|
-
)
|
|
45
|
+
response = create_client(headers=self.headers).get(f"{self.url}/titles/{self.media_id}-{self.series_name}")
|
|
57
46
|
response.raise_for_status()
|
|
58
47
|
|
|
59
48
|
# Extract series info from JSON response
|
|
@@ -75,7 +64,6 @@ class GetSerieInfo:
|
|
|
75
64
|
'number': season_data.get('number', 0),
|
|
76
65
|
'name': f"Season {season_data.get('number', 0)}",
|
|
77
66
|
'slug': season_data.get('slug', ''),
|
|
78
|
-
'type': title_data.get('type', '')
|
|
79
67
|
})
|
|
80
68
|
|
|
81
69
|
except Exception as e:
|
|
@@ -98,17 +86,13 @@ class GetSerieInfo:
|
|
|
98
86
|
if not season:
|
|
99
87
|
logging.error(f"Season {number_season} not found")
|
|
100
88
|
return
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
},
|
|
109
|
-
timeout=max_timeout,
|
|
110
|
-
verify=ssl_verify
|
|
111
|
-
)
|
|
89
|
+
|
|
90
|
+
custom_headers = self.headers.copy()
|
|
91
|
+
custom_headers.update({
|
|
92
|
+
'x-inertia': 'true',
|
|
93
|
+
'x-inertia-version': self.version,
|
|
94
|
+
})
|
|
95
|
+
response = create_client(headers=custom_headers).get(f"{self.url}/titles/{self.media_id}-{self.series_name}/season-{number_season}")
|
|
112
96
|
|
|
113
97
|
# Extract episodes from JSON response
|
|
114
98
|
json_response = response.json().get('props', {}).get('loadedSeason', {}).get('episodes', [])
|
|
@@ -9,6 +9,7 @@ from rich.console import Console
|
|
|
9
9
|
|
|
10
10
|
# Internal utilities
|
|
11
11
|
from StreamingCommunity.Util.os import os_manager
|
|
12
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
12
13
|
from StreamingCommunity.Util.message import start_message
|
|
13
14
|
|
|
14
15
|
|
|
@@ -24,6 +25,7 @@ from StreamingCommunity.Api.Player.hdplayer import VideoSource
|
|
|
24
25
|
|
|
25
26
|
# Variable
|
|
26
27
|
console = Console()
|
|
28
|
+
extension_output = config_manager.get("M3U8_CONVERSION", "extension")
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
def download_film(select_title: MediaItem) -> str:
|
|
@@ -45,8 +47,8 @@ def download_film(select_title: MediaItem) -> str:
|
|
|
45
47
|
master_playlist = video_source.get_m3u8_url(select_title.url)
|
|
46
48
|
|
|
47
49
|
# Define the filename and path for the downloaded film
|
|
48
|
-
title_name = os_manager.get_sanitize_file(select_title.name) +
|
|
49
|
-
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(
|
|
50
|
+
title_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
|
|
51
|
+
mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))
|
|
50
52
|
|
|
51
53
|
# Download the film using the m3u8 playlist, and output filename
|
|
52
54
|
hls_process = HLS_Downloader(
|
|
@@ -21,7 +21,8 @@ from StreamingCommunity.Api.Template.Util import (
|
|
|
21
21
|
map_episode_title,
|
|
22
22
|
validate_selection,
|
|
23
23
|
validate_episode_selection,
|
|
24
|
-
display_episodes_list
|
|
24
|
+
display_episodes_list,
|
|
25
|
+
display_seasons_list
|
|
25
26
|
)
|
|
26
27
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
27
28
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
@@ -53,7 +54,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
|
|
|
53
54
|
|
|
54
55
|
# Get episode information
|
|
55
56
|
obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
|
|
56
|
-
console.print(f"\n[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
|
|
57
|
+
console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
|
|
57
58
|
|
|
58
59
|
# Define filename and path for the downloaded video
|
|
59
60
|
mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
|
|
@@ -134,20 +135,11 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
134
135
|
- episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
|
|
135
136
|
"""
|
|
136
137
|
scrape_serie = GetSerieInfo(select_season.url)
|
|
137
|
-
|
|
138
|
-
# Get total number of seasons
|
|
139
138
|
seasons_count = scrape_serie.getNumberSeason()
|
|
140
139
|
|
|
141
|
-
# Prompt user for season selection and download episodes
|
|
142
|
-
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
|
|
143
|
-
|
|
144
140
|
# If season_selection is provided, use it instead of asking for input
|
|
145
141
|
if season_selection is None:
|
|
146
|
-
index_season_selected =
|
|
147
|
-
"\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
|
|
148
|
-
"[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
|
|
149
|
-
)
|
|
150
|
-
|
|
142
|
+
index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
|
|
151
143
|
else:
|
|
152
144
|
index_season_selected = season_selection
|
|
153
145
|
console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
|
|
@@ -159,8 +151,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
|
|
|
159
151
|
# Loop through the selected seasons and download episodes
|
|
160
152
|
for i_season in list_season_select:
|
|
161
153
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
|
162
|
-
# Download all episodes if multiple seasons are selected or if '*' is used
|
|
163
154
|
download_episode(i_season, scrape_serie, download_all=True)
|
|
164
155
|
else:
|
|
165
|
-
# Otherwise, let the user select specific episodes for the single season
|
|
166
156
|
download_episode(i_season, scrape_serie, download_all=False, episode_selection=episode_selection)
|
|
@@ -4,13 +4,12 @@ import re
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
# External libraries
|
|
7
|
-
import httpx
|
|
8
7
|
from bs4 import BeautifulSoup
|
|
9
8
|
from rich.console import Console
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
# Internal utilities
|
|
13
|
-
from StreamingCommunity.Util.
|
|
12
|
+
from StreamingCommunity.Util.http_client import create_client
|
|
14
13
|
from StreamingCommunity.Util.headers import get_userAgent
|
|
15
14
|
from StreamingCommunity.Util.table import TVShowManager
|
|
16
15
|
|
|
@@ -24,18 +23,13 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
|
|
|
24
23
|
console = Console()
|
|
25
24
|
media_search_manager = MediaManager()
|
|
26
25
|
table_show_manager = TVShowManager()
|
|
27
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
def extract_nonce() -> str:
|
|
31
29
|
"""Extract nonce value from the page script"""
|
|
32
|
-
response =
|
|
33
|
-
site_constant.FULL_URL,
|
|
34
|
-
headers={'user-agent': get_userAgent()},
|
|
35
|
-
timeout=max_timeout
|
|
36
|
-
)
|
|
37
|
-
|
|
30
|
+
response = create_client(headers={'user-agent': get_userAgent()}).get(site_constant.FULL_URL)
|
|
38
31
|
soup = BeautifulSoup(response.content, 'html.parser')
|
|
32
|
+
|
|
39
33
|
script = soup.find('script', id='live-search-js-extra')
|
|
40
34
|
if script:
|
|
41
35
|
match = re.search(r'"admin_ajax_nonce":"([^"]+)"', script.text)
|
|
@@ -73,15 +67,7 @@ def title_search(query: str) -> int:
|
|
|
73
67
|
'_wpnonce': _wpnonce
|
|
74
68
|
}
|
|
75
69
|
|
|
76
|
-
response =
|
|
77
|
-
search_url,
|
|
78
|
-
headers={
|
|
79
|
-
'origin': site_constant.FULL_URL,
|
|
80
|
-
'user-agent': get_userAgent()
|
|
81
|
-
},
|
|
82
|
-
data=data,
|
|
83
|
-
timeout=max_timeout
|
|
84
|
-
)
|
|
70
|
+
response = create_client(headers={'origin': site_constant.FULL_URL, 'user-agent': get_userAgent()}).post(search_url, data=data)
|
|
85
71
|
response.raise_for_status()
|
|
86
72
|
soup = BeautifulSoup(response.text, 'html.parser')
|
|
87
73
|
|
|
@@ -11,12 +11,9 @@ from bs4 import BeautifulSoup
|
|
|
11
11
|
# Internal utilities
|
|
12
12
|
from StreamingCommunity.Util.headers import get_userAgent
|
|
13
13
|
from StreamingCommunity.Util.http_client import create_client
|
|
14
|
-
from StreamingCommunity.Util.config_json import config_manager
|
|
15
14
|
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager, Episode
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
# Variable
|
|
19
|
-
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
20
17
|
|
|
21
18
|
|
|
22
19
|
class GetSerieInfo:
|
|
@@ -6,7 +6,8 @@ from .manage_ep import (
|
|
|
6
6
|
validate_episode_selection,
|
|
7
7
|
validate_selection,
|
|
8
8
|
dynamic_format_number,
|
|
9
|
-
display_episodes_list
|
|
9
|
+
display_episodes_list,
|
|
10
|
+
display_seasons_list
|
|
10
11
|
)
|
|
11
12
|
|
|
12
13
|
__all__ = [
|
|
@@ -15,5 +16,6 @@ __all__ = [
|
|
|
15
16
|
"validate_episode_selection",
|
|
16
17
|
"validate_selection",
|
|
17
18
|
"dynamic_format_number",
|
|
18
|
-
"display_episodes_list"
|
|
19
|
+
"display_episodes_list",
|
|
20
|
+
display_seasons_list
|
|
19
21
|
]
|