StreamingCommunity 3.3.9__py3-none-any.whl → 3.4.2__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 (70) hide show
  1. StreamingCommunity/Api/Player/hdplayer.py +0 -5
  2. StreamingCommunity/Api/Player/mediapolisvod.py +4 -13
  3. StreamingCommunity/Api/Player/supervideo.py +3 -8
  4. StreamingCommunity/Api/Player/sweetpixel.py +1 -9
  5. StreamingCommunity/Api/Player/vixcloud.py +5 -16
  6. StreamingCommunity/Api/Site/altadefinizione/film.py +4 -16
  7. StreamingCommunity/Api/Site/altadefinizione/series.py +3 -12
  8. StreamingCommunity/Api/Site/altadefinizione/site.py +2 -9
  9. StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +2 -7
  10. StreamingCommunity/Api/Site/animeunity/site.py +9 -24
  11. StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +11 -27
  12. StreamingCommunity/Api/Site/animeworld/film.py +4 -2
  13. StreamingCommunity/Api/Site/animeworld/site.py +3 -11
  14. StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +1 -4
  15. StreamingCommunity/Api/Site/crunchyroll/film.py +4 -5
  16. StreamingCommunity/Api/Site/crunchyroll/series.py +5 -17
  17. StreamingCommunity/Api/Site/crunchyroll/site.py +4 -13
  18. StreamingCommunity/Api/Site/crunchyroll/util/ScrapeSerie.py +5 -27
  19. StreamingCommunity/Api/Site/crunchyroll/util/get_license.py +11 -26
  20. StreamingCommunity/Api/Site/guardaserie/series.py +3 -14
  21. StreamingCommunity/Api/Site/guardaserie/site.py +4 -12
  22. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +3 -10
  23. StreamingCommunity/Api/Site/mediasetinfinity/film.py +11 -12
  24. StreamingCommunity/Api/Site/mediasetinfinity/series.py +4 -15
  25. StreamingCommunity/Api/Site/mediasetinfinity/site.py +16 -32
  26. StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +39 -50
  27. StreamingCommunity/Api/Site/mediasetinfinity/util/fix_mpd.py +3 -3
  28. StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +7 -25
  29. StreamingCommunity/Api/Site/raiplay/film.py +6 -8
  30. StreamingCommunity/Api/Site/raiplay/series.py +5 -20
  31. StreamingCommunity/Api/Site/raiplay/site.py +45 -47
  32. StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +91 -55
  33. StreamingCommunity/Api/Site/raiplay/util/get_license.py +3 -12
  34. StreamingCommunity/Api/Site/streamingcommunity/film.py +5 -16
  35. StreamingCommunity/Api/Site/streamingcommunity/series.py +5 -10
  36. StreamingCommunity/Api/Site/streamingcommunity/site.py +3 -22
  37. StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +11 -27
  38. StreamingCommunity/Api/Site/streamingwatch/__init__.py +1 -0
  39. StreamingCommunity/Api/Site/streamingwatch/film.py +4 -2
  40. StreamingCommunity/Api/Site/streamingwatch/series.py +4 -14
  41. StreamingCommunity/Api/Site/streamingwatch/site.py +4 -18
  42. StreamingCommunity/Api/Site/streamingwatch/util/ScrapeSerie.py +0 -3
  43. StreamingCommunity/Api/Template/Util/__init__.py +4 -2
  44. StreamingCommunity/Api/Template/Util/manage_ep.py +66 -0
  45. StreamingCommunity/Api/Template/config_loader.py +0 -7
  46. StreamingCommunity/Lib/Downloader/DASH/decrypt.py +54 -1
  47. StreamingCommunity/Lib/Downloader/DASH/downloader.py +186 -70
  48. StreamingCommunity/Lib/Downloader/DASH/parser.py +2 -3
  49. StreamingCommunity/Lib/Downloader/DASH/segments.py +109 -68
  50. StreamingCommunity/Lib/Downloader/HLS/downloader.py +100 -82
  51. StreamingCommunity/Lib/Downloader/HLS/segments.py +40 -28
  52. StreamingCommunity/Lib/Downloader/MP4/downloader.py +16 -4
  53. StreamingCommunity/Lib/FFmpeg/capture.py +37 -5
  54. StreamingCommunity/Lib/FFmpeg/command.py +32 -90
  55. StreamingCommunity/Lib/M3U8/estimator.py +47 -1
  56. StreamingCommunity/Lib/TMBD/tmdb.py +2 -4
  57. StreamingCommunity/TelegramHelp/config.json +0 -1
  58. StreamingCommunity/Upload/update.py +19 -6
  59. StreamingCommunity/Upload/version.py +1 -1
  60. StreamingCommunity/Util/config_json.py +28 -21
  61. StreamingCommunity/Util/http_client.py +28 -0
  62. StreamingCommunity/Util/os.py +16 -6
  63. StreamingCommunity/Util/table.py +50 -8
  64. {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/METADATA +1 -3
  65. streamingcommunity-3.4.2.dist-info/RECORD +111 -0
  66. streamingcommunity-3.3.9.dist-info/RECORD +0 -111
  67. {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/WHEEL +0 -0
  68. {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/entry_points.txt +0 -0
  69. {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/licenses/LICENSE +0 -0
  70. {streamingcommunity-3.3.9.dist-info → streamingcommunity-3.4.2.dist-info}/top_level.txt +0 -0
@@ -1,8 +1,8 @@
1
1
  # 16.03.25
2
2
 
3
3
  import os
4
- from typing import Tuple
5
4
  from urllib.parse import urlparse, parse_qs
5
+ from typing import Tuple
6
6
 
7
7
 
8
8
  # External library
@@ -12,7 +12,7 @@ from rich.prompt import Prompt
12
12
 
13
13
  # Internal utilities
14
14
  from StreamingCommunity.Util.message import start_message
15
- from StreamingCommunity.Util.os import os_manager, get_wvd_path
15
+ from StreamingCommunity.Util.os import os_manager
16
16
 
17
17
 
18
18
  # Logic class
@@ -22,7 +22,8 @@ from StreamingCommunity.Api.Template.Util import (
22
22
  map_episode_title,
23
23
  validate_selection,
24
24
  validate_episode_selection,
25
- display_episodes_list
25
+ display_episodes_list,
26
+ display_seasons_list
26
27
  )
27
28
  from StreamingCommunity.Api.Template.config_loader import site_constant
28
29
  from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
@@ -72,7 +73,6 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
72
73
 
73
74
  # Download the episode
74
75
  dash_process = DASH_Downloader(
75
- cdm_device=get_wvd_path(),
76
76
  license_url='https://www.crunchyroll.com/license/v1/license/widevine',
77
77
  mpd_url=mpd_url,
78
78
  mpd_sub_list=mpd_list_sub,
@@ -161,20 +161,11 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
161
161
  - episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
162
162
  """
163
163
  scrape_serie = GetSerieInfo(select_season.url.split("/")[-1])
164
-
165
- # Get total number of seasons
166
164
  seasons_count = scrape_serie.getNumberSeason()
167
165
 
168
- # Prompt user for season selection and download episodes
169
- console.print(f"\n[green]Seasons found: [red]{seasons_count}")
170
-
171
166
  # If season_selection is provided, use it instead of asking for input
172
167
  if season_selection is None:
173
- index_season_selected = msg.ask(
174
- "\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
175
- "[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
176
- )
177
-
168
+ index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
178
169
  else:
179
170
  index_season_selected = season_selection
180
171
  console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
@@ -186,9 +177,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
186
177
  # Loop through the selected seasons and download episodes
187
178
  for i_season in list_season_select:
188
179
  if len(list_season_select) > 1 or index_season_selected == "*":
189
- # Download all episodes if multiple seasons are selected or if '*' is used
190
180
  download_episode(i_season, scrape_serie, download_all=True)
191
-
192
181
  else:
193
- # Otherwise, let the user select specific episodes for the single season
194
182
  download_episode(i_season, scrape_serie, download_all=False, episode_selection=episode_selection)
@@ -1,15 +1,13 @@
1
1
  # 16.03.25
2
2
 
3
- import sys
4
-
5
3
 
6
4
  # External libraries
7
- from curl_cffi import requests
8
5
  from rich.console import Console
9
6
 
10
7
 
11
8
  # Internal utilities
12
9
  from StreamingCommunity.Util.config_json import config_manager
10
+ from StreamingCommunity.Util.http_client import create_client_curl
13
11
  from StreamingCommunity.Util.table import TVShowManager
14
12
 
15
13
 
@@ -23,7 +21,6 @@ from .util.get_license import CrunchyrollClient
23
21
  console = Console()
24
22
  media_search_manager = MediaManager()
25
23
  table_show_manager = TVShowManager()
26
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
27
24
 
28
25
 
29
26
  def title_search(query: str) -> int:
@@ -43,13 +40,13 @@ def title_search(query: str) -> int:
43
40
  config = config_manager.get_dict("SITE_LOGIN", "crunchyroll")
44
41
  if not config.get('device_id') or not config.get('etp_rt'):
45
42
  console.print("[bold red] device_id or etp_rt is missing or empty in config.json.[/bold red]")
46
- sys.exit(0)
43
+ raise Exception("device_id or etp_rt is missing or empty in config.json.")
47
44
 
48
45
  # Initialize Crunchyroll client
49
46
  client = CrunchyrollClient()
50
47
  if not client.start():
51
48
  console.print("[bold red] Failed to authenticate with Crunchyroll.[/bold red]")
52
- sys.exit(0)
49
+ raise Exception("Failed to authenticate with Crunchyroll.")
53
50
 
54
51
  # Build new Crunchyroll API search URL
55
52
  api_url = "https://www.crunchyroll.com/content/v2/discover/search"
@@ -68,13 +65,7 @@ def title_search(query: str) -> int:
68
65
  console.print(f"[cyan]Search url: [yellow]{api_url}")
69
66
 
70
67
  try:
71
- response = requests.get(
72
- api_url,
73
- params=params,
74
- headers=headers,
75
- timeout=max_timeout,
76
- impersonate="chrome136"
77
- )
68
+ response = create_client_curl(headers=headers).get(api_url, params=params)
78
69
  response.raise_for_status()
79
70
 
80
71
  except Exception as e:
@@ -3,31 +3,18 @@
3
3
  import logging
4
4
 
5
5
 
6
- # External libraries
7
- from curl_cffi import requests
8
-
9
-
10
6
  # Internal utilities
11
- from StreamingCommunity.Util.config_json import config_manager
12
7
  from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
8
+ from StreamingCommunity.Util.http_client import create_client_curl
13
9
  from .get_license import CrunchyrollClient
14
10
 
15
11
 
16
- # Variable
17
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
18
-
19
-
20
12
  def get_series_seasons(series_id, headers, params):
21
13
  """
22
14
  Fetches the seasons for a given series ID from Crunchyroll.
23
15
  """
24
16
  url = f'https://www.crunchyroll.com/content/v2/cms/series/{series_id}/seasons'
25
- response = requests.get(
26
- url,
27
- params=params,
28
- headers=headers,
29
- impersonate="chrome136"
30
- )
17
+ response = create_client_curl(headers=headers).get(url, params=params)
31
18
  return response
32
19
 
33
20
 
@@ -36,12 +23,7 @@ def get_season_episodes(season_id, headers, params):
36
23
  Fetches the episodes for a given season ID from Crunchyroll.
37
24
  """
38
25
  url = f'https://www.crunchyroll.com/content/v2/cms/seasons/{season_id}/episodes'
39
- response = requests.get(
40
- url,
41
- params=params,
42
- headers=headers,
43
- impersonate="chrome136"
44
- )
26
+ response = create_client_curl(headers=headers).get(url, params=params)
45
27
  return response
46
28
 
47
29
 
@@ -137,12 +119,8 @@ class GetSerieInfo:
137
119
  'ratings': 'true',
138
120
  'locale': 'it-IT',
139
121
  }
140
- response = requests.get(
141
- url,
142
- params=params,
143
- headers=headers,
144
- impersonate="chrome136"
145
- )
122
+
123
+ response = create_client_curl(headers=headers).get(url, params=params)
146
124
 
147
125
  if response.status_code != 200:
148
126
  logging.warning(f"Failed to fetch audio locales for episode {episode_id}")
@@ -1,11 +1,11 @@
1
1
  # 28.07.25
2
2
 
3
3
  from typing import Tuple, List, Dict
4
- from curl_cffi import requests
5
4
 
6
5
 
7
6
  # Internal utilities
8
7
  from StreamingCommunity.Util.config_json import config_manager
8
+ from StreamingCommunity.Util.http_client import create_client_curl
9
9
  from StreamingCommunity.Util.headers import get_userAgent
10
10
 
11
11
 
@@ -44,17 +44,13 @@ class CrunchyrollClient:
44
44
  headers['authorization'] = f'Basic {PUBLIC_TOKEN}'
45
45
  headers['content-type'] = 'application/x-www-form-urlencoded'
46
46
 
47
- response = requests.post(
48
- 'https://www.crunchyroll.com/auth/v1/token',
49
- cookies=self._get_cookies(),
50
- headers=headers,
51
- data={
52
- 'device_id': self.device_id,
53
- 'device_type': 'Chrome on Windows',
54
- 'grant_type': 'etp_rt_cookie',
55
- },
56
- impersonate="chrome136"
57
- )
47
+ data = {
48
+ 'device_id': self.device_id,
49
+ 'device_type': 'Chrome on Windows',
50
+ 'grant_type': 'etp_rt_cookie',
51
+ }
52
+
53
+ response = create_client_curl(headers=headers).post('https://www.crunchyroll.com/auth/v1/token', cookies=self._get_cookies(), data=data)
58
54
 
59
55
  if response.status_code == 400:
60
56
  print("Error 400: Please enter a correct 'etp_rt' value in config.json. You can find the value in the request headers.")
@@ -69,14 +65,8 @@ class CrunchyrollClient:
69
65
 
70
66
  def get_streams(self, media_id: str) -> Dict:
71
67
  """Ottieni gli stream disponibili"""
72
- response = requests.get(
73
- f'https://www.crunchyroll.com/playback/v3/{media_id}/web/chrome/play',
74
- cookies=self._get_cookies(),
75
- headers=self._get_headers(),
76
- params={'locale': self.locale},
77
- impersonate="chrome136"
78
- )
79
-
68
+ response = create_client_curl(headers=self._get_headers()).get(f'https://www.crunchyroll.com/playback/v3/{media_id}/web/chrome/play', cookies=self._get_cookies(), params={'locale': self.locale})
69
+
80
70
  if response.status_code == 403:
81
71
  raise Exception("Playback is Rejected: The current subscription does not have access to this content")
82
72
 
@@ -94,12 +84,7 @@ class CrunchyrollClient:
94
84
 
95
85
  def delete_active_stream(self, media_id: str, token: str) -> bool:
96
86
  """Elimina uno stream attivo"""
97
- response = requests.delete(
98
- f'https://www.crunchyroll.com/playback/v1/token/{media_id}/{token}',
99
- cookies=self._get_cookies(),
100
- headers=self._get_headers(),
101
- impersonate="chrome136"
102
- )
87
+ response = create_client_curl(headers=self._get_headers()).delete(f'https://www.crunchyroll.com/playback/v1/token/{media_id}/{token}', cookies=self._get_cookies())
103
88
  response.raise_for_status()
104
89
  return response.status_code in [200, 204]
105
90
 
@@ -20,7 +20,8 @@ from StreamingCommunity.Api.Template.Util import (
20
20
  dynamic_format_number,
21
21
  validate_selection,
22
22
  validate_episode_selection,
23
- display_episodes_list
23
+ display_episodes_list,
24
+ display_seasons_list
24
25
  )
25
26
  from StreamingCommunity.Api.Template.config_loader import site_constant
26
27
  from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
@@ -145,19 +146,11 @@ def download_series(dict_serie: MediaItem, season_selection: str = None, episode
145
146
 
146
147
  # Create class
147
148
  scrape_serie = GetSerieInfo(dict_serie)
148
-
149
- # Get season count
150
149
  seasons_count = scrape_serie.get_seasons_number()
151
-
152
- # Prompt user for season selection and download episodes
153
- console.print(f"\n[green]Seasons found: [red]{seasons_count}")
154
150
 
155
151
  # If season_selection is provided, use it instead of asking for input
156
152
  if season_selection is None:
157
- index_season_selected = msg.ask(
158
- "\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
159
- "[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
160
- )
153
+ index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
161
154
  else:
162
155
  index_season_selected = season_selection
163
156
  console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
@@ -169,10 +162,6 @@ def download_series(dict_serie: MediaItem, season_selection: str = None, episode
169
162
  # Loop through the selected seasons and download episodes
170
163
  for i_season in list_season_select:
171
164
  if len(list_season_select) > 1 or index_season_selected == "*":
172
-
173
- # Download all episodes if multiple seasons are selected or if '*' is used
174
165
  download_episode(scrape_serie, i_season, download_all=True)
175
166
  else:
176
-
177
- # Otherwise, let the user select specific episodes for the single season
178
167
  download_episode(scrape_serie, i_season, download_all=False, episode_selection=episode_selection)
@@ -1,13 +1,14 @@
1
1
  # 09.06.24
2
2
 
3
+
3
4
  # External libraries
4
- import httpx
5
5
  from bs4 import BeautifulSoup
6
6
  from rich.console import Console
7
7
 
8
+
8
9
  # Internal utilities
9
- from StreamingCommunity.Util.config_json import config_manager
10
10
  from StreamingCommunity.Util.headers import get_userAgent
11
+ from StreamingCommunity.Util.http_client import create_client
11
12
  from StreamingCommunity.Util.table import TVShowManager
12
13
 
13
14
 
@@ -20,8 +21,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
20
21
  console = Console()
21
22
  media_search_manager = MediaManager()
22
23
  table_show_manager = TVShowManager()
23
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
24
-
25
24
 
26
25
 
27
26
  def title_search(query: str) -> int:
@@ -41,15 +40,8 @@ def title_search(query: str) -> int:
41
40
  console.print(f"[cyan]Search url: [yellow]{search_url}")
42
41
 
43
42
  try:
44
- response = httpx.get(
45
- search_url,
46
- headers={'user-agent': get_userAgent()},
47
- timeout=max_timeout,
48
- follow_redirects=True,
49
- verify=False
50
- )
43
+ response = create_client(headers={'user-agent': get_userAgent()}).get(search_url)
51
44
  response.raise_for_status()
52
-
53
45
  except Exception as e:
54
46
  console.print(f"[red]Site: {site_constant.SITE_NAME}, request search error: {e}")
55
47
  return 0
@@ -5,22 +5,18 @@ from typing import List, Dict
5
5
 
6
6
 
7
7
  # External libraries
8
- import httpx
9
8
  from bs4 import BeautifulSoup
10
9
 
11
10
 
12
11
  # Internal utilities
13
12
  from StreamingCommunity.Util.headers import get_userAgent
14
- from StreamingCommunity.Util.config_json import config_manager
13
+ from StreamingCommunity.Util.http_client import create_client
15
14
 
16
15
 
17
16
  # Logic class
18
17
  from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
19
18
 
20
19
 
21
- # Variable
22
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
23
-
24
20
 
25
21
  class GetSerieInfo:
26
22
  def __init__(self, dict_serie: MediaItem) -> None:
@@ -43,8 +39,7 @@ class GetSerieInfo:
43
39
  int: Number of seasons of the TV series. Returns -1 if parsing fails.
44
40
  """
45
41
  try:
46
- # Make an HTTP request to the series URL
47
- response = httpx.get(self.url, headers=self.headers, timeout=max_timeout, follow_redirects=True)
42
+ response = create_client(headers=self.headers).get(self.url)
48
43
  response.raise_for_status()
49
44
 
50
45
  # Find the seasons container
@@ -72,9 +67,7 @@ class GetSerieInfo:
72
67
  List[Dict[str, str]]: List of dictionaries containing episode information.
73
68
  """
74
69
  try:
75
-
76
- # Make an HTTP request to the series URL
77
- response = httpx.get(self.url, headers=self.headers, timeout=max_timeout, follow_redirects=True)
70
+ response = create_client(headers=self.headers).get(self.url)
78
71
  response.raise_for_status()
79
72
 
80
73
  # Parse HTML content of the page
@@ -9,7 +9,8 @@ from rich.console import Console
9
9
 
10
10
 
11
11
  # Internal utilities
12
- from StreamingCommunity.Util.os import os_manager, get_wvd_path
12
+ from StreamingCommunity.Util.config_json import config_manager
13
+ from StreamingCommunity.Util.os import os_manager
13
14
  from StreamingCommunity.Util.message import start_message
14
15
  from StreamingCommunity.Util.headers import get_headers
15
16
 
@@ -22,11 +23,12 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
22
23
  # Player
23
24
  from .util.fix_mpd import get_manifest
24
25
  from StreamingCommunity import DASH_Downloader
25
- from .util.get_license import get_bearer_token, get_playback_url, get_tracking_info, generate_license_url
26
+ from .util.get_license import get_playback_url, get_tracking_info, generate_license_url
26
27
 
27
28
 
28
29
  # Variable
29
30
  console = Console()
31
+ extension_output = config_manager.get("M3U8_CONVERSION", "extension")
30
32
 
31
33
 
32
34
  def download_film(select_title: MediaItem) -> Tuple[str, bool]:
@@ -43,21 +45,18 @@ def download_film(select_title: MediaItem) -> Tuple[str, bool]:
43
45
  console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
44
46
 
45
47
  # Define the filename and path for the downloaded film
46
- title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
47
- mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
48
+ title_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
49
+ mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))
48
50
 
49
- # Generate mpd and license URLs
50
- bearer = get_bearer_token()
51
+ # Get playback URL and tracking info
52
+ playback_json = get_playback_url(select_title.id)
53
+ tracking_info = get_tracking_info(playback_json)['videos'][0]
51
54
 
52
- playback_json = get_playback_url(bearer, select_title.id)
53
- tracking_info = get_tracking_info(bearer, playback_json)[0]
54
-
55
- license_url = generate_license_url(bearer, tracking_info)
56
- mpd_url = get_manifest(tracking_info['video_src'])
55
+ license_url = generate_license_url(tracking_info)
56
+ mpd_url = get_manifest(tracking_info['url'])
57
57
 
58
58
  # Download the episode
59
59
  dash_process = DASH_Downloader(
60
- cdm_device=get_wvd_path(),
61
60
  license_url=license_url,
62
61
  mpd_url=mpd_url,
63
62
  output_path=os.path.join(mp4_path, title_name),
@@ -12,7 +12,7 @@ from rich.prompt import Prompt
12
12
  # Internal utilities
13
13
  from StreamingCommunity.Util.headers import get_headers
14
14
  from StreamingCommunity.Util.message import start_message
15
- from StreamingCommunity.Util.os import os_manager, get_wvd_path
15
+ from StreamingCommunity.Util.os import os_manager
16
16
 
17
17
 
18
18
  # Logic class
@@ -22,7 +22,8 @@ from StreamingCommunity.Api.Template.Util import (
22
22
  map_episode_title,
23
23
  validate_selection,
24
24
  validate_episode_selection,
25
- display_episodes_list
25
+ display_episodes_list,
26
+ display_seasons_list
26
27
  )
27
28
  from StreamingCommunity.Api.Template.config_loader import site_constant
28
29
  from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
@@ -70,7 +71,6 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
70
71
 
71
72
  # Download the episode
72
73
  dash_process = DASH_Downloader(
73
- cdm_device=get_wvd_path(),
74
74
  license_url=license_url,
75
75
  mpd_url=mpd_url,
76
76
  mpd_sub_list=tracking_info['subtitles'],
@@ -149,20 +149,11 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
149
149
  - episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
150
150
  """
151
151
  scrape_serie = GetSerieInfo(select_season.url)
152
-
153
- # Get total number of seasons
154
152
  seasons_count = scrape_serie.getNumberSeason()
155
153
 
156
- # Prompt user for season selection and download episodes
157
- console.print(f"\n[green]Seasons found: [red]{seasons_count}")
158
-
159
154
  # If season_selection is provided, use it instead of asking for input
160
155
  if season_selection is None:
161
- index_season_selected = msg.ask(
162
- "\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
163
- "[yellow](e.g., 1-2) [cyan]for a range of seasons, or [yellow](e.g., 3-*) [cyan]to download from a specific season to the end"
164
- )
165
-
156
+ index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
166
157
  else:
167
158
  index_season_selected = season_selection
168
159
  console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
@@ -174,8 +165,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
174
165
  # Loop through the selected seasons and download episodes
175
166
  for i_season in list_season_select:
176
167
  if len(list_season_select) > 1 or index_season_selected == "*":
177
- # Download all episodes if multiple seasons are selected or if '*' is used
178
168
  download_episode(i_season, scrape_serie, download_all=True)
179
169
  else:
180
- # Otherwise, let the user select specific episodes for the single season
181
170
  download_episode(i_season, scrape_serie, download_all=False, episode_selection=episode_selection)
@@ -4,12 +4,11 @@ from datetime import datetime
4
4
 
5
5
 
6
6
  # External libraries
7
- import httpx
8
7
  from rich.console import Console
9
8
 
10
9
 
11
10
  # Internal utilities
12
- from StreamingCommunity.Util.config_json import config_manager
11
+ from StreamingCommunity.Util.http_client import create_client
13
12
  from StreamingCommunity.Util.table import TVShowManager
14
13
  from StreamingCommunity.Api.Template.config_loader import site_constant
15
14
  from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
@@ -23,7 +22,6 @@ from .util.get_license import get_bearer_token
23
22
  console = Console()
24
23
  media_search_manager = MediaManager()
25
24
  table_show_manager = TVShowManager()
26
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
27
25
 
28
26
 
29
27
  def title_search(query: str) -> int:
@@ -46,15 +44,9 @@ def title_search(query: str) -> int:
46
44
  'extensions': f'{{"persistedQuery":{{"version":1,"sha256Hash":"{class_mediaset_api.getHash256()}"}}}}',
47
45
  'variables': f'{{"first":10,"property":"search","query":"{query}","uxReference":"filteredSearch"}}',
48
46
  }
47
+
49
48
  try:
50
- response = httpx.get(
51
- search_url,
52
- headers=class_mediaset_api.generate_request_headers(),
53
- params=params,
54
- timeout=max_timeout,
55
- follow_redirects=True
56
- )
57
-
49
+ response = create_client(headers=class_mediaset_api.generate_request_headers()).get(search_url, params=params)
58
50
  response.raise_for_status()
59
51
  except Exception as e:
60
52
  console.print(f"[red]Site: {site_constant.SITE_NAME}, request search error: {e}")
@@ -66,33 +58,25 @@ def title_search(query: str) -> int:
66
58
 
67
59
  # Process items
68
60
  for item in items:
69
- item_type = "tv" if item.get("__typename") == "SeriesItem" else "film"
61
+ is_series = (
62
+ item.get("__typename") == "SeriesItem"
63
+ or item.get("cardLink", {}).get("referenceType") == "series"
64
+ or bool(item.get("seasons"))
65
+ )
66
+ item_type = "tv" if is_series else "film"
70
67
 
71
- # Bastava un campo data ma no ...
72
- date = item.get("year")
68
+ # Get date
69
+ date = item.get("year") or ''
73
70
  if not date:
74
- updated = item.get("updated")
71
+ updated = item.get("updated") or item.get("r") or ''
75
72
  if updated:
76
73
  try:
77
- date = datetime.fromisoformat(updated.replace("Z", "+00:00")).year
74
+ date = datetime.fromisoformat(str(updated).replace("Z", "+00:00")).year
78
75
  except Exception:
79
- try:
80
- timestamp_ms = int(updated)
81
- date = datetime.fromtimestamp(timestamp_ms / 1000).year
82
- except Exception:
83
- date = ""
84
-
85
- date = item.get('year', '')
86
- if not date and item.get('updated'):
87
- try:
88
-
89
- timestamp_ms = int(item.get('updated', 0))
90
- date = datetime.fromtimestamp(timestamp_ms / 1000).year
91
- except (ValueError, TypeError):
92
- date = ''
76
+ date = ''
93
77
 
94
78
  media_search_manager.add_media({
95
- "url": item.get("cardLink", "").get("value", ""),
79
+ "url": item.get("cardLink", {}).get("value", ""),
96
80
  "id": item.get("guid", ""),
97
81
  "name": item.get("cardTitle", "No Title"),
98
82
  "type": item_type,
@@ -100,4 +84,4 @@ def title_search(query: str) -> int:
100
84
  "date": date,
101
85
  })
102
86
 
103
- return media_search_manager.get_length()
87
+ return media_search_manager.get_length()