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.

Files changed (38) hide show
  1. StreamingCommunity/Api/Site/altadefinizione/__init__.py +67 -30
  2. StreamingCommunity/Api/Site/animeunity/__init__.py +65 -29
  3. StreamingCommunity/Api/Site/animeworld/__init__.py +80 -10
  4. StreamingCommunity/Api/Site/crunchyroll/__init__.py +75 -15
  5. StreamingCommunity/Api/Site/crunchyroll/site.py +7 -1
  6. StreamingCommunity/Api/Site/guardaserie/__init__.py +80 -10
  7. StreamingCommunity/Api/Site/mediasetinfinity/__init__.py +78 -15
  8. StreamingCommunity/Api/Site/mediasetinfinity/film.py +1 -1
  9. StreamingCommunity/Api/Site/mediasetinfinity/site.py +12 -2
  10. StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +6 -7
  11. StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +162 -0
  12. StreamingCommunity/Api/Site/raiplay/__init__.py +78 -12
  13. StreamingCommunity/Api/Site/raiplay/film.py +2 -1
  14. StreamingCommunity/Api/Site/raiplay/series.py +21 -7
  15. StreamingCommunity/Api/Site/streamingcommunity/__init__.py +12 -9
  16. StreamingCommunity/Api/Site/streamingcommunity/site.py +4 -1
  17. StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +5 -2
  18. StreamingCommunity/Api/Site/streamingwatch/__init__.py +76 -12
  19. StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +8 -0
  20. StreamingCommunity/Lib/Downloader/DASH/downloader.py +109 -75
  21. StreamingCommunity/Lib/Downloader/HLS/downloader.py +18 -6
  22. StreamingCommunity/Lib/Downloader/HLS/segments.py +1 -1
  23. StreamingCommunity/Lib/Downloader/MP4/downloader.py +21 -3
  24. StreamingCommunity/Lib/FFmpeg/command.py +66 -7
  25. StreamingCommunity/Lib/FFmpeg/util.py +16 -13
  26. StreamingCommunity/Upload/update.py +2 -2
  27. StreamingCommunity/Upload/version.py +2 -2
  28. StreamingCommunity/Util/os.py +4 -1
  29. StreamingCommunity/run.py +4 -4
  30. {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/METADATA +2 -7
  31. {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/RECORD +35 -38
  32. StreamingCommunity/Api/Site/cb01new/__init__.py +0 -72
  33. StreamingCommunity/Api/Site/cb01new/film.py +0 -64
  34. StreamingCommunity/Api/Site/cb01new/site.py +0 -78
  35. {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/WHEEL +0 -0
  36. {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/entry_points.txt +0 -0
  37. {streamingcommunity-3.2.9.dist-info → streamingcommunity-3.3.1.dist-info}/licenses/LICENSE +0 -0
  38. {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
- if string_to_search is None:
68
- string_to_search = msg.ask(f"\n[purple]Insert word to search in [green]{site_constant.SITE_NAME}").strip()
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
- # If no results are found, ask again
84
- console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
85
- search()
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 = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
38
-
39
- return msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
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
- if string_to_search is None:
80
- string_to_search = msg.ask(f"\n[purple]Insert a word to search in [green]{site_constant.SITE_NAME}").strip()
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
- # If no results are found, ask again
95
- console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
96
- search()
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
- return None
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': None,
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
- """Ottiene il public ID tramite l'API watchlist"""
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