StreamingCommunity 2.4.0__py3-none-any.whl → 2.5.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 (91) hide show
  1. {StreamingCommunity-2.4.0.dist-info → StreamingCommunity-2.5.0.dist-info}/METADATA +9 -6
  2. StreamingCommunity-2.5.0.dist-info/RECORD +8 -0
  3. StreamingCommunity/Api/Player/Helper/Vixcloud/js_parser.py +0 -143
  4. StreamingCommunity/Api/Player/Helper/Vixcloud/util.py +0 -136
  5. StreamingCommunity/Api/Player/ddl.py +0 -89
  6. StreamingCommunity/Api/Player/maxstream.py +0 -151
  7. StreamingCommunity/Api/Player/supervideo.py +0 -194
  8. StreamingCommunity/Api/Player/vixcloud.py +0 -273
  9. StreamingCommunity/Api/Site/1337xx/__init__.py +0 -51
  10. StreamingCommunity/Api/Site/1337xx/costant.py +0 -15
  11. StreamingCommunity/Api/Site/1337xx/site.py +0 -89
  12. StreamingCommunity/Api/Site/1337xx/title.py +0 -66
  13. StreamingCommunity/Api/Site/altadefinizionegratis/__init__.py +0 -51
  14. StreamingCommunity/Api/Site/altadefinizionegratis/costant.py +0 -19
  15. StreamingCommunity/Api/Site/altadefinizionegratis/film.py +0 -74
  16. StreamingCommunity/Api/Site/altadefinizionegratis/site.py +0 -95
  17. StreamingCommunity/Api/Site/animeunity/__init__.py +0 -51
  18. StreamingCommunity/Api/Site/animeunity/costant.py +0 -19
  19. StreamingCommunity/Api/Site/animeunity/film_serie.py +0 -135
  20. StreamingCommunity/Api/Site/animeunity/site.py +0 -175
  21. StreamingCommunity/Api/Site/animeunity/util/ScrapeSerie.py +0 -97
  22. StreamingCommunity/Api/Site/cb01new/__init__.py +0 -52
  23. StreamingCommunity/Api/Site/cb01new/costant.py +0 -19
  24. StreamingCommunity/Api/Site/cb01new/film.py +0 -73
  25. StreamingCommunity/Api/Site/cb01new/site.py +0 -83
  26. StreamingCommunity/Api/Site/ddlstreamitaly/__init__.py +0 -56
  27. StreamingCommunity/Api/Site/ddlstreamitaly/costant.py +0 -20
  28. StreamingCommunity/Api/Site/ddlstreamitaly/series.py +0 -146
  29. StreamingCommunity/Api/Site/ddlstreamitaly/site.py +0 -99
  30. StreamingCommunity/Api/Site/ddlstreamitaly/util/ScrapeSerie.py +0 -85
  31. StreamingCommunity/Api/Site/guardaserie/__init__.py +0 -51
  32. StreamingCommunity/Api/Site/guardaserie/costant.py +0 -19
  33. StreamingCommunity/Api/Site/guardaserie/series.py +0 -198
  34. StreamingCommunity/Api/Site/guardaserie/site.py +0 -90
  35. StreamingCommunity/Api/Site/guardaserie/util/ScrapeSerie.py +0 -110
  36. StreamingCommunity/Api/Site/ilcorsaronero/__init__.py +0 -52
  37. StreamingCommunity/Api/Site/ilcorsaronero/costant.py +0 -19
  38. StreamingCommunity/Api/Site/ilcorsaronero/site.py +0 -72
  39. StreamingCommunity/Api/Site/ilcorsaronero/title.py +0 -46
  40. StreamingCommunity/Api/Site/ilcorsaronero/util/ilCorsarScraper.py +0 -149
  41. StreamingCommunity/Api/Site/mostraguarda/__init__.py +0 -49
  42. StreamingCommunity/Api/Site/mostraguarda/costant.py +0 -19
  43. StreamingCommunity/Api/Site/mostraguarda/film.py +0 -101
  44. StreamingCommunity/Api/Site/streamingcommunity/__init__.py +0 -56
  45. StreamingCommunity/Api/Site/streamingcommunity/costant.py +0 -19
  46. StreamingCommunity/Api/Site/streamingcommunity/film.py +0 -75
  47. StreamingCommunity/Api/Site/streamingcommunity/series.py +0 -206
  48. StreamingCommunity/Api/Site/streamingcommunity/site.py +0 -142
  49. StreamingCommunity/Api/Site/streamingcommunity/util/ScrapeSerie.py +0 -123
  50. StreamingCommunity/Api/Template/Class/SearchType.py +0 -101
  51. StreamingCommunity/Api/Template/Util/__init__.py +0 -5
  52. StreamingCommunity/Api/Template/Util/get_domain.py +0 -203
  53. StreamingCommunity/Api/Template/Util/manage_ep.py +0 -179
  54. StreamingCommunity/Api/Template/Util/recall_search.py +0 -37
  55. StreamingCommunity/Api/Template/__init__.py +0 -3
  56. StreamingCommunity/Api/Template/site.py +0 -87
  57. StreamingCommunity/Lib/Downloader/HLS/downloader.py +0 -965
  58. StreamingCommunity/Lib/Downloader/HLS/proxyes.py +0 -110
  59. StreamingCommunity/Lib/Downloader/HLS/segments.py +0 -573
  60. StreamingCommunity/Lib/Downloader/MP4/downloader.py +0 -155
  61. StreamingCommunity/Lib/Downloader/TOR/downloader.py +0 -296
  62. StreamingCommunity/Lib/Downloader/__init__.py +0 -5
  63. StreamingCommunity/Lib/FFmpeg/__init__.py +0 -4
  64. StreamingCommunity/Lib/FFmpeg/capture.py +0 -170
  65. StreamingCommunity/Lib/FFmpeg/command.py +0 -296
  66. StreamingCommunity/Lib/FFmpeg/util.py +0 -249
  67. StreamingCommunity/Lib/M3U8/__init__.py +0 -6
  68. StreamingCommunity/Lib/M3U8/decryptor.py +0 -165
  69. StreamingCommunity/Lib/M3U8/estimator.py +0 -229
  70. StreamingCommunity/Lib/M3U8/parser.py +0 -666
  71. StreamingCommunity/Lib/M3U8/url_fixer.py +0 -58
  72. StreamingCommunity/Lib/TMBD/__init__.py +0 -2
  73. StreamingCommunity/Lib/TMBD/obj_tmbd.py +0 -39
  74. StreamingCommunity/Lib/TMBD/tmdb.py +0 -346
  75. StreamingCommunity/Upload/update.py +0 -67
  76. StreamingCommunity/Upload/version.py +0 -5
  77. StreamingCommunity/Util/_jsonConfig.py +0 -228
  78. StreamingCommunity/Util/call_stack.py +0 -42
  79. StreamingCommunity/Util/color.py +0 -20
  80. StreamingCommunity/Util/console.py +0 -12
  81. StreamingCommunity/Util/ffmpeg_installer.py +0 -368
  82. StreamingCommunity/Util/headers.py +0 -160
  83. StreamingCommunity/Util/logger.py +0 -62
  84. StreamingCommunity/Util/message.py +0 -64
  85. StreamingCommunity/Util/os.py +0 -507
  86. StreamingCommunity/Util/table.py +0 -229
  87. StreamingCommunity-2.4.0.dist-info/RECORD +0 -92
  88. {StreamingCommunity-2.4.0.dist-info → StreamingCommunity-2.5.0.dist-info}/LICENSE +0 -0
  89. {StreamingCommunity-2.4.0.dist-info → StreamingCommunity-2.5.0.dist-info}/WHEEL +0 -0
  90. {StreamingCommunity-2.4.0.dist-info → StreamingCommunity-2.5.0.dist-info}/entry_points.txt +0 -0
  91. {StreamingCommunity-2.4.0.dist-info → StreamingCommunity-2.5.0.dist-info}/top_level.txt +0 -0
@@ -1,203 +0,0 @@
1
- # 18.06.24
2
-
3
- import ssl
4
- import time
5
- from urllib.parse import urlparse, unquote
6
-
7
-
8
- # External libraries
9
- import httpx
10
- from googlesearch import search
11
-
12
-
13
- # Internal utilities
14
- from StreamingCommunity.Util.headers import get_headers
15
- from StreamingCommunity.Util.console import console, msg
16
- from StreamingCommunity.Util._jsonConfig import config_manager
17
-
18
-
19
- base_headers = {
20
- 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
21
- 'accept-language': 'it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7',
22
- 'dnt': '1',
23
- 'priority': 'u=0, i',
24
- 'referer': '',
25
- 'sec-ch-ua-mobile': '?0',
26
- 'sec-ch-ua-platform': '"Windows"',
27
- 'sec-fetch-dest': 'document',
28
- 'sec-fetch-mode': 'navigate',
29
- 'sec-fetch-site': 'same-origin',
30
- 'sec-fetch-user': '?1',
31
- 'upgrade-insecure-requests': '1',
32
- 'user-agent': ''
33
- }
34
-
35
-
36
- def get_tld(url_str):
37
- """Extract the TLD (Top-Level Domain) from the URL."""
38
- try:
39
- url_str = unquote(url_str)
40
- parsed = urlparse(url_str)
41
- domain = parsed.netloc.lower()
42
-
43
- if domain.startswith('www.'):
44
- domain = domain[4:]
45
- parts = domain.split('.')
46
-
47
- return parts[-1] if len(parts) >= 2 else None
48
-
49
- except Exception:
50
- return None
51
-
52
- def get_base_domain(url_str):
53
- """Extract base domain without protocol, www and path."""
54
- try:
55
- parsed = urlparse(url_str)
56
- domain = parsed.netloc.lower()
57
- if domain.startswith('www.'):
58
- domain = domain[4:]
59
-
60
- # Check if domain has multiple parts separated by dots
61
- parts = domain.split('.')
62
- if len(parts) > 2: # Handle subdomains
63
- return '.'.join(parts[:-1]) # Return everything except TLD
64
-
65
- return parts[0] # Return base domain
66
-
67
- except Exception:
68
- return None
69
-
70
- def get_base_url(url_str):
71
- """Extract base URL including protocol and domain, removing path and query parameters."""
72
- try:
73
- parsed = urlparse(url_str)
74
- return f"{parsed.scheme}://{parsed.netloc}"
75
-
76
- except Exception:
77
- return None
78
-
79
- def validate_url(url, base_url, max_timeout, max_retries=3, sleep=3):
80
- """Validate if URL is accessible and matches expected base domain."""
81
- console.print(f"\n[cyan]Starting validation for URL[white]: [yellow]{url}")
82
-
83
- # Verify URL structure matches base_url structure
84
- base_domain = get_base_domain(base_url)
85
- url_domain = get_base_domain(url)
86
-
87
- base_headers['referer'] = url
88
- base_headers['user-agent'] = get_headers()
89
-
90
- if base_domain != url_domain:
91
- console.print(f"[red]Domain structure mismatch: {url_domain} != {base_domain}")
92
- return False, None
93
-
94
- # Count dots to ensure we don't have extra subdomains
95
- base_dots = base_url.count('.')
96
- url_dots = url.count('.')
97
- if url_dots > base_dots + 1: # Allow for one extra dot for TLD change
98
- console.print(f"[red]Too many subdomains in URL")
99
- return False, None
100
-
101
- client = httpx.Client(
102
- verify=False,
103
- headers=base_headers,
104
- timeout=max_timeout
105
- )
106
-
107
- for retry in range(max_retries):
108
- try:
109
- time.sleep(sleep)
110
-
111
- # Initial check without redirects
112
- response = client.get(url, follow_redirects=False)
113
- if response.status_code == 403:
114
- console.print(f"[red]Check failed (403) - Attempt {retry + 1}/{max_retries}")
115
- continue
116
-
117
- if response.status_code >= 400:
118
- console.print(f"[red]Check failed: HTTP {response.status_code}")
119
- return False, None
120
-
121
- # Follow redirects and verify final domain
122
- final_response = client.get(url, follow_redirects=True)
123
- final_domain = get_base_domain(str(final_response.url))
124
- console.print(f"[cyan]Redirect url: [red]{final_response.url}")
125
-
126
- if final_domain != base_domain:
127
- console.print(f"[red]Final domain mismatch: {final_domain} != {base_domain}")
128
- return False, None
129
-
130
- new_tld = get_tld(str(final_response.url))
131
- if new_tld != get_tld(url):
132
- return True, new_tld
133
-
134
- return True, None
135
-
136
- except (httpx.RequestError, ssl.SSLError) as e:
137
- console.print(f"[red]Connection error: {str(e)}")
138
- time.sleep(sleep)
139
- continue
140
-
141
- return False, None
142
-
143
- def search_domain(site_name: str, base_url: str, get_first: bool = False):
144
- """Search for valid domain matching site name and base URL."""
145
- max_timeout = config_manager.get_int("REQUESTS", "timeout")
146
- domain = str(config_manager.get_dict("SITE", site_name)['domain'])
147
-
148
- # Test initial URL
149
- try:
150
- is_correct, redirect_tld = validate_url(base_url, base_url, max_timeout)
151
-
152
- if is_correct:
153
- tld = redirect_tld or get_tld(base_url)
154
- config_manager.config['SITE'][site_name]['domain'] = tld
155
- config_manager.write_config()
156
- console.print(f"[green]Successfully validated initial URL")
157
- return tld, base_url
158
-
159
- except Exception as e:
160
- console.print(f"[red]Error testing initial URL: {str(e)}")
161
-
162
- # Google search phase
163
- base_domain = get_base_domain(base_url)
164
- console.print(f"\n[cyan]Searching for alternate domains for[white]: [yellow]{base_domain}")
165
-
166
- try:
167
- search_results = list(search(base_domain, num_results=20, lang="it"))
168
- base_urls = set()
169
-
170
- for url in search_results:
171
- base_url = get_base_url(url)
172
- if base_url:
173
- base_urls.add(base_url)
174
-
175
- # Filter URLs based on domain matching and subdomain count
176
- filtered_results = [
177
- url for url in base_urls
178
- if get_base_domain(url) == base_domain
179
- and url.count('.') <= base_url.count('.') + 1
180
- ]
181
-
182
- for idx, result_url in enumerate(filtered_results, 1):
183
- console.print(f"\n[cyan]Checking result {idx}/{len(filtered_results)}[white]: [yellow]{result_url}")
184
-
185
- is_valid, new_tld = validate_url(result_url, base_url, max_timeout)
186
- if is_valid:
187
- final_tld = new_tld or get_tld(result_url)
188
-
189
- if get_first or msg.ask(
190
- f"\n[cyan]Update site[white] [red]'{site_name}'[cyan] with domain[white] [red]'{final_tld}'",
191
- choices=["y", "n"],
192
- default="y"
193
- ).lower() == "y":
194
-
195
- config_manager.config['SITE'][site_name]['domain'] = final_tld
196
- config_manager.write_config()
197
- return final_tld, f"{base_url}.{final_tld}"
198
-
199
- except Exception as e:
200
- console.print(f"[red]Error during search: {str(e)}")
201
-
202
- console.print("[bold red]No valid URLs found matching the base URL.")
203
- return domain, f"{base_url}.{domain}"
@@ -1,179 +0,0 @@
1
- # 19.06.24
2
-
3
- import logging
4
- from typing import List
5
-
6
-
7
- # Internal utilities
8
- from StreamingCommunity.Util._jsonConfig import config_manager
9
- from StreamingCommunity.Util.os import os_manager
10
-
11
-
12
- # Config
13
- MAP_EPISODE = config_manager.get('DEFAULT', 'map_episode_name')
14
-
15
-
16
- def dynamic_format_number(n: int) -> str:
17
- """
18
- Formats a number by adding a leading zero if it is less than 9.
19
- The width of the resulting string is dynamic, calculated as the number of digits in the number plus one
20
- for numbers less than 9, otherwise the width remains the same.
21
-
22
- Parameters:
23
- - n (int): The number to format.
24
-
25
- Returns:
26
- - str: The formatted number as a string with a leading zero if the number is less than 9.
27
- """
28
- if n < 10:
29
- width = len(str(n)) + 1
30
- else:
31
- width = len(str(n))
32
-
33
- return str(n).zfill(width)
34
-
35
-
36
- def manage_selection(cmd_insert: str, max_count: int) -> List[int]:
37
- """
38
- Manage user selection for seasons or episodes to download.
39
-
40
- Parameters:
41
- - cmd_insert (str): User input for selection.
42
- - max_count (int): Maximum count available.
43
-
44
- Returns:
45
- list_selection (List[int]): List of selected items.
46
- """
47
- list_selection = []
48
- logging.info(f"Command insert: {cmd_insert}, end index: {max_count + 1}")
49
-
50
- # For a single number (e.g., '5')
51
- if cmd_insert.isnumeric():
52
- list_selection.append(int(cmd_insert))
53
-
54
- # For a range (e.g., '5-12')
55
- elif "-" in cmd_insert:
56
- start, end = map(str.strip, cmd_insert.split('-'))
57
- start = int(start)
58
- end = int(end) if end.isnumeric() else max_count
59
-
60
- list_selection = list(range(start, end + 1))
61
-
62
- # For all items ('*')
63
- elif cmd_insert == "*":
64
- list_selection = list(range(1, max_count + 1))
65
-
66
- else:
67
- raise ValueError("Invalid input format")
68
-
69
- logging.info(f"List return: {list_selection}")
70
- return list_selection
71
-
72
-
73
- def map_episode_title(tv_name: str, number_season: int, episode_number: int, episode_name: str) -> str:
74
- """
75
- Maps the episode title to a specific format.
76
-
77
- Parameters:
78
- tv_name (str): The name of the TV show.
79
- number_season (int): The season number.
80
- episode_number (int): The episode number.
81
- episode_name (str): The original name of the episode.
82
-
83
- Returns:
84
- str: The mapped episode title.
85
- """
86
- map_episode_temp = MAP_EPISODE
87
-
88
- if tv_name != None:
89
- map_episode_temp = map_episode_temp.replace("%(tv_name)", os_manager.get_sanitize_file(tv_name))
90
-
91
- if number_season != None:
92
- map_episode_temp = map_episode_temp.replace("%(season)", dynamic_format_number(number_season))
93
- else:
94
- map_episode_temp = map_episode_temp.replace("%(season)", dynamic_format_number(0))
95
-
96
- if episode_number != None:
97
- map_episode_temp = map_episode_temp.replace("%(episode)", dynamic_format_number(episode_number))
98
- else:
99
- map_episode_temp = map_episode_temp.replace("%(episode)", dynamic_format_number(0))
100
-
101
- if episode_name != None:
102
- map_episode_temp = map_episode_temp.replace("%(episode_name)", os_manager.get_sanitize_file(episode_name))
103
-
104
- logging.info(f"Map episode string return: {map_episode_temp}")
105
- return map_episode_temp
106
-
107
-
108
- # --> for season
109
- def validate_selection(list_season_select: List[int], seasons_count: int) -> List[int]:
110
- """
111
- Validates and adjusts the selected seasons based on the available seasons.
112
-
113
- Parameters:
114
- - list_season_select (List[int]): List of seasons selected by the user.
115
- - seasons_count (int): Total number of available seasons.
116
-
117
- Returns:
118
- - List[int]: Adjusted list of valid season numbers.
119
- """
120
- while True:
121
- try:
122
-
123
- # Remove any seasons greater than the available seasons
124
- valid_seasons = [season for season in list_season_select if 1 <= season <= seasons_count]
125
-
126
- # If the list is empty, the input was completely invalid
127
- if not valid_seasons:
128
- logging.error(f"Invalid selection: The selected seasons are outside the available range (1-{seasons_count}). Please try again.")
129
-
130
- # Re-prompt for valid input
131
- input_seasons = input(f"Enter valid season numbers (1-{seasons_count}): ")
132
- list_season_select = list(map(int, input_seasons.split(',')))
133
- continue # Re-prompt the user if the selection is invalid
134
-
135
- return valid_seasons # Return the valid seasons if the input is correct
136
-
137
- except ValueError:
138
- logging.error("Error: Please enter valid integers separated by commas.")
139
-
140
- # Prompt the user for valid input again
141
- input_seasons = input(f"Enter valid season numbers (1-{seasons_count}): ")
142
- list_season_select = list(map(int, input_seasons.split(',')))
143
-
144
-
145
- # --> for episode
146
- def validate_episode_selection(list_episode_select: List[int], episodes_count: int) -> List[int]:
147
- """
148
- Validates and adjusts the selected episodes based on the available episodes.
149
-
150
- Parameters:
151
- - list_episode_select (List[int]): List of episodes selected by the user.
152
- - episodes_count (int): Total number of available episodes in the season.
153
-
154
- Returns:
155
- - List[int]: Adjusted list of valid episode numbers.
156
- """
157
- while True:
158
- try:
159
-
160
- # Remove any episodes greater than the available episodes
161
- valid_episodes = [episode for episode in list_episode_select if 1 <= episode <= episodes_count]
162
-
163
- # If the list is empty, the input was completely invalid
164
- if not valid_episodes:
165
- logging.error(f"Invalid selection: The selected episodes are outside the available range (1-{episodes_count}). Please try again.")
166
-
167
- # Re-prompt for valid input
168
- input_episodes = input(f"Enter valid episode numbers (1-{episodes_count}): ")
169
- list_episode_select = list(map(int, input_episodes.split(',')))
170
- continue # Re-prompt the user if the selection is invalid
171
-
172
- return valid_episodes
173
-
174
- except ValueError:
175
- logging.error("Error: Please enter valid integers separated by commas.")
176
-
177
- # Prompt the user for valid input again
178
- input_episodes = input(f"Enter valid episode numbers (1-{episodes_count}): ")
179
- list_episode_select = list(map(int, input_episodes.split(',')))
@@ -1,37 +0,0 @@
1
- # 19.10.24
2
-
3
- import os
4
- import sys
5
-
6
- def execute_search(info):
7
- """
8
- Dynamically imports and executes a specified function from a module defined in the info dictionary.
9
-
10
- Parameters:
11
- info (dict): A dictionary containing the function name, folder, and module information.
12
- """
13
-
14
- # Define the project path using the folder from the info dictionary
15
- project_path = os.path.dirname(info['folder']) # Get the base path for the project
16
-
17
- # Add the project path to sys.path
18
- if project_path not in sys.path:
19
- sys.path.append(project_path)
20
-
21
- # Attempt to import the specified function from the module
22
- try:
23
- # Construct the import statement dynamically
24
- module_path = f"StreamingCommunity.Api.Site{info['folder_base']}"
25
- exec(f"from {module_path} import {info['function']}")
26
-
27
- # Call the specified function
28
- eval(info['function'])() # Calls the search function
29
-
30
- except ModuleNotFoundError as e:
31
- print(f"ModuleNotFoundError: {e}")
32
-
33
- except ImportError as e:
34
- print(f"ImportError: {e}")
35
-
36
- except Exception as e:
37
- print(f"An error occurred: {e}")
@@ -1,3 +0,0 @@
1
- # 19.06.24
2
-
3
- from .site import get_select_title
@@ -1,87 +0,0 @@
1
- # 19.06.24
2
-
3
- import sys
4
-
5
-
6
- # Internal utilities
7
- from StreamingCommunity.Util.console import console
8
-
9
-
10
- # Variable
11
- available_colors = ['red', 'magenta', 'yellow', 'cyan', 'green', 'blue', 'white']
12
- column_to_hide = ['Slug', 'Sub_ita', 'Last_air_date', 'Seasons_count', 'Url']
13
-
14
-
15
- def get_select_title(table_show_manager, media_search_manager):
16
- """
17
- Display a selection of titles and prompt the user to choose one.
18
-
19
- Returns:
20
- MediaItem: The selected media item.
21
- """
22
-
23
- # Set up table for displaying titles
24
- table_show_manager.set_slice_end(10)
25
-
26
- # Determine column_info dynamically for (search site)
27
- if not media_search_manager.media_list:
28
- console.print("\n[red]No media items available.")
29
- return None
30
-
31
- # Example of available colors for columns
32
- available_colors = ['red', 'magenta', 'yellow', 'cyan', 'green', 'blue', 'white']
33
-
34
- # Retrieve the keys of the first media item as column headers
35
- first_media_item = media_search_manager.media_list[0]
36
- column_info = {"Index": {'color': available_colors[0]}} # Always include Index with a fixed color
37
-
38
- # Assign colors to the remaining keys dynamically
39
- color_index = 1
40
- for key in first_media_item.__dict__.keys():
41
-
42
- if key.capitalize() in column_to_hide:
43
- continue
44
-
45
- if key in ('id', 'type', 'name', 'score'): # Custom prioritization of colors
46
- if key == 'type':
47
- column_info["Type"] = {'color': 'yellow'}
48
- elif key == 'name':
49
- column_info["Name"] = {'color': 'magenta'}
50
- elif key == 'score':
51
- column_info["Score"] = {'color': 'cyan'}
52
-
53
- else:
54
- column_info[key.capitalize()] = {'color': available_colors[color_index % len(available_colors)]}
55
- color_index += 1
56
-
57
- table_show_manager.add_column(column_info)
58
-
59
- # Populate the table with title information
60
- for i, media in enumerate(media_search_manager.media_list):
61
- media_dict = {'Index': str(i)}
62
-
63
- for key in first_media_item.__dict__.keys():
64
- if key.capitalize() in column_to_hide:
65
- continue
66
-
67
- # Ensure all values are strings for rich add table
68
- media_dict[key.capitalize()] = str(getattr(media, key))
69
-
70
- table_show_manager.add_tv_show(media_dict)
71
-
72
- # Run the table and handle user input
73
- last_command = table_show_manager.run(force_int_input=True, max_int_input=len(media_search_manager.media_list))
74
- table_show_manager.clear()
75
-
76
- # Handle user's quit command
77
- if last_command == "q" or last_command == "quit":
78
- console.print("\n[red]Quit [white]...")
79
- sys.exit(0)
80
-
81
- # Check if the selected index is within range
82
- if 0 <= int(last_command) < len(media_search_manager.media_list):
83
- return media_search_manager.get(int(last_command))
84
-
85
- else:
86
- console.print("\n[red]Wrong index")
87
- sys.exit(0)