StreamingCommunity 2.9.8__py3-none-any.whl → 3.0.0__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/ddl.py +2 -10
- StreamingCommunity/Api/Player/mediapolisvod.py +64 -0
- StreamingCommunity/Api/Player/sweetpixel.py +3 -3
- StreamingCommunity/Api/Player/vixcloud.py +4 -9
- StreamingCommunity/Api/Site/1337xx/__init__.py +2 -3
- StreamingCommunity/Api/Site/1337xx/site.py +6 -1
- StreamingCommunity/Api/Site/altadefinizione/__init__.py +24 -9
- StreamingCommunity/Api/Site/altadefinizione/film.py +0 -1
- StreamingCommunity/Api/Site/altadefinizione/series.py +66 -70
- StreamingCommunity/Api/Site/altadefinizione/site.py +8 -2
- StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +37 -2
- StreamingCommunity/Api/Site/animeunity/__init__.py +30 -12
- StreamingCommunity/Api/Site/animeunity/film.py +40 -0
- StreamingCommunity/Api/Site/animeunity/serie.py +153 -0
- StreamingCommunity/Api/Site/animeunity/site.py +64 -37
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +41 -22
- StreamingCommunity/Api/Site/animeworld/__init__.py +26 -14
- StreamingCommunity/Api/Site/animeworld/film.py +63 -0
- StreamingCommunity/Api/Site/animeworld/serie.py +25 -22
- StreamingCommunity/Api/Site/animeworld/site.py +8 -2
- StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +32 -5
- StreamingCommunity/Api/Site/cb01new/__init__.py +2 -3
- StreamingCommunity/Api/Site/cb01new/site.py +7 -1
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +2 -3
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +31 -32
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +8 -3
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +30 -2
- StreamingCommunity/Api/Site/guardaserie/__init__.py +22 -9
- StreamingCommunity/Api/Site/guardaserie/series.py +55 -53
- StreamingCommunity/Api/Site/guardaserie/site.py +10 -3
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +27 -1
- StreamingCommunity/Api/Site/raiplay/__init__.py +92 -0
- StreamingCommunity/Api/Site/raiplay/film.py +65 -0
- StreamingCommunity/Api/Site/raiplay/series.py +162 -0
- StreamingCommunity/Api/Site/raiplay/site.py +173 -0
- StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +127 -0
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +30 -24
- StreamingCommunity/Api/Site/streamingcommunity/film.py +1 -2
- StreamingCommunity/Api/Site/streamingcommunity/series.py +76 -90
- StreamingCommunity/Api/Site/streamingcommunity/site.py +8 -4
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +41 -15
- StreamingCommunity/Api/Template/site.py +2 -2
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +1 -1
- StreamingCommunity/Lib/Downloader/HLS/segments.py +9 -18
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +2 -1
- StreamingCommunity/Lib/Downloader/TOR/downloader.py +7 -14
- StreamingCommunity/Lib/FFmpeg/capture.py +1 -5
- StreamingCommunity/Lib/FFmpeg/util.py +57 -19
- StreamingCommunity/Lib/M3U8/estimator.py +57 -41
- StreamingCommunity/Lib/M3U8/parser.py +26 -6
- StreamingCommunity/Upload/update.py +22 -3
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/ffmpeg_installer.py +26 -1
- StreamingCommunity/Util/os.py +13 -15
- StreamingCommunity/Util/table.py +4 -2
- StreamingCommunity/global_search.py +1 -4
- StreamingCommunity/run.py +1 -4
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/METADATA +1 -1
- streamingcommunity-3.0.0.dist-info/RECORD +91 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/WHEEL +1 -1
- StreamingCommunity/Api/Site/animeunity/film_serie.py +0 -181
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +0 -73
- StreamingCommunity/Api/Site/mostraguarda/film.py +0 -93
- streamingcommunity-2.9.8.dist-info/RECORD +0 -85
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-3.0.0.dist-info}/top_level.txt +0 -0
|
@@ -26,8 +26,7 @@ from .series import download_series
|
|
|
26
26
|
# Variable
|
|
27
27
|
indice = 0
|
|
28
28
|
_useFor = "film_serie"
|
|
29
|
-
|
|
30
|
-
_priority = 1
|
|
29
|
+
_priority = 0
|
|
31
30
|
_engineDownload = "hls"
|
|
32
31
|
|
|
33
32
|
msg = Prompt()
|
|
@@ -58,52 +57,59 @@ def get_user_input(string_to_search: str = None):
|
|
|
58
57
|
|
|
59
58
|
return string_to_search
|
|
60
59
|
|
|
61
|
-
def process_search_result(select_title):
|
|
60
|
+
def process_search_result(select_title, selections=None):
|
|
62
61
|
"""
|
|
63
62
|
Handles the search result and initiates the download for either a film or series.
|
|
63
|
+
|
|
64
|
+
Parameters:
|
|
65
|
+
select_title (MediaItem): The selected media item
|
|
66
|
+
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
67
|
+
{'season': season_selection, 'episode': episode_selection}
|
|
64
68
|
"""
|
|
65
69
|
if select_title.type == 'tv':
|
|
66
|
-
|
|
70
|
+
season_selection = None
|
|
71
|
+
episode_selection = None
|
|
72
|
+
|
|
73
|
+
if selections:
|
|
74
|
+
season_selection = selections.get('season')
|
|
75
|
+
episode_selection = selections.get('episode')
|
|
76
|
+
|
|
77
|
+
download_series(select_title, season_selection, episode_selection)
|
|
78
|
+
|
|
67
79
|
else:
|
|
68
80
|
download_film(select_title)
|
|
69
81
|
|
|
70
|
-
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
|
82
|
+
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
71
83
|
"""
|
|
72
|
-
Main function of the application for search
|
|
84
|
+
Main function of the application for search.
|
|
73
85
|
|
|
74
86
|
Parameters:
|
|
75
87
|
string_to_search (str, optional): String to search for
|
|
76
|
-
|
|
88
|
+
get_onlyDatabase (bool, optional): If True, return only the database object
|
|
77
89
|
direct_item (dict, optional): Direct item to process (bypass search)
|
|
90
|
+
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
91
|
+
{'season': season_selection, 'episode': episode_selection}
|
|
78
92
|
"""
|
|
79
93
|
if direct_item:
|
|
80
94
|
select_title = MediaItem(**direct_item)
|
|
81
|
-
process_search_result(select_title)
|
|
95
|
+
process_search_result(select_title, selections)
|
|
82
96
|
return
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
#
|
|
88
|
-
len_database = title_search(
|
|
97
|
+
|
|
98
|
+
if string_to_search is None:
|
|
99
|
+
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
100
|
+
|
|
101
|
+
# Search on database
|
|
102
|
+
len_database = title_search(string_to_search)
|
|
89
103
|
|
|
90
104
|
# If only the database is needed, return the manager
|
|
91
105
|
if get_onlyDatabase:
|
|
92
106
|
return media_search_manager
|
|
93
107
|
|
|
94
|
-
if site_constant.TELEGRAM_BOT:
|
|
95
|
-
bot = get_bot_instance()
|
|
96
|
-
|
|
97
108
|
if len_database > 0:
|
|
98
109
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
|
99
|
-
process_search_result(select_title)
|
|
110
|
+
process_search_result(select_title, selections)
|
|
100
111
|
|
|
101
112
|
else:
|
|
102
|
-
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
103
|
-
|
|
104
|
-
if site_constant.TELEGRAM_BOT:
|
|
105
|
-
bot.send_message(f"No results found, please try again", None)
|
|
106
|
-
|
|
107
113
|
# If no results are found, ask again
|
|
108
|
-
|
|
114
|
+
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
109
115
|
search()
|
|
@@ -55,8 +55,7 @@ def download_film(select_title: MediaItem) -> str:
|
|
|
55
55
|
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
|
|
56
56
|
|
|
57
57
|
# Init class
|
|
58
|
-
video_source = VideoSource(site_constant.FULL_URL, False)
|
|
59
|
-
video_source.setup(select_title.id)
|
|
58
|
+
video_source = VideoSource(site_constant.FULL_URL, False, select_title.id)
|
|
60
59
|
|
|
61
60
|
# Retrieve scws and if available master playlist
|
|
62
61
|
video_source.get_iframe(select_title.id)
|
|
@@ -39,28 +39,22 @@ console = Console()
|
|
|
39
39
|
|
|
40
40
|
def download_video(index_season_selected: int, index_episode_selected: int, scrape_serie: GetSerieInfo, video_source: VideoSource) -> Tuple[str,bool]:
|
|
41
41
|
"""
|
|
42
|
-
|
|
42
|
+
Downloads a specific episode from the specified season.
|
|
43
43
|
|
|
44
44
|
Parameters:
|
|
45
|
-
- index_season_selected (int):
|
|
46
|
-
- index_episode_selected (int):
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
45
|
+
- index_season_selected (int): Season number
|
|
46
|
+
- index_episode_selected (int): Episode index
|
|
47
|
+
- scrape_serie (GetSerieInfo): Scraper object with series information
|
|
48
|
+
- video_source (VideoSource): Video source handler
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
- str: Path to downloaded file
|
|
52
|
+
- bool: Whether download was stopped
|
|
51
53
|
"""
|
|
52
54
|
start_message()
|
|
53
|
-
index_season_selected = dynamic_format_number(str(index_season_selected))
|
|
54
|
-
|
|
55
|
-
# SPECIAL: Get season number
|
|
56
|
-
season = None
|
|
57
|
-
for s in scrape_serie.seasons_manager.seasons:
|
|
58
|
-
if s.number == int(index_season_selected):
|
|
59
|
-
season = s
|
|
60
|
-
break
|
|
61
55
|
|
|
62
|
-
# Get
|
|
63
|
-
obj_episode =
|
|
56
|
+
# Get episode information
|
|
57
|
+
obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
|
|
64
58
|
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
|
|
65
59
|
|
|
66
60
|
if site_constant.TELEGRAM_BOT:
|
|
@@ -98,28 +92,28 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
|
|
|
98
92
|
|
|
99
93
|
return r_proc['path'], r_proc['stopped']
|
|
100
94
|
|
|
101
|
-
|
|
95
|
+
|
|
96
|
+
def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, video_source: VideoSource, download_all: bool = False, episode_selection: str = None) -> None:
|
|
102
97
|
"""
|
|
103
|
-
|
|
98
|
+
Handle downloading episodes for a specific season.
|
|
104
99
|
|
|
105
100
|
Parameters:
|
|
106
|
-
- index_season_selected (int):
|
|
107
|
-
-
|
|
101
|
+
- index_season_selected (int): Season number
|
|
102
|
+
- scrape_serie (GetSerieInfo): Scraper object with series information
|
|
103
|
+
- video_source (VideoSource): Video source object
|
|
104
|
+
- download_all (bool): Whether to download all episodes
|
|
105
|
+
- episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
|
|
108
106
|
"""
|
|
109
|
-
|
|
110
|
-
scrape_serie.
|
|
111
|
-
|
|
112
|
-
# SPECIAL: Get season number
|
|
113
|
-
season = None
|
|
114
|
-
for s in scrape_serie.seasons_manager.seasons:
|
|
115
|
-
if s.number == index_season_selected:
|
|
116
|
-
season = s
|
|
117
|
-
break
|
|
118
|
-
episodes_count = len(season.episodes.episodes)
|
|
107
|
+
# Get episodes for the selected season
|
|
108
|
+
episodes = scrape_serie.getEpisodeSeasons(index_season_selected)
|
|
109
|
+
episodes_count = len(episodes)
|
|
119
110
|
|
|
120
|
-
if
|
|
111
|
+
if episodes_count == 0:
|
|
112
|
+
console.print(f"[red]No episodes found for season {index_season_selected}")
|
|
113
|
+
return
|
|
121
114
|
|
|
122
|
-
|
|
115
|
+
if download_all:
|
|
116
|
+
# Download all episodes in the season
|
|
123
117
|
for i_episode in range(1, episodes_count + 1):
|
|
124
118
|
path, stopped = download_video(index_season_selected, i_episode, scrape_serie, video_source)
|
|
125
119
|
|
|
@@ -129,16 +123,16 @@ def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, vid
|
|
|
129
123
|
console.print(f"\n[red]End downloaded [yellow]season: [red]{index_season_selected}.")
|
|
130
124
|
|
|
131
125
|
else:
|
|
132
|
-
|
|
133
126
|
# Display episodes list and manage user selection
|
|
134
|
-
|
|
127
|
+
if episode_selection is None:
|
|
128
|
+
last_command = display_episodes_list(episodes)
|
|
129
|
+
else:
|
|
130
|
+
last_command = episode_selection
|
|
131
|
+
console.print(f"\n[cyan]Using provided episode selection: [yellow]{episode_selection}")
|
|
132
|
+
|
|
133
|
+
# Validate the selection
|
|
135
134
|
list_episode_select = manage_selection(last_command, episodes_count)
|
|
136
|
-
|
|
137
|
-
try:
|
|
138
|
-
list_episode_select = validate_episode_selection(list_episode_select, episodes_count)
|
|
139
|
-
except ValueError as e:
|
|
140
|
-
console.print(f"[red]{str(e)}")
|
|
141
|
-
return
|
|
135
|
+
list_episode_select = validate_episode_selection(list_episode_select, episodes_count)
|
|
142
136
|
|
|
143
137
|
# Download selected episodes if not stopped
|
|
144
138
|
for i_episode in list_episode_select:
|
|
@@ -147,70 +141,65 @@ def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, vid
|
|
|
147
141
|
if stopped:
|
|
148
142
|
break
|
|
149
143
|
|
|
150
|
-
|
|
144
|
+
|
|
145
|
+
def download_series(select_season: MediaItem, season_selection: str = None, episode_selection: str = None) -> None:
|
|
151
146
|
"""
|
|
152
|
-
|
|
147
|
+
Handle downloading a complete series.
|
|
153
148
|
|
|
154
149
|
Parameters:
|
|
155
|
-
- select_season (MediaItem):
|
|
156
|
-
-
|
|
150
|
+
- select_season (MediaItem): Series metadata from search
|
|
151
|
+
- season_selection (str, optional): Pre-defined season selection that bypasses manual input
|
|
152
|
+
- episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
|
|
157
153
|
"""
|
|
158
|
-
if site_constant.TELEGRAM_BOT:
|
|
159
|
-
bot = get_bot_instance()
|
|
160
|
-
|
|
161
|
-
# Start message and set up video source
|
|
162
154
|
start_message()
|
|
163
155
|
|
|
164
156
|
# Init class
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
# Setup video source
|
|
169
|
-
scrape_serie.setup(select_season.id, select_season.slug)
|
|
170
|
-
video_source.setup(select_season.id)
|
|
157
|
+
video_source = VideoSource(site_constant.FULL_URL, True, select_season.id)
|
|
158
|
+
scrape_serie = GetSerieInfo(site_constant.FULL_URL, select_season.id, select_season.name)
|
|
171
159
|
|
|
172
|
-
# Collect information about
|
|
173
|
-
scrape_serie.
|
|
160
|
+
# Collect information about season
|
|
161
|
+
scrape_serie.getNumberSeason()
|
|
174
162
|
seasons_count = len(scrape_serie.seasons_manager)
|
|
175
163
|
|
|
164
|
+
if site_constant.TELEGRAM_BOT:
|
|
165
|
+
bot = get_bot_instance()
|
|
166
|
+
|
|
176
167
|
# Prompt user for season selection and download episodes
|
|
177
168
|
console.print(f"\n[green]Seasons found: [red]{seasons_count}")
|
|
178
169
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
170
|
+
# If season_selection is provided, use it instead of asking for input
|
|
171
|
+
if season_selection is None:
|
|
172
|
+
if site_constant.TELEGRAM_BOT:
|
|
173
|
+
console.print("\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
|
|
174
|
+
"[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")
|
|
175
|
+
|
|
176
|
+
bot.send_message(f"Stagioni trovate: {seasons_count}", None)
|
|
177
|
+
|
|
178
|
+
index_season_selected = bot.ask(
|
|
179
|
+
"select_title_episode",
|
|
180
|
+
"Menu di selezione delle stagioni\n\n"
|
|
181
|
+
"- Inserisci il numero della stagione (ad esempio, 1)\n"
|
|
182
|
+
"- Inserisci * per scaricare tutte le stagioni\n"
|
|
183
|
+
"- Inserisci un intervallo di stagioni (ad esempio, 1-2) per scaricare da una stagione all'altra\n"
|
|
184
|
+
"- Inserisci (ad esempio, 3-*) per scaricare dalla stagione specificata fino alla fine della serie",
|
|
185
|
+
None
|
|
186
|
+
)
|
|
194
187
|
|
|
188
|
+
else:
|
|
189
|
+
index_season_selected = msg.ask(
|
|
190
|
+
"\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
|
|
191
|
+
"[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"
|
|
192
|
+
)
|
|
195
193
|
else:
|
|
196
|
-
index_season_selected =
|
|
197
|
-
|
|
198
|
-
"[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"
|
|
199
|
-
)
|
|
194
|
+
index_season_selected = season_selection
|
|
195
|
+
console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
|
|
200
196
|
|
|
201
|
-
#
|
|
197
|
+
# Validate the selection
|
|
202
198
|
list_season_select = manage_selection(index_season_selected, seasons_count)
|
|
203
|
-
|
|
204
|
-
try:
|
|
205
|
-
list_season_select = validate_selection(list_season_select, seasons_count)
|
|
206
|
-
except ValueError as e:
|
|
207
|
-
console.print(f"[red]{str(e)}")
|
|
208
|
-
return
|
|
199
|
+
list_season_select = validate_selection(list_season_select, seasons_count)
|
|
209
200
|
|
|
210
201
|
# Loop through the selected seasons and download episodes
|
|
211
202
|
for i_season in list_season_select:
|
|
212
|
-
|
|
213
|
-
# SPECIAL: Get season number
|
|
214
203
|
season = None
|
|
215
204
|
for s in scrape_serie.seasons_manager.seasons:
|
|
216
205
|
if s.number == i_season:
|
|
@@ -219,13 +208,10 @@ def download_series(select_season: MediaItem) -> None:
|
|
|
219
208
|
season_number = season.number
|
|
220
209
|
|
|
221
210
|
if len(list_season_select) > 1 or index_season_selected == "*":
|
|
222
|
-
|
|
223
|
-
# Download all episodes if multiple seasons are selected or if '*' is used
|
|
224
211
|
download_episode(season_number, scrape_serie, video_source, download_all=True)
|
|
212
|
+
|
|
225
213
|
else:
|
|
226
|
-
|
|
227
|
-
# Otherwise, let the user select specific episodes for the single season
|
|
228
|
-
download_episode(season_number, scrape_serie, video_source, download_all=False)
|
|
214
|
+
download_episode(season_number, scrape_serie, video_source, download_all=False, episode_selection=episode_selection)
|
|
229
215
|
|
|
230
216
|
if site_constant.TELEGRAM_BOT:
|
|
231
217
|
bot.send_message(f"Finito di scaricare tutte le serie e episodi", None)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# 10.12.23
|
|
2
2
|
|
|
3
|
-
import sys
|
|
4
|
-
|
|
5
3
|
|
|
6
4
|
# External libraries
|
|
7
5
|
import httpx
|
|
@@ -47,7 +45,13 @@ def title_search(query: str) -> int:
|
|
|
47
45
|
console.print(f"[cyan]Search url: [yellow]{search_url}")
|
|
48
46
|
|
|
49
47
|
try:
|
|
50
|
-
response = httpx.get(
|
|
48
|
+
response = httpx.get(
|
|
49
|
+
search_url,
|
|
50
|
+
headers={'user-agent': get_userAgent()},
|
|
51
|
+
timeout=max_timeout,
|
|
52
|
+
follow_redirects=True,
|
|
53
|
+
verify=False
|
|
54
|
+
)
|
|
51
55
|
response.raise_for_status()
|
|
52
56
|
|
|
53
57
|
except Exception as e:
|
|
@@ -75,7 +79,7 @@ def title_search(query: str) -> int:
|
|
|
75
79
|
'name': dict_title.get('name'),
|
|
76
80
|
'type': dict_title.get('type'),
|
|
77
81
|
'date': dict_title.get('last_air_date'),
|
|
78
|
-
'
|
|
82
|
+
'image': f"{site_constant.FULL_URL.replace('stream', 'cdn.stream')}/images/{dict_title.get('images')[0].get('filename')}"
|
|
79
83
|
})
|
|
80
84
|
|
|
81
85
|
if site_constant.TELEGRAM_BOT:
|
|
@@ -20,31 +20,21 @@ max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class GetSerieInfo:
|
|
23
|
-
def __init__(self, url):
|
|
23
|
+
def __init__(self, url, media_id: int = None, series_name: str = None):
|
|
24
24
|
"""
|
|
25
25
|
Initialize the GetSerieInfo class for scraping TV series information.
|
|
26
26
|
|
|
27
27
|
Args:
|
|
28
28
|
- url (str): The URL of the streaming site.
|
|
29
|
+
- media_id (int, optional): Unique identifier for the media
|
|
30
|
+
- series_name (str, optional): Name of the TV series
|
|
29
31
|
"""
|
|
30
32
|
self.is_series = False
|
|
31
33
|
self.headers = {'user-agent': get_userAgent()}
|
|
32
34
|
self.url = url
|
|
33
|
-
|
|
34
|
-
# Initialize the SeasonManager
|
|
35
|
-
self.seasons_manager = SeasonManager()
|
|
36
|
-
|
|
37
|
-
def setup(self, media_id: int = None, series_name: str = None):
|
|
38
|
-
"""
|
|
39
|
-
Set up the scraper with specific media details.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
media_id (int, optional): Unique identifier for the media
|
|
43
|
-
series_name (str, optional): Name of the TV series
|
|
44
|
-
"""
|
|
45
35
|
self.media_id = media_id
|
|
36
|
+
self.seasons_manager = SeasonManager()
|
|
46
37
|
|
|
47
|
-
# If series name is provided, initialize series-specific properties
|
|
48
38
|
if series_name is not None:
|
|
49
39
|
self.is_series = True
|
|
50
40
|
self.series_name = series_name
|
|
@@ -127,4 +117,40 @@ class GetSerieInfo:
|
|
|
127
117
|
|
|
128
118
|
except Exception as e:
|
|
129
119
|
logging.error(f"Error collecting episodes for season {number_season}: {e}")
|
|
130
|
-
raise
|
|
120
|
+
raise
|
|
121
|
+
|
|
122
|
+
# ------------- FOR GUI -------------
|
|
123
|
+
def getNumberSeason(self) -> int:
|
|
124
|
+
"""
|
|
125
|
+
Get the total number of seasons available for the series.
|
|
126
|
+
"""
|
|
127
|
+
if not self.seasons_manager.seasons:
|
|
128
|
+
self.collect_info_title()
|
|
129
|
+
|
|
130
|
+
return len(self.seasons_manager.seasons)
|
|
131
|
+
|
|
132
|
+
def getEpisodeSeasons(self, season_number: int) -> list:
|
|
133
|
+
"""
|
|
134
|
+
Get all episodes for a specific season.
|
|
135
|
+
"""
|
|
136
|
+
season = self.seasons_manager.get_season_by_number(season_number)
|
|
137
|
+
|
|
138
|
+
if not season:
|
|
139
|
+
logging.error(f"Season {season_number} not found")
|
|
140
|
+
return []
|
|
141
|
+
|
|
142
|
+
if not season.episodes.episodes:
|
|
143
|
+
self.collect_info_season(season_number)
|
|
144
|
+
|
|
145
|
+
return season.episodes.episodes
|
|
146
|
+
|
|
147
|
+
def selectEpisode(self, season_number: int, episode_index: int) -> dict:
|
|
148
|
+
"""
|
|
149
|
+
Get information for a specific episode in a specific season.
|
|
150
|
+
"""
|
|
151
|
+
episodes = self.getEpisodeSeasons(season_number)
|
|
152
|
+
if not episodes or episode_index < 0 or episode_index >= len(episodes):
|
|
153
|
+
logging.error(f"Episode index {episode_index} is out of range for season {season_number}")
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
return episodes[episode_index]
|
|
@@ -10,7 +10,7 @@ from rich.console import Console
|
|
|
10
10
|
# Variable
|
|
11
11
|
console = Console()
|
|
12
12
|
available_colors = ['red', 'magenta', 'yellow', 'cyan', 'green', 'blue', 'white']
|
|
13
|
-
column_to_hide = ['Slug', 'Sub_ita', 'Last_air_date', 'Seasons_count', 'Url']
|
|
13
|
+
column_to_hide = ['Slug', 'Sub_ita', 'Last_air_date', 'Seasons_count', 'Url', 'Image', 'Path_id']
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
def get_select_title(table_show_manager, media_search_manager):
|
|
@@ -81,4 +81,4 @@ def get_select_title(table_show_manager, media_search_manager):
|
|
|
81
81
|
|
|
82
82
|
else:
|
|
83
83
|
console.print("\n[red]Wrong index")
|
|
84
|
-
sys.exit(0)
|
|
84
|
+
sys.exit(0)
|
|
@@ -514,7 +514,7 @@ class HLS_Downloader:
|
|
|
514
514
|
for item in self.download_manager.missing_segments:
|
|
515
515
|
if int(item['nFailed']) >= 1:
|
|
516
516
|
missing_ts = True
|
|
517
|
-
missing_info += f"[red]TS Failed: {item['nFailed']} {item['type']} tracks[/red]
|
|
517
|
+
missing_info += f"[red]TS Failed: {item['nFailed']} {item['type']} tracks[/red]"
|
|
518
518
|
|
|
519
519
|
file_size = internet_manager.format_file_size(os.path.getsize(self.path_manager.output_path))
|
|
520
520
|
duration = print_duration_table(self.path_manager.output_path, description=False, return_string=True)
|
|
@@ -23,7 +23,7 @@ from rich.console import Console
|
|
|
23
23
|
# Internal utilities
|
|
24
24
|
from StreamingCommunity.Util.color import Colors
|
|
25
25
|
from StreamingCommunity.Util.headers import get_userAgent
|
|
26
|
-
from StreamingCommunity.Util.config_json import config_manager
|
|
26
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
# Logic class
|
|
@@ -41,10 +41,9 @@ REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
|
|
|
41
41
|
DEFAULT_VIDEO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_video_workser')
|
|
42
42
|
DEFAULT_AUDIO_WORKERS = config_manager.get_int('M3U8_DOWNLOAD', 'default_audio_workser')
|
|
43
43
|
MAX_TIMEOOUT = config_manager.get_int("REQUESTS", "timeout")
|
|
44
|
-
MAX_INTERRUPT_COUNT = 3
|
|
45
44
|
SEGMENT_MAX_TIMEOUT = config_manager.get_int("M3U8_DOWNLOAD", "segment_timeout")
|
|
46
45
|
TELEGRAM_BOT = config_manager.get_bool('DEFAULT', 'telegram_bot')
|
|
47
|
-
|
|
46
|
+
MAX_INTERRUPT_COUNT = 3
|
|
48
47
|
|
|
49
48
|
# Variable
|
|
50
49
|
console = Console()
|
|
@@ -160,7 +159,7 @@ class M3U8_Segments:
|
|
|
160
159
|
if self.is_index_url:
|
|
161
160
|
try:
|
|
162
161
|
client_params = {'headers': {'User-Agent': get_userAgent()}, 'timeout': MAX_TIMEOOUT}
|
|
163
|
-
response = httpx.get(self.url, **client_params)
|
|
162
|
+
response = httpx.get(self.url, **client_params, follow_redirects=True)
|
|
164
163
|
response.raise_for_status()
|
|
165
164
|
|
|
166
165
|
self.parse_data(response.text)
|
|
@@ -408,20 +407,12 @@ class M3U8_Segments:
|
|
|
408
407
|
"""
|
|
409
408
|
Generate platform-appropriate progress bar format.
|
|
410
409
|
"""
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
else:
|
|
419
|
-
return (
|
|
420
|
-
f"{Colors.YELLOW}[HLS] {Colors.WHITE}({Colors.CYAN}{description}{Colors.WHITE}): "
|
|
421
|
-
f"{Colors.RED}{{percentage:.2f}}% "
|
|
422
|
-
f"{Colors.MAGENTA}{{bar}} "
|
|
423
|
-
f"{Colors.YELLOW}{{elapsed}}{Colors.WHITE} < {Colors.CYAN}{{remaining}}{Colors.WHITE}{{postfix}}{Colors.WHITE}"
|
|
424
|
-
)
|
|
410
|
+
return (
|
|
411
|
+
f"{Colors.YELLOW}[HLS] {Colors.WHITE}({Colors.CYAN}{description}{Colors.WHITE}): "
|
|
412
|
+
f"{Colors.RED}{{percentage:.2f}}% "
|
|
413
|
+
f"{Colors.MAGENTA}{{bar}} "
|
|
414
|
+
f"{Colors.YELLOW}{{elapsed}}{Colors.WHITE} < {Colors.CYAN}{{remaining}}{Colors.WHITE}{{postfix}}{Colors.WHITE}"
|
|
415
|
+
)
|
|
425
416
|
|
|
426
417
|
def _get_worker_count(self, stream_type: str) -> int:
|
|
427
418
|
"""
|
|
@@ -21,7 +21,7 @@ from rich.panel import Panel
|
|
|
21
21
|
from StreamingCommunity.Util.headers import get_userAgent
|
|
22
22
|
from StreamingCommunity.Util.color import Colors
|
|
23
23
|
from StreamingCommunity.Util.config_json import config_manager
|
|
24
|
-
from StreamingCommunity.Util.os import internet_manager
|
|
24
|
+
from StreamingCommunity.Util.os import internet_manager, os_manager
|
|
25
25
|
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
26
26
|
|
|
27
27
|
|
|
@@ -80,6 +80,7 @@ def MP4_downloader(url: str, path: str, referer: str = None, headers_: dict = No
|
|
|
80
80
|
bot = get_bot_instance()
|
|
81
81
|
console.log("####")
|
|
82
82
|
|
|
83
|
+
path = os_manager.get_sanitize_path(path)
|
|
83
84
|
if os.path.exists(path):
|
|
84
85
|
console.log("[red]Output file already exists.")
|
|
85
86
|
if TELEGRAM_BOT:
|
|
@@ -18,7 +18,7 @@ import qbittorrentapi
|
|
|
18
18
|
# Internal utilities
|
|
19
19
|
from StreamingCommunity.Util.color import Colors
|
|
20
20
|
from StreamingCommunity.Util.os import internet_manager
|
|
21
|
-
from StreamingCommunity.Util.config_json import config_manager
|
|
21
|
+
from StreamingCommunity.Util.config_json import config_manager
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
# Configuration
|
|
@@ -316,19 +316,12 @@ class TOR_downloader:
|
|
|
316
316
|
# Ensure the torrent is started
|
|
317
317
|
self.qb.torrents_resume(torrent_hashes=self.latest_torrent_hash)
|
|
318
318
|
|
|
319
|
-
# Configure progress bar display format
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
)
|
|
326
|
-
else:
|
|
327
|
-
bar_format = (
|
|
328
|
-
f"{Colors.YELLOW}Proc{Colors.WHITE}: "
|
|
329
|
-
f"{Colors.RED}{{percentage:.2f}}% {Colors.WHITE}| "
|
|
330
|
-
f"{Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
331
|
-
)
|
|
319
|
+
# Configure progress bar display format
|
|
320
|
+
bar_format = (
|
|
321
|
+
f"{Colors.YELLOW}[TOR] {Colors.WHITE}({Colors.CYAN}video{Colors.WHITE}): "
|
|
322
|
+
f"{Colors.RED}{{percentage:.2f}}% {Colors.MAGENTA}{{bar}} {Colors.WHITE}[ "
|
|
323
|
+
f"{Colors.YELLOW}{{elapsed}} {Colors.WHITE}< {Colors.CYAN}{{remaining}}{{postfix}} {Colors.WHITE}]"
|
|
324
|
+
)
|
|
332
325
|
|
|
333
326
|
# Initialize progress bar
|
|
334
327
|
with tqdm(
|
|
@@ -36,11 +36,7 @@ def capture_output(process: subprocess.Popen, description: str) -> None:
|
|
|
36
36
|
if not line:
|
|
37
37
|
continue
|
|
38
38
|
|
|
39
|
-
logging.info(f"
|
|
40
|
-
|
|
41
|
-
# Capture only error
|
|
42
|
-
if "rror" in str(line):
|
|
43
|
-
console.log(f"[red]FFMPEG: {str(line).strip()}")
|
|
39
|
+
logging.info(f"CAPTURE ffmpeg line: {line}")
|
|
44
40
|
|
|
45
41
|
# Check if termination is requested
|
|
46
42
|
if terminate_flag.is_set():
|