StreamingCommunity 2.5.7__py3-none-any.whl → 2.5.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 (65) hide show
  1. StreamingCommunity/Api/Player/ddl.py +2 -3
  2. StreamingCommunity/Api/Site/1337xx/__init__.py +5 -6
  3. StreamingCommunity/Api/Site/1337xx/site.py +7 -14
  4. StreamingCommunity/Api/Site/1337xx/title.py +3 -5
  5. StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +7 -6
  6. StreamingCommunity/Api/Site/altadefinizionegratis/film.py +14 -19
  7. StreamingCommunity/Api/Site/altadefinizionegratis/site.py +6 -14
  8. StreamingCommunity/Api/Site/animeunity/__init__.py +7 -7
  9. StreamingCommunity/Api/Site/animeunity/film_serie.py +29 -31
  10. StreamingCommunity/Api/Site/animeunity/site.py +14 -22
  11. StreamingCommunity/Api/Site/cb01new/__init__.py +5 -4
  12. StreamingCommunity/Api/Site/cb01new/film.py +2 -5
  13. StreamingCommunity/Api/Site/cb01new/site.py +5 -13
  14. StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +5 -4
  15. StreamingCommunity/Api/Site/ddlstreamitaly/series.py +12 -49
  16. StreamingCommunity/Api/Site/ddlstreamitaly/site.py +6 -16
  17. StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +2 -3
  18. StreamingCommunity/Api/Site/guardaserie/__init__.py +5 -4
  19. StreamingCommunity/Api/Site/guardaserie/series.py +11 -46
  20. StreamingCommunity/Api/Site/guardaserie/site.py +5 -13
  21. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +10 -14
  22. StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +5 -4
  23. StreamingCommunity/Api/Site/ilcorsaronero/site.py +5 -13
  24. StreamingCommunity/Api/Site/ilcorsaronero/title.py +3 -5
  25. StreamingCommunity/Api/Site/mostraguarda/__init__.py +2 -2
  26. StreamingCommunity/Api/Site/mostraguarda/film.py +4 -8
  27. StreamingCommunity/Api/Site/streamingcommunity/__init__.py +8 -7
  28. StreamingCommunity/Api/Site/streamingcommunity/film.py +14 -18
  29. StreamingCommunity/Api/Site/streamingcommunity/series.py +25 -76
  30. StreamingCommunity/Api/Site/streamingcommunity/site.py +11 -23
  31. StreamingCommunity/Api/Template/Util/__init__.py +8 -1
  32. StreamingCommunity/Api/Template/Util/manage_ep.py +46 -2
  33. StreamingCommunity/Api/Template/config_loader.py +71 -0
  34. StreamingCommunity/Lib/Downloader/HLS/downloader.py +60 -59
  35. StreamingCommunity/Lib/Downloader/HLS/segments.py +40 -14
  36. StreamingCommunity/Lib/Downloader/MP4/downloader.py +47 -40
  37. StreamingCommunity/Lib/FFmpeg/command.py +59 -3
  38. StreamingCommunity/Lib/M3U8/estimator.py +5 -5
  39. StreamingCommunity/Lib/M3U8/parser.py +12 -51
  40. StreamingCommunity/Lib/TMBD/tmdb.py +66 -99
  41. StreamingCommunity/TelegramHelp/telegram_bot.py +222 -68
  42. StreamingCommunity/Util/_jsonConfig.py +14 -13
  43. StreamingCommunity/Util/ffmpeg_installer.py +70 -64
  44. StreamingCommunity/Util/headers.py +11 -122
  45. StreamingCommunity/Util/os.py +64 -55
  46. StreamingCommunity/Util/table.py +62 -108
  47. StreamingCommunity/run.py +15 -10
  48. {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/METADATA +56 -22
  49. StreamingCommunity-2.5.8.dist-info/RECORD +86 -0
  50. StreamingCommunity/Api/Site/1337xx/costant.py +0 -15
  51. StreamingCommunity/Api/Site/altadefinizionegratis/costant.py +0 -21
  52. StreamingCommunity/Api/Site/animeunity/costant.py +0 -21
  53. StreamingCommunity/Api/Site/cb01new/costant.py +0 -19
  54. StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +0 -20
  55. StreamingCommunity/Api/Site/guardaserie/costant.py +0 -19
  56. StreamingCommunity/Api/Site/ilcorsaronero/costant.py +0 -19
  57. StreamingCommunity/Api/Site/mostraguarda/costant.py +0 -19
  58. StreamingCommunity/Api/Site/streamingcommunity/costant.py +0 -21
  59. StreamingCommunity/TelegramHelp/request_manager.py +0 -82
  60. StreamingCommunity/TelegramHelp/session.py +0 -56
  61. StreamingCommunity-2.5.7.dist-info/RECORD +0 -96
  62. {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/LICENSE +0 -0
  63. {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/WHEEL +0 -0
  64. {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/entry_points.txt +0 -0
  65. {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/top_level.txt +0 -0
@@ -3,7 +3,7 @@
3
3
  import sys
4
4
  import logging
5
5
  import subprocess
6
- from typing import List, Dict
6
+ from typing import List, Dict, Tuple, Optional
7
7
 
8
8
 
9
9
  # Internal utilities
@@ -34,6 +34,62 @@ USE_LARGE_BAR = not ("android" in sys.platform or "ios" in sys.platform)
34
34
  FFMPEG_PATH = os_summary.ffmpeg_path
35
35
 
36
36
 
37
+
38
+ def check_subtitle_encoders() -> Tuple[Optional[bool], Optional[bool]]:
39
+ """
40
+ Executes 'ffmpeg -encoders' and checks if 'mov_text' and 'webvtt' encoders are available.
41
+
42
+ Returns:
43
+ Tuple[Optional[bool], Optional[bool]]: A tuple containing (mov_text_supported, webvtt_supported)
44
+ Returns (None, None) if the FFmpeg command fails
45
+ """
46
+ try:
47
+ result = subprocess.run(
48
+ [FFMPEG_PATH, '-encoders'],
49
+ capture_output=True,
50
+ text=True,
51
+ check=True
52
+ )
53
+
54
+ # Check for encoder presence in output
55
+ output = result.stdout
56
+ mov_text_supported = "mov_text" in output
57
+ webvtt_supported = "webvtt" in output
58
+
59
+ return mov_text_supported, webvtt_supported
60
+
61
+ except subprocess.CalledProcessError as e:
62
+ print(f"Error executing 'ffmpeg -encoders': {e}")
63
+ return None, None
64
+
65
+
66
+ def select_subtitle_encoder() -> Optional[str]:
67
+ """
68
+ Determines the best available subtitle encoder to use.
69
+ Prefers mov_text over webvtt if both are available.
70
+
71
+ Returns:
72
+ Optional[str]: Name of the best available encoder ('mov_text' or 'webvtt')
73
+ or None if no supported encoder is found
74
+ """
75
+ mov_text_supported, webvtt_supported = check_subtitle_encoders()
76
+
77
+ # Return early if check failed
78
+ if mov_text_supported is None:
79
+ return None
80
+
81
+ # Prioritize mov_text over webvtt
82
+ if mov_text_supported:
83
+ logging.info("Using 'mov_text' as the subtitle encoder.")
84
+ return "mov_text"
85
+ elif webvtt_supported:
86
+ logging.info("Using 'webvtt' as the subtitle encoder.")
87
+ return "webvtt"
88
+
89
+ logging.error("No supported subtitle encoder found.")
90
+ return None
91
+
92
+
37
93
  def join_video(video_path: str, out_path: str, codec: M3U8_Codec = None):
38
94
  """
39
95
  Joins single ts video file to mp4
@@ -238,9 +294,9 @@ def join_subtitle(video_path: str, subtitles_list: List[Dict[str, str]], out_pat
238
294
 
239
295
  # Add output Parameters
240
296
  if USE_CODEC:
241
- ffmpeg_cmd.extend(['-c:v', 'copy', '-c:a', 'copy', '-c:s', 'mov_text'])
297
+ ffmpeg_cmd.extend(['-c:v', 'copy', '-c:a', 'copy', '-c:s', select_subtitle_encoder()])
242
298
  else:
243
- ffmpeg_cmd.extend(['-c', 'copy', '-c:s', 'mov_text'])
299
+ ffmpeg_cmd.extend(['-c', 'copy', '-c:s', select_subtitle_encoder()])
244
300
 
245
301
  # Overwrite
246
302
  ffmpeg_cmd += [out_path, "-y"]
@@ -127,16 +127,16 @@ class M3U8_Ts_Estimator:
127
127
  retry_count = self.segments_instance.active_retries if self.segments_instance else 0
128
128
  progress_str = (
129
129
  #f"{Colors.WHITE}[ {Colors.GREEN}{number_file_downloaded} {Colors.WHITE}< "
130
- f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size} "
131
- f"{Colors.WHITE}| {Colors.CYAN}{average_internet_speed} {Colors.RED}{average_internet_unit} "
132
- f"{Colors.WHITE}| {Colors.GREEN}CRR {Colors.RED}{retry_count}"
130
+ f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size}"
131
+ f"{Colors.WHITE} {Colors.CYAN}{average_internet_speed} {Colors.RED}{average_internet_unit}"
132
+ f"{Colors.WHITE} {Colors.GREEN}CRR {Colors.RED}{retry_count} "
133
133
  )
134
134
  else:
135
135
  retry_count = self.segments_instance.active_retries if self.segments_instance else 0
136
136
  progress_str = (
137
137
  #f"{Colors.WHITE}[ {Colors.GREEN}{number_file_downloaded} {Colors.WHITE}< "
138
- f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size} "
139
- f"{Colors.WHITE}| {Colors.GREEN}CRR {Colors.RED}{retry_count}"
138
+ f"{Colors.GREEN}{number_file_total_size} {Colors.RED}{units_file_total_size}"
139
+ f"{Colors.WHITE} {Colors.GREEN}CRR {Colors.RED}{retry_count} "
140
140
  )
141
141
 
142
142
  progress_counter.set_postfix_str(progress_str)
@@ -39,12 +39,17 @@ CODEC_MAPPINGS = {
39
39
  }
40
40
 
41
41
  RESOLUTIONS = [
42
- (7680, 4320),
43
- (3840, 2160),
44
- (2560, 1440),
45
- (1920, 1080),
46
- (1280, 720),
47
- (640, 480)
42
+ (7680, 4320), # 8K
43
+ (3840, 2160), # 4K
44
+ (2560, 1440), # 1440p
45
+ (1920, 1080), # 1080p
46
+ (1280, 720), # 720p
47
+ (640, 480), # VGA
48
+ (640, 360), # 360p
49
+ (480, 320), # HVGA
50
+ (426, 240), # 240p
51
+ (320, 240), # QVGA
52
+ (256, 144), # 144p
48
53
  ]
49
54
 
50
55
 
@@ -377,47 +382,6 @@ class M3U8_Subtitle:
377
382
  return subtitle
378
383
  return None
379
384
 
380
- def download_all(self, custom_subtitle):
381
- """
382
- Download all subtitles listed in the object's attributes, filtering based on a provided list of custom subtitles.
383
-
384
- Parameters:
385
- - custom_subtitle (list): A list of custom subtitles to download.
386
-
387
- Returns:
388
- list: A list containing dictionaries with subtitle information including name, language, and URI.
389
- """
390
-
391
- output = [] # Initialize an empty list to store subtitle information
392
-
393
- # Iterate through all available subtitles
394
- for obj_subtitle in self.subtitle_get_all_uris_and_names():
395
-
396
- # Check if the subtitle name is not in the list of custom subtitles, and skip if not found
397
- if obj_subtitle.get('name') not in custom_subtitle:
398
- continue
399
-
400
- # Send a request to retrieve the subtitle content
401
- logging.info(f"Download subtitle: {obj_subtitle.get('name')}")
402
- response_subitle = httpx.get(obj_subtitle.get('uri'))
403
-
404
- try:
405
- # Try to extract the VTT URL from the subtitle content
406
- sub_parse = M3U8_Parser()
407
- sub_parse.parse_data(obj_subtitle.get('uri'), response_subitle.text)
408
- url_subititle = sub_parse.subtitle[0]
409
-
410
- output.append({
411
- 'name': obj_subtitle.get('name'),
412
- 'language': obj_subtitle.get('language'),
413
- 'uri': url_subititle
414
- })
415
-
416
- except Exception as e:
417
- logging.error(f"Cant download: {obj_subtitle.get('name')}, error: {e}")
418
-
419
- return output
420
-
421
385
 
422
386
  class M3U8_Parser:
423
387
  def __init__(self):
@@ -555,7 +519,6 @@ class M3U8_Parser:
555
519
  - m3u8_obj: The M3U8 object containing encryption keys.
556
520
  """
557
521
  try:
558
-
559
522
  if m3u8_obj.key is not None:
560
523
  if self.keys is None:
561
524
  self.keys = {
@@ -564,7 +527,6 @@ class M3U8_Parser:
564
527
  'uri': m3u8_obj.key.uri
565
528
  }
566
529
 
567
-
568
530
  except Exception as e:
569
531
  logging.error(f"Error parsing encryption keys: {e}")
570
532
  sys.exit(0)
@@ -629,7 +591,6 @@ class M3U8_Parser:
629
591
  """
630
592
  Initialize variables for video, audio, and subtitle playlists.
631
593
  """
632
-
633
594
  self._video = M3U8_Video(self.video_playlist)
634
595
  self._audio = M3U8_Audio(self.audio_playlist)
635
596
  self._subtitle = M3U8_Subtitle(self.subtitle_playlist)
@@ -663,4 +624,4 @@ class M3U8_Parser:
663
624
  if return_string:
664
625
  return f"[yellow]{int(hours)}[red]h [yellow]{int(minutes)}[red]m [yellow]{int(seconds)}[red]s"
665
626
  else:
666
- return {'h': int(hours), 'm': int(minutes), 's': int(seconds)}
627
+ return {'h': int(hours), 'm': int(minutes), 's': int(seconds)}
@@ -6,17 +6,19 @@ from typing import Dict
6
6
 
7
7
  # External libraries
8
8
  import httpx
9
- from rich.console import Console
10
9
 
11
10
 
12
11
  # Internal utilities
13
12
  from .obj_tmbd import Json_film
13
+ from StreamingCommunity.Util.console import console
14
+ from StreamingCommunity.Util._jsonConfig import config_manager
14
15
  from StreamingCommunity.Util.table import TVShowManager
15
16
 
16
17
 
17
18
  # Variable
18
19
  table_show_manager = TVShowManager()
19
20
  api_key = "a800ed6c93274fb857ea61bd9e7256c5"
21
+ MAX_TIMEOUT = config_manager.get_int("REQUESTS", "timeout")
20
22
 
21
23
 
22
24
 
@@ -33,7 +35,7 @@ def get_select_title(table_show_manager, generic_obj):
33
35
 
34
36
  # Check if the generic_obj list is empty
35
37
  if not generic_obj:
36
- Console.print("\n[red]No media items available.")
38
+ console.print("\n[red]No media items available.")
37
39
  return None
38
40
 
39
41
  # Example of available colors for columns
@@ -76,7 +78,7 @@ def get_select_title(table_show_manager, generic_obj):
76
78
 
77
79
  # Handle user's quit command
78
80
  if last_command == "q" or last_command == "quit":
79
- Console.print("\n[red]Quit [white]...")
81
+ console.print("\n[red]Quit [white]...")
80
82
  sys.exit(0)
81
83
 
82
84
  # Check if the selected index is within range
@@ -84,7 +86,7 @@ def get_select_title(table_show_manager, generic_obj):
84
86
  return generic_obj[int(last_command)]
85
87
 
86
88
  else:
87
- Console.print("\n[red]Wrong index")
89
+ console.print("\n[red]Wrong index")
88
90
  sys.exit(0)
89
91
 
90
92
 
@@ -98,8 +100,9 @@ class TheMovieDB:
98
100
  """
99
101
  self.api_key = api_key
100
102
  self.base_url = "https://api.themoviedb.org/3"
101
- self.console = Console()
102
103
  #self.genres = self._fetch_genres()
104
+ self._cached_trending_tv = None
105
+ self._cached_trending_movies = None
103
106
 
104
107
  def _make_request(self, endpoint, params=None):
105
108
  """
@@ -117,7 +120,7 @@ class TheMovieDB:
117
120
 
118
121
  params['api_key'] = self.api_key
119
122
  url = f"{self.base_url}/{endpoint}"
120
- response = httpx.get(url, params=params)
123
+ response = httpx.get(url, params=params, timeout=MAX_TIMEOUT)
121
124
  response.raise_for_status()
122
125
 
123
126
  return response.json()
@@ -132,78 +135,66 @@ class TheMovieDB:
132
135
  genres = self._make_request("genre/movie/list")
133
136
  return {genre['id']: genre['name'] for genre in genres.get('genres', [])}
134
137
 
135
- def _process_and_add_tv_shows(self, data, columns):
138
+ def _display_top_5(self, category: str, data, name_key='title'):
136
139
  """
137
- Process TV show data and add it to the TV show manager.
140
+ Display top 5 most popular items in a single line with colors.
138
141
 
139
142
  Parameters:
140
- - data (list): List of dictionaries containing the data to process.
141
- - columns (list): A list of tuples, where each tuple contains the column name and the key to fetch the data from the dictionary.
143
+ - category (str): Category label (e.g., "Trending films", "Trending TV shows")
144
+ - data (list): List of media items
145
+ - name_key (str): Key to use for the name ('title' for movies, 'name' for TV shows)
142
146
  """
143
- # Define column styles with colors
144
- tv_show_manager = TVShowManager()
145
- column_info = {
146
- col[0]: {'color': col[2] if len(col) > 2 else 'white'}
147
- for col in columns
148
- }
149
- tv_show_manager.add_column(column_info)
150
-
151
- # Add each item to the TV show manager, including rank
152
- for index, item in enumerate(data):
153
-
154
- # Convert genre IDs to genre names
155
- genre_names = [self.genres.get(genre_id, 'Unknown') for genre_id in item.get('genre_ids', [])]
156
- tv_show = {
157
- col[0]: str(item.get(col[1], 'N/A')) if col[1] != 'genre_ids' else ', '.join(genre_names)
158
- for col in columns
159
- }
160
-
161
- tv_show_manager.add_tv_show(tv_show)
147
+ # Colors for the titles
148
+ colors = ['cyan', 'magenta', 'yellow', 'green', 'blue']
162
149
 
163
- # Display the processed TV show data
164
- tv_show_manager.display_data(tv_show_manager.tv_shows[tv_show_manager.slice_start:tv_show_manager.slice_end])
150
+ # Sort by popularity and get top 5
151
+ sorted_data = sorted(data, key=lambda x: x.get('popularity', 0), reverse=True)[:5]
152
+
153
+ # Create list of colored titles
154
+ colored_items = []
155
+ for item, color in zip(sorted_data, colors):
156
+ title = item.get(name_key, 'Unknown')
157
+ colored_items.append(f"[{color}]{title}[/]")
158
+
159
+ # Join with colored arrows and print with proper category label
160
+ console.print(
161
+ f"[bold purple]{category}:[/] {' [red]→[/] '.join(colored_items)}"
162
+ )
165
163
 
166
- def _display_with_title(self, title: str, data, columns):
164
+ def display_trending_tv_shows(self):
167
165
  """
168
- Display data with a title.
169
-
170
- Parameters:
171
- - title (str): The title to display.
172
- - data (list): List of dictionaries containing the data to process.
173
- - columns (list): A list of tuples, where each tuple contains the column name and the key to fetch the data from the dictionary.
166
+ Fetch and display the top 5 trending TV shows of the week.
167
+ Uses cached data if available, otherwise makes a new request.
174
168
  """
175
- self.console.print(f"\n{title}", style="bold underline")
176
- self._process_and_add_tv_shows(data, columns)
169
+ if self._cached_trending_tv is None:
170
+ self._cached_trending_tv = self._make_request("trending/tv/week").get("results", [])
171
+
172
+ self._display_top_5("Trending TV shows", self._cached_trending_tv, name_key='name')
177
173
 
178
- def display_trending_tv_shows(self):
174
+ def refresh_trending_tv_shows(self):
179
175
  """
180
- Fetch and display the trending TV shows of the week.
176
+ Force a refresh of the trending TV shows cache.
181
177
  """
182
- data = self._make_request("trending/tv/week").get("results", [])
183
- columns = [
184
- ("Title", "name", 'cyan'),
185
- ("First Air Date", "first_air_date", 'green'),
186
- ("Popularity", "popularity", 'magenta'),
187
- ("Genres", "genre_ids", 'blue'),
188
- ("Origin Country", "origin_country", 'red'),
189
- ("Vote Average", "vote_average", 'yellow')
190
- ]
191
- self._display_with_title("Trending TV Shows of the Week", data, columns)
178
+ self._cached_trending_tv = self._make_request("trending/tv/week").get("results", [])
179
+ return self._cached_trending_tv
192
180
 
193
181
  def display_trending_films(self):
194
182
  """
195
- Fetch and display the trending films of the week.
183
+ Fetch and display the top 5 trending films of the week.
184
+ Uses cached data if available, otherwise makes a new request.
196
185
  """
197
- data = self._make_request("trending/movie/week").get("results", [])
198
- columns = [
199
- ("Title", "title", 'cyan'),
200
- ("Release Date", "release_date", 'green'),
201
- ("Popularity", "popularity", 'magenta'),
202
- ("Genres", "genre_ids", 'blue'),
203
- ("Vote Average", "vote_average", 'yellow')
204
- ]
205
- self._display_with_title("Trending Films of the Week", data, columns)
186
+ if self._cached_trending_movies is None:
187
+ self._cached_trending_movies = self._make_request("trending/movie/week").get("results", [])
188
+
189
+ self._display_top_5("Trending films", self._cached_trending_movies, name_key='title')
206
190
 
191
+ def refresh_trending_films(self):
192
+ """
193
+ Force a refresh of the trending films cache.
194
+ """
195
+ self._cached_trending_movies = self._make_request("trending/movie/week").get("results", [])
196
+ return self._cached_trending_movies
197
+
207
198
  def search_movie(self, movie_name: str):
208
199
  """
209
200
  Search for a movie by name and return its TMDB ID.
@@ -217,10 +208,10 @@ class TheMovieDB:
217
208
  generic_obj = []
218
209
  data = self._make_request("search/movie", {"query": movie_name}).get("results", [])
219
210
  if not data:
220
- self.console.print("No movies found with that name.", style="red")
211
+ console.print("No movies found with that name.", style="red")
221
212
  return None
222
213
 
223
- self.console.print("\nSelect a Movie:")
214
+ console.print("\nSelect a Movie:")
224
215
  for i, movie in enumerate(data, start=1):
225
216
  generic_obj.append({
226
217
  'name': movie['title'],
@@ -243,7 +234,7 @@ class TheMovieDB:
243
234
  """
244
235
  movie = self._make_request(f"movie/{tmdb_id}")
245
236
  if not movie:
246
- self.console.print("Movie not found.", style="red")
237
+ console.print("Movie not found.", style="red")
247
238
  return None
248
239
 
249
240
  return Json_film(movie)
@@ -260,12 +251,12 @@ class TheMovieDB:
260
251
  """
261
252
  data = self._make_request("search/tv", {"query": tv_name}).get("results", [])
262
253
  if not data:
263
- self.console.print("No TV shows found with that name.", style="red")
254
+ console.print("No TV shows found with that name.", style="red")
264
255
  return None
265
256
 
266
- self.console.print("\nSelect a TV Show:")
257
+ console.print("\nSelect a TV Show:")
267
258
  for i, show in enumerate(data, start=1):
268
- self.console.print(f"{i}. {show['name']} (First Air Date: {show.get('first_air_date', 'N/A')})")
259
+ console.print(f"{i}. {show['name']} (First Air Date: {show.get('first_air_date', 'N/A')})")
269
260
 
270
261
  choice = int(input("Enter the number of the show you want: ")) - 1
271
262
  selected_show = data[choice]
@@ -283,12 +274,12 @@ class TheMovieDB:
283
274
  """
284
275
  data = self._make_request(f"tv/{tv_show_id}").get("seasons", [])
285
276
  if not data:
286
- self.console.print("No seasons found for this TV show.", style="red")
277
+ console.print("No seasons found for this TV show.", style="red")
287
278
  return None
288
279
 
289
- self.console.print("\nSelect a Season:")
280
+ console.print("\nSelect a Season:")
290
281
  for i, season in enumerate(data, start=1):
291
- self.console.print(f"{i}. {season['name']} (Episodes: {season['episode_count']})")
282
+ console.print(f"{i}. {season['name']} (Episodes: {season['episode_count']})")
292
283
 
293
284
  choice = int(input("Enter the number of the season you want: ")) - 1
294
285
  return data[choice]["season_number"]
@@ -306,12 +297,12 @@ class TheMovieDB:
306
297
  """
307
298
  data = self._make_request(f"tv/{tv_show_id}/season/{season_number}").get("episodes", [])
308
299
  if not data:
309
- self.console.print("No episodes found for this season.", style="red")
300
+ console.print("No episodes found for this season.", style="red")
310
301
  return None
311
302
 
312
- self.console.print("\nSelect an Episode:")
303
+ console.print("\nSelect an Episode:")
313
304
  for i, episode in enumerate(data, start=1):
314
- self.console.print(f"{i}. {episode['name']} (Air Date: {episode.get('air_date', 'N/A')})")
305
+ console.print(f"{i}. {episode['name']} (Air Date: {episode.get('air_date', 'N/A')})")
315
306
 
316
307
  choice = int(input("Enter the number of the episode you want: ")) - 1
317
308
  return data[choice]
@@ -319,28 +310,4 @@ class TheMovieDB:
319
310
 
320
311
 
321
312
  # Output
322
- tmdb = TheMovieDB(api_key)
323
-
324
-
325
- """
326
- Example:
327
-
328
-
329
- @ movie
330
- movie_name = "Interstellar"
331
- movie_id = tmdb.search_movie(movie_name)
332
-
333
- if movie_id:
334
- movie_details = tmdb.get_movie_details(tmdb_id=movie_id)
335
- print(movie_details)
336
-
337
-
338
- @ series
339
- tv_name = "Game of Thrones"
340
- tv_show_id = tmdb.search_tv_show(tv_name)
341
- if tv_show_id:
342
- season_number = tmdb.get_seasons(tv_show_id=tv_show_id)
343
- if season_number:
344
- episode = tmdb.get_episodes(tv_show_id=tv_show_id, season_number=season_number)
345
- print(episode)
346
- """
313
+ tmdb = TheMovieDB(api_key)