StreamingCommunity 3.3.8__py3-none-any.whl → 3.4.0__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 (64) 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 -15
  7. StreamingCommunity/Api/Site/altadefinizione/site.py +2 -7
  8. StreamingCommunity/Api/Site/altadefinizione/util/ScrapeSerie.py +2 -7
  9. StreamingCommunity/Api/Site/animeunity/site.py +9 -24
  10. StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +11 -27
  11. StreamingCommunity/Api/Site/animeworld/film.py +4 -2
  12. StreamingCommunity/Api/Site/animeworld/site.py +3 -11
  13. StreamingCommunity/Api/Site/animeworld/util/ScrapeSerie.py +1 -4
  14. StreamingCommunity/Api/Site/crunchyroll/film.py +17 -8
  15. StreamingCommunity/Api/Site/crunchyroll/series.py +8 -9
  16. StreamingCommunity/Api/Site/crunchyroll/site.py +14 -16
  17. StreamingCommunity/Api/Site/crunchyroll/util/ScrapeSerie.py +18 -65
  18. StreamingCommunity/Api/Site/crunchyroll/util/get_license.py +97 -106
  19. StreamingCommunity/Api/Site/guardaserie/site.py +4 -12
  20. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +3 -10
  21. StreamingCommunity/Api/Site/mediasetinfinity/film.py +11 -12
  22. StreamingCommunity/Api/Site/mediasetinfinity/series.py +1 -2
  23. StreamingCommunity/Api/Site/mediasetinfinity/site.py +3 -11
  24. StreamingCommunity/Api/Site/mediasetinfinity/util/ScrapeSerie.py +39 -50
  25. StreamingCommunity/Api/Site/mediasetinfinity/util/fix_mpd.py +3 -3
  26. StreamingCommunity/Api/Site/mediasetinfinity/util/get_license.py +8 -26
  27. StreamingCommunity/Api/Site/raiplay/film.py +6 -7
  28. StreamingCommunity/Api/Site/raiplay/series.py +1 -12
  29. StreamingCommunity/Api/Site/raiplay/site.py +8 -24
  30. StreamingCommunity/Api/Site/raiplay/util/ScrapeSerie.py +15 -22
  31. StreamingCommunity/Api/Site/raiplay/util/get_license.py +3 -12
  32. StreamingCommunity/Api/Site/streamingcommunity/film.py +5 -16
  33. StreamingCommunity/Api/Site/streamingcommunity/site.py +3 -22
  34. StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +11 -26
  35. StreamingCommunity/Api/Site/streamingwatch/__init__.py +1 -0
  36. StreamingCommunity/Api/Site/streamingwatch/film.py +4 -2
  37. StreamingCommunity/Api/Site/streamingwatch/series.py +1 -1
  38. StreamingCommunity/Api/Site/streamingwatch/site.py +4 -18
  39. StreamingCommunity/Api/Site/streamingwatch/util/ScrapeSerie.py +0 -3
  40. StreamingCommunity/Api/Template/config_loader.py +0 -7
  41. StreamingCommunity/Lib/Downloader/DASH/cdm_helpher.py +8 -3
  42. StreamingCommunity/Lib/Downloader/DASH/decrypt.py +55 -1
  43. StreamingCommunity/Lib/Downloader/DASH/downloader.py +139 -55
  44. StreamingCommunity/Lib/Downloader/DASH/parser.py +458 -101
  45. StreamingCommunity/Lib/Downloader/DASH/segments.py +131 -74
  46. StreamingCommunity/Lib/Downloader/HLS/downloader.py +31 -50
  47. StreamingCommunity/Lib/Downloader/HLS/segments.py +266 -365
  48. StreamingCommunity/Lib/Downloader/MP4/downloader.py +1 -1
  49. StreamingCommunity/Lib/FFmpeg/capture.py +37 -5
  50. StreamingCommunity/Lib/FFmpeg/command.py +35 -93
  51. StreamingCommunity/Lib/M3U8/estimator.py +0 -1
  52. StreamingCommunity/Lib/TMBD/tmdb.py +2 -4
  53. StreamingCommunity/TelegramHelp/config.json +0 -1
  54. StreamingCommunity/Upload/version.py +1 -1
  55. StreamingCommunity/Util/config_json.py +28 -21
  56. StreamingCommunity/Util/http_client.py +28 -0
  57. StreamingCommunity/Util/os.py +16 -6
  58. {streamingcommunity-3.3.8.dist-info → streamingcommunity-3.4.0.dist-info}/METADATA +1 -3
  59. streamingcommunity-3.4.0.dist-info/RECORD +111 -0
  60. streamingcommunity-3.3.8.dist-info/RECORD +0 -111
  61. {streamingcommunity-3.3.8.dist-info → streamingcommunity-3.4.0.dist-info}/WHEEL +0 -0
  62. {streamingcommunity-3.3.8.dist-info → streamingcommunity-3.4.0.dist-info}/entry_points.txt +0 -0
  63. {streamingcommunity-3.3.8.dist-info → streamingcommunity-3.4.0.dist-info}/licenses/LICENSE +0 -0
  64. {streamingcommunity-3.3.8.dist-info → streamingcommunity-3.4.0.dist-info}/top_level.txt +0 -0
@@ -9,13 +9,8 @@ from bs4 import BeautifulSoup
9
9
  # Internal utilities
10
10
  from StreamingCommunity.Util.headers import get_userAgent
11
11
  from StreamingCommunity.Util.http_client import create_client
12
- from StreamingCommunity.Util.config_json import config_manager
13
12
 
14
13
 
15
- # Variable
16
- MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
17
- REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
18
-
19
14
 
20
15
  class VideoSource:
21
16
  def __init__(self):
@@ -1,21 +1,12 @@
1
1
  # 11.04.25
2
2
 
3
3
 
4
- # External libraries
5
- import httpx
6
-
7
-
8
4
  # Internal utilities
9
- from StreamingCommunity.Util.config_json import config_manager
5
+ from StreamingCommunity.Util.http_client import create_client
10
6
  from StreamingCommunity.Util.headers import get_headers
11
7
 
12
8
 
13
- # Variable
14
- MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
15
- REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
16
-
17
9
  class VideoSource:
18
-
19
10
  @staticmethod
20
11
  def extract_m3u8_url(video_url: str) -> str:
21
12
  """Extract the m3u8 streaming URL from a RaiPlay video URL."""
@@ -29,7 +20,7 @@ class VideoSource:
29
20
  return "Error: Unable to determine video JSON URL"
30
21
 
31
22
  try:
32
- response = httpx.get(video_url, headers=get_headers(), timeout=MAX_TIMEOUT, verify=REQUEST_VERIFY)
23
+ response = create_client(headers=get_headers()).get(video_url)
33
24
  if response.status_code != 200:
34
25
  return f"Error: Failed to fetch video data (Status: {response.status_code})"
35
26
 
@@ -50,8 +41,8 @@ class VideoSource:
50
41
  'cont': element_key,
51
42
  'output': '62',
52
43
  }
53
- stream_response = httpx.get('https://mediapolisvod.rai.it/relinker/relinkerServlet.htm', params=params, headers=get_headers(), timeout=MAX_TIMEOUT, verify=REQUEST_VERIFY)
54
-
44
+
45
+ stream_response = create_client(headers=get_headers()).get('https://mediapolisvod.rai.it/relinker/relinkerServlet.htm', params=params)
55
46
  if stream_response.status_code != 200:
56
47
  return f"Error: Failed to fetch stream URL (Status: {stream_response.status_code})"
57
48
 
@@ -7,19 +7,13 @@ import logging
7
7
  # External libraries
8
8
  import jsbeautifier
9
9
  from bs4 import BeautifulSoup
10
- from curl_cffi import requests
11
10
 
12
11
 
13
12
  # Internal utilities
14
- from StreamingCommunity.Util.config_json import config_manager
13
+ from StreamingCommunity.Util.http_client import create_client_curl
15
14
  from StreamingCommunity.Util.headers import get_headers
16
15
 
17
16
 
18
- # Variable
19
- MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
20
- REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
21
-
22
-
23
17
  class VideoSource:
24
18
  def __init__(self, url: str) -> None:
25
19
  """
@@ -42,10 +36,11 @@ class VideoSource:
42
36
  - str: The response content if successful, None otherwise.
43
37
  """
44
38
  try:
45
- response = requests.get(url, headers=self.headers, timeout=MAX_TIMEOUT, impersonate="chrome110", verify=REQUEST_VERIFY)
39
+ response = create_client_curl(headers=self.headers).get(url)
46
40
  if response.status_code >= 400:
47
41
  logging.error(f"Request failed with status code: {response.status_code}")
48
42
  return None
43
+
49
44
  return response.text
50
45
 
51
46
  except Exception as e:
@@ -3,19 +3,11 @@
3
3
  import logging
4
4
 
5
5
 
6
- # External libraries
7
-
8
-
9
6
  # Internal utilities
10
- from StreamingCommunity.Util.config_json import config_manager
11
7
  from StreamingCommunity.Util.headers import get_userAgent
12
8
  from StreamingCommunity.Util.http_client import create_client
13
9
 
14
10
 
15
- # Variable
16
- MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
17
- REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
18
-
19
11
  class VideoSource:
20
12
  def __init__(self, site_url, episode_data, session_id, csrf_token):
21
13
  """Initialize the VideoSource with session details, episode data, and URL."""
@@ -44,4 +36,4 @@ class VideoSource:
44
36
 
45
37
  except Exception as e:
46
38
  logging.error(f"Error in new API system: {e}")
47
- return None
39
+ return None
@@ -6,21 +6,18 @@ from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
6
6
 
7
7
 
8
8
  # External libraries
9
- import httpx
10
9
  from bs4 import BeautifulSoup
11
10
  from rich.console import Console
12
11
 
13
12
 
14
13
  # Internal utilities
15
14
  from StreamingCommunity.Util.headers import get_userAgent
16
- from StreamingCommunity.Util.config_json import config_manager
15
+ from StreamingCommunity.Util.http_client import create_client
17
16
  from .Helper.Vixcloud.util import WindowVideo, WindowParameter, StreamsCollection
18
17
  from .Helper.Vixcloud.js_parser import JavaScriptParser
19
18
 
20
19
 
21
20
  # Variable
22
- MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
23
- REQUEST_VERIFY = config_manager.get_bool('REQUESTS', 'verify')
24
21
  console = Console()
25
22
 
26
23
 
@@ -57,7 +54,7 @@ class VideoSource:
57
54
  }
58
55
 
59
56
  try:
60
- response = httpx.get(f"{self.url}/iframe/{self.media_id}", headers=self.headers, params=params, timeout=MAX_TIMEOUT, verify=REQUEST_VERIFY)
57
+ response = create_client(headers=self.headers).get(f"{self.url}/iframe/{self.media_id}", params=params)
61
58
  response.raise_for_status()
62
59
 
63
60
  # Parse response with BeautifulSoup to get iframe source
@@ -100,7 +97,7 @@ class VideoSource:
100
97
  """
101
98
  try:
102
99
  if self.iframe_src is not None:
103
- response = httpx.get(self.iframe_src, headers=self.headers, timeout=MAX_TIMEOUT, verify=REQUEST_VERIFY)
100
+ response = create_client(headers=self.headers).get(self.iframe_src)
104
101
  response.raise_for_status()
105
102
 
106
103
  # Parse response with BeautifulSoup to get content
@@ -110,14 +107,6 @@ class VideoSource:
110
107
  # Parse script to get video information
111
108
  self.parse_script(script_text=script)
112
109
 
113
- except httpx.HTTPStatusError as e:
114
- if e.response.status_code == 404:
115
- console.print("[yellow]This content will be available soon![/yellow]")
116
- return
117
-
118
- logging.error(f"Error getting content: {e}")
119
- raise
120
-
121
110
  except Exception as e:
122
111
  logging.error(f"Error getting content: {e}")
123
112
  raise
@@ -178,7 +167,7 @@ class VideoSourceAnime(VideoSource):
178
167
  str: Parsed script content
179
168
  """
180
169
  try:
181
- response = httpx.get(f"{self.url}/embed-url/{episode_id}", headers=self.headers, timeout=MAX_TIMEOUT, verify=REQUEST_VERIFY)
170
+ response = create_client(headers=self.headers).get(f"{self.url}/embed-url/{episode_id}")
182
171
  response.raise_for_status()
183
172
 
184
173
  # Extract and clean embed URL
@@ -186,7 +175,7 @@ class VideoSourceAnime(VideoSource):
186
175
  self.iframe_src = embed_url
187
176
 
188
177
  # Fetch video content using embed URL
189
- video_response = httpx.get(embed_url, verify=REQUEST_VERIFY)
178
+ video_response = create_client(headers=self.headers).get(embed_url)
190
179
  video_response.raise_for_status()
191
180
 
192
181
  # Parse response with BeautifulSoup to get content of the scriot
@@ -15,7 +15,7 @@ from StreamingCommunity.Util.headers import get_headers
15
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
- from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance, TelegramSession
18
+ from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession
19
19
 
20
20
 
21
21
  # Logic class
@@ -31,6 +31,7 @@ from StreamingCommunity.Api.Player.supervideo import VideoSource
31
31
  # Variable
32
32
  console = Console()
33
33
  max_timeout = config_manager.get_int("REQUESTS", "timeout")
34
+ extension_output = config_manager.get("M3U8_CONVERSION", "extension")
34
35
 
35
36
 
36
37
  def download_film(select_title: MediaItem) -> str:
@@ -43,18 +44,6 @@ def download_film(select_title: MediaItem) -> str:
43
44
  Return:
44
45
  - str: output path if successful, otherwise None
45
46
  """
46
- if site_constant.TELEGRAM_BOT:
47
- bot = get_bot_instance()
48
- bot.send_message(f"Download in corso:\n{select_title.name}", None)
49
-
50
- # Viene usato per lo screen
51
- console.print(f"## Download: [red]{select_title.name} ##")
52
-
53
- # Get script_id
54
- script_id = TelegramSession.get_session()
55
- if script_id != "unknown":
56
- TelegramSession.updateScriptId(script_id, select_title.name)
57
-
58
47
  start_message()
59
48
  console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
60
49
 
@@ -92,8 +81,8 @@ def download_film(select_title: MediaItem) -> str:
92
81
  master_playlist = video_source.get_playlist()
93
82
 
94
83
  # Define the filename and path for the downloaded film
95
- title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
96
- mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
84
+ title_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
85
+ mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))
97
86
 
98
87
  # Download the film using the m3u8 playlist, and output filename
99
88
  hls_process = HLS_Downloader(
@@ -2,7 +2,6 @@
2
2
 
3
3
 
4
4
  # External libraries
5
- import httpx
6
5
  from bs4 import BeautifulSoup
7
6
  from rich.console import Console
8
7
 
@@ -10,6 +9,7 @@ from rich.console import Console
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
  from StreamingCommunity.Util.table import TVShowManager
14
14
  from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
15
15
 
@@ -46,12 +46,7 @@ def title_search(query: str) -> int:
46
46
  console.print(f"[cyan]Search url: [yellow]{search_url}")
47
47
 
48
48
  try:
49
- response = httpx.post(
50
- search_url,
51
- headers={'user-agent': get_userAgent()},
52
- timeout=max_timeout,
53
- follow_redirects=True
54
- )
49
+ response = create_client(headers={'user-agent': get_userAgent()}).get(search_url)
55
50
  response.raise_for_status()
56
51
 
57
52
  except Exception as e:
@@ -4,20 +4,15 @@ import logging
4
4
 
5
5
 
6
6
  # External libraries
7
- import httpx
8
7
  from bs4 import BeautifulSoup
9
8
 
10
9
 
11
10
  # Internal utilities
12
11
  from StreamingCommunity.Util.headers import get_userAgent
13
- from StreamingCommunity.Util.config_json import config_manager
12
+ from StreamingCommunity.Util.http_client import create_client
14
13
  from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
15
14
 
16
15
 
17
- # Variable
18
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
19
-
20
-
21
16
  class GetSerieInfo:
22
17
  def __init__(self, url):
23
18
  """
@@ -34,7 +29,7 @@ class GetSerieInfo:
34
29
  """
35
30
  Retrieve all episodes for all seasons
36
31
  """
37
- response = httpx.get(self.url, headers=self.headers)
32
+ response = create_client(headers=self.headers).get(self.url)
38
33
  soup = BeautifulSoup(response.text, "html.parser")
39
34
  self.series_name = soup.find("title").get_text(strip=True).split(" - ")[0]
40
35
 
@@ -1,15 +1,15 @@
1
1
  # 10.12.23
2
2
 
3
- # External libraries
4
3
  import urllib.parse
5
- import httpx
6
- from curl_cffi import requests
4
+
5
+
6
+ # External libraries
7
7
  from rich.console import Console
8
8
 
9
9
 
10
10
  # Internal utilities
11
- 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, create_client_curl
13
13
  from StreamingCommunity.Util.table import TVShowManager
14
14
  from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
15
15
 
@@ -18,21 +18,18 @@ from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
18
18
  from StreamingCommunity.Api.Template.config_loader import site_constant
19
19
  from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
20
20
 
21
+
22
+ # Variable
21
23
  console = Console()
22
24
  media_search_manager = MediaManager()
23
25
  table_show_manager = TVShowManager()
24
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
25
26
 
26
27
 
27
28
  def get_token(user_agent: str) -> dict:
28
29
  """
29
30
  Retrieve session cookies from the site.
30
31
  """
31
- response = requests.get(
32
- site_constant.FULL_URL,
33
- headers={'user-agent': user_agent},
34
- impersonate="chrome120"
35
- )
32
+ response = create_client_curl(headers={'user-agent': user_agent}).get(site_constant.FULL_URL)
36
33
  response.raise_for_status()
37
34
  all_cookies = {name: value for name, value in response.cookies.items()}
38
35
 
@@ -80,13 +77,7 @@ def title_search(query: str) -> int:
80
77
 
81
78
  # First call: /livesearch
82
79
  try:
83
- response1 = httpx.post(
84
- f'{site_constant.FULL_URL}/livesearch',
85
- cookies=cookies,
86
- headers=headers,
87
- json={'title': query},
88
- timeout=max_timeout
89
- )
80
+ response1 = create_client(headers=headers).post(f'{site_constant.FULL_URL}/livesearch', cookies=cookies, json={'title': query})
90
81
  response1.raise_for_status()
91
82
  process_results(response1.json().get('records', []), seen_titles, media_search_manager, choices)
92
83
 
@@ -107,13 +98,7 @@ def title_search(query: str) -> int:
107
98
  'dubbed': False,
108
99
  'season': False
109
100
  }
110
- response2 = httpx.post(
111
- f'{site_constant.FULL_URL}/archivio/get-animes',
112
- cookies=cookies,
113
- headers=headers,
114
- json=json_data,
115
- timeout=max_timeout
116
- )
101
+ response2 = create_client(headers=headers).post(f'{site_constant.FULL_URL}/archivio/get-animes', cookies=cookies, json=json_data)
117
102
  response2.raise_for_status()
118
103
  process_results(response2.json().get('records', []), seen_titles, media_search_manager, choices)
119
104
 
@@ -3,21 +3,12 @@
3
3
  import logging
4
4
 
5
5
 
6
- # External libraries
7
- import httpx
8
-
9
-
10
6
  # Internal utilities
11
- from StreamingCommunity.Util.headers import get_userAgent
12
- from StreamingCommunity.Util.config_json import config_manager
7
+ from StreamingCommunity.Util.headers import get_headers
8
+ from StreamingCommunity.Util.http_client import create_client
13
9
  from StreamingCommunity.Api.Player.Helper.Vixcloud.util import EpisodeManager, Episode
14
10
 
15
11
 
16
- # Variable
17
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
18
-
19
-
20
-
21
12
  class ScrapeSerieAnime:
22
13
  def __init__(self, url: str):
23
14
  """
@@ -27,7 +18,7 @@ class ScrapeSerieAnime:
27
18
  url (str): Url of the streaming site
28
19
  """
29
20
  self.is_series = False
30
- self.headers = {'user-agent': get_userAgent()}
21
+ self.headers = get_headers()
31
22
  self.url = url
32
23
  self.episodes_cache = None
33
24
 
@@ -61,11 +52,7 @@ class ScrapeSerieAnime:
61
52
  """
62
53
  try:
63
54
  # Get initial episode count
64
- response = httpx.get(
65
- url=f"{self.url}/info_api/{self.media_id}/",
66
- headers=self.headers,
67
- timeout=max_timeout
68
- )
55
+ response = create_client(headers=self.headers).get(f"{self.url}/info_api/{self.media_id}/")
69
56
  response.raise_for_status()
70
57
  initial_count = response.json()["episodes_count"]
71
58
 
@@ -75,18 +62,15 @@ class ScrapeSerieAnime:
75
62
  # Fetch episodes in chunks
76
63
  while start_range <= initial_count:
77
64
  end_range = min(start_range + 119, initial_count)
65
+
66
+ params={
67
+ "start_range": start_range,
68
+ "end_range": end_range
69
+ }
78
70
 
79
- response = httpx.get(
80
- url=f"{self.url}/info_api/{self.media_id}/1",
81
- params={
82
- "start_range": start_range,
83
- "end_range": end_range
84
- },
85
- headers=self.headers,
86
- timeout=max_timeout
87
- )
71
+ response = create_client(headers=self.headers).get(f"{self.url}/info_api/{self.media_id}/1", params=params)
88
72
  response.raise_for_status()
89
-
73
+
90
74
  chunk_episodes = response.json().get("episodes", [])
91
75
  all_episodes.extend(chunk_episodes)
92
76
  start_range = end_range + 1
@@ -2,6 +2,7 @@
2
2
 
3
3
  import os
4
4
 
5
+
5
6
  # External library
6
7
  from rich.console import Console
7
8
 
@@ -44,8 +45,9 @@ def download_film(select_title: MediaItem):
44
45
  console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] ([cyan]{scrape_serie.get_name()}[/cyan]) \n")
45
46
 
46
47
  # Define filename and path for the downloaded video
47
- mp4_name = f"{scrape_serie.get_name()}.mp4"
48
- mp4_path = os.path.join(site_constant.ANIME_FOLDER, scrape_serie.get_name())
48
+ serie_name_with_year = os_manager.get_sanitize_file(scrape_serie.get_name(), select_title.date)
49
+ mp4_name = f"{serie_name_with_year}.mp4"
50
+ mp4_path = os.path.join(site_constant.ANIME_FOLDER, serie_name_with_year.replace('.mp4', ''))
49
51
 
50
52
  # Create output folder
51
53
  os_manager.create_path(mp4_path)
@@ -2,15 +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
  from rich.console import Console
9
9
 
10
10
 
11
11
  # Internal utilities
12
- from StreamingCommunity.Util.config_json import config_manager
13
- from StreamingCommunity.Util.headers import get_userAgent, get_headers
12
+ from StreamingCommunity.Util.headers import get_headers
14
13
  from StreamingCommunity.Util.http_client import create_client
15
14
  from StreamingCommunity.Util.table import TVShowManager
16
15
 
@@ -24,7 +23,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
24
23
  console = Console()
25
24
  media_search_manager = MediaManager()
26
25
  table_show_manager = TVShowManager()
27
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
28
26
 
29
27
 
30
28
  def get_session_and_csrf() -> dict:
@@ -72,13 +70,7 @@ def title_search(query: str) -> int:
72
70
 
73
71
  # Make the GET request
74
72
  try:
75
- response = httpx.get(
76
- search_url,
77
- headers={'User-Agent': get_userAgent()},
78
- timeout=max_timeout,
79
- verify=False
80
- )
81
-
73
+ response = create_client(headers=get_headers()).get(search_url)
82
74
  except Exception as e:
83
75
  console.print(f"[red]Site: {site_constant.SITE_NAME}, request search error: {e}")
84
76
  return 0
@@ -10,7 +10,6 @@ from bs4 import BeautifulSoup
10
10
  # Internal utilities
11
11
  from StreamingCommunity.Util.headers import get_userAgent
12
12
  from StreamingCommunity.Util.http_client import create_client
13
- from StreamingCommunity.Util.config_json import config_manager
14
13
  from StreamingCommunity.Util.os import os_manager
15
14
 
16
15
 
@@ -19,8 +18,6 @@ from ..site import get_session_and_csrf
19
18
  from StreamingCommunity.Api.Player.sweetpixel import VideoSource
20
19
 
21
20
 
22
- # Variable
23
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
24
21
 
25
22
 
26
23
  class ScrapSerie:
@@ -34,7 +31,7 @@ class ScrapSerie:
34
31
  )
35
32
 
36
33
  try:
37
- self.response = self.client.get(self.url, timeout=max_timeout, follow_redirects=True)
34
+ self.response = self.client.get(self.url)
38
35
  self.response.raise_for_status()
39
36
 
40
37
  except Exception as e:
@@ -11,7 +11,7 @@ from rich.console import Console
11
11
  # Internal utilities
12
12
  from StreamingCommunity.Util.message import start_message
13
13
  from StreamingCommunity.Util.config_json import config_manager
14
- from StreamingCommunity.Util.os import os_manager, get_wvd_path
14
+ from StreamingCommunity.Util.os import os_manager
15
15
 
16
16
 
17
17
  # Logic class
@@ -21,12 +21,12 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
21
21
 
22
22
  # Player
23
23
  from StreamingCommunity import DASH_Downloader
24
- from .util.get_license import get_playback_session, get_auth_token, generate_device_id
24
+ from .util.get_license import get_playback_session, CrunchyrollClient
25
25
 
26
26
 
27
27
  # Variable
28
28
  console = Console()
29
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
29
+ extension_output = config_manager.get("M3U8_CONVERSION", "extension")
30
30
 
31
31
 
32
32
  def download_film(select_title: MediaItem) -> str:
@@ -42,20 +42,24 @@ def download_film(select_title: MediaItem) -> str:
42
42
  start_message()
43
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
+ # Initialize Crunchyroll client
46
+ client = CrunchyrollClient()
47
+ if not client.start():
48
+ console.print("[bold red]Failed to authenticate with Crunchyroll.[/bold red]")
49
+ return None, True
50
+
45
51
  # Define filename and path for the downloaded video
46
- mp4_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
47
- mp4_path = os.path.join(site_constant.MOVIE_FOLDER, mp4_name.replace(".mp4", ""))
52
+ mp4_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
53
+ mp4_path = os.path.join(site_constant.MOVIE_FOLDER, mp4_name.replace(extension_output, ""))
48
54
 
49
55
  # Generate mpd and license URLs
50
56
  url_id = select_title.get('url').split('/')[-1]
51
- device_id = generate_device_id()
52
- mpd_url, mpd_headers, mpd_list_sub = get_playback_session(get_auth_token(device_id), device_id, url_id)
57
+ mpd_url, mpd_headers, mpd_list_sub = get_playback_session(client, url_id)
53
58
  parsed_url = urlparse(mpd_url)
54
59
  query_params = parse_qs(parsed_url.query)
55
60
 
56
61
  # Download the episode
57
62
  dash_process = DASH_Downloader(
58
- cdm_device=get_wvd_path(),
59
63
  license_url='https://www.crunchyroll.com/license/v1/license/widevine',
60
64
  mpd_url=mpd_url,
61
65
  mpd_sub_list=mpd_list_sub,
@@ -82,4 +86,9 @@ def download_film(select_title: MediaItem) -> str:
82
86
  except Exception:
83
87
  pass
84
88
 
89
+ # Delete stream after download
90
+ token = query_params['playbackGuid'][0]
91
+ if token:
92
+ client.delete_active_stream(url_id, token)
93
+
85
94
  return status['path'], status['stopped']
@@ -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,11 +12,11 @@ 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
19
- from .util.ScrapeSerie import GetSerieInfo, delete_stream_episode
19
+ from .util.ScrapeSerie import GetSerieInfo
20
20
  from StreamingCommunity.Api.Template.Util import (
21
21
  manage_selection,
22
22
  map_episode_title,
@@ -30,7 +30,7 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
30
30
 
31
31
  # Player
32
32
  from StreamingCommunity import DASH_Downloader
33
- from .util.get_license import get_playback_session, get_auth_token, generate_device_id
33
+ from .util.get_license import get_playback_session
34
34
 
35
35
 
36
36
  # Variable
@@ -52,6 +52,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
52
52
  - bool: Whether download was stopped
53
53
  """
54
54
  start_message()
55
+ client = scrape_serie.client
55
56
 
56
57
  # Get episode information
57
58
  obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
@@ -64,16 +65,13 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
64
65
 
65
66
  # Generate mpd and license URLs
66
67
  url_id = obj_episode.get('url').split('/')[-1]
67
- device_id = generate_device_id()
68
- token_mpd = get_auth_token(device_id)
69
68
 
70
- mpd_url, mpd_headers, mpd_list_sub = get_playback_session(token_mpd, device_id, url_id)
69
+ mpd_url, mpd_headers, mpd_list_sub = get_playback_session(client, url_id)
71
70
  parsed_url = urlparse(mpd_url)
72
71
  query_params = parse_qs(parsed_url.query)
73
72
 
74
73
  # Download the episode
75
74
  dash_process = DASH_Downloader(
76
- cdm_device=get_wvd_path(),
77
75
  license_url='https://www.crunchyroll.com/license/v1/license/widevine',
78
76
  mpd_url=mpd_url,
79
77
  mpd_sub_list=mpd_list_sub,
@@ -101,7 +99,8 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
101
99
  pass
102
100
 
103
101
  # Delete episode stream
104
- delete_stream_episode(url_id, query_params['playbackGuid'][0], mpd_headers)
102
+ token = query_params['playbackGuid'][0]
103
+ client.delete_active_stream(url_id, token)
105
104
 
106
105
  return status['path'], status['stopped']
107
106