Open-AutoTools 0.0.3rc2__py3-none-any.whl → 0.0.3rc3__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,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: Open-AutoTools
3
- Version: 0.0.3rc2
3
+ Version: 0.0.3rc3
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
@@ -49,6 +49,8 @@ Requires-Dist: setuptools>=40.8.0
49
49
  Requires-Dist: language-tool-python>=2.7.1
50
50
  Requires-Dist: spacy>=3.7.2
51
51
  Requires-Dist: beautifulsoup4>=4.12.0
52
+ Requires-Dist: halo>=0.0.31
53
+ Requires-Dist: ffmpeg-python>=0.2.0
52
54
  Provides-Extra: test
53
55
  Requires-Dist: pytest>=7.4.0; extra == "test"
54
56
  Requires-Dist: pytest-cov>=4.1.0; extra == "test"
@@ -66,7 +68,18 @@ Dynamic: summary
66
68
 
67
69
  # Open-AutoTools
68
70
 
69
- Open-AutoTools is an innovative project developed in Python, specifically designed to offer a suite of automated tools directly accessible via the terminal. This project aims to simplify and automate daily tasks for developers and terminal users. It is designed to be used as a set of CLI commands, making its features directly accessible from the user's terminal.
71
+ [PYPI_BADGE]: https://badge.fury.io/py/Open-AutoTools.svg
72
+ [PYPI_URL]: https://pypi.org/project/Open-AutoTools/
73
+ [PYTHON_BADGE]: https://img.shields.io/badge/Python-3.11-blue.svg
74
+ [PYTHON_URL]: https://www.python.org/downloads/
75
+ [CHANGELOG_BADGE]: https://img.shields.io/badge/CHANGELOG-red.svg
76
+ [CHANGELOG_URL]: CHANGELOG.md
77
+ [TODO_BADGE]: https://img.shields.io/badge/TODO-purple.svg
78
+ [TODO_URL]: TODO.md
79
+
80
+ [![PyPI][PYPI_BADGE]][PYPI_URL] [![Python][PYTHON_BADGE]][PYTHON_URL] [![CHANGELOG][CHANGELOG_BADGE]][CHANGELOG_URL] [![TODO][TODO_BADGE]][TODO_URL]
81
+
82
+ Open-AutoTools is a comprehensive Python CLI toolkit that streamlines everyday developer tasks through a collection of powerful command-line utilities. Each tool is designed to enhance productivity directly from your terminal.
70
83
 
71
84
  https://github.com/BabylooPro/Open-AutoTools/assets/35376790/d57f2b9d-55f8-4368-bb40-c0010eb9d49a
72
85
 
@@ -135,16 +148,14 @@ pip install -e .
135
148
  ```
136
149
  - **Options:**
137
150
  - `--length, -l`: Set password length (default: 12)
138
- - `--no-uppercase`: Exclude uppercase letters
139
- - `--no-numbers`: Exclude numbers
140
- - `--no-special`: Exclude special characters
141
- - `--min-special`: Minimum number of special characters (default: 1)
142
- - `--min-numbers`: Minimum number of numbers (default: 1)
143
- - `--gen-key`: Generate a random encryption key
144
- - `--password-key`: Generate an encryption key from a password
145
- - `--analyze`: Show password strength analysis
146
-
147
- These examples demonstrate how the terminal will display the results after executing each command, providing a straightforward way for users to understand the immediate effects of these commands.
151
+ - `--no-uppercase, -u`: Exclude uppercase letters
152
+ - `--no-numbers, -n`: Exclude numbers
153
+ - `--no-special, -s`: Exclude special characters
154
+ - `--min-special, -m`: Minimum number of special characters (default: 1)
155
+ - `--min-numbers, -d`: Minimum number of numbers (default: 1)
156
+ - `--analyze, -a`: Show password strength analysis
157
+ - `--gen-key, -g`: Generate a random encryption key
158
+ - `--password-key, -p`: Generate an encryption key from password
148
159
 
149
160
  ### AutoTranslate
150
161
 
@@ -172,6 +183,7 @@ These examples demonstrate how the terminal will display the results after execu
172
183
  - `--copy`: Copy translation to clipboard
173
184
  - `--detect`: Show detected source language
174
185
  - `--list-languages`: Show all supported language codes and names
186
+ - `--output, -o`: Save translation to file
175
187
 
176
188
  ### AutoSpell (unreleased)
177
189
 
@@ -180,14 +192,17 @@ These examples demonstrate how the terminal will display the results after execu
180
192
  ```
181
193
  ~ ❯ autospell "Your text with misspellings"
182
194
  ~ ❯ autospell --lang fr "Votre texte avec des fautes"
183
- ~ ❯ autospell --file document.txt
195
+ ~ ❯ autospell --fix "Text to autocorrect"
184
196
  ```
185
197
  - **Options:**
186
- - `--lang`: Language code (default: en)
187
- - `--file`: Input from file
188
- - `--copy`: Copy corrected text to clipboard
189
- - `--suggest`: Show alternative suggestions
190
- - `--interactive`: Interactive correction mode
198
+ - `--lang, -l`: Language code (default: auto)
199
+ - `--fix, -f`: Auto-fix text and copy to clipboard
200
+ - `--copy, -c`: Copy result to clipboard
201
+ - `--list-languages`: Show supported languages
202
+ - `--json, -j`: Output results as JSON
203
+ - `--ignore, -i`: Error types to ignore (spelling/grammar/style/punctuation)
204
+ - `--interactive, -n`: Interactive mode - confirm each correction
205
+ - `--output, -o`: Save corrections to file
191
206
 
192
207
  ### AutoDownload
193
208
 
@@ -205,52 +220,30 @@ These examples demonstrate how the terminal will display the results after execu
205
220
 
206
221
  - **Options:**
207
222
 
208
- - `--format`: Choose output format (mp4 or mp3)
209
- - `--quality`: Select video quality (best, 1440p, 1080p, 720p, 480p, 360p, 240p)
223
+ - `--format, -f`: Choose output format (mp4 or mp3)
224
+ - `--quality, -q`: Select video quality (best, 1440p, 1080p, 720p, 480p, 360p, 240p)
210
225
 
211
226
  - **Features:**
212
227
 
213
228
  - Automatic bot detection bypass
214
- - Browser cookie integration
215
- - Progress tracking
229
+ - Mobile API integration for better reliability
230
+ - Progress tracking with detailed status
216
231
  - Multiple quality options
217
232
  - MP3 audio extraction
218
233
  - Downloads to user's Downloads folder
219
234
  - Supports both YouTube and general file downloads
235
+ - File existence checks with user prompts
220
236
 
221
237
  - **Setup Requirements:**
222
238
 
223
- - Chrome browser installed and configured:
224
-
225
- ```bash
226
- # First time setup:
227
- 1. Open Chrome and sign in to YouTube
228
- 2. Make sure you're logged into your Google account
229
- 3. Accept YouTube's terms of service in browser
230
- ```
231
-
232
- - **Troubleshooting:**
233
-
234
- - If downloads fail with "Sign in to confirm you're not a bot":
235
-
236
- 1. Open YouTube in Chrome
237
- 2. Sign in if not already
238
- 3. Solve any CAPTCHA if prompted
239
- 4. Try download again
240
-
241
- - If you get cookie errors:
242
- 1. Clear Chrome cookies
243
- 2. Sign in to YouTube again
244
- 3. Wait a few minutes before downloading
245
-
239
+ - No special setup required
246
240
  - **Technical Requirements:**
247
- - Chrome browser (for cookie and session handling)
248
- - Active YouTube/Google account
249
241
  - Internet connection
250
242
  - Sufficient storage space
251
243
  - yt-dlp library (automatically installed)
244
+ - FFmpeg (required for format conversion)
252
245
 
253
- > **Note:** The tool uses your Chrome browser's cookies to authenticate with YouTube. This is required to bypass YouTube's bot detection and download restrictions.
246
+ > **Note:** The tool uses YouTube's mobile API for better compatibility and reliability.
254
247
 
255
248
  ### AutoIP
256
249
 
@@ -258,28 +251,9 @@ These examples demonstrate how the terminal will display the results after execu
258
251
  - **Usage:**
259
252
 
260
253
  ```bash
261
- # Display IP addresses
262
254
  ~ ❯ autoip
263
-
264
- # Run speed test
265
255
  ~ ❯ autoip --speed
266
-
267
- # Test connectivity
268
- ~ ❯ autoip --test
269
-
270
- # Show location info
271
256
  ~ ❯ autoip --location
272
-
273
- # Monitor network traffic
274
- ~ ❯ autoip --monitor
275
-
276
- # Check common ports
277
- ~ ❯ autoip --ports
278
-
279
- # Show DNS servers
280
- ~ ❯ autoip --dns
281
-
282
- # Hide IP display and only show tests
283
257
  ~ ❯ autoip --no-ip --test --speed
284
258
  ```
285
259
 
@@ -288,6 +262,7 @@ These examples demonstrate how the terminal will display the results after execu
288
262
  - `--test, -t`: Run connectivity tests to popular services
289
263
  - `--speed, -s`: Run internet speed test
290
264
  - `--monitor, -m`: Monitor real-time network traffic
265
+ - `--interval, -i`: Monitoring interval in seconds
291
266
  - `--ports, -p`: Check status of common ports
292
267
  - `--dns, -d`: Show DNS server configuration
293
268
  - `--location, -l`: Show IP geolocation information
@@ -297,11 +272,27 @@ These examples demonstrate how the terminal will display the results after execu
297
272
  - Local and public IP detection (IPv4 & IPv6)
298
273
  - Internet speed testing
299
274
  - Network connectivity checks
275
+ - Monitoring interval (10 seconds)
300
276
  - Real-time traffic monitoring
301
277
  - Port scanning
302
278
  - DNS server information
303
279
  - IP geolocation
304
280
 
281
+ ### Test Suite (DEVELOPMENT ONLY)
282
+
283
+ - **Description:** Run the test suite for Open-AutoTools
284
+ - **Usage:**
285
+ ```bash
286
+ ~ ❯ autotools test
287
+ ```
288
+ - **Options:**
289
+
290
+ - `--unit, -u`: Run only unit tests
291
+ - `--integration, -i`: Run only integration tests
292
+ - `--no-cov`: Disable coverage report
293
+ - `--html`: Generate HTML coverage report
294
+ - `--module, -m`: Test specific module (e.g., autocaps, autolower)
295
+
305
296
  ## License
306
297
 
307
298
  This project is licensed under the MIT License. For more details, see the [LICENSE](LICENSE) file.
@@ -1,31 +1,44 @@
1
1
  autotools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- autotools/cli.py,sha256=FczekeSEiPjjbfw-tBT2alYbEVaHLVC7skN4QjTjKN4,23432
2
+ autotools/cli.py,sha256=WBFH0NZwUW3QpoB_dOW-Ukpul_klc8PJSptfALewU04,3538
3
3
  autotools/autocaps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ autotools/autocaps/commands.py,sha256=YIoSRTjfwpupbUl5r4P6LH6PXrTBcehf9gZwOOKxv9I,477
4
5
  autotools/autocaps/core.py,sha256=NnOacVp0kMoq__KHWi5UMcApSuq6Iyo5bFxN40dRw7U,253
5
6
  autotools/autocaps/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
6
7
  autotools/autocaps/tests/test_autocaps_core.py,sha256=fzpci_sK7L1fSf_IJ1paJ__bmnHwC9OUOD7ftd3w07c,1672
7
8
  autotools/autocaps/tests/test_autocaps_integration.py,sha256=Qe2hzVEvzf0-INp14oTTrHi0RiRDCE2fxo9abVNcd_E,1435
8
9
  autotools/autodownload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- autotools/autodownload/core.py,sha256=rd-jWYiNduRC9VUfl-jGBe13NhhmjeL07FGqdp_Eii8,8358
10
+ autotools/autodownload/commands.py,sha256=WBG4o5716zQ63t23k-qJLNv41L58RnL2XTvNl_TsK-w,1442
11
+ autotools/autodownload/core.py,sha256=z9SBQx0SUZbAcCRmVA4TWYI7BPPco79JpDWqi5X1FfU,12181
10
12
  autotools/autoip/__init__.py,sha256=T_5hz9G4reFPXDucdzRoMFPYlAKwTPt9TejOpkRPgn0,23
13
+ autotools/autoip/commands.py,sha256=c4s22yb7aharRAwOmD37Kgbj6rm05XNBtCVyxU7rc7M,1425
11
14
  autotools/autoip/core.py,sha256=Q3dzLstZQruwYkSbCSlKQNmKVGCyNpo1DGst5VFtHLU,10123
12
15
  autotools/autoip/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
13
16
  autotools/autoip/tests/test_autoip_core.py,sha256=Q8865qqhopcGBzS4mIlDlEzxu-mTIbZxpgJyzIyuQXc,2153
14
17
  autotools/autoip/tests/test_autoip_integration.py,sha256=-vS2gnY8ZfT-tfY2FRbUtTzY0lcIBtVZHbPbWsKyueo,2746
15
18
  autotools/autolower/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
+ autotools/autolower/commands.py,sha256=Od_5hWGjFr8CLApmtMnoM5QhNRe1ttWy2qLi7S9hTts,480
16
20
  autotools/autolower/core.py,sha256=vjM2ognA3tDCbv10a9vta9WPuAiqTPjOXZ1JHL_b-nk,260
17
21
  autotools/autolower/tests/__init__.py,sha256=CckydfM7SZdXtW3pLgAeRdrC60sovNx_v59nyFvslFo,23
18
22
  autotools/autolower/tests/test_autolower_core.py,sha256=ChkS3qZgXz75iLfC9EXVH_kMd-sjaxpRKFjaxKoBnxo,1694
19
23
  autotools/autolower/tests/test_autolower_integration.py,sha256=M2yN1Ym7kGulys62-IwKq-uWn7CFvI3sCnoo-e3CTaA,1446
20
24
  autotools/autopassword/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
21
- autotools/autopassword/core.py,sha256=GQrd-QGWpgxuq6Nf28URcTZRku8Gji1NfpbecXAsIF0,3146
25
+ autotools/autopassword/commands.py,sha256=lyNM833UXCcafqnBa0ojxpdgPPEUadO-t2HrAP4UIaM,3137
26
+ autotools/autopassword/core.py,sha256=3aeXJaF7yYvHAH0VkVxGxaKawxgZDlSoI5lUcDCu264,3193
22
27
  autotools/autospell/__init__.py,sha256=jkpkiE7pksBgllXKfkNpYYvqtlm8vN0h4kXnQOqcb_U,60
28
+ autotools/autospell/commands.py,sha256=SG_kP9xAOj7H2jnXXq7auwRALt5ml6r0oz8dKnE5z04,5956
23
29
  autotools/autospell/core.py,sha256=WPvi9Xs6uF3dte_g2I9oHfTjCV1-NasrJElLP9bbC8U,8103
24
30
  autotools/autotranslate/__init__.py,sha256=6BxuZqhyQhfsZ5x7DkB1BAEpC08GT_5l5bl0AY_eLpU,64
31
+ autotools/autotranslate/commands.py,sha256=6M1D27mrk41uWTLgwGeO-HTUtq0iiHFrptIb1BM7A-s,1794
25
32
  autotools/autotranslate/core.py,sha256=H2f90IWr_jNGiJD3XAv-20i5sRGM-VDYWrYt65EDEkI,1836
26
- Open_AutoTools-0.0.3rc2.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
27
- Open_AutoTools-0.0.3rc2.dist-info/METADATA,sha256=UdpA1NEK1ilsER2aLOBwTlAUdqsZlSJ6NYcjif314n0,9120
28
- Open_AutoTools-0.0.3rc2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
29
- Open_AutoTools-0.0.3rc2.dist-info/entry_points.txt,sha256=QLIsUk6vHo0wAYDk1K74kIuYunJMwWe2xbwQhJXLoKo,312
30
- Open_AutoTools-0.0.3rc2.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
31
- Open_AutoTools-0.0.3rc2.dist-info/RECORD,,
33
+ autotools/test/__init__.py,sha256=_xWAfk2kKSboEOW9fVUlmNfVHAx-qGYWFb8dxCz8g1w,48
34
+ autotools/test/commands.py,sha256=ZDSl-BCCeH1CsGjpQr_b6x3cMEGK8dSgNdPDqXgSxpw,4846
35
+ autotools/utils/__init__.py,sha256=2uAirI6ZbOwSFPSg5wuEjA0gMWf1XBJ4yP_WcGeND7M,183
36
+ autotools/utils/loading.py,sha256=cRh8rvNLT4B2aVgWq7flg8bNpnp1XlNBV3_cvxjfm8E,439
37
+ autotools/utils/updates.py,sha256=ZGS8pAVxvy5ORuey_zrBWdA0_hKNmEcwzJ-6c22x4Yo,1140
38
+ autotools/utils/version.py,sha256=sHwkZ8MNTKQdTntV1B-8QInbMnMtR7Xr3DAY5-wf5-0,3027
39
+ Open_AutoTools-0.0.3rc3.dist-info/LICENSE,sha256=SpbSRxNWos2l0-geleCa6d0L9G_bOsZRkY4rB9OduJ0,1069
40
+ Open_AutoTools-0.0.3rc3.dist-info/METADATA,sha256=ymNaYp1DaA28ufYkUDE3y3EMi8yXpEIrMAwqfukKGFU,9280
41
+ Open_AutoTools-0.0.3rc3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
42
+ Open_AutoTools-0.0.3rc3.dist-info/entry_points.txt,sha256=QLIsUk6vHo0wAYDk1K74kIuYunJMwWe2xbwQhJXLoKo,312
43
+ Open_AutoTools-0.0.3rc3.dist-info/top_level.txt,sha256=x5ZRvdQw7DQnVmR0YDqVSAuuS94KTHDmk6uIeW7YOPw,10
44
+ Open_AutoTools-0.0.3rc3.dist-info/RECORD,,
@@ -0,0 +1,17 @@
1
+ import click
2
+ from .core import autocaps_transform
3
+ from ..utils.loading import LoadingAnimation
4
+ from ..utils.updates import check_for_updates
5
+
6
+ @click.command()
7
+ @click.argument('text', nargs=-1)
8
+ def autocaps(text):
9
+ """Convert text to UPPERCASE."""
10
+ with LoadingAnimation():
11
+ result = autocaps_transform(" ".join(text))
12
+ click.echo(result)
13
+
14
+ # UPDATE CHECK AT THE END
15
+ update_msg = check_for_updates()
16
+ if update_msg:
17
+ click.echo(update_msg)
@@ -0,0 +1,38 @@
1
+ import click
2
+ import sys
3
+ from .core import download_youtube_video, download_file, validate_youtube_url
4
+ from ..utils.loading import LoadingAnimation
5
+ from ..utils.updates import check_for_updates
6
+
7
+ @click.command()
8
+ @click.argument('url')
9
+ @click.option('--format', '-f', type=click.Choice(['mp4', 'mp3'], case_sensitive=False),
10
+ default='mp4', help='Output file format (mp4 for video, mp3 for audio)')
11
+ @click.option('--quality', '-q', type=click.Choice(['best', '2160p', '1440p', '1080p', '720p', '480p', '360p', '240p'],
12
+ case_sensitive=False), default='best', help='Video quality (mp4 only)')
13
+ def autodownload(url, format, quality):
14
+ """Download videos from YouTube or files from any URL.
15
+
16
+ Supports YouTube video download with quality selection and format conversion (mp4/mp3).
17
+
18
+ For non-YouTube URLs, downloads the file directly."""
19
+
20
+ loading = LoadingAnimation()
21
+
22
+ if "youtube.com" in url or "youtu.be" in url:
23
+ with loading:
24
+ if not validate_youtube_url(url):
25
+ click.echo("Invalid YouTube URL", err=True)
26
+ sys.exit(1)
27
+
28
+ if not download_youtube_video(url, format, quality):
29
+ sys.exit(1)
30
+ else:
31
+ with loading:
32
+ if not download_file(url):
33
+ sys.exit(1)
34
+
35
+ # UPDATE CHECK AT THE END
36
+ update_msg = check_for_updates()
37
+ if update_msg:
38
+ click.echo(update_msg)
@@ -7,6 +7,8 @@ import yt_dlp
7
7
  import platform
8
8
  import subprocess
9
9
  import json
10
+ from rich.progress import Progress
11
+ from ..utils.loading import LoadingAnimation
10
12
 
11
13
 
12
14
  # FUNCTION TO GET DEFAULT DOWNLOAD DIRECTORY
@@ -44,17 +46,23 @@ def open_download_folder(path):
44
46
 
45
47
  # FUNCTION TO VALIDATE YOUTUBE URL FORMAT
46
48
  def validate_youtube_url(url):
47
- try:
48
- # USE YT-DLP TO CHECK IF THE URL IS VALID
49
- with yt_dlp.YoutubeDL({'quiet': True, 'no_warnings': True}) as ydl:
50
- ydl.extract_info(url, download=False)
51
- return True
52
- except yt_dlp.utils.DownloadError as e:
53
- print(f"Invalid YouTube URL: {e}")
54
- return False
55
- except Exception as e:
56
- print(f"Unexpected error during URL validation: {e}")
57
- return False
49
+ """BASIC URL VALIDATION WITH PROPER FORMAT CHECK"""
50
+ # CHECK IF URL CONTAINS YOUTUBE DOMAIN
51
+ is_youtube = any(domain in url for domain in ["youtube.com", "youtu.be", "music.youtube.com"])
52
+
53
+ # CHECK IF URL HAS PROPER VIDEO ID FORMAT
54
+ has_video_id = False
55
+ if "youtube.com/watch" in url and "v=" in url:
56
+ has_video_id = True
57
+ elif "youtu.be/" in url and len(url.split("youtu.be/")[1]) > 0:
58
+ has_video_id = True
59
+ elif any(pattern in url for pattern in ["/watch/", "/shorts/", "/live/"]):
60
+ path_parts = url.split("/")
61
+ has_video_id = len(path_parts[-1]) > 0
62
+ elif "attribution_link" in url and "watch?v=" in url:
63
+ has_video_id = True
64
+
65
+ return is_youtube and has_video_id
58
66
 
59
67
 
60
68
  # FUNCTION TO DOWNLOAD FILES WITH REQUESTS, INCLUDING ERROR HANDLING AND PROGRESS BAR
@@ -85,40 +93,50 @@ def download_file(url):
85
93
  # FUNCTION TO GET CONSENT FILE PATH
86
94
  def get_consent_file_path():
87
95
  """GET PATH TO STORE CONSENT STATUS"""
96
+ # INFO: delete consent file with "rm -f ~/.autotools/consent.json" if you want to force new consent in local development
88
97
  return Path.home() / '.autotools' / 'consent.json'
89
98
 
90
99
  # FUNCTION TO LOAD CONSENT STATUS
91
100
  def load_consent_status():
92
101
  """LOAD SAVED CONSENT STATUS"""
93
- consent_file = get_consent_file_path()
94
-
95
- # CHECK IF CONSENT FILE EXISTS
96
- if consent_file.exists():
97
- try:
98
- with open(consent_file) as f:
99
- return json.load(f).get('youtube_consent', False)
100
- except:
102
+ try:
103
+ consent_file = get_consent_file_path()
104
+
105
+ # FORCE NEW CONSENT IF FILE DOESN'T EXIST OR IS EMPTY
106
+ if not consent_file.exists():
101
107
  return False
102
- return False
108
+
109
+ # READ CONSENT STATUS
110
+ with open(consent_file) as f:
111
+ data = json.load(f)
112
+ return data.get('youtube_consent', False)
113
+ except Exception:
114
+ # IF ANY ERROR OCCURS, FORCE NEW CONSENT
115
+ return False
103
116
 
104
117
  # FUNCTION TO SAVE CONSENT STATUS
105
118
  def save_consent_status(status):
106
119
  """SAVE CONSENT STATUS"""
107
- consent_file = get_consent_file_path()
108
- consent_file.parent.mkdir(exist_ok=True)
109
-
110
- # SAVE CONSENT STATUS TO FILE
111
- with open(consent_file, 'w') as f:
112
- json.dump({'youtube_consent': status}, f)
120
+ try:
121
+ consent_file = get_consent_file_path()
122
+ consent_file.parent.mkdir(exist_ok=True)
123
+
124
+ # SAVE CONSENT STATUS TO FILE
125
+ with open(consent_file, 'w') as f:
126
+ json.dump({'youtube_consent': status}, f)
127
+ return True
128
+ except Exception:
129
+ # IF SAVING FAILS, RETURN FALSE TO FORCE NEW CONSENT NEXT TIME
130
+ return False
113
131
 
114
132
  # FUNCTION TO GET USER CONSENT WITH INTERACTIVE PROMPT
115
133
  def get_user_consent():
116
134
  """GET USER CONSENT WITH INTERACTIVE PROMPT"""
117
135
  print("\n⚠️ Important Notice:")
118
136
  print("This tool will:")
119
- print("1. Access your Chrome browser cookies")
120
- print("2. Use them to authenticate with YouTube")
121
- print("3. Download video content to your local machine")
137
+ print("1. Download video content from YouTube")
138
+ print("2. Save files to your local machine")
139
+ print("3. Use mobile API for better compatibility")
122
140
 
123
141
  # GET USER CONSENT WITH INTERACTIVE PROMPT
124
142
  while True:
@@ -132,40 +150,116 @@ def get_user_consent():
132
150
  print("Please answer 'yes' or 'no'")
133
151
 
134
152
 
153
+ # FUNCTION TO CHECK IF VIDEO EXISTS AND GET USER CONSENT FOR REPLACEMENT
154
+ def check_existing_video(info, format='mp4'):
155
+ """CHECK IF VIDEO EXISTS AND ASK FOR REPLACEMENT"""
156
+ download_dir = get_default_download_dir()
157
+ title = info.get('title', '').replace('/', '_') # SANITIZE TITLE
158
+ filename = f"{title}.{format}"
159
+ filepath = download_dir / filename
160
+
161
+ # CHECK IF FILE EXISTS AND ASK FOR REPLACEMENT
162
+ if filepath.exists():
163
+ print(f"\n⚠️ File already exists: {filename}")
164
+ while True:
165
+ response = input("Do you want to replace it? (yes/no): ").lower()
166
+ if response in ['yes', 'y']:
167
+ return True
168
+ elif response in ['no', 'n']:
169
+ # OPEN DOWNLOADS FOLDER TO SHOW EXISTING FILE
170
+ open_download_folder(download_dir)
171
+ return False
172
+ print("Please answer 'yes' or 'no'")
173
+ return True
174
+
175
+
135
176
  # FUNCTION TO DOWNLOAD YOUTUBE VIDEOS WITH YT-DLP AND SPECIFIED FORMAT AND QUALITY
136
177
  def download_youtube_video(url, format='mp4', quality='best'):
137
178
  """DOWNLOAD VIDEO WITH CONSENT CHECK"""
138
- # CHECK IF CONSENT IS REQUIRED
139
- if not load_consent_status():
140
- if not get_user_consent():
141
- print("\n❌ Download cancelled by user")
142
- return False
179
+ # VALIDATE URL FIRST
180
+ if not validate_youtube_url(url):
181
+ print("\n❌ Invalid YouTube URL")
182
+ return False
183
+
184
+ # CHECK FOR SAVED CONSENT FIRST AND GET NEW CONSENT IF NEEDED
185
+ if not load_consent_status() and not get_user_consent():
186
+ print("\n❌ Download cancelled by user")
187
+ return False
188
+
189
+ # FIRST CHECK VIDEO INFO AND EXISTENCE
190
+ try:
191
+ with yt_dlp.YoutubeDL({
192
+ 'quiet': True,
193
+ 'no_warnings': True,
194
+ 'extractor_args': {'youtube': {
195
+ 'player_client': ['android'],
196
+ 'formats': ['missing_pot'] # ALLOW FORMATS WITHOUT PO TOKEN
197
+ }}
198
+ }) as ydl:
199
+ info = ydl.extract_info(url, download=False)
200
+ formats = info.get('formats', [])
201
+ if not formats:
202
+ print("\n❌ No formats available for this video")
203
+ return False
204
+
205
+ # CHECK IF FILE EXISTS AND GET REPLACEMENT CONSENT
206
+ force_download = check_existing_video(info, format)
207
+ if not force_download:
208
+ print("\n❌ Download cancelled - file already exists")
209
+ return False
210
+
211
+ # OPEN DOWNLOADS FOLDER IF STARTING NEW DOWNLOAD OR REPLACING
212
+ download_dir = get_default_download_dir()
213
+ open_download_folder(download_dir)
214
+
215
+ except Exception as e:
216
+ print(f"\n❌ Error checking video: {str(e)}")
217
+ return False
218
+
219
+ loading = LoadingAnimation()
220
+
221
+ # START LOADING FOR DOWNLOAD PROCESS
222
+ with loading:
223
+ loading._spinner.start()
224
+ print("\n🔍 Starting download...")
143
225
 
144
226
  print(f"\n🎥 Downloading video from: {url}")
145
227
  print(f"📋 Format: {format}, Quality: {quality}\n")
146
228
 
229
+ # YT-DLP PERMISSION OPTIONS FOR DOWNLOADING YOUTUBE VIDEOS
147
230
  ydl_opts = {
148
231
  'format': 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best' if format == 'mp4' else 'bestaudio[ext=mp3]/best',
149
- 'quiet': False,
150
- 'no_warnings': False,
151
- 'cookiesfrombrowser': ('chrome',),
152
- 'extractor_args': {'youtube': {'player_client': ['android']}},
232
+ 'quiet': True,
233
+ 'no_warnings': True,
234
+ 'progress': True,
235
+ 'progress_hooks': [lambda d: print(f"⏳ {d['_percent_str']} of {d.get('_total_bytes_str', 'Unknown size')}") if d['status'] == 'downloading' else None],
236
+ 'extractor_args': {
237
+ 'youtube': {
238
+ 'player_client': ['android'],
239
+ 'formats': ['missing_pot'] # ALLOW FORMATS WITHOUT PO TOKEN
240
+ }
241
+ },
153
242
  'http_headers': {
154
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
155
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
156
- 'Accept-Language': 'en-us,en;q=0.5',
157
- 'Sec-Fetch-Mode': 'navigate'
243
+ 'User-Agent': 'Mozilla/5.0 (Linux; Android 12; SM-S906N Build/QP1A.190711.020; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/80.0.3987.119 Mobile Safari/537.36'
158
244
  },
159
- 'progress_hooks': [lambda d: print(f"⏳ {d['_percent_str']} of {d.get('_total_bytes_str', 'Unknown size')}") if d['status'] == 'downloading' else None]
245
+ 'outtmpl': str(download_dir / '%(title)s.%(ext)s'), # SET OUTPUT TEMPLATE
246
+ 'overwrites': True # FORCE OVERWRITE IF USER CONSENTED
160
247
  }
161
248
 
162
249
  try:
250
+ # THEN DOWNLOAD
163
251
  with yt_dlp.YoutubeDL(ydl_opts) as ydl:
164
252
  ydl.download([url])
165
253
  print("\n✅ Download completed successfully!")
166
254
  return True
167
255
  except Exception as e:
168
- print(f"\n❌ ERROR: {str(e)}")
256
+ error_msg = str(e)
257
+ if "Requested format is not available" in error_msg:
258
+ print("\n❌ Format not available. Available formats are:")
259
+ for f in formats:
260
+ print(f"- {f.get('format_id', 'N/A')}: {f.get('ext', 'N/A')} ({f.get('format_note', 'N/A')})")
261
+ else:
262
+ print(f"\n❌ ERROR: {error_msg}")
169
263
  return False
170
264
 
171
265
 
@@ -0,0 +1,29 @@
1
+ import click
2
+ from .core import run
3
+ from ..utils.loading import LoadingAnimation
4
+ from ..utils.updates import check_for_updates
5
+
6
+ @click.command()
7
+ @click.option('--test', '-t', is_flag=True, help='Run connectivity tests')
8
+ @click.option('--speed', '-s', is_flag=True, help='Run internet speed test')
9
+ @click.option('--monitor', '-m', is_flag=True, help='Monitor network traffic')
10
+ @click.option('--interval', '-i', default=1, help='Monitoring interval in seconds')
11
+ @click.option('--ports', '-p', is_flag=True, help='Check common ports status')
12
+ @click.option('--dns', '-d', is_flag=True, help='Show DNS servers')
13
+ @click.option('--location', '-l', is_flag=True, help='Show IP location info')
14
+ @click.option('--no-ip', '-n', is_flag=True, help='Hide IP addresses')
15
+ def autoip(test, speed, monitor, interval, ports, dns, location, no_ip):
16
+ """Display network information and diagnostics.
17
+
18
+ Shows local and public IP addresses, runs network diagnostics,
19
+ performs speed tests, monitors traffic with custom intervals,
20
+ checks ports, displays DNS information and provides geolocation data."""
21
+ with LoadingAnimation():
22
+ output = run(test=test, speed=speed, monitor=monitor, interval=interval,
23
+ ports=ports, dns=dns, location=location, no_ip=no_ip)
24
+ click.echo(output)
25
+
26
+ # UPDATE CHECK AT THE END
27
+ update_msg = check_for_updates()
28
+ if update_msg:
29
+ click.echo(update_msg)
@@ -0,0 +1,17 @@
1
+ import click
2
+ from .core import autolower_transform
3
+ from ..utils.loading import LoadingAnimation
4
+ from ..utils.updates import check_for_updates
5
+
6
+ @click.command()
7
+ @click.argument('text', nargs=-1)
8
+ def autolower(text):
9
+ """Convert text to lowercase."""
10
+ with LoadingAnimation():
11
+ result = autolower_transform(" ".join(text))
12
+ click.echo(result)
13
+
14
+ # UPDATE CHECK AT THE END
15
+ update_msg = check_for_updates()
16
+ if update_msg:
17
+ click.echo(update_msg)