Open-AutoTools 0.0.3rc4__py3-none-any.whl → 0.0.3rc5__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.
@@ -1,15 +1,17 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Open-AutoTools
3
- Version: 0.0.3rc4
3
+ Version: 0.0.3rc5
4
4
  Summary: A suite of automated tools accessible via CLI with a simple `autotools` command
5
5
  Home-page: https://github.com/BabylooPro/Open-AutoTools
6
6
  Author: BabylooPro
7
7
  Author-email: maxremy.dev@gmail.com
8
8
  Project-URL: Bug Tracker, https://github.com/BabylooPro/Open-AutoTools/issues
9
- Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
10
12
  Classifier: License :: OSI Approved :: MIT License
11
13
  Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.6
14
+ Requires-Python: >=3.10
13
15
  Description-Content-Type: text/markdown
14
16
  License-File: LICENSE
15
17
  Requires-Dist: Brotli==1.1.0
@@ -54,6 +56,9 @@ Requires-Dist: ffmpeg-python>=0.2.0
54
56
  Provides-Extra: test
55
57
  Requires-Dist: pytest>=7.4.0; extra == "test"
56
58
  Requires-Dist: pytest-cov>=4.1.0; extra == "test"
59
+ Requires-Dist: pytest-sugar>=1.0.0; extra == "test"
60
+ Requires-Dist: pytest-xdist>=3.5.0; extra == "test"
61
+ Requires-Dist: pytest-timeout>=2.2.0; extra == "test"
57
62
  Dynamic: author
58
63
  Dynamic: author-email
59
64
  Dynamic: classifier
@@ -109,6 +114,10 @@ pip install -r requirements.txt
109
114
 
110
115
  # For development, install in editable mode
111
116
  pip install -e .
117
+
118
+ # INFO: if you want to run tests and some errors occur before see test executable
119
+ # install test dependencies directly (optional)
120
+ pip install -e ".[test]"
112
121
  ```
113
122
 
114
123
  ## Key Features
@@ -8,7 +8,7 @@ autotools/autocaps/tests/test_autocaps_core.py,sha256=fzpci_sK7L1fSf_IJ1paJ__bmn
8
8
  autotools/autocaps/tests/test_autocaps_integration.py,sha256=Qe2hzVEvzf0-INp14oTTrHi0RiRDCE2fxo9abVNcd_E,1435
9
9
  autotools/autodownload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
10
  autotools/autodownload/commands.py,sha256=WBG4o5716zQ63t23k-qJLNv41L58RnL2XTvNl_TsK-w,1442
11
- autotools/autodownload/core.py,sha256=hM7RzNhUlhWFjVhMI3e3PSnpzQN21wYUZmgM9mmLsyg,14429
11
+ autotools/autodownload/core.py,sha256=h_PoNmGjmKS8owe8rR0Lkm5FsSMPKB9AQ6RjMLBEqtc,16919
12
12
  autotools/autoip/__init__.py,sha256=T_5hz9G4reFPXDucdzRoMFPYlAKwTPt9TejOpkRPgn0,23
13
13
  autotools/autoip/commands.py,sha256=c4s22yb7aharRAwOmD37Kgbj6rm05XNBtCVyxU7rc7M,1425
14
14
  autotools/autoip/core.py,sha256=Q3dzLstZQruwYkSbCSlKQNmKVGCyNpo1DGst5VFtHLU,10123
@@ -31,14 +31,14 @@ autotools/autotranslate/__init__.py,sha256=6BxuZqhyQhfsZ5x7DkB1BAEpC08GT_5l5bl0A
31
31
  autotools/autotranslate/commands.py,sha256=6M1D27mrk41uWTLgwGeO-HTUtq0iiHFrptIb1BM7A-s,1794
32
32
  autotools/autotranslate/core.py,sha256=H2f90IWr_jNGiJD3XAv-20i5sRGM-VDYWrYt65EDEkI,1836
33
33
  autotools/test/__init__.py,sha256=_xWAfk2kKSboEOW9fVUlmNfVHAx-qGYWFb8dxCz8g1w,48
34
- autotools/test/commands.py,sha256=ZDSl-BCCeH1CsGjpQr_b6x3cMEGK8dSgNdPDqXgSxpw,4846
34
+ autotools/test/commands.py,sha256=0IMW_tnbVuyVIOOhWwjJ7SclD8l0m0JobTNc6QHx0-s,4643
35
35
  autotools/utils/__init__.py,sha256=2uAirI6ZbOwSFPSg5wuEjA0gMWf1XBJ4yP_WcGeND7M,183
36
36
  autotools/utils/loading.py,sha256=cRh8rvNLT4B2aVgWq7flg8bNpnp1XlNBV3_cvxjfm8E,439
37
37
  autotools/utils/updates.py,sha256=ZGS8pAVxvy5ORuey_zrBWdA0_hKNmEcwzJ-6c22x4Yo,1140
38
38
  autotools/utils/version.py,sha256=sHwkZ8MNTKQdTntV1B-8QInbMnMtR7Xr3DAY5-wf5-0,3027
39
- Open_AutoTools-0.0.3rc4.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
40
- Open_AutoTools-0.0.3rc4.dist-info/METADATA,sha256=QspEAu8ipTWu606dWGmKdy1FYRxBTOp5nNH7JRZEemA,10086
41
- Open_AutoTools-0.0.3rc4.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
42
- Open_AutoTools-0.0.3rc4.dist-info/entry_points.txt,sha256=QLIsUk6vHo0wAYDk1K74kIuYunJMwWe2xbwQhJXLoKo,312
43
- Open_AutoTools-0.0.3rc4.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
44
- Open_AutoTools-0.0.3rc4.dist-info/RECORD,,
39
+ Open_AutoTools-0.0.3rc5.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
40
+ Open_AutoTools-0.0.3rc5.dist-info/METADATA,sha256=J92dDLDCnxrBMvTwP6XstY3ps97jSK_QlD0bQOlQLYk,10506
41
+ Open_AutoTools-0.0.3rc5.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
42
+ Open_AutoTools-0.0.3rc5.dist-info/entry_points.txt,sha256=QLIsUk6vHo0wAYDk1K74kIuYunJMwWe2xbwQhJXLoKo,312
43
+ Open_AutoTools-0.0.3rc5.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
44
+ Open_AutoTools-0.0.3rc5.dist-info/RECORD,,
@@ -129,10 +129,26 @@ def save_consent_status(status):
129
129
  # IF SAVING FAILS, RETURN FALSE TO FORCE NEW CONSENT NEXT TIME
130
130
  return False
131
131
 
132
+ # FUNCTION TO SAFELY PRINT WITH EMOJI FALLBACK
133
+ def safe_print(text):
134
+ """PRINT TEXT WITH EMOJI FALLBACK FOR WINDOWS"""
135
+ try:
136
+ print(text)
137
+ except UnicodeEncodeError:
138
+ # REPLACE EMOJIS WITH ASCII ALTERNATIVES
139
+ text = (text.replace('⚠️', '!')
140
+ .replace('🔍', '*')
141
+ .replace('🎥', '>')
142
+ .replace('📋', '+')
143
+ .replace('❌', 'X')
144
+ .replace('✅', 'V')
145
+ .replace('↓', 'v'))
146
+ print(text)
147
+
132
148
  # FUNCTION TO GET USER CONSENT WITH INTERACTIVE PROMPT
133
149
  def get_user_consent():
134
150
  """GET USER CONSENT WITH INTERACTIVE PROMPT"""
135
- print("\n⚠️ Important Notice:")
151
+ safe_print("\n! Important Notice:")
136
152
  print("This tool will:")
137
153
  print("1. Download video content from YouTube")
138
154
  print("2. Save files to your local machine")
@@ -178,12 +194,12 @@ def download_youtube_video(url, format='mp4', quality='best'):
178
194
  """DOWNLOAD VIDEO WITH CONSENT CHECK"""
179
195
  # VALIDATE URL FIRST
180
196
  if not validate_youtube_url(url):
181
- print("\n❌ Invalid YouTube URL")
197
+ safe_print("\nX Invalid YouTube URL")
182
198
  return False
183
199
 
184
200
  # CHECK FOR SAVED CONSENT FIRST AND GET NEW CONSENT IF NEEDED
185
201
  if not load_consent_status() and not get_user_consent():
186
- print("\n❌ Download cancelled by user")
202
+ safe_print("\nX Download cancelled by user")
187
203
  return False
188
204
 
189
205
  # FIRST CHECK VIDEO INFO AND EXISTENCE
@@ -199,7 +215,7 @@ def download_youtube_video(url, format='mp4', quality='best'):
199
215
  info = ydl.extract_info(url, download=False)
200
216
  formats = info.get('formats', [])
201
217
  if not formats:
202
- print("\n❌ No formats available for this video")
218
+ safe_print("\nX No formats available for this video")
203
219
  return False
204
220
 
205
221
  # FIND BEST AVAILABLE QUALITY
@@ -218,7 +234,7 @@ def download_youtube_video(url, format='mp4', quality='best'):
218
234
  height = best_height
219
235
  # ASK FOR CONFIRMATION IF 4K OR HIGHER (ONLY FOR MP4)
220
236
  if format == 'mp4' and height >= 2160:
221
- print(f"\n⚠️ This video is available in {height}p quality!")
237
+ safe_print(f"\n! This video is available in {height}p quality!")
222
238
  while True:
223
239
  response = input(f"Do you want to download in {height}p quality? (yes/no): ").lower()
224
240
  if response in ['no', 'n']:
@@ -238,7 +254,7 @@ def download_youtube_video(url, format='mp4', quality='best'):
238
254
  # CHECK IF FILE EXISTS AND GET REPLACEMENT CONSENT
239
255
  force_download = check_existing_video(info, format)
240
256
  if not force_download:
241
- print("\n❌ Download cancelled - file already exists")
257
+ safe_print("\nX Download cancelled - file already exists")
242
258
  return False
243
259
 
244
260
  # OPEN DOWNLOADS FOLDER IF STARTING NEW DOWNLOAD OR REPLACING
@@ -246,7 +262,7 @@ def download_youtube_video(url, format='mp4', quality='best'):
246
262
  open_download_folder(download_dir)
247
263
 
248
264
  except Exception as e:
249
- print(f"\n❌ Error checking video: {str(e)}")
265
+ safe_print(f"\nX Error checking video: {str(e)}")
250
266
  return False
251
267
 
252
268
  loading = LoadingAnimation()
@@ -254,17 +270,22 @@ def download_youtube_video(url, format='mp4', quality='best'):
254
270
  # START LOADING FOR DOWNLOAD PROCESS
255
271
  with loading:
256
272
  loading._spinner.start()
257
- print("\n🔍 Starting download...")
273
+ safe_print("\n* Starting download...")
258
274
 
259
- print(f"\n🎥 Downloading video from: {url}")
275
+ safe_print(f"\n> Downloading video from: {url}")
260
276
  if format == 'mp3':
261
- print(f"📋 Format: {format}\n")
277
+ safe_print(f"+ Format: {format}\n")
262
278
  else:
263
- print(f"📋 Format: {format}, Quality: {height}p\n")
279
+ safe_print(f"+ Format: {format}, Quality: {height}p\n")
264
280
 
265
281
  # YT-DLP PERMISSION OPTIONS FOR DOWNLOADING YOUTUBE VIDEOS
266
282
  ydl_opts = {
267
- 'format': f'bestvideo[height={height}][ext=mp4]+bestaudio[ext=m4a]/bestvideo[height<={height}][ext=mp4]+bestaudio[ext=m4a]/best[height<={height}][ext=mp4]/best[ext=mp4]/best' if format == 'mp4' else 'bestaudio/best',
283
+ 'format': (
284
+ f'bestvideo[height<={height}][ext=mp4]+bestaudio[ext=m4a]/' # TRY EXACT HEIGHT MATCH FIRST
285
+ f'bestvideo[height<={height}][ext=webm]+bestaudio[ext=webm]/' # TRY WEBM AS FALLBACK
286
+ f'best[height<={height}]/' # TRY COMBINED FORMATS
287
+ 'best' # FALLBACK TO BEST AVAILABLE
288
+ ) if format == 'mp4' else 'bestaudio/best',
268
289
  'postprocessors': [{
269
290
  'key': 'FFmpegExtractAudio',
270
291
  'preferredcodec': 'mp3',
@@ -276,13 +297,13 @@ def download_youtube_video(url, format='mp4', quality='best'):
276
297
  'progress_hooks': [lambda d: update_progress(d)],
277
298
  'extractor_args': {
278
299
  'youtube': {
279
- 'player_client': ['web', 'android'], # USE WEB CLIENT FIRST
300
+ 'player_client': ['android', 'web'], # USE ANDROID FIRST AND WEB PLAYER CLIENTS IF ANDROID FAILS
280
301
  'formats': ['missing_pot'], # ALLOW FORMATS WITHOUT PO TOKEN
281
302
  'player_skip': ['configs', 'webpage'] # SKIP UNNECESSARY CONFIGS
282
303
  }
283
304
  },
284
305
  'http_headers': {
285
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
306
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 12) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36',
286
307
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
287
308
  'Accept-Language': 'en-us,en;q=0.5',
288
309
  'Sec-Fetch-Mode': 'navigate'
@@ -290,15 +311,42 @@ def download_youtube_video(url, format='mp4', quality='best'):
290
311
  'outtmpl': str(download_dir / '%(title)s.%(ext)s'), # SET OUTPUT TEMPLATE
291
312
  'overwrites': True, # FORCE OVERWRITE IF USER CONSENTED
292
313
  'no_check_certificates': True, # SKIP CERTIFICATE VALIDATION
293
- 'cookiesfrombrowser': ('chrome',), # USE CHROME COOKIES IF AVAILABLE
314
+ 'ignoreerrors': False, # CATCH ERRORS PROPERLY
315
+ 'cookiesfrombrowser': None, # DISABLE COOKIE FILE
316
+ 'cookiefile': None, # DISABLE COOKIE FILE
294
317
  }
295
318
 
296
319
  try:
297
320
  # THEN DOWNLOAD
298
321
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
299
- ydl.download([url])
300
- print("\n✅ Download completed successfully!")
301
- return True
322
+ try:
323
+ ydl.download([url])
324
+ safe_print("\nV Download completed successfully!")
325
+ return True
326
+ except Exception as e:
327
+ if "HTTP Error 403" in str(e):
328
+ safe_print("\n! Access denied for requested quality. Trying lower quality...")
329
+ # TRY DOWNLOADING WITH LOWER QUALITY
330
+ if height > 720:
331
+ new_height = min(height - 360, 1080) # STEP DOWN QUALITY
332
+ safe_print(f"v Falling back to {new_height}p")
333
+ ydl_opts['format'] = (
334
+ f'bestvideo[height<={new_height}][ext=mp4]+bestaudio[ext=m4a]/'
335
+ f'bestvideo[height<={new_height}][ext=webm]+bestaudio[ext=webm]/'
336
+ f'best[height<={new_height}]/'
337
+ 'best'
338
+ )
339
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl2:
340
+ ydl2.download([url])
341
+ safe_print("\nV Download completed successfully!")
342
+ return True
343
+ else:
344
+ safe_print("\nX Failed to download video at any quality")
345
+ return False
346
+ else:
347
+ raise e
348
+
349
+ # CATCH ANY EXCEPTIONS AND HANDLE THEM
302
350
  except Exception as e:
303
351
  error_msg = str(e)
304
352
  if "Requested format is not available" in error_msg:
@@ -371,3 +419,15 @@ def download_file_with_tqdm(url):
371
419
  open_download_folder(download_dir)
372
420
  except requests.exceptions.RequestException as e:
373
421
  print(f"Error during file download: {e}")
422
+
423
+
424
+ # FUNCTION TO GET BROWSER COOKIES
425
+ def get_browser_cookies():
426
+ """GET BROWSER COOKIES WITH FALLBACK OPTIONS"""
427
+ try:
428
+ return ('chrome',) # TRY CHROME FIRST
429
+ except Exception:
430
+ try:
431
+ return ('firefox',) # TRY FIREFOX IF CHROME FAILS
432
+ except Exception:
433
+ return None # RETURN NONE IF BOTH FAIL
@@ -28,34 +28,32 @@ def test(unit, integration, no_cov, html, module):
28
28
 
29
29
  # BASE COMMAND WITH ENHANCED VERBOSITY
30
30
  cmd = [
31
- 'python', '-m', 'pytest', # PYTHON MODULE AND TEST COMMAND
32
- '--capture=no', # SHOW PRINT STATEMENTS AND CAPTURED OUTPUT
33
- '--full-trace', # SHOW FULL TRACEBACK
34
- '-vv', # VERY VERBOSE OUTPUT
35
- '--durations=0', # SHOW ALL TEST DURATIONS
36
- '--showlocals', # SHOW LOCAL VARIABLES IN TRACEBACKS
37
- '--log-cli-level=DEBUG', # SHOW DEBUG LOGS
38
- '--tb=long', # LONG TRACEBACK STYLE
39
- '-s' # SHORTCUT FOR --capture=no
31
+ sys.executable, # USE SYSTEM PYTHON EXECUTABLE
32
+ '-m', 'pytest', # RUN PYTEST AS MODULE
33
+ '-vv', # VERY VERBOSE OUTPUT
34
+ '--capture=no', # SHOW PRINT STATEMENTS
35
+ '--showlocals', # SHOW LOCAL VARIABLES IN TRACEBACKS
36
+ '--log-cli-level=DEBUG', # SHOW DEBUG LOGS
37
+ '-s', # DISABLE CAPTURE
40
38
  ]
41
39
 
42
40
  # COVERAGE OPTIONS
43
41
  if not no_cov:
44
- cmd.extend(['--cov=autotools'])
45
42
  if html:
46
- cmd.extend(['--cov-report=html'])
43
+ cmd.extend(['--cov-report=html', '--cov=autotools'])
47
44
  else:
48
- cmd.extend(['--cov-report=term-missing'])
45
+ cmd.extend(['--cov-report=term-missing', '--cov=autotools'])
49
46
 
50
47
  # TEST SELECTION
51
- test_path = 'autotools'
52
48
  if module:
49
+ test_path = f'autotools/{module}/tests'
53
50
  if unit and not integration:
54
- cmd.append(f'autotools/{module}/tests/test_{module}_core.py')
51
+ test_path = f'{test_path}/unit'
55
52
  elif integration and not unit:
56
- cmd.append(f'autotools/{module}/tests/test_{module}_integration.py')
57
- else:
58
- cmd.append(f'autotools/{module}/tests')
53
+ test_path = f'{test_path}/integration'
54
+ cmd.append(test_path)
55
+ else:
56
+ cmd.append('autotools')
59
57
 
60
58
  # SHOW COMMAND BEING RUN
61
59
  click.echo(click.style("\nRunning tests with command:", fg='blue', bold=True))