StreamingCommunity 3.2.9__py3-none-any.whl → 3.3.1__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/Site/altadefinizione/__init__.py +67 -30
- StreamingCommunity/Api/Site/animeunity/__init__.py +65 -29
- StreamingCommunity/Api/Site/animeworld/__init__.py +80 -10
- StreamingCommunity/Api/Site/crunchyroll/__init__.py +75 -15
- StreamingCommunity/Api/Site/crunchyroll/site.py +7 -1
- StreamingCommunity/Api/Site/guardaserie/__init__.py +80 -10
- StreamingCommunity/Api/Site/mediasetinfinity/__init__.py +78 -15
- StreamingCommunity/Api/Site/mediasetinfinity/film.py +1 -1
- StreamingCommunity/Api/Site/mediasetinfinity/site.py +12 -2
- StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +6 -7
- StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +162 -0
- StreamingCommunity/Api/Site/raiplay/__init__.py +78 -12
- StreamingCommunity/Api/Site/raiplay/film.py +2 -1
- StreamingCommunity/Api/Site/raiplay/series.py +21 -7
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +12 -9
- StreamingCommunity/Api/Site/streamingcommunity/site.py +4 -1
- StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +5 -2
- StreamingCommunity/Api/Site/streamingwatch/__init__.py +76 -12
- StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +8 -0
- StreamingCommunity/Lib/Downloader/DASH/downloader.py +109 -75
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +18 -6
- StreamingCommunity/Lib/Downloader/HLS/segments.py +1 -1
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +21 -3
- StreamingCommunity/Lib/FFmpeg/command.py +66 -7
- StreamingCommunity/Lib/FFmpeg/util.py +16 -13
- StreamingCommunity/Upload/update.py +2 -2
- StreamingCommunity/Upload/version.py +2 -2
- StreamingCommunity/Util/os.py +4 -1
- StreamingCommunity/run.py +4 -4
- {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/METADATA +2 -7
- {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/RECORD +35 -38
- StreamingCommunity/Api/Site/cb01new/__init__.py +0 -72
- StreamingCommunity/Api/Site/cb01new/film.py +0 -64
- StreamingCommunity/Api/Site/cb01new/site.py +0 -78
- {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/WHEEL +0 -0
- {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/entry_points.txt +0 -0
- {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/licenses/LICENSE +0 -0
- {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 09.06.24
|
|
2
2
|
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
3
5
|
from urllib.parse import quote_plus
|
|
4
6
|
|
|
5
7
|
|
|
@@ -12,6 +14,7 @@ from rich.prompt import Prompt
|
|
|
12
14
|
from StreamingCommunity.Api.Template import get_select_title
|
|
13
15
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
14
16
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
17
|
+
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
# Logic class
|
|
@@ -30,6 +33,44 @@ msg = Prompt()
|
|
|
30
33
|
console = Console()
|
|
31
34
|
|
|
32
35
|
|
|
36
|
+
def get_user_input(string_to_search: str = None):
|
|
37
|
+
"""
|
|
38
|
+
Asks the user to input a search term.
|
|
39
|
+
Handles both Telegram bot input and direct input.
|
|
40
|
+
If string_to_search is provided, it's returned directly (after stripping).
|
|
41
|
+
"""
|
|
42
|
+
if string_to_search is not None:
|
|
43
|
+
return string_to_search.strip()
|
|
44
|
+
|
|
45
|
+
if site_constant.TELEGRAM_BOT:
|
|
46
|
+
bot = get_bot_instance()
|
|
47
|
+
user_response = bot.ask(
|
|
48
|
+
"key_search", # Request type
|
|
49
|
+
"Enter the search term\nor type 'back' to return to the menu: ",
|
|
50
|
+
None
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if user_response is None:
|
|
54
|
+
bot.send_message("Timeout: No search term entered.", None)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
if user_response.lower() == 'back':
|
|
58
|
+
bot.send_message("Returning to the main menu...", None)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
# Restart the script
|
|
62
|
+
subprocess.Popen([sys.executable] + sys.argv)
|
|
63
|
+
sys.exit()
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
bot.send_message(f"Error during restart attempt: {e}", None)
|
|
67
|
+
return None # Return None if restart fails
|
|
68
|
+
|
|
69
|
+
return user_response.strip()
|
|
70
|
+
|
|
71
|
+
else:
|
|
72
|
+
return msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
73
|
+
|
|
33
74
|
def process_search_result(select_title, selections=None):
|
|
34
75
|
"""
|
|
35
76
|
Handles the search result and initiates the download for either a film or series.
|
|
@@ -38,7 +79,18 @@ def process_search_result(select_title, selections=None):
|
|
|
38
79
|
select_title (MediaItem): The selected media item
|
|
39
80
|
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
40
81
|
{'season': season_selection, 'episode': episode_selection}
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
bool: True if processing was successful, False otherwise
|
|
41
85
|
"""
|
|
86
|
+
if not select_title:
|
|
87
|
+
if site_constant.TELEGRAM_BOT:
|
|
88
|
+
bot = get_bot_instance()
|
|
89
|
+
bot.send_message("No title selected or selection cancelled.", None)
|
|
90
|
+
else:
|
|
91
|
+
console.print("[yellow]No title selected or selection cancelled.")
|
|
92
|
+
return False
|
|
93
|
+
|
|
42
94
|
season_selection = None
|
|
43
95
|
episode_selection = None
|
|
44
96
|
|
|
@@ -47,6 +99,7 @@ def process_search_result(select_title, selections=None):
|
|
|
47
99
|
episode_selection = selections.get('episode')
|
|
48
100
|
|
|
49
101
|
download_series(select_title, season_selection, episode_selection)
|
|
102
|
+
return True
|
|
50
103
|
|
|
51
104
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
52
105
|
"""
|
|
@@ -59,27 +112,44 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
59
112
|
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
60
113
|
{'season': season_selection, 'episode': episode_selection}
|
|
61
114
|
"""
|
|
115
|
+
bot = None
|
|
116
|
+
if site_constant.TELEGRAM_BOT:
|
|
117
|
+
try:
|
|
118
|
+
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
119
|
+
bot = get_bot_instance()
|
|
120
|
+
except Exception:
|
|
121
|
+
bot = None
|
|
122
|
+
|
|
62
123
|
if direct_item:
|
|
63
124
|
select_title = MediaItem(**direct_item)
|
|
64
125
|
process_search_result(select_title, selections)
|
|
126
|
+
return True
|
|
127
|
+
|
|
128
|
+
# Get the user input for the search term
|
|
129
|
+
actual_search_query = get_user_input(string_to_search)
|
|
130
|
+
|
|
131
|
+
# Handle empty input
|
|
132
|
+
if not actual_search_query:
|
|
133
|
+
if bot:
|
|
134
|
+
if actual_search_query is None:
|
|
135
|
+
bot.send_message("Search term not provided or operation cancelled. Returning.", None)
|
|
65
136
|
return
|
|
66
137
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
# Search on database
|
|
71
|
-
len_database = title_search(quote_plus(string_to_search))
|
|
138
|
+
# Search on database (preserve quote_plus usage)
|
|
139
|
+
len_database = title_search(quote_plus(actual_search_query))
|
|
72
140
|
|
|
73
141
|
# If only the database is needed, return the manager
|
|
74
142
|
if get_onlyDatabase:
|
|
75
143
|
return media_search_manager
|
|
76
144
|
|
|
77
145
|
if len_database > 0:
|
|
78
|
-
select_title = get_select_title(table_show_manager, media_search_manager,len_database)
|
|
146
|
+
select_title = get_select_title(table_show_manager, media_search_manager, len_database)
|
|
79
147
|
process_search_result(select_title, selections)
|
|
148
|
+
return True
|
|
80
149
|
|
|
81
150
|
else:
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
151
|
+
if bot:
|
|
152
|
+
bot.send_message(f"No results found for: '{actual_search_query}'", None)
|
|
153
|
+
else:
|
|
154
|
+
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{actual_search_query}")
|
|
155
|
+
return
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# 21.05.24
|
|
2
2
|
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
5
|
+
|
|
3
6
|
|
|
4
7
|
# External library
|
|
5
8
|
from rich.console import Console
|
|
@@ -10,6 +13,7 @@ from rich.prompt import Prompt
|
|
|
10
13
|
from StreamingCommunity.Api.Template import get_select_title
|
|
11
14
|
from StreamingCommunity.Api.Template.config_loader import site_constant
|
|
12
15
|
from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
|
|
16
|
+
from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
# Logic class
|
|
@@ -32,11 +36,40 @@ console = Console()
|
|
|
32
36
|
def get_user_input(string_to_search: str = None):
|
|
33
37
|
"""
|
|
34
38
|
Asks the user to input a search term.
|
|
39
|
+
Handles both Telegram bot input and direct input.
|
|
40
|
+
If string_to_search is provided, it's returned directly (after stripping).
|
|
35
41
|
"""
|
|
36
|
-
if string_to_search is None:
|
|
37
|
-
string_to_search
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
if string_to_search is not None:
|
|
43
|
+
return string_to_search.strip()
|
|
44
|
+
|
|
45
|
+
if site_constant.TELEGRAM_BOT:
|
|
46
|
+
bot = get_bot_instance()
|
|
47
|
+
user_response = bot.ask(
|
|
48
|
+
"key_search", # Request type
|
|
49
|
+
"Enter the search term\nor type 'back' to return to the menu: ",
|
|
50
|
+
None
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if user_response is None:
|
|
54
|
+
bot.send_message("Timeout: No search term entered.", None)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
if user_response.lower() == 'back':
|
|
58
|
+
bot.send_message("Returning to the main menu...", None)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
# Restart the script
|
|
62
|
+
subprocess.Popen([sys.executable] + sys.argv)
|
|
63
|
+
sys.exit()
|
|
64
|
+
|
|
65
|
+
except Exception as e:
|
|
66
|
+
bot.send_message(f"Error during restart attempt: {e}", None)
|
|
67
|
+
return None # Return None if restart fails
|
|
68
|
+
|
|
69
|
+
return user_response.strip()
|
|
70
|
+
|
|
71
|
+
else:
|
|
72
|
+
return msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
|
|
40
73
|
|
|
41
74
|
def process_search_result(select_title, selections=None):
|
|
42
75
|
"""
|
|
@@ -46,7 +79,18 @@ def process_search_result(select_title, selections=None):
|
|
|
46
79
|
select_title (MediaItem): The selected media item
|
|
47
80
|
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
48
81
|
{'season': season_selection, 'episode': episode_selection}
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
bool: True if processing was successful, False otherwise
|
|
49
85
|
"""
|
|
86
|
+
if not select_title:
|
|
87
|
+
if site_constant.TELEGRAM_BOT:
|
|
88
|
+
bot = get_bot_instance()
|
|
89
|
+
bot.send_message("No title selected or selection cancelled.", None)
|
|
90
|
+
else:
|
|
91
|
+
console.print("[yellow]No title selected or selection cancelled.")
|
|
92
|
+
return False
|
|
93
|
+
|
|
50
94
|
if select_title.type == 'tv':
|
|
51
95
|
season_selection = None
|
|
52
96
|
episode_selection = None
|
|
@@ -56,9 +100,11 @@ def process_search_result(select_title, selections=None):
|
|
|
56
100
|
episode_selection = selections.get('episode')
|
|
57
101
|
|
|
58
102
|
download_series(select_title, season_selection, episode_selection)
|
|
103
|
+
return True
|
|
59
104
|
|
|
60
105
|
else:
|
|
61
106
|
download_film(select_title)
|
|
107
|
+
return True
|
|
62
108
|
|
|
63
109
|
def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_item: dict = None, selections: dict = None):
|
|
64
110
|
"""
|
|
@@ -71,26 +117,43 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
|
|
|
71
117
|
selections (dict, optional): Dictionary containing selection inputs that bypass manual input
|
|
72
118
|
{'season': season_selection, 'episode': episode_selection}
|
|
73
119
|
"""
|
|
120
|
+
bot = None
|
|
121
|
+
if site_constant.TELEGRAM_BOT:
|
|
122
|
+
bot = get_bot_instance()
|
|
123
|
+
|
|
74
124
|
if direct_item:
|
|
75
125
|
select_title = MediaItem(**direct_item)
|
|
76
126
|
process_search_result(select_title, selections)
|
|
127
|
+
return True
|
|
128
|
+
|
|
129
|
+
# Get the user input for the search term
|
|
130
|
+
actual_search_query = get_user_input(string_to_search)
|
|
131
|
+
|
|
132
|
+
# Handle cases where user input is empty, or 'back' was handled (sys.exit or None return)
|
|
133
|
+
if not actual_search_query:
|
|
134
|
+
if bot:
|
|
135
|
+
if actual_search_query is None: # Specifically for timeout from bot.ask or failed restart
|
|
136
|
+
bot.send_message("Search term not provided or operation cancelled. Returning.", None)
|
|
77
137
|
return
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
# Search on database
|
|
83
|
-
len_database = title_search(string_to_search)
|
|
138
|
+
|
|
139
|
+
# Perform the database search
|
|
140
|
+
len_database = title_search(actual_search_query)
|
|
84
141
|
|
|
85
142
|
# If only the database is needed, return the manager
|
|
86
143
|
if get_onlyDatabase:
|
|
87
144
|
return media_search_manager
|
|
88
|
-
|
|
145
|
+
|
|
89
146
|
if len_database > 0:
|
|
90
|
-
select_title = get_select_title(table_show_manager, media_search_manager,len_database)
|
|
147
|
+
select_title = get_select_title(table_show_manager, media_search_manager, len_database)
|
|
91
148
|
process_search_result(select_title, selections)
|
|
149
|
+
return True
|
|
92
150
|
|
|
93
151
|
else:
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
152
|
+
if bot:
|
|
153
|
+
bot.send_message(f"No results found for: '{actual_search_query}'", None)
|
|
154
|
+
else:
|
|
155
|
+
console.print(f"\n[red]Nothing matching was found for[white]: [purple]{actual_search_query}")
|
|
156
|
+
|
|
157
|
+
# Do not call search() recursively here to avoid infinite loops on no results.
|
|
158
|
+
# The flow should return to the caller (e.g., main menu in run.py).
|
|
159
|
+
return
|
|
@@ -60,7 +60,7 @@ def download_film(select_title: MediaItem) -> Tuple[str, bool]:
|
|
|
60
60
|
cdm_device=get_wvd_path(),
|
|
61
61
|
license_url=license_url,
|
|
62
62
|
mpd_url=mpd_url,
|
|
63
|
-
output_path=mp4_path,
|
|
63
|
+
output_path=os.path.join(mp4_path, title_name),
|
|
64
64
|
)
|
|
65
65
|
dash_process.parse_manifest(custom_headers=get_headers())
|
|
66
66
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# 25.07.25
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
4
6
|
|
|
5
7
|
# External libraries
|
|
6
8
|
import httpx
|
|
@@ -44,7 +46,14 @@ def title_search(query: str) -> int:
|
|
|
44
46
|
cdm_device_path = get_wvd_path()
|
|
45
47
|
if not cdm_device_path or not isinstance(cdm_device_path, (str, bytes, os.PathLike)) or not os.path.isfile(cdm_device_path):
|
|
46
48
|
console.print(f"[bold red] CDM file not found or invalid path: {cdm_device_path}[/bold red]")
|
|
47
|
-
|
|
49
|
+
sys.exit(0)
|
|
50
|
+
|
|
51
|
+
# Check if beToken is present
|
|
52
|
+
if (config_manager.get_dict("SITE_LOGIN", "mediasetinfinity")["beToken"] is None or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity")["beToken"] == "") and \
|
|
53
|
+
(config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("username") is None or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("username") == "" \
|
|
54
|
+
or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("password") is None or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("password") == ""):
|
|
55
|
+
console.print("[bold red] beToken or credentials are missing or empty.[/bold red]")
|
|
56
|
+
sys.exit(0)
|
|
48
57
|
|
|
49
58
|
search_url = 'https://api-ott-prod-fe.mediaset.net/PROD/play/reco/account/v2.0'
|
|
50
59
|
console.print(f"[cyan]Search url: [yellow]{search_url}")
|
|
@@ -114,7 +123,8 @@ def title_search(query: str) -> int:
|
|
|
114
123
|
'name': item.get('title', ''),
|
|
115
124
|
'type': media_type,
|
|
116
125
|
'url': page_url,
|
|
117
|
-
'image':
|
|
126
|
+
'image': item.get('thumbnails', {}).get('image_header_poster-768x384', '').get('url', ''),
|
|
127
|
+
'date': item.get('year', ''),
|
|
118
128
|
})
|
|
119
129
|
|
|
120
130
|
return media_search_manager.get_length()
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# 16.03.25
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
import logging
|
|
5
4
|
from urllib.parse import urlparse
|
|
6
5
|
|
|
@@ -16,10 +15,6 @@ from StreamingCommunity.Util.config_json import config_manager
|
|
|
16
15
|
from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
# Logic class
|
|
20
|
-
from .get_license import get_bearer_token
|
|
21
|
-
|
|
22
|
-
|
|
23
18
|
# Variable
|
|
24
19
|
max_timeout = config_manager.get_int("REQUESTS", "timeout")
|
|
25
20
|
|
|
@@ -47,7 +42,10 @@ class GetSerieInfo:
|
|
|
47
42
|
return self.serie_id
|
|
48
43
|
|
|
49
44
|
def _get_public_id(self):
|
|
50
|
-
|
|
45
|
+
self.public_id = "PR1GhC"
|
|
46
|
+
return self.public_id
|
|
47
|
+
|
|
48
|
+
"""
|
|
51
49
|
bearer_token = get_bearer_token()
|
|
52
50
|
headers = {
|
|
53
51
|
'authorization': f'Bearer {bearer_token}',
|
|
@@ -73,6 +71,7 @@ class GetSerieInfo:
|
|
|
73
71
|
else:
|
|
74
72
|
logging.error(f"Failed to get public ID: {response.status_code}")
|
|
75
73
|
return None
|
|
74
|
+
"""
|
|
76
75
|
|
|
77
76
|
def _get_series_data(self):
|
|
78
77
|
"""Ottiene i dati della serie tramite l'API"""
|
|
@@ -290,4 +289,4 @@ class GetSerieInfo:
|
|
|
290
289
|
logging.error(f"Episode index {episode_index} is out of range for season {season_number}")
|
|
291
290
|
return None
|
|
292
291
|
|
|
293
|
-
return episodes[episode_index]
|
|
292
|
+
return episodes[episode_index]
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
# 16.03.25
|
|
2
2
|
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
3
5
|
from urllib.parse import urlencode
|
|
4
6
|
import xml.etree.ElementTree as ET
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
# External library
|
|
8
10
|
import httpx
|
|
11
|
+
from rich.console import Console
|
|
12
|
+
from seleniumbase import Driver
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
# Internal utilities
|
|
@@ -14,9 +18,143 @@ from StreamingCommunity.Util.headers import get_headers, get_userAgent
|
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
# Variable
|
|
21
|
+
console = Console()
|
|
17
22
|
MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
|
|
23
|
+
beToken = None
|
|
24
|
+
network_data = []
|
|
18
25
|
|
|
19
26
|
|
|
27
|
+
def save_network_data(data):
|
|
28
|
+
"""Save network data and check for beToken"""
|
|
29
|
+
global network_data
|
|
30
|
+
|
|
31
|
+
# Filter only for login API responses
|
|
32
|
+
if data.get('method') == 'Network.responseReceived':
|
|
33
|
+
params = data.get('params', {})
|
|
34
|
+
response = params.get('response', {})
|
|
35
|
+
url = response.get('url', '')
|
|
36
|
+
|
|
37
|
+
if "persona/login/v2.0" in url and params.get('type') != 'Preflight':
|
|
38
|
+
network_data.append(data)
|
|
39
|
+
console.print(f"[green]Found login API request to: {url}")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def generate_betoken(username: str, password: str, sleep_action: float = 1.0) -> str:
|
|
43
|
+
driver = Driver(uc=True, uc_cdp_events=True, incognito=True, headless=True)
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
console.print("[cyan]Launching browser...")
|
|
47
|
+
be_token_holder = {"token": None}
|
|
48
|
+
global network_data
|
|
49
|
+
network_data = [] # Reset network data
|
|
50
|
+
|
|
51
|
+
# Load home page
|
|
52
|
+
console.print("[cyan]Navigating to Mediaset Play...")
|
|
53
|
+
driver.uc_open_with_reconnect("https://www.mediasetplay.mediaset.it", sleep_action)
|
|
54
|
+
|
|
55
|
+
# Add CDP listeners after opening the page
|
|
56
|
+
driver.add_cdp_listener(
|
|
57
|
+
"Network.responseReceived",
|
|
58
|
+
lambda data: save_network_data(data)
|
|
59
|
+
)
|
|
60
|
+
driver.sleep(sleep_action)
|
|
61
|
+
|
|
62
|
+
# Accept privacy policy if present
|
|
63
|
+
try:
|
|
64
|
+
driver.click("#rti-privacy-accept-btn-screen1-id", timeout=3)
|
|
65
|
+
except Exception:
|
|
66
|
+
pass
|
|
67
|
+
|
|
68
|
+
# Click Login using the specific div structure
|
|
69
|
+
console.print("[cyan]Clicking login button...")
|
|
70
|
+
try:
|
|
71
|
+
driver.click('div.dwv_v span:contains("Login")', timeout=5)
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f"Error clicking login: {e}")
|
|
74
|
+
try:
|
|
75
|
+
driver.click('div.dwv_v', timeout=3)
|
|
76
|
+
except Exception:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
driver.sleep(sleep_action)
|
|
80
|
+
|
|
81
|
+
# Click "Accedi con email e password" using the specific input
|
|
82
|
+
console.print("[cyan]Clicking email/password login...")
|
|
83
|
+
try:
|
|
84
|
+
driver.click('input.gigya-input-submit[value="Accedi con email e password"]', timeout=5)
|
|
85
|
+
except Exception as e:
|
|
86
|
+
print(f"Error clicking email login: {e}")
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
driver.sleep(sleep_action)
|
|
90
|
+
|
|
91
|
+
# Fill login credentials using specific IDs
|
|
92
|
+
console.print("[cyan]Filling login credentials...")
|
|
93
|
+
try:
|
|
94
|
+
email_input = 'input[name="username"].gigya-input-text'
|
|
95
|
+
driver.wait_for_element(email_input, timeout=5)
|
|
96
|
+
driver.type(email_input, username)
|
|
97
|
+
|
|
98
|
+
password_input = 'input[name="password"].gigya-input-password'
|
|
99
|
+
driver.wait_for_element(password_input, timeout=5)
|
|
100
|
+
driver.type(password_input, password)
|
|
101
|
+
|
|
102
|
+
except Exception as e:
|
|
103
|
+
print(f"Error filling credentials: {e}")
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
driver.sleep(sleep_action)
|
|
107
|
+
|
|
108
|
+
# Click Continue/Procedi using the submit button
|
|
109
|
+
console.print("[cyan]Clicking continue button...")
|
|
110
|
+
try:
|
|
111
|
+
driver.click('input.gigya-input-submit[type="submit"][value="Continua"]', timeout=5)
|
|
112
|
+
except Exception as e:
|
|
113
|
+
print(f"Error clicking continue: {e}")
|
|
114
|
+
return None
|
|
115
|
+
|
|
116
|
+
# Wait for login response and parse network data
|
|
117
|
+
console.print("[cyan]Waiting for login response...")
|
|
118
|
+
for attempt in range(30):
|
|
119
|
+
driver.sleep(0.3)
|
|
120
|
+
|
|
121
|
+
# Check network data for beToken - skip preflight requests
|
|
122
|
+
for data in network_data:
|
|
123
|
+
if data.get('method') == 'Network.responseReceived':
|
|
124
|
+
params = data.get('params', {})
|
|
125
|
+
response = params.get('response', {})
|
|
126
|
+
url = response.get('url', '')
|
|
127
|
+
request_type = params.get('type', '')
|
|
128
|
+
|
|
129
|
+
if "persona/login/v2.0" in url and request_type != 'Preflight':
|
|
130
|
+
request_id = params.get('requestId')
|
|
131
|
+
|
|
132
|
+
if request_id:
|
|
133
|
+
try:
|
|
134
|
+
response_body = driver.execute_cdp_cmd(
|
|
135
|
+
'Network.getResponseBody',
|
|
136
|
+
{'requestId': request_id}
|
|
137
|
+
)
|
|
138
|
+
body = response_body.get('body', '')
|
|
139
|
+
|
|
140
|
+
if body:
|
|
141
|
+
response_data = json.loads(body)
|
|
142
|
+
be_token = response_data.get("response", {}).get("beToken")
|
|
143
|
+
|
|
144
|
+
if be_token:
|
|
145
|
+
be_token_holder["token"] = be_token
|
|
146
|
+
console.print("[green]Login successful! BeToken found!")
|
|
147
|
+
return be_token
|
|
148
|
+
|
|
149
|
+
except Exception:
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
console.print(f"[yellow]Login completed. Total network events captured: {len(network_data)}")
|
|
153
|
+
return be_token_holder["token"]
|
|
154
|
+
|
|
155
|
+
finally:
|
|
156
|
+
driver.quit()
|
|
157
|
+
|
|
20
158
|
def get_bearer_token():
|
|
21
159
|
"""
|
|
22
160
|
Gets the BEARER_TOKEN for authentication.
|
|
@@ -24,6 +162,29 @@ def get_bearer_token():
|
|
|
24
162
|
Returns:
|
|
25
163
|
str: The bearer token string.
|
|
26
164
|
"""
|
|
165
|
+
global beToken
|
|
166
|
+
|
|
167
|
+
# Read beToken from config if already present
|
|
168
|
+
beToken = config_manager.get_dict("SITE_LOGIN", "mediasetinfinity")["beToken"]
|
|
169
|
+
if beToken is not None and len(beToken) != 0:
|
|
170
|
+
return beToken
|
|
171
|
+
|
|
172
|
+
username = config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("username", "")
|
|
173
|
+
password = config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("password", "")
|
|
174
|
+
|
|
175
|
+
if username and password:
|
|
176
|
+
beToken = generate_betoken(username, password)
|
|
177
|
+
|
|
178
|
+
if beToken is not None:
|
|
179
|
+
|
|
180
|
+
# Save current beToken
|
|
181
|
+
current_value = config_manager.get("SITE_LOGIN", "mediasetinfinity", dict)
|
|
182
|
+
current_value["beToken"] = beToken
|
|
183
|
+
config_manager.set_key("SITE_LOGIN", "mediasetinfinity", current_value)
|
|
184
|
+
config_manager.save_config()
|
|
185
|
+
|
|
186
|
+
return beToken
|
|
187
|
+
|
|
27
188
|
return config_manager.get_dict("SITE_LOGIN", "mediasetinfinity")["beToken"]
|
|
28
189
|
|
|
29
190
|
def get_playback_url(BEARER_TOKEN, CONTENT_ID):
|
|
@@ -158,6 +319,7 @@ def get_tracking_info(BEARER_TOKEN, PLAYBACK_JSON):
|
|
|
158
319
|
response.raise_for_status()
|
|
159
320
|
|
|
160
321
|
smil_xml = response.text
|
|
322
|
+
time.sleep(0.2)
|
|
161
323
|
results = parse_smil_for_tracking_and_video(smil_xml)
|
|
162
324
|
return results
|
|
163
325
|
|