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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 11.03.24
|
|
2
|
+
|
|
3
|
+
# External library
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# Logic class
|
|
8
|
+
from .serie import download_episode
|
|
9
|
+
from .util.ScrapeSerie import ScrapeSerieAnime
|
|
10
|
+
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
11
|
+
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Player
|
|
15
|
+
from StreamingCommunity.Api.Player.vixcloud import VideoSourceAnime
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# Variable
|
|
19
|
+
console = Console()
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def download_film(select_title: MediaItem):
|
|
23
|
+
"""
|
|
24
|
+
Function to download a film.
|
|
25
|
+
|
|
26
|
+
Parameters:
|
|
27
|
+
- id_film (int): The ID of the film.
|
|
28
|
+
- title_name (str): The title of the film.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
# Init class
|
|
32
|
+
scrape_serie = ScrapeSerieAnime(site_constant.FULL_URL)
|
|
33
|
+
video_source = VideoSourceAnime(site_constant.FULL_URL)
|
|
34
|
+
|
|
35
|
+
# Set up video source (only configure scrape_serie now)
|
|
36
|
+
scrape_serie.setup(None, select_title.id, select_title.slug)
|
|
37
|
+
scrape_serie.is_series = False
|
|
38
|
+
|
|
39
|
+
# Start download
|
|
40
|
+
download_episode(0, scrape_serie, video_source)
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# 11.03.24
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from typing import Tuple
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# External library
|
|
8
|
+
from rich.console import Console
|
|
9
|
+
from rich.prompt import Prompt
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# Internal utilities
|
|
13
|
+
from StreamingCommunity.Util.os import os_manager
|
|
14
|
+
from StreamingCommunity.Util.message import start_message
|
|
15
|
+
from StreamingCommunity.Lib.Downloader import MP4_downloader
|
|
16
|
+
from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bot_instance
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Logic class
|
|
20
|
+
from .util.ScrapeSerie import ScrapeSerieAnime
|
|
21
|
+
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
22
|
+
from StreamingCommunity.Api.Template.Util import manage_selection, dynamic_format_number
|
|
23
|
+
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Player
|
|
27
|
+
from StreamingCommunity.Api.Player.vixcloud import VideoSourceAnime
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# Variable
|
|
31
|
+
console = Console()
|
|
32
|
+
msg = Prompt()
|
|
33
|
+
KILL_HANDLER = bool(False)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_source: VideoSourceAnime) -> Tuple[str,bool]:
|
|
37
|
+
"""
|
|
38
|
+
Downloads the selected episode.
|
|
39
|
+
|
|
40
|
+
Parameters:
|
|
41
|
+
- index_select (int): Index of the episode to download.
|
|
42
|
+
|
|
43
|
+
Return:
|
|
44
|
+
- str: output path
|
|
45
|
+
- bool: kill handler status
|
|
46
|
+
"""
|
|
47
|
+
start_message()
|
|
48
|
+
|
|
49
|
+
# Get episode information
|
|
50
|
+
obj_episode = scrape_serie.selectEpisode(1, index_select)
|
|
51
|
+
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]E{obj_episode.number}[/cyan]) \n")
|
|
52
|
+
|
|
53
|
+
if site_constant.TELEGRAM_BOT:
|
|
54
|
+
bot = get_bot_instance()
|
|
55
|
+
bot.send_message(f"Download in corso\nAnime: {scrape_serie.series_name}\nEpisodio: {obj_episode.number}", None)
|
|
56
|
+
|
|
57
|
+
# Get script_id and update it
|
|
58
|
+
script_id = TelegramSession.get_session()
|
|
59
|
+
if script_id != "unknown":
|
|
60
|
+
TelegramSession.updateScriptId(script_id, f"{scrape_serie.series_name} - E{obj_episode.number}")
|
|
61
|
+
|
|
62
|
+
# Collect mp4 url
|
|
63
|
+
video_source.get_embed(obj_episode.id)
|
|
64
|
+
|
|
65
|
+
# Create output path
|
|
66
|
+
mp4_name = f"{scrape_serie.series_name}_EP_{dynamic_format_number(str(obj_episode.number))}.mp4"
|
|
67
|
+
|
|
68
|
+
if scrape_serie.is_series:
|
|
69
|
+
mp4_path = os_manager.get_sanitize_path(os.path.join(site_constant.ANIME_FOLDER, scrape_serie.series_name))
|
|
70
|
+
else:
|
|
71
|
+
mp4_path = os_manager.get_sanitize_path(os.path.join(site_constant.MOVIE_FOLDER, scrape_serie.series_name))
|
|
72
|
+
|
|
73
|
+
# Create output folder
|
|
74
|
+
os_manager.create_path(mp4_path)
|
|
75
|
+
|
|
76
|
+
# Start downloading
|
|
77
|
+
path, kill_handler = MP4_downloader(
|
|
78
|
+
url=str(video_source.src_mp4).strip(),
|
|
79
|
+
path=os.path.join(mp4_path, mp4_name)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
return path, kill_handler
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def download_series(select_title: MediaItem, season_selection: str = None, episode_selection: str = None):
|
|
86
|
+
"""
|
|
87
|
+
Function to download episodes of a TV series.
|
|
88
|
+
|
|
89
|
+
Parameters:
|
|
90
|
+
- select_title (MediaItem): The selected media item
|
|
91
|
+
- season_selection (str, optional): Season selection input that bypasses manual input (usually '1' for anime)
|
|
92
|
+
- episode_selection (str, optional): Episode selection input that bypasses manual input
|
|
93
|
+
"""
|
|
94
|
+
start_message()
|
|
95
|
+
|
|
96
|
+
if site_constant.TELEGRAM_BOT:
|
|
97
|
+
bot = get_bot_instance()
|
|
98
|
+
|
|
99
|
+
scrape_serie = ScrapeSerieAnime(site_constant.FULL_URL)
|
|
100
|
+
video_source = VideoSourceAnime(site_constant.FULL_URL)
|
|
101
|
+
|
|
102
|
+
# Set up video source (only configure scrape_serie now)
|
|
103
|
+
scrape_serie.setup(None, select_title.id, select_title.slug)
|
|
104
|
+
|
|
105
|
+
# Get episode information
|
|
106
|
+
episoded_count = scrape_serie.get_count_episodes()
|
|
107
|
+
console.print(f"[green]Episodes count:[/green] [red]{episoded_count}[/red]")
|
|
108
|
+
|
|
109
|
+
# Telegram bot integration
|
|
110
|
+
if episode_selection is None:
|
|
111
|
+
if site_constant.TELEGRAM_BOT:
|
|
112
|
+
console.print(f"\n[cyan]Insert media [red]index [yellow]or [red]* [cyan]to download all media [yellow]or [red]1-2 [cyan]or [red]3-* [cyan]for a range of media")
|
|
113
|
+
bot.send_message(f"Episodi trovati: {episoded_count}", None)
|
|
114
|
+
|
|
115
|
+
last_command = bot.ask(
|
|
116
|
+
"select_title",
|
|
117
|
+
"Menu di selezione degli episodi: \n\n"
|
|
118
|
+
"- Inserisci il numero dell'episodio (ad esempio, 1)\n"
|
|
119
|
+
"- Inserisci * per scaricare tutti gli episodi\n"
|
|
120
|
+
"- Inserisci un intervallo di episodi (ad esempio, 1-2) per scaricare da un episodio all'altro\n"
|
|
121
|
+
"- Inserisci (ad esempio, 3-*) per scaricare dall'episodio specificato fino alla fine della serie",
|
|
122
|
+
None
|
|
123
|
+
)
|
|
124
|
+
else:
|
|
125
|
+
# Prompt user to select an episode index
|
|
126
|
+
last_command = msg.ask("\n[cyan]Insert media [red]index [yellow]or [red]* [cyan]to download all media [yellow]or [red]1-2 [cyan]or [red]3-* [cyan]for a range of media")
|
|
127
|
+
else:
|
|
128
|
+
last_command = episode_selection
|
|
129
|
+
console.print(f"\n[cyan]Using provided episode selection: [yellow]{episode_selection}")
|
|
130
|
+
|
|
131
|
+
# Manage user selection
|
|
132
|
+
list_episode_select = manage_selection(last_command, episoded_count)
|
|
133
|
+
|
|
134
|
+
# Download selected episodes
|
|
135
|
+
if len(list_episode_select) == 1 and last_command != "*":
|
|
136
|
+
path, _ = download_episode(list_episode_select[0]-1, scrape_serie, video_source)
|
|
137
|
+
return path
|
|
138
|
+
|
|
139
|
+
# Download all other episodes selected
|
|
140
|
+
else:
|
|
141
|
+
kill_handler = False
|
|
142
|
+
for i_episode in list_episode_select:
|
|
143
|
+
if kill_handler:
|
|
144
|
+
break
|
|
145
|
+
_, kill_handler = download_episode(i_episode-1, scrape_serie, video_source)
|
|
146
|
+
|
|
147
|
+
if site_constant.TELEGRAM_BOT:
|
|
148
|
+
bot.send_message(f"Finito di scaricare tutte le serie e episodi", None)
|
|
149
|
+
|
|
150
|
+
# Get script_id
|
|
151
|
+
script_id = TelegramSession.get_session()
|
|
152
|
+
if script_id != "unknown":
|
|
153
|
+
TelegramSession.deleteScriptId(script_id)
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# 10.12.23
|
|
2
2
|
|
|
3
|
-
import sys
|
|
4
3
|
import logging
|
|
5
4
|
|
|
6
5
|
|
|
@@ -52,10 +51,8 @@ def get_token() -> dict:
|
|
|
52
51
|
|
|
53
52
|
for html_meta in soup.find_all("meta"):
|
|
54
53
|
if html_meta.get('name') == "csrf-token":
|
|
55
|
-
|
|
56
54
|
find_csrf_token = html_meta.get('content')
|
|
57
55
|
|
|
58
|
-
logging.info(f"Extract: ('animeunity_session': {response.cookies['animeunity_session']}, 'csrf_token': {find_csrf_token})")
|
|
59
56
|
return {
|
|
60
57
|
'animeunity_session': response.cookies['animeunity_session'],
|
|
61
58
|
'csrf_token': find_csrf_token
|
|
@@ -65,9 +62,6 @@ def get_token() -> dict:
|
|
|
65
62
|
def get_real_title(record):
|
|
66
63
|
"""
|
|
67
64
|
Get the real title from a record.
|
|
68
|
-
|
|
69
|
-
This function takes a record, which is assumed to be a dictionary representing a row of JSON data.
|
|
70
|
-
It looks for a title in the record, prioritizing English over Italian titles if available.
|
|
71
65
|
|
|
72
66
|
Parameters:
|
|
73
67
|
- record (dict): A dictionary representing a row of JSON data.
|
|
@@ -85,7 +79,7 @@ def get_real_title(record):
|
|
|
85
79
|
|
|
86
80
|
def title_search(query: str) -> int:
|
|
87
81
|
"""
|
|
88
|
-
Function to perform an anime search using
|
|
82
|
+
Function to perform an anime search using both APIs and combine results.
|
|
89
83
|
|
|
90
84
|
Parameters:
|
|
91
85
|
- query (str): The query to search for.
|
|
@@ -98,63 +92,96 @@ def title_search(query: str) -> int:
|
|
|
98
92
|
|
|
99
93
|
media_search_manager.clear()
|
|
100
94
|
table_show_manager.clear()
|
|
95
|
+
seen_titles = set()
|
|
96
|
+
choices = [] if site_constant.TELEGRAM_BOT else None
|
|
101
97
|
|
|
102
98
|
# Create parameter for request
|
|
103
99
|
data = get_token()
|
|
104
|
-
cookies = {
|
|
100
|
+
cookies = {
|
|
101
|
+
'animeunity_session': data.get('animeunity_session')
|
|
102
|
+
}
|
|
105
103
|
headers = {
|
|
106
104
|
'user-agent': get_userAgent(),
|
|
107
105
|
'x-csrf-token': data.get('csrf_token')
|
|
108
106
|
}
|
|
109
|
-
json_data = {'title': query}
|
|
110
107
|
|
|
111
|
-
#
|
|
108
|
+
# First API call - livesearch
|
|
109
|
+
try:
|
|
110
|
+
response1 = httpx.post(
|
|
111
|
+
f'{site_constant.FULL_URL}/livesearch',
|
|
112
|
+
cookies=cookies,
|
|
113
|
+
headers=headers,
|
|
114
|
+
json={'title': query},
|
|
115
|
+
timeout=max_timeout
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
response1.raise_for_status()
|
|
119
|
+
process_results(response1.json()['records'], seen_titles, media_search_manager, choices)
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
console.print(f"Site: {site_constant.SITE_NAME}, livesearch error: {e}")
|
|
123
|
+
|
|
124
|
+
# Second API call - archivio
|
|
112
125
|
try:
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
126
|
+
json_data = {
|
|
127
|
+
'title': query,
|
|
128
|
+
'type': False,
|
|
129
|
+
'year': False,
|
|
130
|
+
'order': 'Lista A-Z',
|
|
131
|
+
'status': False,
|
|
132
|
+
'genres': False,
|
|
133
|
+
'offset': 0,
|
|
134
|
+
'dubbed': False,
|
|
135
|
+
'season': False
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
response2 = httpx.post(
|
|
139
|
+
f'{site_constant.FULL_URL}/archivio/get-animes',
|
|
140
|
+
cookies=cookies,
|
|
141
|
+
headers=headers,
|
|
117
142
|
json=json_data,
|
|
118
143
|
timeout=max_timeout
|
|
119
144
|
)
|
|
120
|
-
|
|
145
|
+
|
|
146
|
+
response2.raise_for_status()
|
|
147
|
+
process_results(response2.json()['records'], seen_titles, media_search_manager, choices)
|
|
121
148
|
|
|
122
149
|
except Exception as e:
|
|
123
|
-
console.print(f"Site: {site_constant.SITE_NAME},
|
|
124
|
-
return 0
|
|
150
|
+
console.print(f"Site: {site_constant.SITE_NAME}, archivio search error: {e}")
|
|
125
151
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
152
|
+
if site_constant.TELEGRAM_BOT and choices and len(choices) > 0:
|
|
153
|
+
bot.send_message(f"Lista dei risultati:", choices)
|
|
154
|
+
|
|
155
|
+
result_count = media_search_manager.get_length()
|
|
156
|
+
if result_count == 0:
|
|
157
|
+
console.print(f"Nothing matching was found for: {query}")
|
|
158
|
+
|
|
159
|
+
return result_count
|
|
129
160
|
|
|
130
|
-
|
|
161
|
+
def process_results(records: list, seen_titles: set, media_manager: MediaManager, choices: list = None) -> None:
|
|
162
|
+
"""Helper function to process search results and add unique entries."""
|
|
163
|
+
for dict_title in records:
|
|
131
164
|
try:
|
|
132
|
-
|
|
133
|
-
|
|
165
|
+
title_id = dict_title.get('id')
|
|
166
|
+
if title_id in seen_titles:
|
|
167
|
+
continue
|
|
168
|
+
|
|
169
|
+
seen_titles.add(title_id)
|
|
134
170
|
dict_title['name'] = get_real_title(dict_title)
|
|
135
171
|
|
|
136
|
-
|
|
137
|
-
'id':
|
|
172
|
+
media_manager.add_media({
|
|
173
|
+
'id': title_id,
|
|
138
174
|
'slug': dict_title.get('slug'),
|
|
139
175
|
'name': dict_title.get('name'),
|
|
140
176
|
'type': dict_title.get('type'),
|
|
141
177
|
'status': dict_title.get('status'),
|
|
142
178
|
'episodes_count': dict_title.get('episodes_count'),
|
|
143
|
-
'
|
|
179
|
+
'image': dict_title.get('imageurl')
|
|
144
180
|
})
|
|
145
181
|
|
|
146
|
-
if
|
|
147
|
-
|
|
148
|
-
# Crea una stringa formattata per ogni scelta con numero
|
|
182
|
+
if choices is not None:
|
|
149
183
|
choice_text = f"{len(choices)} - {dict_title.get('name')} ({dict_title.get('type')}) - Episodi: {dict_title.get('episodes_count')}"
|
|
150
184
|
choices.append(choice_text)
|
|
151
185
|
|
|
152
186
|
except Exception as e:
|
|
153
|
-
print(f"Error parsing a
|
|
154
|
-
|
|
155
|
-
if site_constant.TELEGRAM_BOT:
|
|
156
|
-
if choices:
|
|
157
|
-
bot.send_message(f"Lista dei risultati:", choices)
|
|
158
|
-
|
|
159
|
-
# Return the length of media search manager
|
|
160
|
-
return media_search_manager.get_length()
|
|
187
|
+
print(f"Error parsing a title entry: {e}")
|
|
@@ -29,6 +29,7 @@ class ScrapeSerieAnime:
|
|
|
29
29
|
self.is_series = False
|
|
30
30
|
self.headers = {'user-agent': get_userAgent()}
|
|
31
31
|
self.url = url
|
|
32
|
+
self.episodes_cache = None
|
|
32
33
|
|
|
33
34
|
def setup(self, version: str = None, media_id: int = None, series_name: str = None):
|
|
34
35
|
self.version = version
|
|
@@ -62,35 +63,53 @@ class ScrapeSerieAnime:
|
|
|
62
63
|
logging.error(f"Error fetching episode count: {e}")
|
|
63
64
|
return None
|
|
64
65
|
|
|
65
|
-
def
|
|
66
|
+
def _fetch_all_episodes(self):
|
|
66
67
|
"""
|
|
67
|
-
Fetch
|
|
68
|
-
|
|
69
|
-
Args:
|
|
70
|
-
index_ep (int): Zero-based index of the target episode
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
Episode: Detailed episode information
|
|
68
|
+
Fetch all episodes data at once and cache it
|
|
74
69
|
"""
|
|
75
70
|
try:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"end_range": index_ep + 1
|
|
80
|
-
}
|
|
71
|
+
count = self.get_count_episodes()
|
|
72
|
+
if not count:
|
|
73
|
+
return
|
|
81
74
|
|
|
82
75
|
response = httpx.get(
|
|
83
|
-
url=f"{self.url}/info_api/{self.media_id}/
|
|
84
|
-
|
|
85
|
-
|
|
76
|
+
url=f"{self.url}/info_api/{self.media_id}/1",
|
|
77
|
+
params={
|
|
78
|
+
"start_range": 1,
|
|
79
|
+
"end_range": count
|
|
80
|
+
},
|
|
81
|
+
headers=self.headers,
|
|
86
82
|
timeout=max_timeout
|
|
87
83
|
)
|
|
88
84
|
response.raise_for_status()
|
|
85
|
+
|
|
86
|
+
self.episodes_cache = response.json()["episodes"]
|
|
87
|
+
except Exception as e:
|
|
88
|
+
logging.error(f"Error fetching all episodes: {e}")
|
|
89
|
+
self.episodes_cache = None
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
def get_info_episode(self, index_ep: int) -> Episode:
|
|
92
|
+
"""
|
|
93
|
+
Get episode info from cache
|
|
94
|
+
"""
|
|
95
|
+
if self.episodes_cache is None:
|
|
96
|
+
self._fetch_all_episodes()
|
|
97
|
+
|
|
98
|
+
if self.episodes_cache and 0 <= index_ep < len(self.episodes_cache):
|
|
99
|
+
return Episode(self.episodes_cache[index_ep])
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# ------------- FOR GUI -------------
|
|
104
|
+
def getNumberSeason(self) -> int:
|
|
105
|
+
"""
|
|
106
|
+
Get the total number of seasons available for the anime.
|
|
107
|
+
Note: AnimeUnity typically doesn't have seasons, so returns 1.
|
|
108
|
+
"""
|
|
109
|
+
return 1
|
|
93
110
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
111
|
+
def selectEpisode(self, season_number: int = 1, episode_index: int = 0) -> Episode:
|
|
112
|
+
"""
|
|
113
|
+
Get information for a specific episode.
|
|
114
|
+
"""
|
|
115
|
+
return self.get_info_episode(episode_index)
|
|
@@ -14,13 +14,13 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
|
14
14
|
# Logic class
|
|
15
15
|
from .site import title_search, media_search_manager, table_show_manager
|
|
16
16
|
from .serie import download_series
|
|
17
|
+
from .film import download_film
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
# Variable
|
|
20
21
|
indice = 8
|
|
21
22
|
_useFor = "anime"
|
|
22
|
-
|
|
23
|
-
_priority = 2
|
|
23
|
+
_priority = 0
|
|
24
24
|
_engineDownload = "mp4"
|
|
25
25
|
|
|
26
26
|
msg = Prompt()
|
|
@@ -28,44 +28,56 @@ console = Console()
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
|
|
31
|
-
def process_search_result(select_title):
|
|
31
|
+
def process_search_result(select_title, selections=None):
|
|
32
32
|
"""
|
|
33
33
|
Handles the search result and initiates the download for either a film or series.
|
|
34
|
+
|
|
35
|
+
Parameters:
|
|
36
|
+
select_title (MediaItem): The selected media item
|
|
37
|
+
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
38
|
+
{'season': season_selection, 'episode': episode_selection}
|
|
34
39
|
"""
|
|
35
40
|
if select_title.type == "TV":
|
|
36
|
-
|
|
41
|
+
episode_selection = None
|
|
42
|
+
if selections:
|
|
43
|
+
episode_selection = selections.get('episode')
|
|
44
|
+
download_series(select_title, episode_selection)
|
|
45
|
+
|
|
46
|
+
else:
|
|
47
|
+
download_film(select_title)
|
|
37
48
|
|
|
38
|
-
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
|
49
|
+
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
39
50
|
"""
|
|
40
|
-
Main function of the application for search
|
|
51
|
+
Main function of the application for search.
|
|
41
52
|
|
|
42
53
|
Parameters:
|
|
43
54
|
string_to_search (str, optional): String to search for
|
|
44
55
|
get_onlyDatabase (bool, optional): If True, return only the database object
|
|
45
56
|
direct_item (dict, optional): Direct item to process (bypass search)
|
|
57
|
+
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
58
|
+
{'season': season_selection, 'episode': episode_selection}
|
|
46
59
|
"""
|
|
47
60
|
if direct_item:
|
|
48
61
|
select_title = MediaItem(**direct_item)
|
|
49
|
-
process_search_result(select_title)
|
|
62
|
+
process_search_result(select_title, selections)
|
|
50
63
|
return
|
|
51
64
|
|
|
52
65
|
# Get the user input for the search term
|
|
53
|
-
string_to_search
|
|
66
|
+
if string_to_search is None:
|
|
67
|
+
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
54
68
|
|
|
55
69
|
# Perform the database search
|
|
56
70
|
len_database = title_search(string_to_search)
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
# If only the database is needed, return the manager
|
|
59
73
|
if get_onlyDatabase:
|
|
60
74
|
return media_search_manager
|
|
61
75
|
|
|
62
76
|
if len_database > 0:
|
|
63
77
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
|
64
|
-
process_search_result(select_title)
|
|
65
|
-
|
|
78
|
+
process_search_result(select_title, selections)
|
|
79
|
+
|
|
66
80
|
else:
|
|
67
|
-
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
68
|
-
|
|
69
81
|
# If no results are found, ask again
|
|
70
|
-
|
|
82
|
+
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
71
83
|
search()
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 11.03.24
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# External library
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Internal utilities
|
|
10
|
+
from StreamingCommunity.Util.os import os_manager
|
|
11
|
+
from StreamingCommunity.Util.message import start_message
|
|
12
|
+
from StreamingCommunity.Lib.Downloader import MP4_downloader
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Logic class
|
|
16
|
+
from .util.ScrapeSerie import ScrapSerie
|
|
17
|
+
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
18
|
+
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# Player
|
|
22
|
+
from StreamingCommunity.Api.Player.sweetpixel import VideoSource
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# Variable
|
|
26
|
+
console = Console()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def download_film(select_title: MediaItem):
|
|
30
|
+
"""
|
|
31
|
+
Function to download a film.
|
|
32
|
+
|
|
33
|
+
Parameters:
|
|
34
|
+
- id_film (int): The ID of the film.
|
|
35
|
+
- title_name (str): The title of the film.
|
|
36
|
+
"""
|
|
37
|
+
start_message()
|
|
38
|
+
|
|
39
|
+
scrape_serie = ScrapSerie(select_title.url, site_constant.FULL_URL)
|
|
40
|
+
episodes = scrape_serie.get_episodes()
|
|
41
|
+
|
|
42
|
+
# Get episode information
|
|
43
|
+
episode_data = episodes[0]
|
|
44
|
+
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]{scrape_serie.get_name()}[/cyan]) \n")
|
|
45
|
+
|
|
46
|
+
# Define filename and path for the downloaded video
|
|
47
|
+
mp4_name = f"{scrape_serie.get_name()}.mp4"
|
|
48
|
+
mp4_path = os.path.join(site_constant.ANIME_FOLDER, scrape_serie.get_name())
|
|
49
|
+
|
|
50
|
+
# Create output folder
|
|
51
|
+
os_manager.create_path(mp4_path)
|
|
52
|
+
|
|
53
|
+
# Get video source for the episode
|
|
54
|
+
video_source = VideoSource(site_constant.FULL_URL, episode_data, scrape_serie.session_id, scrape_serie.csrf_token)
|
|
55
|
+
mp4_link = video_source.get_playlist()
|
|
56
|
+
|
|
57
|
+
# Start downloading
|
|
58
|
+
path, kill_handler = MP4_downloader(
|
|
59
|
+
url=str(mp4_link).strip(),
|
|
60
|
+
path=os.path.join(mp4_path, mp4_name)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return path, kill_handler
|