StreamingCommunity 2.9.8__py3-none-any.whl → 2.9.9__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 +1 -1
- StreamingCommunity/Api/Site/altadefinizione/__init__.py +23 -7
- StreamingCommunity/Api/Site/altadefinizione/film.py +0 -1
- StreamingCommunity/Api/Site/altadefinizione/series.py +66 -70
- StreamingCommunity/Api/Site/altadefinizione/site.py +2 -1
- StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +37 -2
- StreamingCommunity/Api/Site/animeunity/__init__.py +29 -10
- StreamingCommunity/Api/Site/animeunity/film.py +40 -0
- StreamingCommunity/Api/Site/animeunity/serie.py +153 -0
- StreamingCommunity/Api/Site/animeunity/site.py +1 -2
- StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +15 -0
- StreamingCommunity/Api/Site/animeworld/__init__.py +25 -12
- StreamingCommunity/Api/Site/animeworld/film.py +63 -0
- StreamingCommunity/Api/Site/animeworld/serie.py +25 -22
- StreamingCommunity/Api/Site/animeworld/site.py +2 -1
- StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +32 -5
- StreamingCommunity/Api/Site/cb01new/__init__.py +1 -1
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +1 -1
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +31 -32
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +2 -2
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +30 -2
- StreamingCommunity/Api/Site/guardaserie/__init__.py +21 -7
- StreamingCommunity/Api/Site/guardaserie/series.py +55 -53
- StreamingCommunity/Api/Site/guardaserie/site.py +3 -2
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +27 -1
- StreamingCommunity/Api/Site/raiplay/__init__.py +93 -0
- StreamingCommunity/Api/Site/raiplay/film.py +65 -0
- StreamingCommunity/Api/Site/raiplay/series.py +162 -0
- StreamingCommunity/Api/Site/raiplay/site.py +166 -0
- StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +127 -0
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +29 -22
- StreamingCommunity/Api/Site/streamingcommunity/film.py +1 -2
- StreamingCommunity/Api/Site/streamingcommunity/series.py +76 -90
- StreamingCommunity/Api/Site/streamingcommunity/site.py +1 -3
- 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 +2 -3
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +2 -1
- StreamingCommunity/Lib/FFmpeg/util.py +47 -17
- StreamingCommunity/Lib/M3U8/estimator.py +50 -21
- StreamingCommunity/Lib/M3U8/parser.py +26 -6
- StreamingCommunity/Upload/update.py +22 -3
- StreamingCommunity/Upload/version.py +1 -1
- StreamingCommunity/Util/table.py +4 -2
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-2.9.9.dist-info}/METADATA +1 -1
- streamingcommunity-2.9.9.dist-info/RECORD +91 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-2.9.9.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-2.9.9.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-2.9.9.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-2.9.8.dist-info → streamingcommunity-2.9.9.dist-info}/top_level.txt +0 -0
|
@@ -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
|
|
|
@@ -140,7 +139,7 @@ def title_search(query: str) -> int:
|
|
|
140
139
|
'type': dict_title.get('type'),
|
|
141
140
|
'status': dict_title.get('status'),
|
|
142
141
|
'episodes_count': dict_title.get('episodes_count'),
|
|
143
|
-
'
|
|
142
|
+
'image': dict_title.get('imageurl')
|
|
144
143
|
})
|
|
145
144
|
|
|
146
145
|
if site_constant.TELEGRAM_BOT:
|
|
@@ -94,3 +94,18 @@ class ScrapeSerieAnime:
|
|
|
94
94
|
except Exception as e:
|
|
95
95
|
logging.error(f"Error fetching episode information: {e}")
|
|
96
96
|
return None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# ------------- FOR GUI -------------
|
|
100
|
+
def getNumberSeason(self) -> int:
|
|
101
|
+
"""
|
|
102
|
+
Get the total number of seasons available for the anime.
|
|
103
|
+
Note: AnimeUnity typically doesn't have seasons, so returns 1.
|
|
104
|
+
"""
|
|
105
|
+
return 1
|
|
106
|
+
|
|
107
|
+
def selectEpisode(self, season_number: int = 1, episode_index: int = 0) -> Episode:
|
|
108
|
+
"""
|
|
109
|
+
Get information for a specific episode.
|
|
110
|
+
"""
|
|
111
|
+
return self.get_info_episode(episode_index)
|
|
@@ -14,6 +14,7 @@ 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
|
|
@@ -28,44 +29,56 @@ console = Console()
|
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
def process_search_result(select_title):
|
|
32
|
+
def process_search_result(select_title, selections=None):
|
|
32
33
|
"""
|
|
33
34
|
Handles the search result and initiates the download for either a film or series.
|
|
35
|
+
|
|
36
|
+
Parameters:
|
|
37
|
+
select_title (MediaItem): The selected media item
|
|
38
|
+
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
39
|
+
{'season': season_selection, 'episode': episode_selection}
|
|
34
40
|
"""
|
|
35
41
|
if select_title.type == "TV":
|
|
36
|
-
|
|
42
|
+
episode_selection = None
|
|
43
|
+
if selections:
|
|
44
|
+
episode_selection = selections.get('episode')
|
|
45
|
+
download_series(select_title, episode_selection)
|
|
46
|
+
|
|
47
|
+
else:
|
|
48
|
+
download_film(select_title)
|
|
37
49
|
|
|
38
|
-
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
|
50
|
+
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
39
51
|
"""
|
|
40
|
-
Main function of the application for search
|
|
52
|
+
Main function of the application for search.
|
|
41
53
|
|
|
42
54
|
Parameters:
|
|
43
55
|
string_to_search (str, optional): String to search for
|
|
44
56
|
get_onlyDatabase (bool, optional): If True, return only the database object
|
|
45
57
|
direct_item (dict, optional): Direct item to process (bypass search)
|
|
58
|
+
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
59
|
+
{'season': season_selection, 'episode': episode_selection}
|
|
46
60
|
"""
|
|
47
61
|
if direct_item:
|
|
48
62
|
select_title = MediaItem(**direct_item)
|
|
49
|
-
process_search_result(select_title)
|
|
63
|
+
process_search_result(select_title, selections)
|
|
50
64
|
return
|
|
51
65
|
|
|
52
66
|
# Get the user input for the search term
|
|
53
|
-
string_to_search
|
|
67
|
+
if string_to_search is None:
|
|
68
|
+
string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
54
69
|
|
|
55
70
|
# Perform the database search
|
|
56
71
|
len_database = title_search(string_to_search)
|
|
57
72
|
|
|
58
|
-
|
|
73
|
+
# If only the database is needed, return the manager
|
|
59
74
|
if get_onlyDatabase:
|
|
60
75
|
return media_search_manager
|
|
61
76
|
|
|
62
77
|
if len_database > 0:
|
|
63
78
|
select_title = get_select_title(table_show_manager, media_search_manager)
|
|
64
|
-
process_search_result(select_title)
|
|
65
|
-
|
|
79
|
+
process_search_result(select_title, selections)
|
|
80
|
+
|
|
66
81
|
else:
|
|
67
|
-
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
68
|
-
|
|
69
82
|
# If no results are found, ask again
|
|
70
|
-
|
|
83
|
+
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
|
|
71
84
|
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
|
|
@@ -19,12 +19,12 @@ from StreamingCommunity.Lib.Downloader import MP4_downloader
|
|
|
19
19
|
# Logic class
|
|
20
20
|
from .util.ScrapeSerie import ScrapSerie
|
|
21
21
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
22
|
-
from StreamingCommunity.Api.Template.Util import manage_selection, dynamic_format_number
|
|
22
|
+
from StreamingCommunity.Api.Template.Util import manage_selection, dynamic_format_number
|
|
23
23
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
# Player
|
|
27
|
-
from StreamingCommunity.Api.Player.sweetpixel import
|
|
27
|
+
from StreamingCommunity.Api.Player.sweetpixel import VideoSource
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
# Variable
|
|
@@ -33,8 +33,7 @@ msg = Prompt()
|
|
|
33
33
|
KILL_HANDLER = bool(False)
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
def download_episode(index_select: int, scrape_serie: ScrapSerie, episodes) -> Tuple[str,bool]:
|
|
36
|
+
def download_episode(index_select: int, scrape_serie: ScrapSerie) -> Tuple[str,bool]:
|
|
38
37
|
"""
|
|
39
38
|
Downloads the selected episode.
|
|
40
39
|
|
|
@@ -47,7 +46,8 @@ def download_episode(index_select: int, scrape_serie: ScrapSerie, episodes) -> T
|
|
|
47
46
|
"""
|
|
48
47
|
start_message()
|
|
49
48
|
|
|
50
|
-
# Get information
|
|
49
|
+
# Get episode information
|
|
50
|
+
episode_data = scrape_serie.selectEpisode(1, index_select)
|
|
51
51
|
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]E{index_select+1}[/cyan]) \n")
|
|
52
52
|
|
|
53
53
|
# Define filename and path for the downloaded video
|
|
@@ -57,9 +57,9 @@ def download_episode(index_select: int, scrape_serie: ScrapSerie, episodes) -> T
|
|
|
57
57
|
# Create output folder
|
|
58
58
|
os_manager.create_path(mp4_path)
|
|
59
59
|
|
|
60
|
-
#
|
|
61
|
-
video_source =
|
|
62
|
-
mp4_link = video_source.
|
|
60
|
+
# Get video source for the episode
|
|
61
|
+
video_source = VideoSource(site_constant.FULL_URL, episode_data, scrape_serie.session_id, scrape_serie.csrf_token)
|
|
62
|
+
mp4_link = video_source.get_playlist()
|
|
63
63
|
|
|
64
64
|
# Start downloading
|
|
65
65
|
path, kill_handler = MP4_downloader(
|
|
@@ -70,38 +70,41 @@ def download_episode(index_select: int, scrape_serie: ScrapSerie, episodes) -> T
|
|
|
70
70
|
return path, kill_handler
|
|
71
71
|
|
|
72
72
|
|
|
73
|
-
def download_series(select_title: MediaItem):
|
|
73
|
+
def download_series(select_title: MediaItem, episode_selection: str = None):
|
|
74
74
|
"""
|
|
75
75
|
Function to download episodes of a TV series.
|
|
76
76
|
|
|
77
77
|
Parameters:
|
|
78
|
-
-
|
|
79
|
-
-
|
|
78
|
+
- select_title (MediaItem): The selected media item
|
|
79
|
+
- episode_selection (str, optional): Episode selection input that bypasses manual input
|
|
80
80
|
"""
|
|
81
81
|
start_message()
|
|
82
82
|
|
|
83
|
+
# Create scrap instance
|
|
83
84
|
scrape_serie = ScrapSerie(select_title.url, site_constant.FULL_URL)
|
|
85
|
+
episodes = scrape_serie.get_episodes()
|
|
84
86
|
|
|
85
|
-
# Get
|
|
86
|
-
|
|
87
|
-
episoded_count = len(episodes)
|
|
88
|
-
console.print(f"[cyan]Episodes find: [red]{episoded_count}")
|
|
87
|
+
# Get episode count
|
|
88
|
+
console.print(f"[green]Episodes found:[/green] [red]{len(episodes)}[/red]")
|
|
89
89
|
|
|
90
|
-
#
|
|
91
|
-
|
|
90
|
+
# Display episodes list and get user selection
|
|
91
|
+
if episode_selection is None:
|
|
92
|
+
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")
|
|
93
|
+
else:
|
|
94
|
+
last_command = episode_selection
|
|
95
|
+
console.print(f"\n[cyan]Using provided episode selection: [yellow]{episode_selection}")
|
|
92
96
|
|
|
93
|
-
|
|
94
|
-
list_episode_select = manage_selection(last_command, episoded_count)
|
|
97
|
+
list_episode_select = manage_selection(last_command, len(episodes))
|
|
95
98
|
|
|
96
99
|
# Download selected episodes
|
|
97
100
|
if len(list_episode_select) == 1 and last_command != "*":
|
|
98
|
-
path, _ = download_episode(list_episode_select[0]-1, scrape_serie
|
|
101
|
+
path, _ = download_episode(list_episode_select[0]-1, scrape_serie)
|
|
99
102
|
return path
|
|
100
103
|
|
|
101
|
-
# Download all
|
|
104
|
+
# Download all selected episodes
|
|
102
105
|
else:
|
|
103
106
|
kill_handler = False
|
|
104
107
|
for i_episode in list_episode_select:
|
|
105
108
|
if kill_handler:
|
|
106
109
|
break
|
|
107
|
-
_, kill_handler = download_episode(i_episode-1, scrape_serie
|
|
110
|
+
_, kill_handler = download_episode(i_episode-1, scrape_serie)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# 21.03.25
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
|
|
4
5
|
# External libraries
|
|
5
6
|
import httpx
|
|
@@ -14,7 +15,7 @@ from StreamingCommunity.Util.os import os_manager
|
|
|
14
15
|
|
|
15
16
|
# Player
|
|
16
17
|
from ..site import get_session_and_csrf
|
|
17
|
-
from StreamingCommunity.Api.Player.sweetpixel import
|
|
18
|
+
from StreamingCommunity.Api.Player.sweetpixel import VideoSource
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
# Variable
|
|
@@ -40,7 +41,6 @@ class ScrapSerie:
|
|
|
40
41
|
except:
|
|
41
42
|
raise Exception(f"Failed to retrieve anime page.")
|
|
42
43
|
|
|
43
|
-
|
|
44
44
|
def get_name(self):
|
|
45
45
|
"""Extract and return the name of the anime series."""
|
|
46
46
|
soup = BeautifulSoup(self.response.content, "html.parser")
|
|
@@ -68,12 +68,39 @@ class ScrapSerie:
|
|
|
68
68
|
return episodes
|
|
69
69
|
|
|
70
70
|
def get_episode(self, index):
|
|
71
|
-
"""Fetch a specific episode based on the index, and return an
|
|
71
|
+
"""Fetch a specific episode based on the index, and return an VideoSource instance."""
|
|
72
72
|
episodes = self.get_episodes()
|
|
73
73
|
|
|
74
74
|
if 0 <= index < len(episodes):
|
|
75
75
|
episode_data = episodes[index]
|
|
76
|
-
return
|
|
76
|
+
return VideoSource(episode_data, self.session_id, self.csrf_token)
|
|
77
77
|
|
|
78
78
|
else:
|
|
79
|
-
raise IndexError("Episode index out of range")
|
|
79
|
+
raise IndexError("Episode index out of range")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# ------------- FOR GUI -------------
|
|
83
|
+
def getNumberSeason(self) -> int:
|
|
84
|
+
"""
|
|
85
|
+
Get the total number of seasons available for the anime.
|
|
86
|
+
Note: AnimeWorld typically doesn't have seasons, so returns 1.
|
|
87
|
+
"""
|
|
88
|
+
return 1
|
|
89
|
+
|
|
90
|
+
def getEpisodeSeasons(self, season_number: int = 1) -> list:
|
|
91
|
+
"""
|
|
92
|
+
Get all episodes for a specific season.
|
|
93
|
+
Note: For AnimeWorld, this returns all episodes as they're typically in one season.
|
|
94
|
+
"""
|
|
95
|
+
return self.get_episodes()
|
|
96
|
+
|
|
97
|
+
def selectEpisode(self, season_number: int = 1, episode_index: int = 0) -> dict:
|
|
98
|
+
"""
|
|
99
|
+
Get information for a specific episode.
|
|
100
|
+
"""
|
|
101
|
+
episodes = self.get_episodes()
|
|
102
|
+
if not episodes or episode_index < 0 or episode_index >= len(episodes):
|
|
103
|
+
logging.error(f"Episode index {episode_index} is out of range")
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
return episodes[episode_index]
|
|
@@ -39,7 +39,7 @@ def process_search_result(select_title):
|
|
|
39
39
|
|
|
40
40
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
|
41
41
|
"""
|
|
42
|
-
Main function of the application for search
|
|
42
|
+
Main function of the application for search.
|
|
43
43
|
|
|
44
44
|
Parameters:
|
|
45
45
|
string_to_search (str, optional): String to search for
|
|
@@ -42,7 +42,7 @@ def process_search_result(select_title):
|
|
|
42
42
|
|
|
43
43
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None):
|
|
44
44
|
"""
|
|
45
|
-
Main function of the application for search
|
|
45
|
+
Main function of the application for search.
|
|
46
46
|
|
|
47
47
|
Parameters:
|
|
48
48
|
string_to_search (str, optional): String to search for
|
|
@@ -35,22 +35,22 @@ from StreamingCommunity.Api.Player.ddl import VideoSource
|
|
|
35
35
|
console = Console()
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo
|
|
38
|
+
def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo) -> Tuple[str,bool]:
|
|
39
39
|
"""
|
|
40
|
-
|
|
40
|
+
Downloads a specific episode.
|
|
41
41
|
|
|
42
42
|
Parameters:
|
|
43
|
-
-
|
|
44
|
-
-
|
|
43
|
+
- index_episode_selected (int): Episode index
|
|
44
|
+
- scape_info_serie (GetSerieInfo): Scraper object with series information
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
- str:
|
|
48
|
-
- bool:
|
|
46
|
+
Returns:
|
|
47
|
+
- str: Path to downloaded file
|
|
48
|
+
- bool: Whether download was stopped
|
|
49
49
|
"""
|
|
50
50
|
start_message()
|
|
51
51
|
|
|
52
|
-
# Get
|
|
53
|
-
obj_episode = scape_info_serie.
|
|
52
|
+
# Get episode information
|
|
53
|
+
obj_episode = scape_info_serie.selectEpisode(1, index_episode_selected-1)
|
|
54
54
|
console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]E{index_episode_selected}[/cyan]) \n")
|
|
55
55
|
|
|
56
56
|
# Define filename and path for the downloaded video
|
|
@@ -63,7 +63,7 @@ def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo,
|
|
|
63
63
|
os_manager.create_path(mp4_path)
|
|
64
64
|
|
|
65
65
|
# Setup video source
|
|
66
|
-
video_source.
|
|
66
|
+
video_source = VideoSource(site_constant.COOKIE, obj_episode.get('url'))
|
|
67
67
|
|
|
68
68
|
# Get m3u8 master playlist
|
|
69
69
|
master_playlist = video_source.get_playlist()
|
|
@@ -82,38 +82,37 @@ def download_video(index_episode_selected: int, scape_info_serie: GetSerieInfo,
|
|
|
82
82
|
console.print("[green]Result: ")
|
|
83
83
|
console.print(r_proc)
|
|
84
84
|
|
|
85
|
-
return os.path.join(mp4_path, title_name)
|
|
85
|
+
return os.path.join(mp4_path, title_name), False
|
|
86
86
|
|
|
87
87
|
|
|
88
|
-
def download_thread(dict_serie: MediaItem):
|
|
88
|
+
def download_thread(dict_serie: MediaItem, episode_selection: str = None):
|
|
89
89
|
"""
|
|
90
90
|
Download all episode of a thread
|
|
91
|
+
|
|
92
|
+
Parameters:
|
|
93
|
+
dict_serie (MediaItem): The selected media item
|
|
94
|
+
episode_selection (str, optional): Episode selection input that bypasses manual input
|
|
91
95
|
"""
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# Collect information about thread
|
|
99
|
-
list_dict_episode = scape_info_serie.get_episode_number()
|
|
100
|
-
episodes_count = len(list_dict_episode)
|
|
101
|
-
|
|
96
|
+
scrape_serie = GetSerieInfo(dict_serie, site_constant.COOKIE)
|
|
97
|
+
|
|
98
|
+
# Get episode list
|
|
99
|
+
episodes = scrape_serie.getEpisodeSeasons()
|
|
100
|
+
episodes_count = len(episodes)
|
|
101
|
+
|
|
102
102
|
# Display episodes list and manage user selection
|
|
103
|
-
|
|
103
|
+
if episode_selection is None:
|
|
104
|
+
last_command = display_episodes_list(scrape_serie.list_episodes)
|
|
105
|
+
else:
|
|
106
|
+
last_command = episode_selection
|
|
107
|
+
console.print(f"\n[cyan]Using provided episode selection: [yellow]{episode_selection}")
|
|
108
|
+
|
|
109
|
+
# Validate episode selection
|
|
104
110
|
list_episode_select = manage_selection(last_command, episodes_count)
|
|
105
|
-
|
|
106
|
-
try:
|
|
107
|
-
list_episode_select = validate_episode_selection(list_episode_select, episodes_count)
|
|
108
|
-
|
|
109
|
-
except ValueError as e:
|
|
110
|
-
console.print(f"[red]{str(e)}")
|
|
111
|
-
return
|
|
111
|
+
list_episode_select = validate_episode_selection(list_episode_select, episodes_count)
|
|
112
112
|
|
|
113
113
|
# Download selected episodes
|
|
114
114
|
kill_handler = bool(False)
|
|
115
115
|
for i_episode in list_episode_select:
|
|
116
116
|
if kill_handler:
|
|
117
117
|
break
|
|
118
|
-
|
|
119
|
-
kill_handler = download_video(i_episode, scape_info_serie, video_source)[1]
|
|
118
|
+
kill_handler = download_video(i_episode, scrape_serie)[1]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# 09.06.24
|
|
2
2
|
|
|
3
|
-
import sys
|
|
4
3
|
import logging
|
|
5
4
|
|
|
6
5
|
|
|
@@ -67,7 +66,8 @@ def title_search(query: str) -> int:
|
|
|
67
66
|
title_info = {
|
|
68
67
|
'name': name,
|
|
69
68
|
'url': link,
|
|
70
|
-
'type': title_type
|
|
69
|
+
'type': title_type,
|
|
70
|
+
'image': title_div.find("div", class_="ipsColumn").find("img").get("src")
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
media_search_manager.add_media(title_info)
|