StreamingCommunity 3.3.6__py3-none-any.whl → 3.3.8__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 (48) hide show
  1. StreamingCommunity/Api/Site/altadefinizione/film.py +1 -1
  2. StreamingCommunity/Api/Site/altadefinizione/series.py +1 -1
  3. StreamingCommunity/Api/Site/animeunity/serie.py +2 -2
  4. StreamingCommunity/Api/Site/animeworld/film.py +1 -1
  5. StreamingCommunity/Api/Site/animeworld/serie.py +2 -2
  6. StreamingCommunity/Api/Site/crunchyroll/film.py +3 -2
  7. StreamingCommunity/Api/Site/crunchyroll/series.py +3 -2
  8. StreamingCommunity/Api/Site/crunchyroll/site.py +0 -8
  9. StreamingCommunity/Api/Site/crunchyroll/util/get_license.py +11 -105
  10. StreamingCommunity/Api/Site/guardaserie/series.py +1 -1
  11. StreamingCommunity/Api/Site/mediasetinfinity/film.py +1 -1
  12. StreamingCommunity/Api/Site/mediasetinfinity/series.py +7 -9
  13. StreamingCommunity/Api/Site/mediasetinfinity/site.py +29 -66
  14. StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +5 -1
  15. StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +151 -233
  16. StreamingCommunity/Api/Site/raiplay/film.py +2 -10
  17. StreamingCommunity/Api/Site/raiplay/series.py +2 -10
  18. StreamingCommunity/Api/Site/raiplay/site.py +1 -0
  19. StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +7 -1
  20. StreamingCommunity/Api/Site/streamingcommunity/film.py +1 -1
  21. StreamingCommunity/Api/Site/streamingcommunity/series.py +1 -1
  22. StreamingCommunity/Api/Site/streamingwatch/film.py +1 -1
  23. StreamingCommunity/Api/Site/streamingwatch/series.py +1 -1
  24. StreamingCommunity/Api/Template/loader.py +158 -0
  25. StreamingCommunity/Lib/Downloader/DASH/downloader.py +267 -51
  26. StreamingCommunity/Lib/Downloader/DASH/segments.py +46 -15
  27. StreamingCommunity/Lib/Downloader/HLS/downloader.py +51 -36
  28. StreamingCommunity/Lib/Downloader/HLS/segments.py +105 -25
  29. StreamingCommunity/Lib/Downloader/MP4/downloader.py +12 -13
  30. StreamingCommunity/Lib/FFmpeg/command.py +18 -81
  31. StreamingCommunity/Lib/FFmpeg/util.py +14 -10
  32. StreamingCommunity/Lib/M3U8/estimator.py +13 -12
  33. StreamingCommunity/Lib/M3U8/parser.py +16 -16
  34. StreamingCommunity/Upload/update.py +2 -4
  35. StreamingCommunity/Upload/version.py +2 -2
  36. StreamingCommunity/Util/config_json.py +3 -132
  37. StreamingCommunity/Util/installer/bento4_install.py +21 -31
  38. StreamingCommunity/Util/installer/device_install.py +0 -1
  39. StreamingCommunity/Util/installer/ffmpeg_install.py +0 -1
  40. StreamingCommunity/Util/message.py +8 -9
  41. StreamingCommunity/Util/os.py +0 -8
  42. StreamingCommunity/run.py +4 -44
  43. {streamingcommunity-3.3.6.dist-info → streamingcommunity-3.3.8.dist-info}/METADATA +1 -3
  44. {streamingcommunity-3.3.6.dist-info → streamingcommunity-3.3.8.dist-info}/RECORD +48 -47
  45. {streamingcommunity-3.3.6.dist-info → streamingcommunity-3.3.8.dist-info}/WHEEL +0 -0
  46. {streamingcommunity-3.3.6.dist-info → streamingcommunity-3.3.8.dist-info}/entry_points.txt +0 -0
  47. {streamingcommunity-3.3.6.dist-info → streamingcommunity-3.3.8.dist-info}/licenses/LICENSE +0 -0
  48. {streamingcommunity-3.3.6.dist-info → streamingcommunity-3.3.8.dist-info}/top_level.txt +0 -0
@@ -56,7 +56,7 @@ def download_film(select_title: MediaItem) -> str:
56
56
  TelegramSession.updateScriptId(script_id, select_title.name)
57
57
 
58
58
  start_message()
59
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
59
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
60
60
 
61
61
  # Extract mostraguarda URL
62
62
  try:
@@ -54,7 +54,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
54
54
 
55
55
  # Get episode information
56
56
  obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
57
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
57
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
58
58
 
59
59
  # Telegram integration
60
60
  if site_constant.TELEGRAM_BOT:
@@ -48,7 +48,7 @@ def download_episode(index_select: int, scrape_serie: ScrapeSerieAnime, video_so
48
48
 
49
49
  # Get episode information
50
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]{scrape_serie.series_name}[/cyan] ([cyan]E{obj_episode.number}[/cyan]) \n")
51
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] ([cyan]E{obj_episode.number}[/cyan]) \n")
52
52
 
53
53
  if site_constant.TELEGRAM_BOT:
54
54
  bot = get_bot_instance()
@@ -104,7 +104,7 @@ def download_series(select_title: MediaItem, season_selection: str = None, episo
104
104
 
105
105
  # Get episode information
106
106
  episoded_count = scrape_serie.get_count_episodes()
107
- console.print(f"[green]Episodes count:[/green] [red]{episoded_count}[/red]")
107
+ console.print(f"\n[green]Episodes count:[/green] [red]{episoded_count}[/red]")
108
108
 
109
109
  # Telegram bot integration
110
110
  if episode_selection is None:
@@ -41,7 +41,7 @@ def download_film(select_title: MediaItem):
41
41
 
42
42
  # Get episode information
43
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")
44
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]{scrape_serie.get_name()}[/cyan]) \n")
45
45
 
46
46
  # Define filename and path for the downloaded video
47
47
  mp4_name = f"{scrape_serie.get_name()}.mp4"
@@ -47,7 +47,7 @@ def download_episode(index_select: int, scrape_serie: ScrapSerie) -> Tuple[str,b
47
47
 
48
48
  # Get episode information
49
49
  episode_data = scrape_serie.selectEpisode(1, index_select)
50
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.get_name()}[/cyan] ([cyan]E{str(index_select+1)}[/cyan]) \n")
50
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.get_name()}[/cyan] ([cyan]E{str(index_select+1)}[/cyan]) \n")
51
51
 
52
52
  # Define filename and path for the downloaded video
53
53
  mp4_name = f"{scrape_serie.get_name()}_EP_{dynamic_format_number(str(index_select+1))}.mp4"
@@ -84,7 +84,7 @@ def download_series(select_title: MediaItem, episode_selection: str = None):
84
84
  episodes = scrape_serie.get_episodes()
85
85
 
86
86
  # Get episode count
87
- console.print(f"[green]Episodes found:[/green] [red]{len(episodes)}[/red]")
87
+ console.print(f"\n[green]Episodes count:[/green] [red]{len(episodes)}[/red]")
88
88
 
89
89
  # Display episodes list and get user selection
90
90
  if episode_selection is None:
@@ -40,7 +40,7 @@ def download_film(select_title: MediaItem) -> str:
40
40
  - str: output path if successful, otherwise None
41
41
  """
42
42
  start_message()
43
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
43
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
44
44
 
45
45
  # Define filename and path for the downloaded video
46
46
  mp4_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
@@ -49,7 +49,7 @@ def download_film(select_title: MediaItem) -> str:
49
49
  # Generate mpd and license URLs
50
50
  url_id = select_title.get('url').split('/')[-1]
51
51
  device_id = generate_device_id()
52
- mpd_url, mpd_headers = get_playback_session(get_auth_token(device_id), device_id, url_id)
52
+ mpd_url, mpd_headers, mpd_list_sub = get_playback_session(get_auth_token(device_id), device_id, url_id)
53
53
  parsed_url = urlparse(mpd_url)
54
54
  query_params = parse_qs(parsed_url.query)
55
55
 
@@ -58,6 +58,7 @@ def download_film(select_title: MediaItem) -> str:
58
58
  cdm_device=get_wvd_path(),
59
59
  license_url='https://www.crunchyroll.com/license/v1/license/widevine',
60
60
  mpd_url=mpd_url,
61
+ mpd_sub_list=mpd_list_sub,
61
62
  output_path=os.path.join(mp4_path, mp4_name),
62
63
  )
63
64
  dash_process.parse_manifest(custom_headers=mpd_headers)
@@ -56,7 +56,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
56
56
  # Get episode information
57
57
  obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
58
58
 
59
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
59
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
60
60
 
61
61
  # Define filename and path for the downloaded video
62
62
  mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.get('name'))}.mp4"
@@ -67,7 +67,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
67
67
  device_id = generate_device_id()
68
68
  token_mpd = get_auth_token(device_id)
69
69
 
70
- mpd_url, mpd_headers = get_playback_session(token_mpd, device_id, url_id)
70
+ mpd_url, mpd_headers, mpd_list_sub = get_playback_session(token_mpd, device_id, url_id)
71
71
  parsed_url = urlparse(mpd_url)
72
72
  query_params = parse_qs(parsed_url.query)
73
73
 
@@ -76,6 +76,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
76
76
  cdm_device=get_wvd_path(),
77
77
  license_url='https://www.crunchyroll.com/license/v1/license/widevine',
78
78
  mpd_url=mpd_url,
79
+ mpd_sub_list=mpd_list_sub,
79
80
  output_path=os.path.join(mp4_path, mp4_name),
80
81
  )
81
82
  dash_process.parse_manifest(custom_headers=mpd_headers)
@@ -1,6 +1,5 @@
1
1
  # 16.03.25
2
2
 
3
- import os
4
3
  import sys
5
4
 
6
5
 
@@ -11,7 +10,6 @@ from rich.console import Console
11
10
 
12
11
  # Internal utilities
13
12
  from StreamingCommunity.Util.config_json import config_manager
14
- from StreamingCommunity.Util.os import get_wvd_path
15
13
  from StreamingCommunity.Util.headers import get_headers
16
14
  from StreamingCommunity.Util.table import TVShowManager
17
15
 
@@ -42,12 +40,6 @@ def title_search(query: str) -> int:
42
40
  media_search_manager.clear()
43
41
  table_show_manager.clear()
44
42
 
45
- # Check CDM file before usage
46
- cdm_device_path = get_wvd_path()
47
- if not cdm_device_path or not isinstance(cdm_device_path, (str, bytes, os.PathLike)) or not os.path.isfile(cdm_device_path):
48
- console.print(f"[bold red] CDM file not found or invalid path: {cdm_device_path}[/bold red]")
49
- sys.exit(0)
50
-
51
43
  # Check if x_cr_tab_id or etp_rt is present
52
44
  if config_manager.get_dict("SITE_LOGIN", "crunchyroll")['x_cr_tab_id'] is None or config_manager.get_dict("SITE_LOGIN", "crunchyroll")['x_cr_tab_id'] == "" or config_manager.get_dict("SITE_LOGIN", "crunchyroll")['etp_rt'] is None or config_manager.get_dict("SITE_LOGIN", "crunchyroll")['etp_rt'] == "":
53
45
  console.print("[bold red] x_cr_tab_id or etp_rt is missing or empty.[/bold red]")
@@ -11,7 +11,7 @@ from curl_cffi.requests import Session
11
11
 
12
12
  # Internal utilities
13
13
  from StreamingCommunity.Util.config_json import config_manager
14
- from StreamingCommunity.Util.headers import get_userAgent, get_headers
14
+ from StreamingCommunity.Util.headers import get_userAgent
15
15
 
16
16
 
17
17
  # Variable
@@ -34,22 +34,6 @@ class Token:
34
34
  extra: Dict[str, Any] = field(default_factory=dict)
35
35
 
36
36
 
37
- @dataclass
38
- class Account:
39
- account_id: Optional[str] = None
40
- external_id: Optional[str] = None
41
- email: Optional[str] = None
42
- extra: Dict[str, Any] = field(default_factory=dict)
43
-
44
-
45
- @dataclass
46
- class Profile:
47
- profile_id: Optional[str] = None
48
- email: Optional[str] = None
49
- profile_name: Optional[str] = None
50
- extra: Dict[str, Any] = field(default_factory=dict)
51
-
52
-
53
37
 
54
38
  def generate_device_id():
55
39
  global device_id
@@ -102,95 +86,9 @@ def get_auth_token(device_id):
102
86
  )
103
87
 
104
88
 
105
- def get_account(token: Token, device_id):
106
- with Session(impersonate="chrome110") as session:
107
- country = (token.country or "IT")
108
- cookies = {
109
- 'device_id': device_id,
110
- 'c_locale': f'{country.lower()}-{country.upper()}',
111
- }
112
- response = session.get(
113
- 'https://www.crunchyroll.com/accounts/v1/me',
114
- headers={
115
- 'authorization': f'Bearer {token.access_token}',
116
- 'user-agent': get_userAgent(),
117
- },
118
- cookies=cookies
119
- )
120
- response.raise_for_status()
121
-
122
- # Get the JSON response
123
- data = response.json()
124
- known = {
125
- 'account_id', 'external_id', 'email'
126
- }
127
- extra = {k: v for k, v in data.items() if k not in known}
128
- return Account(
129
- account_id=data.get('account_id'),
130
- external_id=data.get('external_id'),
131
- email=data.get('email'),
132
- extra=extra
133
- )
134
-
135
-
136
- def get_profiles(token: Token, device_id):
137
- with Session(impersonate="chrome110") as session:
138
- country = token.country
139
- cookies = {
140
- 'device_id': device_id,
141
- 'c_locale': f'{country.lower()}-{country.upper()}',
142
- }
143
- response = session.get(
144
- 'https://www.crunchyroll.com/accounts/v1/me/multiprofile',
145
- headers={
146
- 'authorization': f'Bearer {token.access_token}',
147
- 'user-agent': get_userAgent(),
148
- },
149
- cookies=cookies
150
- )
151
- response.raise_for_status()
152
-
153
- # Get the JSON response
154
- data = response.json()
155
- profiles = []
156
- for p in data.get('profiles', []):
157
- known = {
158
- 'profile_id', 'email', 'profile_name'
159
- }
160
- extra = {k: v for k, v in p.items() if k not in known}
161
- profiles.append(Profile(
162
- profile_id=p.get('profile_id'),
163
- email=p.get('email'),
164
- profile_name=p.get('profile_name'),
165
- extra=extra
166
- ))
167
- return profiles
168
-
169
-
170
- def cr_login_session(device_id: str, email: str, password: str):
171
- """
172
- Esegue una richiesta di login a Crunchyroll SSO usando curl_cffi.requests.
173
- """
174
- cookies = {
175
- 'device_id': device_id,
176
- }
177
- data = (
178
- f'{{"email":"{email}","password":"{password}","eventSettings":{{}}}}'
179
- )
180
- with Session(impersonate="chrome110") as session:
181
- response = session.post(
182
- 'https://sso.crunchyroll.com/api/login',
183
- cookies=cookies,
184
- headers=get_headers(),
185
- data=data
186
- )
187
- response.raise_for_status()
188
- return response
189
-
190
-
191
89
  def get_playback_session(token: Token, device_id: str, url_id: str):
192
90
  """
193
- Crea una sessione per ottenere i dati di playback da Crunchyroll.
91
+ Crea una sessione per ottenere i dati di playback e sottotitoli da Crunchyroll.
194
92
  """
195
93
  cookies = {
196
94
  'device_id': device_id,
@@ -224,4 +122,12 @@ def get_playback_session(token: Token, device_id: str, url_id: str):
224
122
  raise Exception("Playback is Rejected: Premium required")
225
123
 
226
124
  url = data.get('url')
227
- return url, headers
125
+
126
+ subtitles = []
127
+ if 'subtitles' in data:
128
+ subtitles = [
129
+ {'language': lang, 'url': info['url'], 'format': info.get('format')}
130
+ for lang, info in data['subtitles'].items()
131
+ ]
132
+
133
+ return url, headers, subtitles
@@ -55,7 +55,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scap
55
55
  # Get episode information
56
56
  obj_episode = scape_info_serie.selectEpisode(index_season_selected, index_episode_selected-1)
57
57
  index_season_selected = dynamic_format_number(str(index_season_selected))
58
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scape_info_serie.tv_name}[/cyan] \\ [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
58
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scape_info_serie.tv_name}[/cyan] \\ [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
59
59
 
60
60
  # Define filename and path for the downloaded video
61
61
  mp4_name = f"{map_episode_title(scape_info_serie.tv_name, index_season_selected, index_episode_selected, obj_episode.get('name'))}.mp4"
@@ -40,7 +40,7 @@ def download_film(select_title: MediaItem) -> Tuple[str, bool]:
40
40
  - str: output path if successful, otherwise None
41
41
  """
42
42
  start_message()
43
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
43
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
44
44
 
45
45
  # Define the filename and path for the downloaded film
46
46
  title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
@@ -31,7 +31,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
31
31
  # Player
32
32
  from .util.fix_mpd import get_manifest
33
33
  from StreamingCommunity import DASH_Downloader
34
- from .util.get_license import get_bearer_token, get_playback_url, get_tracking_info, generate_license_url
34
+ from .util.get_license import get_playback_url, get_tracking_info, generate_license_url
35
35
 
36
36
 
37
37
  # Variable
@@ -56,26 +56,24 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
56
56
 
57
57
  # Get episode information
58
58
  obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
59
- console.print(f"[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
59
+ console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{scrape_serie.series_name}[/cyan] \\ [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
60
60
 
61
61
  # Define filename and path for the downloaded video
62
62
  mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
63
63
  mp4_path = os_manager.get_sanitize_path(os.path.join(site_constant.SERIES_FOLDER, scrape_serie.series_name, f"S{index_season_selected}"))
64
64
 
65
65
  # Generate mpd and license URLs
66
- bearer = get_bearer_token()
67
-
68
- playback_json = get_playback_url(bearer, obj_episode.id)
69
- tracking_info = get_tracking_info(bearer, playback_json)[0]
70
-
71
- license_url = generate_license_url(bearer, tracking_info)
72
- mpd_url = get_manifest(tracking_info['video_src'])
66
+ playback_json = get_playback_url(obj_episode.id)
67
+ tracking_info = get_tracking_info(playback_json)
68
+ license_url = generate_license_url(tracking_info['videos'][0])
69
+ mpd_url = get_manifest(tracking_info['videos'][0]['url'])
73
70
 
74
71
  # Download the episode
75
72
  dash_process = DASH_Downloader(
76
73
  cdm_device=get_wvd_path(),
77
74
  license_url=license_url,
78
75
  mpd_url=mpd_url,
76
+ mpd_sub_list=tracking_info['subtitles'],
79
77
  output_path=os.path.join(mp4_path, mp4_name),
80
78
  )
81
79
  dash_process.parse_manifest(custom_headers=get_headers())
@@ -1,7 +1,5 @@
1
1
  # 25.07.25
2
2
 
3
- import os
4
- import sys
5
3
  from datetime import datetime
6
4
 
7
5
 
@@ -12,8 +10,6 @@ from rich.console import Console
12
10
 
13
11
  # Internal utilities
14
12
  from StreamingCommunity.Util.config_json import config_manager
15
- from StreamingCommunity.Util.os import get_wvd_path
16
- from StreamingCommunity.Util.headers import get_headers
17
13
  from StreamingCommunity.Util.table import TVShowManager
18
14
  from StreamingCommunity.Api.Template.config_loader import site_constant
19
15
  from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
@@ -42,44 +38,18 @@ def title_search(query: str) -> int:
42
38
  """
43
39
  media_search_manager.clear()
44
40
  table_show_manager.clear()
45
-
46
- # Check CDM file before usage
47
- cdm_device_path = get_wvd_path()
48
- if not cdm_device_path or not isinstance(cdm_device_path, (str, bytes, os.PathLike)) or not os.path.isfile(cdm_device_path):
49
- console.print(f"[bold red] CDM file not found or invalid path: {cdm_device_path}[/bold red]")
50
- sys.exit(0)
51
-
52
- # Check if beToken is present
53
- if (config_manager.get_dict("SITE_LOGIN", "mediasetinfinity")["beToken"] is None or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity")["beToken"] == "") and \
54
- (config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("username") is None or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("username") == "" \
55
- or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("password") is None or config_manager.get_dict("SITE_LOGIN", "mediasetinfinity").get("password") == ""):
56
- console.print("[bold red] beToken or credentials are missing or empty.[/bold red]")
57
- sys.exit(0)
58
-
59
- search_url = 'https://api-ott-prod-fe.mediaset.net/PROD/play/reco/account/v2.0'
41
+ class_mediaset_api = get_bearer_token()
42
+ search_url = 'https://mediasetplay.api-graph.mediaset.it/'
60
43
  console.print(f"[cyan]Search url: [yellow]{search_url}")
61
44
 
62
45
  params = {
63
- 'uxReference': 'filteredSearch',
64
- 'shortId': '',
65
- 'query': query.strip(),
66
- 'params': 'channel≈;variant≈',
67
- 'contentId': '',
68
- 'property': 'search',
69
- 'tenant': 'play-prod-v2',
70
- 'aresContext': '',
71
- 'clientId': 'client_id',
72
- 'page': '1',
73
- 'hitsPerPage': '8',
46
+ 'extensions': f'{{"persistedQuery":{{"version":1,"sha256Hash":"{class_mediaset_api.getHash256()}"}}}}',
47
+ 'variables': f'{{"first":10,"property":"search","query":"{query}","uxReference":"filteredSearch"}}',
74
48
  }
75
-
76
- headers = get_headers()
77
- headers['authorization'] = f'Bearer {get_bearer_token()}'
78
-
79
49
  try:
80
50
  response = httpx.get(
81
51
  search_url,
82
- headers=headers,
52
+ headers=class_mediaset_api.generate_request_headers(),
83
53
  params=params,
84
54
  timeout=max_timeout,
85
55
  follow_redirects=True
@@ -92,32 +62,25 @@ def title_search(query: str) -> int:
92
62
 
93
63
  # Parse response
94
64
  resp_json = response.json()
95
- blocks = resp_json.get('response', {}).get('blocks', [])
96
- items = []
97
- for block in blocks:
98
- if 'items' in block:
99
- items.extend(block['items'])
100
- elif 'results' in block and 'items' in block['results']:
101
- items.extend(block['results']['items'])
102
-
65
+ items = resp_json.get("data", {}).get("getSearchPage", {}).get("areaContainersConnection", {}).get("areaContainers", [])[0].get("areas", [])[0].get("sections", [])[0].get("collections", [])[0].get("itemsConnection", {}).get("items", [])
66
+
103
67
  # Process items
104
68
  for item in items:
105
-
106
- # Get the media type
107
- program_type = item.get('programType', '') or item.get('programtype', '')
108
- program_type = program_type.lower()
109
-
110
- if program_type in ('movie', 'film'):
111
- media_type = 'film'
112
- page_url = item.get('mediasetprogram$videoPageUrl', '')
113
- elif program_type in ('series', 'serie'):
114
- media_type = 'tv'
115
- page_url = item.get('mediasetprogram$pageUrl', '')
116
- else:
117
- continue
118
-
119
- if page_url and page_url.startswith('//'):
120
- page_url = f"https:{page_url}"
69
+ item_type = "tv" if item.get("__typename") == "SeriesItem" else "film"
70
+
71
+ # Bastava un campo data ma no ...
72
+ date = item.get("year")
73
+ if not date:
74
+ updated = item.get("updated")
75
+ if updated:
76
+ try:
77
+ date = datetime.fromisoformat(updated.replace("Z", "+00:00")).year
78
+ except Exception:
79
+ try:
80
+ timestamp_ms = int(updated)
81
+ date = datetime.fromtimestamp(timestamp_ms / 1000).year
82
+ except Exception:
83
+ date = ""
121
84
 
122
85
  date = item.get('year', '')
123
86
  if not date and item.get('updated'):
@@ -129,12 +92,12 @@ def title_search(query: str) -> int:
129
92
  date = ''
130
93
 
131
94
  media_search_manager.add_media({
132
- 'id': item.get('guid', '') or item.get('_id', ''),
133
- 'name': item.get('title', ''),
134
- 'type': media_type,
135
- 'url': page_url,
136
- 'image': next(iter(item.get('thumbnails', {}).values()), {}).get('url', ''),
137
- 'date': date,
95
+ "url": item.get("cardLink", "").get("value", ""),
96
+ "id": item.get("guid", ""),
97
+ "name": item.get("cardTitle", "No Title"),
98
+ "type": item_type,
99
+ "image": None,
100
+ "date": date,
138
101
  })
139
102
 
140
- return media_search_manager.get_length()
103
+ return media_search_manager.get_length()
@@ -112,8 +112,8 @@ class GetSerieInfo:
112
112
  season['page_url'],
113
113
  headers={'User-Agent': get_userAgent()}
114
114
  )
115
+
115
116
  print("Response for _extract_season_sb_ids:", response_page.status_code, " season index:", season['tvSeasonNumber'])
116
-
117
117
  soup = BeautifulSoup(response_page.text, 'html.parser')
118
118
 
119
119
  # Try first with 'Episodi', then with 'Puntate intere'
@@ -121,10 +121,14 @@ class GetSerieInfo:
121
121
  if not link:
122
122
  #print("Using word: Puntate intere")
123
123
  link = soup.find('a', string='Puntate intere')
124
+
125
+ if link is None:
126
+ link = soup.find('a', class_ = 'titleCarousel')
124
127
 
125
128
  if link and link.has_attr('href'):
126
129
  if not link.string == 'Puntate intere':
127
130
  print("Using word: Episodi")
131
+
128
132
  season['sb'] = link['href'].split(',')[-1]
129
133
  else:
130
134
  logging.warning(f"Link 'Episodi' or 'Puntate intere' not found for season {season['tvSeasonNumber']}")