StreamingCommunity 3.2.7__py3-none-any.whl → 3.2.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of StreamingCommunity might be problematic. Click here for more details.

Files changed (79) hide show
  1. StreamingCommunity/Api/Player/Helper/Vixcloud/util.py +2 -1
  2. StreamingCommunity/Api/Player/hdplayer.py +2 -2
  3. StreamingCommunity/Api/Player/sweetpixel.py +5 -8
  4. StreamingCommunity/Api/Site/altadefinizione/__init__.py +2 -2
  5. StreamingCommunity/Api/Site/altadefinizione/film.py +10 -8
  6. StreamingCommunity/Api/Site/altadefinizione/series.py +9 -7
  7. StreamingCommunity/Api/Site/altadefinizione/site.py +1 -1
  8. StreamingCommunity/Api/Site/animeunity/__init__.py +2 -2
  9. StreamingCommunity/Api/Site/animeunity/serie.py +2 -2
  10. StreamingCommunity/Api/Site/animeworld/site.py +3 -5
  11. StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +8 -10
  12. StreamingCommunity/Api/Site/cb01new/film.py +7 -5
  13. StreamingCommunity/Api/Site/crunchyroll/__init__.py +1 -3
  14. StreamingCommunity/Api/Site/crunchyroll/film.py +9 -7
  15. StreamingCommunity/Api/Site/crunchyroll/series.py +9 -7
  16. StreamingCommunity/Api/Site/crunchyroll/site.py +10 -1
  17. StreamingCommunity/Api/Site/guardaserie/series.py +8 -6
  18. StreamingCommunity/Api/Site/guardaserie/site.py +0 -3
  19. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +1 -2
  20. StreamingCommunity/Api/Site/mediasetinfinity/__init__.py +1 -1
  21. StreamingCommunity/Api/Site/mediasetinfinity/film.py +10 -16
  22. StreamingCommunity/Api/Site/mediasetinfinity/series.py +12 -18
  23. StreamingCommunity/Api/Site/mediasetinfinity/site.py +11 -3
  24. StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +214 -180
  25. StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +2 -31
  26. StreamingCommunity/Api/Site/raiplay/__init__.py +1 -1
  27. StreamingCommunity/Api/Site/raiplay/film.py +41 -10
  28. StreamingCommunity/Api/Site/raiplay/series.py +44 -12
  29. StreamingCommunity/Api/Site/raiplay/site.py +4 -1
  30. StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +2 -1
  31. StreamingCommunity/Api/Site/raiplay/util/get_license.py +40 -0
  32. StreamingCommunity/Api/Site/streamingcommunity/__init__.py +0 -1
  33. StreamingCommunity/Api/Site/streamingcommunity/film.py +7 -5
  34. StreamingCommunity/Api/Site/streamingcommunity/series.py +9 -7
  35. StreamingCommunity/Api/Site/streamingcommunity/site.py +4 -2
  36. StreamingCommunity/Api/Site/streamingwatch/film.py +7 -5
  37. StreamingCommunity/Api/Site/streamingwatch/series.py +8 -6
  38. StreamingCommunity/Api/Site/streamingwatch/site.py +3 -1
  39. StreamingCommunity/Api/Site/streamingwatch/util/ScrapeSerie.py +3 -3
  40. StreamingCommunity/Api/Template/Util/__init__.py +10 -1
  41. StreamingCommunity/Api/Template/Util/manage_ep.py +4 -4
  42. StreamingCommunity/Api/Template/__init__.py +5 -1
  43. StreamingCommunity/Api/Template/site.py +10 -6
  44. StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +5 -12
  45. StreamingCommunity/Lib/Downloader/DASH/decrypt.py +1 -1
  46. StreamingCommunity/Lib/Downloader/DASH/downloader.py +1 -1
  47. StreamingCommunity/Lib/Downloader/DASH/parser.py +1 -1
  48. StreamingCommunity/Lib/Downloader/DASH/segments.py +4 -3
  49. StreamingCommunity/Lib/Downloader/HLS/downloader.py +11 -9
  50. StreamingCommunity/Lib/Downloader/HLS/segments.py +253 -144
  51. StreamingCommunity/Lib/Downloader/MP4/downloader.py +4 -3
  52. StreamingCommunity/Lib/Downloader/TOR/downloader.py +3 -5
  53. StreamingCommunity/Lib/Downloader/__init__.py +9 -1
  54. StreamingCommunity/Lib/FFmpeg/__init__.py +10 -1
  55. StreamingCommunity/Lib/FFmpeg/command.py +4 -6
  56. StreamingCommunity/Lib/FFmpeg/util.py +1 -1
  57. StreamingCommunity/Lib/M3U8/__init__.py +9 -1
  58. StreamingCommunity/Lib/M3U8/decryptor.py +8 -4
  59. StreamingCommunity/Lib/M3U8/estimator.py +0 -6
  60. StreamingCommunity/Lib/M3U8/parser.py +1 -1
  61. StreamingCommunity/Lib/M3U8/url_fixer.py +1 -1
  62. StreamingCommunity/Lib/TMBD/__init__.py +6 -1
  63. StreamingCommunity/TelegramHelp/config.json +1 -5
  64. StreamingCommunity/TelegramHelp/telegram_bot.py +9 -10
  65. StreamingCommunity/Upload/version.py +2 -2
  66. StreamingCommunity/Util/config_json.py +139 -59
  67. StreamingCommunity/Util/http_client.py +201 -0
  68. StreamingCommunity/Util/message.py +1 -1
  69. StreamingCommunity/Util/os.py +5 -5
  70. StreamingCommunity/Util/table.py +3 -3
  71. StreamingCommunity/__init__.py +9 -1
  72. StreamingCommunity/run.py +396 -260
  73. {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/METADATA +143 -45
  74. streamingcommunity-3.2.9.dist-info/RECORD +113 -0
  75. streamingcommunity-3.2.7.dist-info/RECORD +0 -111
  76. {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/WHEEL +0 -0
  77. {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/entry_points.txt +0 -0
  78. {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/licenses/LICENSE +0 -0
  79. {streamingcommunity-3.2.7.dist-info → streamingcommunity-3.2.9.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  # 23.11.24
2
2
 
3
- from typing import Dict, Any, List, Union, List, Optional
3
+ from typing import Dict, Any, List, Optional
4
4
 
5
5
 
6
6
  class Episode:
@@ -12,6 +12,7 @@ class Episode:
12
12
  self.name: str = data.get('name', '')
13
13
  self.duration: int = data.get('duration', 0)
14
14
  self.url: str = data.get('url', '')
15
+ self.mpd_id: str = data.get('mpd_id', '')
15
16
 
16
17
  def __str__(self):
17
18
  return f"Episode(id={self.id}, number={self.number}, name='{self.name}', duration={self.duration} sec)"
@@ -3,12 +3,12 @@
3
3
  import re
4
4
 
5
5
  # External library
6
- import httpx
7
6
  from bs4 import BeautifulSoup
8
7
 
9
8
 
10
9
  # Internal utilities
11
10
  from StreamingCommunity.Util.headers import get_userAgent
11
+ from StreamingCommunity.Util.http_client import create_client
12
12
  from StreamingCommunity.Util.config_json import config_manager
13
13
 
14
14
 
@@ -19,7 +19,7 @@ REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
19
19
 
20
20
  class VideoSource:
21
21
  def __init__(self):
22
- self.client = httpx.Client(headers={'user-agent': get_userAgent()}, timeout=MAX_TIMEOUT, verify=REQUEST_VERIFY)
22
+ self.client = create_client(headers={'user-agent': get_userAgent()})
23
23
 
24
24
  def extractLinkHdPlayer(self, response):
25
25
  """Extract iframe source from the page."""
@@ -4,12 +4,12 @@ import logging
4
4
 
5
5
 
6
6
  # External libraries
7
- import httpx
8
7
 
9
8
 
10
9
  # Internal utilities
11
10
  from StreamingCommunity.Util.config_json import config_manager
12
11
  from StreamingCommunity.Util.headers import get_userAgent
12
+ from StreamingCommunity.Util.http_client import create_client
13
13
 
14
14
 
15
15
  # Variable
@@ -17,21 +17,18 @@ MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
17
17
  REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
18
18
 
19
19
  class VideoSource:
20
- def __init__(self, full_url, episode_data, session_id, csrf_token):
20
+ def __init__(self, site_url, episode_data, session_id, csrf_token):
21
21
  """Initialize the VideoSource with session details, episode data, and URL."""
22
22
  self.session_id = session_id
23
23
  self.csrf_token = csrf_token
24
24
  self.episode_data = episode_data
25
25
  self.number = episode_data['number']
26
- self.link = episode_data['link']
26
+ self.link = site_url + episode_data['link']
27
27
 
28
28
  # Create an HTTP client with session cookies, headers, and base URL.
29
- self.client = httpx.Client(
29
+ self.client = create_client(
30
30
  cookies={"sessionId": session_id},
31
- headers={"User-Agent": get_userAgent(), "csrf-token": csrf_token},
32
- base_url=full_url,
33
- timeout=MAX_TIMEOUT,
34
- verify=REQUEST_VERIFY
31
+ headers={"User-Agent": get_userAgent(), "csrf-token": csrf_token}
35
32
  )
36
33
 
37
34
  def get_playlist(self):
@@ -43,7 +43,7 @@ def get_user_input(string_to_search: str = None):
43
43
  bot = get_bot_instance()
44
44
  string_to_search = bot.ask(
45
45
  "key_search",
46
- f"Enter the search term\nor type 'back' to return to the menu: ",
46
+ "Enter the search term\nor type 'back' to return to the menu: ",
47
47
  None
48
48
  )
49
49
 
@@ -117,7 +117,7 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
117
117
  console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
118
118
 
119
119
  if site_constant.TELEGRAM_BOT:
120
- bot.send_message(f"No results found, please try again", None)
120
+ bot.send_message("No results found, please try again", None)
121
121
 
122
122
  # If no results are found, ask again
123
123
  string_to_search = get_user_input()
@@ -5,7 +5,6 @@ import re
5
5
 
6
6
 
7
7
  # External library
8
- import httpx
9
8
  from bs4 import BeautifulSoup
10
9
  from rich.console import Console
11
10
 
@@ -13,6 +12,7 @@ from rich.console import Console
13
12
  # Internal utilities
14
13
  from StreamingCommunity.Util.os import os_manager
15
14
  from StreamingCommunity.Util.headers import get_headers
15
+ from StreamingCommunity.Util.http_client import create_client
16
16
  from StreamingCommunity.Util.message import start_message
17
17
  from StreamingCommunity.Util.config_json import config_manager
18
18
  from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance, TelegramSession
@@ -60,7 +60,7 @@ def download_film(select_title: MediaItem) -> str:
60
60
 
61
61
  # Extract mostraguarda URL
62
62
  try:
63
- response = httpx.get(select_title.url, headers=get_headers(), timeout=10)
63
+ response = create_client(headers=get_headers()).get(select_title.url)
64
64
  response.raise_for_status()
65
65
 
66
66
  soup = BeautifulSoup(response.text, 'html.parser')
@@ -74,7 +74,7 @@ def download_film(select_title: MediaItem) -> str:
74
74
  # Extract supervideo URL
75
75
  supervideo_url = None
76
76
  try:
77
- response = httpx.get(mostraguarda, headers=get_headers(), timeout=10)
77
+ response = create_client(headers=get_headers()).get(mostraguarda)
78
78
  response.raise_for_status()
79
79
 
80
80
  soup = BeautifulSoup(response.text, 'html.parser')
@@ -96,7 +96,7 @@ def download_film(select_title: MediaItem) -> str:
96
96
  mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
97
97
 
98
98
  # Download the film using the m3u8 playlist, and output filename
99
- r_proc = HLS_Downloader(
99
+ hls_process = HLS_Downloader(
100
100
  m3u8_url=master_playlist,
101
101
  output_path=os.path.join(mp4_path, title_name)
102
102
  ).start()
@@ -108,8 +108,10 @@ def download_film(select_title: MediaItem) -> str:
108
108
  if script_id != "unknown":
109
109
  TelegramSession.deleteScriptId(script_id)
110
110
 
111
- if r_proc['error'] is not None:
112
- try: os.remove(r_proc['path'])
113
- except: pass
111
+ if hls_process['error'] is not None:
112
+ try:
113
+ os.remove(hls_process['path'])
114
+ except Exception:
115
+ pass
114
116
 
115
- return r_proc['path']
117
+ return hls_process['path']
@@ -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] → [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
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")
58
58
 
59
59
  # Telegram integration
60
60
  if site_constant.TELEGRAM_BOT:
@@ -81,16 +81,18 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
81
81
  master_playlist = video_source.get_playlist()
82
82
 
83
83
  # Download the episode
84
- r_proc = HLS_Downloader(
84
+ hls_process = HLS_Downloader(
85
85
  m3u8_url=master_playlist,
86
86
  output_path=os.path.join(mp4_path, mp4_name)
87
87
  ).start()
88
88
 
89
- if r_proc['error'] is not None:
90
- try: os.remove(r_proc['path'])
91
- except: pass
89
+ if hls_process['error'] is not None:
90
+ try:
91
+ os.remove(hls_process['path'])
92
+ except Exception:
93
+ pass
92
94
 
93
- return r_proc['path'], r_proc['stopped']
95
+ return hls_process['path'], hls_process['stopped']
94
96
 
95
97
 
96
98
  def download_episode(index_season_selected: int, scrape_serie: GetSerieInfo, download_all: bool = False, episode_selection: str = None) -> None:
@@ -196,7 +198,7 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
196
198
  download_episode(i_season, scrape_serie, download_all=False, episode_selection=episode_selection)
197
199
 
198
200
  if site_constant.TELEGRAM_BOT:
199
- bot.send_message(f"Finito di scaricare tutte le serie e episodi", None)
201
+ bot.send_message("Finito di scaricare tutte le serie e episodi", None)
200
202
 
201
203
  # Get script_id
202
204
  script_id = TelegramSession.get_session()
@@ -93,7 +93,7 @@ def title_search(query: str) -> int:
93
93
 
94
94
  if site_constant.TELEGRAM_BOT:
95
95
  if choices:
96
- bot.send_message(f"Lista dei risultati:", choices)
96
+ bot.send_message("Lista dei risultati:", choices)
97
97
 
98
98
  # Return the number of titles found
99
99
  return media_search_manager.get_length()
@@ -43,7 +43,7 @@ def get_user_input(string_to_search: str = None):
43
43
  bot = get_bot_instance()
44
44
  string_to_search = bot.ask(
45
45
  "key_search",
46
- f"Enter the search term\nor type 'back' to return to the menu: ",
46
+ "Enter the search term\nor type 'back' to return to the menu: ",
47
47
  None
48
48
  )
49
49
 
@@ -116,7 +116,7 @@ def search(string_to_search: str = None, get_onlyDatabase: bool = False, direct_
116
116
  console.print(f"\n[red]Nothing matching was found for[white]: [purple]{string_to_search}")
117
117
 
118
118
  if site_constant.TELEGRAM_BOT:
119
- bot.send_message(f"No results found, please try again", None)
119
+ bot.send_message("No results found, please try again", None)
120
120
 
121
121
  # If no results are found, ask again
122
122
  string_to_search = get_user_input()
@@ -109,7 +109,7 @@ def download_series(select_title: MediaItem, season_selection: str = None, episo
109
109
  # Telegram bot integration
110
110
  if episode_selection is None:
111
111
  if site_constant.TELEGRAM_BOT:
112
- console.print(f"\n[cyan]Insert media [red]index [yellow]or [red]* [cyan]to download all media [yellow]or [red]1-2 [cyan]or [red]3-* [cyan]for a range of media")
112
+ console.print("\n[cyan]Insert media [red]index [yellow]or [red]* [cyan]to download all media [yellow]or [red]1-2 [cyan]or [red]3-* [cyan]for a range of media")
113
113
  bot.send_message(f"Episodi trovati: {episoded_count}", None)
114
114
 
115
115
  last_command = bot.ask(
@@ -145,7 +145,7 @@ def download_series(select_title: MediaItem, season_selection: str = None, episo
145
145
  _, kill_handler = download_episode(i_episode-1, scrape_serie, video_source)
146
146
 
147
147
  if site_constant.TELEGRAM_BOT:
148
- bot.send_message(f"Finito di scaricare tutte le serie e episodi", None)
148
+ bot.send_message("Finito di scaricare tutte le serie e episodi", None)
149
149
 
150
150
  # Get script_id
151
151
  script_id = TelegramSession.get_session()
@@ -11,6 +11,7 @@ from rich.console import Console
11
11
  # Internal utilities
12
12
  from StreamingCommunity.Util.config_json import config_manager
13
13
  from StreamingCommunity.Util.headers import get_userAgent, get_headers
14
+ from StreamingCommunity.Util.http_client import create_client
14
15
  from StreamingCommunity.Util.table import TVShowManager
15
16
 
16
17
 
@@ -31,11 +32,8 @@ def get_session_and_csrf() -> dict:
31
32
  Get the session ID and CSRF token from the website's cookies and HTML meta data.
32
33
  """
33
34
  # Send an initial GET request to the website
34
- response = httpx.get(
35
- site_constant.FULL_URL,
36
- headers=get_headers(),
37
- verify=False
38
- )
35
+ client = create_client(headers=get_headers())
36
+ response = client.get(site_constant.FULL_URL)
39
37
 
40
38
  # Extract the sessionId from the cookies
41
39
  session_id = response.cookies.get('sessionId')
@@ -2,13 +2,14 @@
2
2
 
3
3
  import logging
4
4
 
5
+
5
6
  # External libraries
6
- import httpx
7
7
  from bs4 import BeautifulSoup
8
8
 
9
9
 
10
10
  # Internal utilities
11
11
  from StreamingCommunity.Util.headers import get_userAgent
12
+ from StreamingCommunity.Util.http_client import create_client
12
13
  from StreamingCommunity.Util.config_json import config_manager
13
14
  from StreamingCommunity.Util.os import os_manager
14
15
 
@@ -23,24 +24,21 @@ max_timeout = config_manager.get_int("REQUESTS", "timeout")
23
24
 
24
25
 
25
26
  class ScrapSerie:
26
- def __init__(self, url, full_url):
27
+ def __init__(self, url, site_url):
27
28
  """Initialize the ScrapSerie object with the provided URL and setup the HTTP client."""
28
29
  self.url = url
29
- self.link = httpx.URL(url).path
30
30
  self.session_id, self.csrf_token = get_session_and_csrf()
31
- self.client = httpx.Client(
31
+ self.client = create_client(
32
32
  cookies={"sessionId": self.session_id},
33
- headers={"User-Agent": get_userAgent(), "csrf-token": self.csrf_token},
34
- base_url=full_url,
35
- verify=False
33
+ headers={"User-Agent": get_userAgent(), "csrf-token": self.csrf_token}
36
34
  )
37
35
 
38
36
  try:
39
- self.response = self.client.get(self.link, timeout=max_timeout, follow_redirects=True)
37
+ self.response = self.client.get(self.url, timeout=max_timeout, follow_redirects=True)
40
38
  self.response.raise_for_status()
41
39
 
42
- except:
43
- raise Exception(f"Failed to retrieve anime page.")
40
+ except Exception as e:
41
+ raise Exception(f"Failed to retrieve anime page: {str(e)}")
44
42
 
45
43
  def get_name(self):
46
44
  """Extract and return the name of the anime series."""
@@ -50,13 +50,15 @@ def download_film(select_title: MediaItem) -> str:
50
50
  master_playlist = video_source.get_playlist()
51
51
 
52
52
  # Download the film using the m3u8 playlist, and output filename
53
- r_proc = HLS_Downloader(
53
+ hls_process = HLS_Downloader(
54
54
  m3u8_url=master_playlist,
55
55
  output_path=os.path.join(mp4_path, title_name)
56
56
  ).start()
57
57
 
58
- if r_proc['error'] is not None:
59
- try: os.remove(r_proc['path'])
60
- except: pass
58
+ if hls_process['error'] is not None:
59
+ try:
60
+ os.remove(hls_process['path'])
61
+ except Exception:
62
+ pass
61
63
 
62
- return r_proc['path']
64
+ return hls_process['path']
@@ -1,7 +1,5 @@
1
1
  # 16.03.25
2
2
 
3
- import sys
4
- import subprocess
5
3
  from urllib.parse import quote_plus
6
4
 
7
5
 
@@ -25,7 +23,7 @@ from .series import download_series
25
23
  indice = 8
26
24
  _useFor = "Anime"
27
25
  _priority = 0
28
- _engineDownload = "hls"
26
+ _engineDownload = "dash"
29
27
  _deprecate = False
30
28
 
31
29
  msg = Prompt()
@@ -54,13 +54,13 @@ def download_film(select_title: MediaItem) -> str:
54
54
  query_params = parse_qs(parsed_url.query)
55
55
 
56
56
  # Download the episode
57
- r_proc = DASH_Downloader(
57
+ dash_process = DASH_Downloader(
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
61
  output_path=os.path.join(mp4_path, mp4_name),
62
62
  )
63
- r_proc.parse_manifest(custom_headers=mpd_headers)
63
+ dash_process.parse_manifest(custom_headers=mpd_headers)
64
64
 
65
65
  # Create headers for license request
66
66
  license_headers = mpd_headers.copy()
@@ -69,14 +69,16 @@ def download_film(select_title: MediaItem) -> str:
69
69
  "x-cr-video-token": query_params['playbackGuid'][0],
70
70
  })
71
71
 
72
- if r_proc.download_and_decrypt(custom_headers=license_headers):
73
- r_proc.finalize_output()
72
+ if dash_process.download_and_decrypt(custom_headers=license_headers):
73
+ dash_process.finalize_output()
74
74
 
75
75
  # Get final output path and status
76
- status = r_proc.get_status()
76
+ status = dash_process.get_status()
77
77
 
78
78
  if status['error'] is not None and status['path']:
79
- try: os.remove(status['path'])
80
- except Exception: pass
79
+ try:
80
+ os.remove(status['path'])
81
+ except Exception:
82
+ pass
81
83
 
82
84
  return status['path'], status['stopped']
@@ -71,13 +71,13 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
71
71
  query_params = parse_qs(parsed_url.query)
72
72
 
73
73
  # Download the episode
74
- r_proc = DASH_Downloader(
74
+ dash_process = DASH_Downloader(
75
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
  output_path=os.path.join(mp4_path, mp4_name),
79
79
  )
80
- r_proc.parse_manifest(custom_headers=mpd_headers)
80
+ dash_process.parse_manifest(custom_headers=mpd_headers)
81
81
 
82
82
  # Create headers for license request
83
83
  license_headers = mpd_headers.copy()
@@ -86,15 +86,17 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
86
86
  "x-cr-video-token": query_params['playbackGuid'][0],
87
87
  })
88
88
 
89
- if r_proc.download_and_decrypt(custom_headers=license_headers):
90
- r_proc.finalize_output()
89
+ if dash_process.download_and_decrypt(custom_headers=license_headers):
90
+ dash_process.finalize_output()
91
91
 
92
92
  # Get final output path and status
93
- status = r_proc.get_status()
93
+ status = dash_process.get_status()
94
94
 
95
95
  if status['error'] is not None and status['path']:
96
- try: os.remove(status['path'])
97
- except Exception: pass
96
+ try:
97
+ os.remove(status['path'])
98
+ except Exception:
99
+ pass
98
100
 
99
101
  # Delete episode stream
100
102
  delete_stream_episode(url_id, query_params['playbackGuid'][0], mpd_headers)
@@ -1,5 +1,7 @@
1
1
  # 16.03.25
2
2
 
3
+ import os
4
+
3
5
 
4
6
  # External libraries
5
7
  from curl_cffi import requests
@@ -8,6 +10,7 @@ from rich.console import Console
8
10
 
9
11
  # Internal utilities
10
12
  from StreamingCommunity.Util.config_json import config_manager
13
+ from StreamingCommunity.Util.os import get_wvd_path
11
14
  from StreamingCommunity.Util.headers import get_headers
12
15
  from StreamingCommunity.Util.table import TVShowManager
13
16
 
@@ -38,8 +41,14 @@ def title_search(query: str) -> int:
38
41
  media_search_manager.clear()
39
42
  table_show_manager.clear()
40
43
 
44
+ # Check CDM file before usage
45
+ cdm_device_path = get_wvd_path()
46
+ if not cdm_device_path or not isinstance(cdm_device_path, (str, bytes, os.PathLike)) or not os.path.isfile(cdm_device_path):
47
+ console.print(f"[bold red] CDM file not found or invalid path: {cdm_device_path}[/bold red]")
48
+ return None
49
+
41
50
  # Build new Crunchyroll API search URL
42
- api_url = f"https://www.crunchyroll.com/content/v2/discover/search"
51
+ api_url = "https://www.crunchyroll.com/content/v2/discover/search"
43
52
 
44
53
  params = {
45
54
  "q": query,
@@ -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] → [bold magenta]{obj_episode.get('name')}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
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")
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"
@@ -68,16 +68,18 @@ def download_video(index_season_selected: int, index_episode_selected: int, scap
68
68
  master_playlist = video_source.get_playlist()
69
69
 
70
70
  # Download the film using the m3u8 playlist, and output filename
71
- r_proc = HLS_Downloader(
71
+ hls_process = HLS_Downloader(
72
72
  m3u8_url=master_playlist,
73
73
  output_path=os.path.join(mp4_path, mp4_name)
74
74
  ).start()
75
75
 
76
- if r_proc['error'] is not None:
77
- try: os.remove(r_proc['path'])
78
- except: pass
76
+ if hls_process['error'] is not None:
77
+ try:
78
+ os.remove(hls_process['path'])
79
+ except Exception:
80
+ pass
79
81
 
80
- return r_proc['path'], r_proc['stopped']
82
+ return hls_process['path'], hls_process['stopped']
81
83
 
82
84
 
83
85
  def download_episode(scape_info_serie: GetSerieInfo, index_season_selected: int, download_all: bool = False, episode_selection: str = None) -> None:
@@ -1,8 +1,5 @@
1
1
  # 09.06.24
2
2
 
3
- import sys
4
-
5
-
6
3
  # External libraries
7
4
  import httpx
8
5
  from bs4 import BeautifulSoup
@@ -53,8 +53,7 @@ class GetSerieInfo:
53
53
  seasons_number = len(table_content.find_all("li"))
54
54
 
55
55
  # Try to get the title, with fallback
56
- title_element = soup.find("h1", class_="entry-title")
57
- self.tv_name = title_element.get_text(strip=True) if title_element else "Unknown Title"
56
+ self.tv_name = soup.find('h1', class_="front_title").get_text(strip=True) if soup.find('h1', class_="front_title") else "Unknown Series"
58
57
 
59
58
  return seasons_number
60
59
 
@@ -22,7 +22,7 @@ from .film import download_film
22
22
  indice = 3
23
23
  _useFor = "Film_&_Serie"
24
24
  _priority = 0
25
- _engineDownload = "hls"
25
+ _engineDownload = "dash"
26
26
  _deprecate = False
27
27
 
28
28
  msg = Prompt()
@@ -49,37 +49,31 @@ def download_film(select_title: MediaItem) -> Tuple[str, bool]:
49
49
  # Generate mpd and license URLs
50
50
  bearer = get_bearer_token()
51
51
 
52
- # Extract ID from the episode URL
53
- episode_id = select_title.url.split('_')[-1]
54
- if "http" in episode_id:
55
- try: episode_id = select_title.url.split('/')[-1]
56
- except Exception:
57
- console.print(f"[red]Error:[/red] Failed to parse episode ID from URL: {select_title.url}")
58
- return None, True
59
-
60
- playback_json = get_playback_url(bearer, episode_id)
52
+ playback_json = get_playback_url(bearer, select_title.id)
61
53
  tracking_info = get_tracking_info(bearer, playback_json)[0]
62
54
 
63
55
  license_url = generate_license_url(bearer, tracking_info)
64
56
  mpd_url = get_manifest(tracking_info['video_src'])
65
57
 
66
58
  # Download the episode
67
- r_proc = DASH_Downloader(
59
+ dash_process = DASH_Downloader(
68
60
  cdm_device=get_wvd_path(),
69
61
  license_url=license_url,
70
62
  mpd_url=mpd_url,
71
63
  output_path=mp4_path,
72
64
  )
73
- r_proc.parse_manifest(custom_headers=get_headers())
65
+ dash_process.parse_manifest(custom_headers=get_headers())
74
66
 
75
- if r_proc.download_and_decrypt():
76
- r_proc.finalize_output()
67
+ if dash_process.download_and_decrypt():
68
+ dash_process.finalize_output()
77
69
 
78
70
  # Get final output path and status
79
- status = r_proc.get_status()
71
+ status = dash_process.get_status()
80
72
 
81
73
  if status['error'] is not None and status['path']:
82
- try: os.remove(status['path'])
83
- except Exception: pass
74
+ try:
75
+ os.remove(status['path'])
76
+ except Exception:
77
+ pass
84
78
 
85
79
  return status['path'], status['stopped']
@@ -56,7 +56,7 @@ 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] → [bold magenta]{obj_episode.name}[/bold magenta] ([cyan]S{index_season_selected}E{index_episode_selected}[/cyan]) \n")
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")
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"
@@ -64,39 +64,33 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
64
64
 
65
65
  # Generate mpd and license URLs
66
66
  bearer = get_bearer_token()
67
-
68
- # Extract ID from the episode URL
69
- episode_id = obj_episode.url.split('_')[-1]
70
- if "http" in episode_id:
71
- try: episode_id = obj_episode.url.split('/')[-1]
72
- except Exception:
73
- console.print(f"[red]Error:[/red] Failed to parse episode ID from URL: {obj_episode.url}")
74
- return None, True
75
-
76
- playback_json = get_playback_url(bearer, episode_id)
67
+
68
+ playback_json = get_playback_url(bearer, obj_episode.id)
77
69
  tracking_info = get_tracking_info(bearer, playback_json)[0]
78
70
 
79
71
  license_url = generate_license_url(bearer, tracking_info)
80
72
  mpd_url = get_manifest(tracking_info['video_src'])
81
73
 
82
74
  # Download the episode
83
- r_proc = DASH_Downloader(
75
+ dash_process = DASH_Downloader(
84
76
  cdm_device=get_wvd_path(),
85
77
  license_url=license_url,
86
78
  mpd_url=mpd_url,
87
79
  output_path=os.path.join(mp4_path, mp4_name),
88
80
  )
89
- r_proc.parse_manifest(custom_headers=get_headers())
81
+ dash_process.parse_manifest(custom_headers=get_headers())
90
82
 
91
- if r_proc.download_and_decrypt():
92
- r_proc.finalize_output()
83
+ if dash_process.download_and_decrypt():
84
+ dash_process.finalize_output()
93
85
 
94
86
  # Get final output path and status
95
- status = r_proc.get_status()
87
+ status = dash_process.get_status()
96
88
 
97
89
  if status['error'] is not None and status['path']:
98
- try: os.remove(status['path'])
99
- except Exception: pass
90
+ try:
91
+ os.remove(status['path'])
92
+ except Exception:
93
+ pass
100
94
 
101
95
  return status['path'], status['stopped']
102
96