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.
- StreamingCommunity/Api/Player/ddl.py +2 -3
- StreamingCommunity/Api/Site/1337xx/__init__.py +5 -6
- StreamingCommunity/Api/Site/1337xx/site.py +7 -14
- StreamingCommunity/Api/Site/1337xx/title.py +3 -5
- StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +7 -6
- StreamingCommunity/Api/Site/altadefinizionegratis/film.py +14 -19
- StreamingCommunity/Api/Site/altadefinizionegratis/site.py +6 -14
- StreamingCommunity/Api/Site/animeunity/__init__.py +7 -7
- StreamingCommunity/Api/Site/animeunity/film_serie.py +29 -31
- StreamingCommunity/Api/Site/animeunity/site.py +14 -22
- StreamingCommunity/Api/Site/cb01new/__init__.py +5 -4
- StreamingCommunity/Api/Site/cb01new/film.py +2 -5
- StreamingCommunity/Api/Site/cb01new/site.py +5 -13
- StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +5 -4
- StreamingCommunity/Api/Site/ddlstreamitaly/series.py +12 -49
- StreamingCommunity/Api/Site/ddlstreamitaly/site.py +6 -16
- StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +2 -3
- StreamingCommunity/Api/Site/guardaserie/__init__.py +5 -4
- StreamingCommunity/Api/Site/guardaserie/series.py +11 -46
- StreamingCommunity/Api/Site/guardaserie/site.py +5 -13
- StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +10 -14
- StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +5 -4
- StreamingCommunity/Api/Site/ilcorsaronero/site.py +5 -13
- StreamingCommunity/Api/Site/ilcorsaronero/title.py +3 -5
- StreamingCommunity/Api/Site/mostraguarda/__init__.py +2 -2
- StreamingCommunity/Api/Site/mostraguarda/film.py +4 -8
- StreamingCommunity/Api/Site/streamingcommunity/__init__.py +8 -7
- StreamingCommunity/Api/Site/streamingcommunity/film.py +14 -18
- StreamingCommunity/Api/Site/streamingcommunity/series.py +25 -76
- StreamingCommunity/Api/Site/streamingcommunity/site.py +11 -23
- StreamingCommunity/Api/Template/Util/__init__.py +8 -1
- StreamingCommunity/Api/Template/Util/manage_ep.py +46 -2
- StreamingCommunity/Api/Template/config_loader.py +71 -0
- StreamingCommunity/Lib/Downloader/HLS/downloader.py +60 -59
- StreamingCommunity/Lib/Downloader/HLS/segments.py +40 -14
- StreamingCommunity/Lib/Downloader/MP4/downloader.py +47 -40
- StreamingCommunity/Lib/FFmpeg/command.py +59 -3
- StreamingCommunity/Lib/M3U8/estimator.py +5 -5
- StreamingCommunity/Lib/M3U8/parser.py +12 -51
- StreamingCommunity/Lib/TMBD/tmdb.py +66 -99
- StreamingCommunity/TelegramHelp/telegram_bot.py +222 -68
- StreamingCommunity/Util/_jsonConfig.py +14 -13
- StreamingCommunity/Util/ffmpeg_installer.py +70 -64
- StreamingCommunity/Util/headers.py +11 -122
- StreamingCommunity/Util/os.py +64 -55
- StreamingCommunity/Util/table.py +62 -108
- StreamingCommunity/run.py +15 -10
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/METADATA +56 -22
- StreamingCommunity-2.5.8.dist-info/RECORD +86 -0
- StreamingCommunity/Api/Site/1337xx/costant.py +0 -15
- StreamingCommunity/Api/Site/altadefinizionegratis/costant.py +0 -21
- StreamingCommunity/Api/Site/animeunity/costant.py +0 -21
- StreamingCommunity/Api/Site/cb01new/costant.py +0 -19
- StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +0 -20
- StreamingCommunity/Api/Site/guardaserie/costant.py +0 -19
- StreamingCommunity/Api/Site/ilcorsaronero/costant.py +0 -19
- StreamingCommunity/Api/Site/mostraguarda/costant.py +0 -19
- StreamingCommunity/Api/Site/streamingcommunity/costant.py +0 -21
- StreamingCommunity/TelegramHelp/request_manager.py +0 -82
- StreamingCommunity/TelegramHelp/session.py +0 -56
- StreamingCommunity-2.5.7.dist-info/RECORD +0 -96
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/LICENSE +0 -0
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/WHEEL +0 -0
- {StreamingCommunity-2.5.7.dist-info → StreamingCommunity-2.5.8.dist-info}/entry_points.txt +0 -0
- {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',
|
|
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',
|
|
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}
|
|
132
|
-
f"{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} "
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
138
|
+
def _display_top_5(self, category: str, data, name_key='title'):
|
|
136
139
|
"""
|
|
137
|
-
|
|
140
|
+
Display top 5 most popular items in a single line with colors.
|
|
138
141
|
|
|
139
142
|
Parameters:
|
|
140
|
-
-
|
|
141
|
-
-
|
|
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
|
-
#
|
|
144
|
-
|
|
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
|
-
#
|
|
164
|
-
|
|
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
|
|
164
|
+
def display_trending_tv_shows(self):
|
|
167
165
|
"""
|
|
168
|
-
|
|
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.
|
|
176
|
-
|
|
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
|
|
174
|
+
def refresh_trending_tv_shows(self):
|
|
179
175
|
"""
|
|
180
|
-
|
|
176
|
+
Force a refresh of the trending TV shows cache.
|
|
181
177
|
"""
|
|
182
|
-
|
|
183
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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
|
-
|
|
211
|
+
console.print("No movies found with that name.", style="red")
|
|
221
212
|
return None
|
|
222
213
|
|
|
223
|
-
|
|
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
|
-
|
|
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
|
-
|
|
254
|
+
console.print("No TV shows found with that name.", style="red")
|
|
264
255
|
return None
|
|
265
256
|
|
|
266
|
-
|
|
257
|
+
console.print("\nSelect a TV Show:")
|
|
267
258
|
for i, show in enumerate(data, start=1):
|
|
268
|
-
|
|
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
|
-
|
|
277
|
+
console.print("No seasons found for this TV show.", style="red")
|
|
287
278
|
return None
|
|
288
279
|
|
|
289
|
-
|
|
280
|
+
console.print("\nSelect a Season:")
|
|
290
281
|
for i, season in enumerate(data, start=1):
|
|
291
|
-
|
|
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
|
-
|
|
300
|
+
console.print("No episodes found for this season.", style="red")
|
|
310
301
|
return None
|
|
311
302
|
|
|
312
|
-
|
|
303
|
+
console.print("\nSelect an Episode:")
|
|
313
304
|
for i, episode in enumerate(data, start=1):
|
|
314
|
-
|
|
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)
|