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
@@ -3,19 +3,12 @@
3
3
  import logging
4
4
 
5
5
 
6
- # External libraries
7
- import httpx
8
-
9
-
10
6
  # Internal utilities
11
7
  from StreamingCommunity.Util.headers import get_headers
12
- from StreamingCommunity.Util.config_json import config_manager
8
+ from StreamingCommunity.Util.http_client import create_client
13
9
  from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
14
10
 
15
11
 
16
- # Variable
17
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
18
-
19
12
 
20
13
  class GetSerieInfo:
21
14
  def __init__(self, path_id: str):
@@ -23,16 +16,17 @@ class GetSerieInfo:
23
16
  self.base_url = "https://www.raiplay.it"
24
17
  self.path_id = path_id
25
18
  self.series_name = None
26
- self.prog_tipology = "film"
27
19
  self.prog_description = None
28
20
  self.prog_year = None
29
21
  self.seasons_manager = SeasonManager()
22
+ self.season_block_mapping = {} # Map season number to block_id
23
+ self.all_seasons_data = [] # Store all seasons before filtering
30
24
 
31
25
  def collect_info_title(self) -> None:
32
- """Get series info including seasons."""
26
+ """Get series info including seasons from all multimedia blocks."""
33
27
  try:
34
28
  program_url = f"{self.base_url}/{self.path_id}"
35
- response = httpx.get(url=program_url, headers=get_headers(), timeout=max_timeout)
29
+ response = create_client(headers=get_headers()).get(program_url)
36
30
 
37
31
  # If 404, content is not yet available
38
32
  if response.status_code == 404:
@@ -43,76 +37,118 @@ class GetSerieInfo:
43
37
  json_data = response.json()
44
38
 
45
39
  # Get basic program info
46
- self.prog_description = json_data.get('program_info', '').get('vanity', '')
47
- self.prog_year = json_data.get('program_info', '').get('year', '')
48
- self.series_name = json_data.get('program_info', '').get('title', '')
40
+ program_info = json_data.get('program_info', {})
41
+ self.prog_description = program_info.get('vanity', '') or program_info.get('description', '')
42
+ self.prog_year = program_info.get('year', '')
43
+ self.series_name = program_info.get('title', '') or program_info.get('name', '')
44
+
45
+ # Collect all seasons from all multimedia blocks
46
+ self.all_seasons_data = []
47
+ blocks_found = {}
49
48
 
50
- # Look for seasons in the 'blocks' property
51
49
  for block in json_data.get('blocks', []):
52
-
53
- # Check if block is a season block or episodi block
54
- if block.get('type') == 'RaiPlay Multimedia Block':
55
- if block.get('name', '').lower() == 'episodi':
56
- self.publishing_block_id = block.get('id')
57
-
58
- # Extract seasons from sets array
59
- for season_set in block.get('sets', []):
60
- self.prog_tipology = "tv"
61
-
62
- if 'stagione' in season_set.get('name', '').lower():
63
- self._add_season(season_set, block.get('id'))
64
-
65
- elif 'stagione' in block.get('name', '').lower():
66
- self.publishing_block_id = block.get('id')
67
- self.prog_tipology = "tv"
68
-
69
- # Extract season directly from block's sets
70
- for season_set in block.get('sets', []):
71
- self._add_season(season_set, block.get('id'))
50
+ block_type = block.get('type', '')
51
+ block_name = block.get('name', 'N/A')
52
+ block_id = block.get('id', '')
53
+
54
+ # Only process multimedia blocks with sets
55
+ if block_type == 'RaiPlay Multimedia Block' and 'sets' in block:
56
+ sets = block.get('sets', [])
57
+
58
+ for season_set in sets:
59
+ episode_size = season_set.get('episode_size', {})
60
+ episode_count = episode_size.get('number', 0)
61
+
62
+ # Only add sets with episodes
63
+ if episode_count > 0:
64
+ self.all_seasons_data.append({
65
+ 'season_set': season_set,
66
+ 'block_id': block_id,
67
+ 'block_name': block_name
68
+ })
69
+
70
+ # Track which blocks we found
71
+ if block_name not in blocks_found:
72
+ blocks_found[block_name] = 0
73
+ blocks_found[block_name] += 1
74
+
75
+ # Add all collected seasons without any filtering (oldest first)
76
+ for season_data in reversed(self.all_seasons_data):
77
+ self._add_season(
78
+ season_data['season_set'],
79
+ season_data['block_id'],
80
+ season_data['block_name']
81
+ )
72
82
 
73
83
  except Exception as e:
74
84
  logging.error(f"Unexpected error collecting series info: {e}")
75
85
 
76
- def _add_season(self, season_set: dict, block_id: str):
86
+ def _add_season(self, season_set: dict, block_id: str, block_name: str):
87
+ """Add a season combining set name and block name."""
88
+ set_name = season_set.get('name', '')
89
+ season_number = len(self.seasons_manager.seasons) + 1
90
+
91
+ # Store block_id mapping
92
+ self.season_block_mapping[season_number] = {
93
+ 'block_id': block_id,
94
+ 'set_id': season_set.get('id', '')
95
+ }
96
+
77
97
  self.seasons_manager.add_season({
78
98
  'id': season_set.get('id', ''),
79
- 'number': len(self.seasons_manager.seasons) + 1,
80
- 'name': season_set.get('name', ''),
81
- 'path': season_set.get('path_id', ''),
82
- 'episodes_count': season_set.get('episode_size', {}).get('number', 0)
99
+ 'number': season_number,
100
+ 'name': set_name,
101
+ #'episodes_count': season_set.get('episode_size', {}).get('number', 0),
102
+ 'type': block_name
83
103
  })
84
104
 
85
105
  def collect_info_season(self, number_season: int) -> None:
86
- """Get episodes for a specific season."""
106
+ """Get episodes for a specific season using episodes.json endpoint."""
87
107
  try:
88
108
  season = self.seasons_manager.get_season_by_number(number_season)
89
-
90
- # Se stai leggendo questo codice spieami perche hai fatto cosi.
91
- url = f"{self.base_url}/{self.path_id.replace(".json", "")}/{self.publishing_block_id}/{season.id}/episodes.json"
92
- response = httpx.get(url=url, headers=get_headers(), timeout=max_timeout)
109
+ block_info = self.season_block_mapping[number_season]
110
+ block_id = block_info['block_id']
111
+ set_id = block_info['set_id']
112
+
113
+ # Build episodes endpoint URL
114
+ base_path = self.path_id.replace('.json', '')
115
+ url = f"{self.base_url}/{base_path}/{block_id}/{set_id}/episodes.json"
116
+
117
+ response = create_client(headers=get_headers()).get(url)
93
118
  response.raise_for_status()
94
119
 
95
120
  episodes_data = response.json()
96
- cards = []
97
121
 
98
- # Extract episodes from different possible structures
99
- if 'seasons' in episodes_data:
100
- for season_data in episodes_data.get('seasons', []):
101
- for episode_set in season_data.get('episodes', []):
102
- cards.extend(episode_set.get('cards', []))
122
+ # Navigate nested structure to find cards
123
+ cards = []
124
+ seasons = episodes_data.get('seasons', [])
125
+ if seasons:
126
+ for season_data in seasons:
127
+ episodes = season_data.get('episodes', [])
128
+ for episode in episodes:
129
+ cards.extend(episode.get('cards', []))
103
130
 
131
+ # Fallback to direct cards if nested structure not found
104
132
  if not cards:
105
133
  cards = episodes_data.get('cards', [])
106
134
 
107
135
  # Add episodes to season
108
136
  for ep in cards:
137
+ video_url = ep.get('video_url', '')
138
+ mpd_id = ''
139
+ if video_url and '=' in video_url:
140
+ mpd_id = video_url.split("=")[1].strip()
141
+
142
+ weblink = ep.get('weblink', '') or ep.get('url', '')
143
+ episode_url = f"{self.base_url}{weblink}" if weblink else ''
144
+
109
145
  episode = {
110
146
  'id': ep.get('id', ''),
111
147
  'number': ep.get('episode', ''),
112
- 'name': ep.get('episode_title', '') or ep.get('toptitle', ''),
113
- 'duration': ep.get('duration', ''),
114
- 'url': f"{self.base_url}{ep.get('weblink', '')}" if 'weblink' in ep else f"{self.base_url}{ep.get('url', '')}",
115
- 'mpd_id': ep.get('video_url').split("=")[1].strip()
148
+ 'name': ep.get('episode_title', '') or ep.get('name', '') or ep.get('toptitle', ''),
149
+ 'duration': ep.get('duration', '') or ep.get('duration_in_minutes', ''),
150
+ 'url': episode_url,
151
+ 'mpd_id': mpd_id
116
152
  }
117
153
  season.episodes.add(episode)
118
154
 
@@ -1,20 +1,11 @@
1
1
  # 16.03.25
2
2
 
3
3
 
4
- # External library
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
-
16
-
17
-
18
9
  def generate_license_url(mpd_id: str):
19
10
  """
20
11
  Generates the URL to obtain the Widevine license.
@@ -29,8 +20,8 @@ def generate_license_url(mpd_id: str):
29
20
  'cont': mpd_id,
30
21
  'output': '62',
31
22
  }
32
-
33
- response = httpx.get('https://mediapolisvod.rai.it/relinker/relinkerServlet.htm', params=params, headers=get_headers(), timeout=MAX_TIMEOUT)
23
+
24
+ response = create_client(headers=get_headers()).get('https://mediapolisvod.rai.it/relinker/relinkerServlet.htm', params=params)
34
25
  response.raise_for_status()
35
26
 
36
27
  # Extract the license URL from the response in two lines
@@ -9,8 +9,9 @@ from rich.console import Console
9
9
 
10
10
  # Internal utilities
11
11
  from StreamingCommunity.Util.os import os_manager
12
+ from StreamingCommunity.Util.config_json import config_manager
12
13
  from StreamingCommunity.Util.message import start_message
13
- from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession, get_bot_instance
14
+ from StreamingCommunity.TelegramHelp.telegram_bot import TelegramSession
14
15
 
15
16
 
16
17
  # Logic class
@@ -25,6 +26,7 @@ from StreamingCommunity.Api.Player.vixcloud import VideoSource
25
26
 
26
27
  # Variable
27
28
  console = Console()
29
+ extension_output = config_manager.get("M3U8_CONVERSION", "extension")
28
30
 
29
31
 
30
32
  def download_film(select_title: MediaItem) -> str:
@@ -38,19 +40,6 @@ def download_film(select_title: MediaItem) -> str:
38
40
  Return:
39
41
  - str: output path
40
42
  """
41
- if site_constant.TELEGRAM_BOT:
42
- bot = get_bot_instance()
43
- bot.send_message(f"Download in corso:\n{select_title.name}", None)
44
-
45
- # Viene usato per lo screen
46
- console.print(f"## Download: [red]{select_title.name} ##")
47
-
48
- # Get script_id
49
- script_id = TelegramSession.get_session()
50
- if script_id != "unknown":
51
- TelegramSession.updateScriptId(script_id, select_title.name)
52
-
53
- # Start message and display film information
54
43
  start_message()
55
44
  console.print(f"\n[bold yellow]Download:[/bold yellow] [red]{site_constant.SITE_NAME}[/red] → [cyan]{select_title.name}[/cyan] \n")
56
45
 
@@ -67,8 +56,8 @@ def download_film(select_title: MediaItem) -> str:
67
56
  return None
68
57
 
69
58
  # Define the filename and path for the downloaded film
70
- title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
71
- mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
59
+ title_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
60
+ mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))
72
61
 
73
62
  # Download the film using the m3u8 playlist, and output filename
74
63
  hls_process = HLS_Downloader(
@@ -21,7 +21,8 @@ from StreamingCommunity.Api.Template.Util import (
21
21
  map_episode_title,
22
22
  validate_selection,
23
23
  validate_episode_selection,
24
- display_episodes_list
24
+ display_episodes_list,
25
+ display_seasons_list
25
26
  )
26
27
  from StreamingCommunity.Api.Template.config_loader import site_constant
27
28
  from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
@@ -166,9 +167,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
166
167
  if site_constant.TELEGRAM_BOT:
167
168
  bot = get_bot_instance()
168
169
 
169
- # Prompt user for season selection and download episodes
170
- console.print(f"\n[green]Seasons found: [red]{seasons_count}")
171
-
172
170
  # If season_selection is provided, use it instead of asking for input
173
171
  if season_selection is None:
174
172
  if site_constant.TELEGRAM_BOT:
@@ -188,10 +186,8 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
188
186
  )
189
187
 
190
188
  else:
191
- index_season_selected = msg.ask(
192
- "\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
193
- "[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"
194
- )
189
+ index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
190
+
195
191
  else:
196
192
  index_season_selected = season_selection
197
193
  console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
@@ -211,7 +207,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
211
207
 
212
208
  if len(list_season_select) > 1 or index_season_selected == "*":
213
209
  download_episode(season_number, scrape_serie, video_source, download_all=True)
214
-
215
210
  else:
216
211
  download_episode(season_number, scrape_serie, video_source, download_all=False, episode_selection=episode_selection)
217
212
 
@@ -221,4 +216,4 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
221
216
  # Get script_id
222
217
  script_id = TelegramSession.get_session()
223
218
  if script_id != "unknown":
224
- TelegramSession.deleteScriptId(script_id)
219
+ TelegramSession.deleteScriptId(script_id)
@@ -4,14 +4,13 @@ import json
4
4
 
5
5
 
6
6
  # External libraries
7
- import httpx
8
7
  from bs4 import BeautifulSoup
9
8
  from rich.console import Console
10
9
 
11
10
 
12
11
  # Internal utilities
13
- from StreamingCommunity.Util.config_json import config_manager
14
12
  from StreamingCommunity.Util.headers import get_userAgent
13
+ from StreamingCommunity.Util.http_client import create_client
15
14
  from StreamingCommunity.Util.table import TVShowManager
16
15
  from StreamingCommunity.TelegramHelp.telegram_bot import get_bot_instance
17
16
 
@@ -25,8 +24,6 @@ from StreamingCommunity.Api.Template.Class.SearchType import MediaManager
25
24
  console = Console()
26
25
  media_search_manager = MediaManager()
27
26
  table_show_manager = TVShowManager()
28
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
29
- ssl_verify = config_manager.get_bool("REQUESTS", "verify")
30
27
 
31
28
 
32
29
  def title_search(query: str) -> int:
@@ -46,13 +43,7 @@ def title_search(query: str) -> int:
46
43
  table_show_manager.clear()
47
44
 
48
45
  try:
49
- response = httpx.get(
50
- f"{site_constant.FULL_URL}/it",
51
- headers={'user-agent': get_userAgent()},
52
- timeout=max_timeout,
53
- verify=ssl_verify,
54
- follow_redirects=True
55
- )
46
+ response = create_client(headers={'user-agent': get_userAgent()}).get(f"{site_constant.FULL_URL}/it")
56
47
  response.raise_for_status()
57
48
 
58
49
  soup = BeautifulSoup(response.text, 'html.parser')
@@ -66,17 +57,7 @@ def title_search(query: str) -> int:
66
57
  console.print(f"[cyan]Search url: [yellow]{search_url}")
67
58
 
68
59
  try:
69
- response = httpx.get(
70
- search_url,
71
- headers = {
72
- 'referer': site_constant.FULL_URL,
73
- 'user-agent': get_userAgent(),
74
- 'x-inertia': 'true',
75
- 'x-inertia-version': version
76
- },
77
- timeout=max_timeout,
78
- verify=ssl_verify
79
- )
60
+ response = create_client(headers={'user-agent': get_userAgent(), 'x-inertia': 'true', 'x-inertia-version': version}).get(search_url)
80
61
  response.raise_for_status()
81
62
 
82
63
  except Exception as e:
@@ -5,21 +5,15 @@ import logging
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
- from StreamingCommunity.Util.headers import get_userAgent
14
- from StreamingCommunity.Util.config_json import config_manager
12
+ from StreamingCommunity.Util.headers import get_headers
13
+ from StreamingCommunity.Util.http_client import create_client
15
14
  from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager
16
15
 
17
16
 
18
- # Variable
19
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
20
- ssl_verify = config_manager.get_bool("REQUESTS", "verify")
21
-
22
-
23
17
  class GetSerieInfo:
24
18
  def __init__(self, url, media_id: int = None, series_name: str = None):
25
19
  """
@@ -31,7 +25,7 @@ class GetSerieInfo:
31
25
  - series_name (str, optional): Name of the TV series
32
26
  """
33
27
  self.is_series = False
34
- self.headers = {'user-agent': get_userAgent()}
28
+ self.headers = get_headers()
35
29
  self.url = url
36
30
  self.media_id = media_id
37
31
  self.seasons_manager = SeasonManager()
@@ -48,12 +42,7 @@ class GetSerieInfo:
48
42
  Exception: If there's an error fetching series information
49
43
  """
50
44
  try:
51
- response = httpx.get(
52
- url=f"{self.url}/titles/{self.media_id}-{self.series_name}",
53
- headers=self.headers,
54
- timeout=max_timeout,
55
- verify=ssl_verify
56
- )
45
+ response = create_client(headers=self.headers).get(f"{self.url}/titles/{self.media_id}-{self.series_name}")
57
46
  response.raise_for_status()
58
47
 
59
48
  # Extract series info from JSON response
@@ -75,7 +64,6 @@ class GetSerieInfo:
75
64
  'number': season_data.get('number', 0),
76
65
  'name': f"Season {season_data.get('number', 0)}",
77
66
  'slug': season_data.get('slug', ''),
78
- 'type': title_data.get('type', '')
79
67
  })
80
68
 
81
69
  except Exception as e:
@@ -98,17 +86,13 @@ class GetSerieInfo:
98
86
  if not season:
99
87
  logging.error(f"Season {number_season} not found")
100
88
  return
101
-
102
- response = httpx.get(
103
- url=f'{self.url}/titles/{self.media_id}-{self.series_name}/season-{number_season}',
104
- headers={
105
- 'User-Agent': self.headers['user-agent'],
106
- 'x-inertia': 'true',
107
- 'x-inertia-version': self.version,
108
- },
109
- timeout=max_timeout,
110
- verify=ssl_verify
111
- )
89
+
90
+ custom_headers = self.headers.copy()
91
+ custom_headers.update({
92
+ 'x-inertia': 'true',
93
+ 'x-inertia-version': self.version,
94
+ })
95
+ response = create_client(headers=custom_headers).get(f"{self.url}/titles/{self.media_id}-{self.series_name}/season-{number_season}")
112
96
 
113
97
  # Extract episodes from JSON response
114
98
  json_response = response.json().get('props', {}).get('loadedSeason', {}).get('episodes', [])
@@ -3,6 +3,7 @@
3
3
  import sys
4
4
  import subprocess
5
5
 
6
+
6
7
  # External library
7
8
  from rich.console import Console
8
9
  from rich.prompt import Prompt
@@ -9,6 +9,7 @@ from rich.console import Console
9
9
 
10
10
  # Internal utilities
11
11
  from StreamingCommunity.Util.os import os_manager
12
+ from StreamingCommunity.Util.config_json import config_manager
12
13
  from StreamingCommunity.Util.message import start_message
13
14
 
14
15
 
@@ -24,6 +25,7 @@ from StreamingCommunity.Api.Player.hdplayer import VideoSource
24
25
 
25
26
  # Variable
26
27
  console = Console()
28
+ extension_output = config_manager.get("M3U8_CONVERSION", "extension")
27
29
 
28
30
 
29
31
  def download_film(select_title: MediaItem) -> str:
@@ -45,8 +47,8 @@ def download_film(select_title: MediaItem) -> str:
45
47
  master_playlist = video_source.get_m3u8_url(select_title.url)
46
48
 
47
49
  # Define the filename and path for the downloaded film
48
- title_name = os_manager.get_sanitize_file(select_title.name) + ".mp4"
49
- mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(".mp4", ""))
50
+ title_name = os_manager.get_sanitize_file(select_title.name, select_title.date) + extension_output
51
+ mp4_path = os.path.join(site_constant.MOVIE_FOLDER, title_name.replace(extension_output, ""))
50
52
 
51
53
  # Download the film using the m3u8 playlist, and output filename
52
54
  hls_process = HLS_Downloader(
@@ -21,7 +21,8 @@ from StreamingCommunity.Api.Template.Util import (
21
21
  map_episode_title,
22
22
  validate_selection,
23
23
  validate_episode_selection,
24
- display_episodes_list
24
+ display_episodes_list,
25
+ display_seasons_list
25
26
  )
26
27
  from StreamingCommunity.Api.Template.config_loader import site_constant
27
28
  from StreamingCommunity.Api.Template.Class.SearchType import MediaItem
@@ -53,7 +54,7 @@ def download_video(index_season_selected: int, index_episode_selected: int, scra
53
54
 
54
55
  # Get episode information
55
56
  obj_episode = scrape_serie.selectEpisode(index_season_selected, index_episode_selected-1)
56
- console.print(f"\n[/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")
57
58
 
58
59
  # Define filename and path for the downloaded video
59
60
  mp4_name = f"{map_episode_title(scrape_serie.series_name, index_season_selected, index_episode_selected, obj_episode.name)}.mp4"
@@ -134,20 +135,11 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
134
135
  - episode_selection (str, optional): Pre-defined episode selection that bypasses manual input
135
136
  """
136
137
  scrape_serie = GetSerieInfo(select_season.url)
137
-
138
- # Get total number of seasons
139
138
  seasons_count = scrape_serie.getNumberSeason()
140
139
 
141
- # Prompt user for season selection and download episodes
142
- console.print(f"\n[green]Seasons found: [red]{seasons_count}")
143
-
144
140
  # If season_selection is provided, use it instead of asking for input
145
141
  if season_selection is None:
146
- index_season_selected = msg.ask(
147
- "\n[cyan]Insert season number [yellow](e.g., 1), [red]* [cyan]to download all seasons, "
148
- "[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"
149
- )
150
-
142
+ index_season_selected = display_seasons_list(scrape_serie.seasons_manager)
151
143
  else:
152
144
  index_season_selected = season_selection
153
145
  console.print(f"\n[cyan]Using provided season selection: [yellow]{season_selection}")
@@ -159,8 +151,6 @@ def download_series(select_season: MediaItem, season_selection: str = None, epis
159
151
  # Loop through the selected seasons and download episodes
160
152
  for i_season in list_season_select:
161
153
  if len(list_season_select) > 1 or index_season_selected == "*":
162
- # Download all episodes if multiple seasons are selected or if '*' is used
163
154
  download_episode(i_season, scrape_serie, download_all=True)
164
155
  else:
165
- # Otherwise, let the user select specific episodes for the single season
166
156
  download_episode(i_season, scrape_serie, download_all=False, episode_selection=episode_selection)
@@ -4,13 +4,12 @@ import re
4
4
 
5
5
 
6
6
  # External libraries
7
- import httpx
8
7
  from bs4 import BeautifulSoup
9
8
  from rich.console import Console
10
9
 
11
10
 
12
11
  # Internal utilities
13
- from StreamingCommunity.Util.config_json import config_manager
12
+ from StreamingCommunity.Util.http_client import create_client
14
13
  from StreamingCommunity.Util.headers import get_userAgent
15
14
  from StreamingCommunity.Util.table import TVShowManager
16
15
 
@@ -24,18 +23,13 @@ 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 extract_nonce() -> str:
31
29
  """Extract nonce value from the page script"""
32
- response = httpx.get(
33
- site_constant.FULL_URL,
34
- headers={'user-agent': get_userAgent()},
35
- timeout=max_timeout
36
- )
37
-
30
+ response = create_client(headers={'user-agent': get_userAgent()}).get(site_constant.FULL_URL)
38
31
  soup = BeautifulSoup(response.content, 'html.parser')
32
+
39
33
  script = soup.find('script', id='live-search-js-extra')
40
34
  if script:
41
35
  match = re.search(r'"admin_ajax_nonce":"([^"]+)"', script.text)
@@ -73,15 +67,7 @@ def title_search(query: str) -> int:
73
67
  '_wpnonce': _wpnonce
74
68
  }
75
69
 
76
- response = httpx.post(
77
- search_url,
78
- headers={
79
- 'origin': site_constant.FULL_URL,
80
- 'user-agent': get_userAgent()
81
- },
82
- data=data,
83
- timeout=max_timeout
84
- )
70
+ response = create_client(headers={'origin': site_constant.FULL_URL, 'user-agent': get_userAgent()}).post(search_url, data=data)
85
71
  response.raise_for_status()
86
72
  soup = BeautifulSoup(response.text, 'html.parser')
87
73
 
@@ -11,12 +11,9 @@ from bs4 import BeautifulSoup
11
11
  # Internal utilities
12
12
  from StreamingCommunity.Util.headers import get_userAgent
13
13
  from StreamingCommunity.Util.http_client import create_client
14
- from StreamingCommunity.Util.config_json import config_manager
15
14
  from StreamingCommunity.Api.Player.Helper.Vixcloud.util import SeasonManager, Episode
16
15
 
17
16
 
18
- # Variable
19
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
20
17
 
21
18
 
22
19
  class GetSerieInfo:
@@ -6,7 +6,8 @@ from .manage_ep import (
6
6
  validate_episode_selection,
7
7
  validate_selection,
8
8
  dynamic_format_number,
9
- display_episodes_list
9
+ display_episodes_list,
10
+ display_seasons_list
10
11
  )
11
12
 
12
13
  __all__ = [
@@ -15,5 +16,6 @@ __all__ = [
15
16
  "validate_episode_selection",
16
17
  "validate_selection",
17
18
  "dynamic_format_number",
18
- "display_episodes_list"
19
+ "display_episodes_list",
20
+ display_seasons_list
19
21
  ]