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
@@ -1,104 +1,24 @@
1
1
  # 4.04.24
2
2
 
3
- import re
4
- import sys
5
3
  import random
6
- from importlib.metadata import version, PackageNotFoundError
7
4
 
8
5
 
9
6
  # External library
10
- from fake_useragent import UserAgent
7
+ import ua_generator
11
8
 
12
9
 
13
- # Variable
14
- try:
15
- ua_version = version('fake-useragent')
16
- except PackageNotFoundError:
17
- ua_version = None
18
-
19
- if not getattr(sys, 'frozen', False):
20
- if ua_version == '1.1.3':
21
- ua = UserAgent(use_external_data=True)
22
- else:
23
- ua = UserAgent()
24
- else:
25
- ua = UserAgent()
26
-
27
-
28
- def extract_versions(user_agent):
29
- """
30
- Extract browser versions from the user agent.
31
-
32
- Parameters:
33
- user_agent (str): User agent of the browser.
34
-
35
- Returns:
36
- list: List of browser versions.
37
- """
38
-
39
- # Patterns to extract versions from various user agents
40
- patterns = {
41
- 'chrome': re.compile(r'Chrome/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
42
- 'firefox': re.compile(r'Firefox/(\d+)\.?(\d+)?\.?(\d+)?'),
43
- 'safari': re.compile(r'Version/(\d+)\.(\d+)\.(\d+) Safari/(\d+)\.(\d+)\.(\d+)'),
44
- 'edge': re.compile(r'Edg/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
45
- 'edgios': re.compile(r'EdgiOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
46
- 'crios': re.compile(r'CriOS/(\d+)\.(\d+)\.(\d+)\.(\d+)'),
47
- }
48
-
49
- for key, pattern in patterns.items():
50
- match = pattern.search(user_agent)
51
- if match:
52
- return [match.group(i+1) for i in range(match.lastindex)]
53
-
54
- # Fallback values if specific versions are not found
55
- return ['99', '0', '0', '0']
56
-
57
- def get_platform(user_agent):
10
+ def get_headers() -> str:
58
11
  """
59
- Determine the device platform from the user agent.
60
-
61
- Parameters:
62
- user_agent (str): User agent of the browser.
12
+ Generate a random user agent to use in HTTP requests.
63
13
 
64
14
  Returns:
65
- str: Device platform.
66
- """
67
- if 'Windows' in user_agent:
68
- return '"Windows"'
69
- elif 'Mac OS X' in user_agent:
70
- return '"macOS"'
71
- elif 'Android' in user_agent:
72
- return '"Android"'
73
- elif 'iPhone' in user_agent or 'iPad' in user_agent:
74
- return '"iOS"'
75
- elif 'Linux' in user_agent:
76
- return '"Linux"'
77
- return '"Unknown"'
78
-
79
- def get_model(user_agent):
15
+ - str: A random user agent string.
80
16
  """
81
- Determine the device model from the user agent.
17
+
18
+ # Get a random user agent string from the user agent rotator
19
+ user_agent = ua_generator.generate().text
20
+ return user_agent
82
21
 
83
- Parameters:
84
- user_agent (str): User agent of the browser.
85
-
86
- Returns:
87
- str: Device model.
88
- """
89
- if 'iPhone' in user_agent:
90
- return '"iPhone"'
91
- elif 'iPad' in user_agent:
92
- return '"iPad"'
93
- elif 'Android' in user_agent:
94
- return '"Android"'
95
- elif 'Windows' in user_agent:
96
- return '"PC"'
97
- elif 'Mac OS X' in user_agent:
98
- return '"Mac"'
99
- elif 'Linux' in user_agent:
100
- return '"Linux"'
101
- return '"Unknown"'
102
22
 
103
23
  def random_headers(referer: str = None):
104
24
  """
@@ -107,26 +27,10 @@ def random_headers(referer: str = None):
107
27
  Returns:
108
28
  dict: Generated HTTP headers.
109
29
  """
110
- user_agent = ua.random
111
- versions = extract_versions(user_agent)
112
- platform = get_platform(user_agent)
113
- model = get_model(user_agent)
114
- is_mobile = 'Mobi' in user_agent or 'Android' in user_agent
115
-
116
- # Generate sec-ch-ua string based on the browser
117
- if 'Chrome' in user_agent or 'CriOS' in user_agent:
118
- sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Google Chrome";v="{versions[0]}"'
119
- elif 'Edg' in user_agent or 'EdgiOS' in user_agent:
120
- sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Chromium";v="{versions[0]}", "Microsoft Edge";v="{versions[0]}"'
121
- elif 'Firefox' in user_agent:
122
- sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Firefox";v="{versions[0]}"'
123
- elif 'Safari' in user_agent:
124
- sec_ch_ua = f'" Not;A Brand";v="{versions[0]}", "Safari";v="{versions[0]}"'
125
- else:
126
- sec_ch_ua = f'" Not;A Brand";v="{versions[0]}"'
30
+ ua = ua_generator.generate()
127
31
 
128
32
  headers = {
129
- 'User-Agent': user_agent,
33
+ 'User-Agent': ua.text,
130
34
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
131
35
  'Accept-Language': random.choice(['en-US', 'en-GB', 'fr-FR', 'es-ES', 'de-DE']),
132
36
  'Accept-Encoding': 'gzip, deflate, br',
@@ -136,25 +40,10 @@ def random_headers(referer: str = None):
136
40
  'Sec-Fetch-Mode': 'navigate',
137
41
  'Sec-Fetch-Site': 'none',
138
42
  'Sec-Fetch-User': '?1',
139
- 'sec-ch-ua-mobile': '?1' if is_mobile else '?0',
140
- 'sec-ch-ua-platform': platform,
141
- 'sec-ch-ua': sec_ch_ua,
142
- 'sec-ch-ua-model': model
143
43
  }
144
44
 
145
45
  if referer:
146
46
  headers['Origin'] = referer
147
47
  headers['Referer'] = referer
148
48
 
149
- return headers
150
-
151
- def get_headers() -> str:
152
- """
153
- Generate a random user agent to use in HTTP requests.
154
-
155
- Returns:
156
- - str: A random user agent string.
157
- """
158
-
159
- # Get a random user agent string from the user agent rotator
160
- return str(ua.chrome)
49
+ return headers
@@ -13,6 +13,7 @@ import subprocess
13
13
  import contextlib
14
14
  import urllib.request
15
15
  import importlib.metadata
16
+ from pathlib import Path
16
17
 
17
18
 
18
19
  # External library
@@ -67,7 +68,7 @@ class OsManager:
67
68
 
68
69
  # Convert Windows separators to Unix
69
70
  normalized = path.replace('\\', '/')
70
-
71
+
71
72
  # Ensure absolute paths start with /
72
73
  if normalized.startswith('/'):
73
74
  return os.path.normpath(normalized)
@@ -82,17 +83,17 @@ class OsManager:
82
83
  # Decode and sanitize
83
84
  decoded = unidecode(filename)
84
85
  sanitized = sanitize_filename(decoded)
85
-
86
+
86
87
  # Split name and extension
87
88
  name, ext = os.path.splitext(sanitized)
88
-
89
+
89
90
  # Calculate available length for name considering the '...' and extension
90
91
  max_name_length = self.max_length - len('...') - len(ext)
91
-
92
+
92
93
  # Truncate name if it exceeds the max name length
93
94
  if len(name) > max_name_length:
94
95
  name = name[:max_name_length] + '...'
95
-
96
+
96
97
  # Ensure the final file name includes the extension
97
98
  return name + ext
98
99
 
@@ -103,7 +104,7 @@ class OsManager:
103
104
 
104
105
  # Decode unicode characters
105
106
  decoded = unidecode(path)
106
-
107
+
107
108
  # Basic path sanitization
108
109
  sanitized = sanitize_filepath(decoded)
109
110
 
@@ -121,7 +122,7 @@ class OsManager:
121
122
  if part
122
123
  ])
123
124
  return '\\'.join(sanitized_parts)
124
-
125
+
125
126
  # Handle drive letters
126
127
  elif len(path) >= 2 and path[1] == ':':
127
128
  drive = path[:2]
@@ -132,7 +133,7 @@ class OsManager:
132
133
  if part
133
134
  ]
134
135
  return '\\'.join(path_parts)
135
-
136
+
136
137
  # Regular path
137
138
  else:
138
139
  parts = path.replace('/', '\\').split('\\')
@@ -146,21 +147,21 @@ class OsManager:
146
147
  for part in parts
147
148
  if part
148
149
  ]
149
-
150
+
150
151
  result = '/'.join(sanitized_parts)
151
152
  if is_absolute:
152
153
  result = '/' + result
153
-
154
+
154
155
  return result
155
-
156
+
156
157
  def create_path(self, path: str, mode: int = 0o755) -> bool:
157
158
  """
158
159
  Create directory path with specified permissions.
159
-
160
+
160
161
  Args:
161
162
  path (str): Path to create.
162
163
  mode (int, optional): Directory permissions. Defaults to 0o755.
163
-
164
+
164
165
  Returns:
165
166
  bool: True if path created successfully, False otherwise.
166
167
  """
@@ -168,7 +169,7 @@ class OsManager:
168
169
  sanitized_path = self.get_sanitize_path(path)
169
170
  os.makedirs(sanitized_path, mode=mode, exist_ok=True)
170
171
  return True
171
-
172
+
172
173
  except Exception as e:
173
174
  logging.error(f"Path creation error: {e}")
174
175
  return False
@@ -176,21 +177,21 @@ class OsManager:
176
177
  def remove_folder(self, folder_path: str) -> bool:
177
178
  """
178
179
  Safely remove a folder.
179
-
180
+
180
181
  Args:
181
182
  folder_path (str): Path of directory to remove.
182
-
183
+
183
184
  Returns:
184
185
  bool: Removal status.
185
186
  """
186
187
  try:
187
188
  shutil.rmtree(folder_path)
188
189
  return True
189
-
190
+
190
191
  except OSError as e:
191
192
  logging.error(f"Folder removal error: {e}")
192
193
  return False
193
-
194
+
194
195
  def remove_files_except_one(self, folder_path: str, keep_file: str) -> None:
195
196
  """
196
197
  Delete all files in a folder except for one specified file.
@@ -201,21 +202,27 @@ class OsManager:
201
202
  """
202
203
 
203
204
  try:
204
- # List all files in the folder
205
- files_in_folder = os.listdir(folder_path)
205
+ # First, try to make all files writable
206
+ for root, dirs, files in os.walk(self.temp_dir):
207
+ for dir_name in dirs:
208
+ dir_path = os.path.join(root, dir_name)
209
+ os.chmod(dir_path, 0o755) # rwxr-xr-x
210
+ for file_name in files:
211
+ file_path = os.path.join(root, file_name)
212
+ os.chmod(file_path, 0o644) # rw-r--r--
206
213
 
207
- # Iterate over each file in the folder
208
- for file_name in files_in_folder:
209
- file_path = os.path.join(folder_path, file_name)
214
+ # Then remove the directory tree
215
+ shutil.rmtree(self.temp_dir, ignore_errors=True)
216
+
217
+ # If directory still exists after rmtree, try force remove
218
+ if os.path.exists(self.temp_dir):
219
+ import subprocess
220
+ subprocess.run(['rm', '-rf', self.temp_dir], check=True)
210
221
 
211
- # Check if the file is not the one to keep and is a regular file
212
- if file_name != keep_file and os.path.isfile(file_path):
213
- os.remove(file_path) # Delete the file
214
-
215
222
  except Exception as e:
216
- logging.error(f"An error occurred: {e}")
217
- raise
218
-
223
+ logging.error(f"Failed to cleanup temporary directory: {str(e)}")
224
+ pass
225
+
219
226
  def check_file(self, file_path: str) -> bool:
220
227
  """
221
228
  Check if a file exists at the given file path.
@@ -229,7 +236,7 @@ class OsManager:
229
236
  try:
230
237
  logging.info(f"Check if file exists: {file_path}")
231
238
  return os.path.exists(file_path)
232
-
239
+
233
240
  except Exception as e:
234
241
  logging.error(f"An error occurred while checking file existence: {e}")
235
242
  return False
@@ -280,12 +287,12 @@ class InternManager():
280
287
  def check_internet():
281
288
  while True:
282
289
  try:
283
- httpx.get("https://www.google.com", timeout=15)
290
+ httpx.get("https://www.google.com", timeout=5)
284
291
  break
285
292
 
286
- except urllib.error.URLError:
293
+ except Exception as e:
287
294
  console.log("[bold red]Internet is not available. Waiting...[/bold red]")
288
- time.sleep(5)
295
+ time.sleep(2)
289
296
 
290
297
 
291
298
  class OsSummary:
@@ -299,7 +306,7 @@ class OsSummary:
299
306
  """Get the binary directory based on OS."""
300
307
  system = platform.system().lower()
301
308
  home = os.path.expanduser('~')
302
-
309
+
303
310
  if system == 'windows':
304
311
  return os.path.join(os.path.splitdrive(home)[0] + os.path.sep, 'binary')
305
312
  elif system == 'darwin':
@@ -315,41 +322,41 @@ class OsSummary:
315
322
  try:
316
323
  result = subprocess.check_output(command, text=True).strip()
317
324
  return result.split('\n')[0] if result else None
318
-
325
+
319
326
  except subprocess.CalledProcessError:
320
327
  return None
321
328
 
322
329
  def get_library_version(self, lib_name: str):
323
330
  """
324
331
  Retrieve the version of a Python library.
325
-
332
+
326
333
  Args:
327
334
  lib_name (str): The name of the Python library.
328
-
335
+
329
336
  Returns:
330
337
  str: The library name followed by its version, or `-not installed` if not found.
331
338
  """
332
339
  try:
333
340
  version = importlib.metadata.version(lib_name)
334
341
  return f"{lib_name}-{version}"
335
-
342
+
336
343
  except importlib.metadata.PackageNotFoundError:
337
344
  return f"{lib_name}-not installed"
338
345
 
339
346
  def download_requirements(self, url: str, filename: str):
340
347
  """
341
348
  Download the requirements.txt file from the specified URL if not found locally using requests.
342
-
349
+
343
350
  Args:
344
351
  url (str): The URL to download the requirements file from.
345
352
  filename (str): The local filename to save the requirements file as.
346
353
  """
347
354
  try:
348
355
  import requests
349
-
356
+
350
357
  logging.info(f"{filename} not found locally. Downloading from {url}...")
351
358
  response = requests.get(url)
352
-
359
+
353
360
  if response.status_code == 200:
354
361
  with open(filename, 'wb') as f:
355
362
  f.write(response.content)
@@ -357,7 +364,7 @@ class OsSummary:
357
364
  else:
358
365
  logging.error(f"Failed to download {filename}. HTTP Status code: {response.status_code}")
359
366
  sys.exit(0)
360
-
367
+
361
368
  except Exception as e:
362
369
  logging.error(f"Failed to download {filename}: {e}")
363
370
  sys.exit(0)
@@ -373,7 +380,7 @@ class OsSummary:
373
380
  console.print(f"Installing {lib_name}...", style="bold yellow")
374
381
  subprocess.check_call([sys.executable, "-m", "pip", "install", lib_name])
375
382
  console.print(f"{lib_name} installed successfully!", style="bold green")
376
-
383
+
377
384
  except subprocess.CalledProcessError as e:
378
385
  console.print(f"Failed to install {lib_name}: {e}", style="bold red")
379
386
  sys.exit(1)
@@ -400,7 +407,7 @@ class OsSummary:
400
407
  arch = platform.machine()
401
408
  os_info = platform.platform()
402
409
  glibc_version = 'glibc ' + '.'.join(map(str, platform.libc_ver()[1]))
403
-
410
+
404
411
  console.print(f"[cyan]Python[white]: [bold red]{python_version} ({python_implementation} {arch}) - {os_info} ({glibc_version})[/bold red]")
405
412
  logging.info(f"Python: {python_version} ({python_implementation} {arch}) - {os_info} ({glibc_version})")
406
413
 
@@ -408,10 +415,10 @@ class OsSummary:
408
415
  binary_dir = self.get_binary_directory()
409
416
  system = platform.system().lower()
410
417
  arch = platform.machine().lower()
411
-
418
+
412
419
  # Map architecture names
413
420
  arch_map = {
414
- 'amd64': 'x64',
421
+ 'amd64': 'x64',
415
422
  'x86_64': 'x64',
416
423
  'x64': 'x64',
417
424
  'arm64': 'arm64',
@@ -424,15 +431,15 @@ class OsSummary:
424
431
 
425
432
  # Check binary directory
426
433
  if os.path.exists(binary_dir):
427
-
434
+
428
435
  # Search for any file containing 'ffmpeg' and the architecture
429
436
  ffmpeg_files = glob.glob(os.path.join(binary_dir, f'*ffmpeg*{arch}*'))
430
437
  ffprobe_files = glob.glob(os.path.join(binary_dir, f'*ffprobe*{arch}*'))
431
-
438
+
432
439
  if ffmpeg_files and ffprobe_files:
433
440
  self.ffmpeg_path = ffmpeg_files[0]
434
441
  self.ffprobe_path = ffprobe_files[0]
435
-
442
+
436
443
  # Set executable permissions if needed
437
444
  if system != 'windows':
438
445
  os.chmod(self.ffmpeg_path, 0o755)
@@ -451,15 +458,17 @@ class OsSummary:
451
458
  # Handle requirements.txt
452
459
  if not getattr(sys, 'frozen', False):
453
460
  requirements_file = 'requirements.txt'
454
-
461
+
462
+ requirements_file = Path(__file__).parent.parent.parent / requirements_file
463
+
455
464
  if not os.path.exists(requirements_file):
456
465
  self.download_requirements(
457
466
  'https://raw.githubusercontent.com/Arrowar/StreamingCommunity/refs/heads/main/requirements.txt',
458
467
  requirements_file
459
468
  )
460
-
469
+
461
470
  optional_libraries = [line.strip().split("=")[0] for line in open(requirements_file, 'r', encoding='utf-8-sig')]
462
-
471
+
463
472
  for lib in optional_libraries:
464
473
  installed_version = self.get_library_version(lib.split("<")[0])
465
474
  if 'not installed' in installed_version:
@@ -468,7 +477,7 @@ class OsSummary:
468
477
  self.install_library(lib)
469
478
  else:
470
479
  logging.info(f"Library: {installed_version}")
471
-
480
+
472
481
  #console.print(f"[cyan]Libraries[white]: [bold red]{', '.join([self.get_library_version(lib) for lib in optional_libraries])}[/bold red]\n")
473
482
  logging.info(f"Libraries: {', '.join([self.get_library_version(lib) for lib in optional_libraries])}")
474
483
 
@@ -495,6 +504,6 @@ def compute_sha1_hash(input_string: str) -> str:
495
504
  """
496
505
  # Compute the SHA-1 hash
497
506
  hashed_string = hashlib.sha1(input_string.encode()).hexdigest()
498
-
507
+
499
508
  # Return the hashed string
500
509
  return hashed_string