idm-cli 0.2.0__tar.gz → 0.2.2__tar.gz
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 idm-cli might be problematic. Click here for more details.
- {idm_cli-0.2.0 → idm_cli-0.2.2}/PKG-INFO +1 -1
- {idm_cli-0.2.0 → idm_cli-0.2.2}/README.md +36 -15
- {idm_cli-0.2.0 → idm_cli-0.2.2}/idm_cli.egg-info/PKG-INFO +1 -1
- {idm_cli-0.2.0 → idm_cli-0.2.2}/setup.py +1 -1
- idm_cli-0.2.2/speedy_dl/__init__.py +2 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/speedy_dl/cli.py +96 -2
- idm_cli-0.2.0/speedy_dl/__init__.py +0 -2
- {idm_cli-0.2.0 → idm_cli-0.2.2}/idm_cli.egg-info/SOURCES.txt +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/idm_cli.egg-info/dependency_links.txt +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/idm_cli.egg-info/entry_points.txt +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/idm_cli.egg-info/requires.txt +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/idm_cli.egg-info/top_level.txt +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/setup.cfg +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/speedy_dl/downloader.py +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/speedy_dl/extractor.py +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/speedy_dl/state.py +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/speedy_dl/ui.py +0 -0
- {idm_cli-0.2.0 → idm_cli-0.2.2}/speedy_dl/updater.py +0 -0
|
@@ -26,23 +26,44 @@
|
|
|
26
26
|
|
|
27
27
|
Ensure you have **Python 3.8+** installed.
|
|
28
28
|
|
|
29
|
-
### 1.
|
|
30
|
-
|
|
31
|
-
cd IDM-Clone-CLI
|
|
32
|
-
```
|
|
29
|
+
### 🌟 1. Global Installation (Recommended via `pipx`)
|
|
30
|
+
For standard users, installing via `pipx` prevents any library conflicts and automatically registers the global commands safely:
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
1. **Install pipx globally:**
|
|
33
|
+
```bash
|
|
34
|
+
pip install pipx
|
|
35
|
+
```
|
|
36
|
+
2. **Configure your system path:**
|
|
37
|
+
```bash
|
|
38
|
+
pipx ensurepath
|
|
39
|
+
```
|
|
40
|
+
*(Note: After running `ensurepath`, close and restart your terminal to activate the changes!)*
|
|
39
41
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
3. **Install IDM-CLI globally:**
|
|
43
|
+
```bash
|
|
44
|
+
pipx install idm-cli
|
|
45
|
+
```
|
|
46
|
+
*(This automatically downloads and bundles the lightweight static FFmpeg binary in the background. Zero manual configuration required!)*
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
### 🛠️ 2. Local Developer Installation (From Source)
|
|
51
|
+
If you want to run or modify the codebase locally:
|
|
52
|
+
|
|
53
|
+
1. **Clone the repository:**
|
|
54
|
+
```bash
|
|
55
|
+
git clone https://github.com/rj41-w2/IDM-Clone-CLI.git
|
|
56
|
+
cd IDM-Clone-CLI
|
|
57
|
+
```
|
|
58
|
+
2. **Create and Activate a Virtual Environment:**
|
|
59
|
+
```powershell
|
|
60
|
+
python -m venv .venv
|
|
61
|
+
.venv\Scripts\Activate.ps1
|
|
62
|
+
```
|
|
63
|
+
3. **Install in Editable Mode:**
|
|
64
|
+
```powershell
|
|
65
|
+
pip install -e .
|
|
66
|
+
```
|
|
46
67
|
|
|
47
68
|
---
|
|
48
69
|
|
|
@@ -324,7 +324,7 @@ def interactive_shell():
|
|
|
324
324
|
f"[bold gold1]★ A new version of idm-cli is available![/bold gold1]\n"
|
|
325
325
|
f"[bold white]Local Version:[/bold white] [red]{speedy_dl.__version__}[/red] ➜ "
|
|
326
326
|
f"[bold white]Latest Version:[/bold white] [green]{new_version}[/green]\n"
|
|
327
|
-
f"Run [bold cyan]
|
|
327
|
+
f"Run [bold cyan]pipx upgrade idm-cli[/bold cyan] to update globally!",
|
|
328
328
|
border_style="bold gold1",
|
|
329
329
|
title="[bold gold1]Update Available[/bold gold1]",
|
|
330
330
|
padding=(1, 2)
|
|
@@ -338,6 +338,8 @@ def interactive_shell():
|
|
|
338
338
|
"[bold white]Developed by:[/bold white] [cyan]Rehan Jamil[/cyan]\n"
|
|
339
339
|
"[bold white]GitHub Profile:[/bold white] [link=https://github.com/rj41-w2][cyan]github.com/rj41-w2[/cyan][/link] [dim](Ctrl + Click to Open)[/dim]\n\n"
|
|
340
340
|
"• Paste any HTTP/HTTPS URL or YouTube URL to download instantly.\n"
|
|
341
|
+
"• Type [bold yellow]queue <URL>[/bold yellow] to add a link to the download queue.\n"
|
|
342
|
+
"• Type [bold yellow]queue[/bold yellow] to list queued links, and [bold yellow]start[/bold yellow] to run them sequentially.\n"
|
|
341
343
|
"• Type [bold yellow]resume <metadata_file>[/bold yellow] to resume a paused download.\n"
|
|
342
344
|
"• Type [bold yellow]help[/bold yellow] to see all available commands.\n"
|
|
343
345
|
"• Type [bold red]exit[/bold red] or press [bold red]Ctrl+C[/bold red] to quit the application.",
|
|
@@ -349,6 +351,8 @@ def interactive_shell():
|
|
|
349
351
|
# Import Table inside for clean scoping
|
|
350
352
|
from rich.table import Table
|
|
351
353
|
|
|
354
|
+
download_queue = []
|
|
355
|
+
|
|
352
356
|
while True:
|
|
353
357
|
try:
|
|
354
358
|
url_input = console.input("[bold cyan]idm>[/bold cyan] ").strip()
|
|
@@ -361,6 +365,10 @@ def interactive_shell():
|
|
|
361
365
|
help_table.add_column("Command", style="bold green", justify="left")
|
|
362
366
|
help_table.add_column("Description", style="white", justify="left")
|
|
363
367
|
help_table.add_row("<URL>", "Paste a direct download link or YouTube/streaming video URL to download.")
|
|
368
|
+
help_table.add_row("queue <URL> / q <URL>", "Adds a direct link or streaming video URL to the sequential download queue.")
|
|
369
|
+
help_table.add_row("queue / q", "Lists all downloads currently queued in the system.")
|
|
370
|
+
help_table.add_row("start / run", "Starts downloading all queued links sequentially (one-by-one).")
|
|
371
|
+
help_table.add_row("clear / clear queue", "Clears all links from the download queue.")
|
|
364
372
|
help_table.add_row("resume <state_file>", "Resumes an interrupted or paused download using its JSON state file.")
|
|
365
373
|
help_table.add_row("help / ?", "Displays this help menu showing all available commands.")
|
|
366
374
|
help_table.add_row("exit / quit", "Safely quits the interactive IDM-CLI shell.")
|
|
@@ -394,8 +402,94 @@ def interactive_shell():
|
|
|
394
402
|
run_async_downloader(downloader)
|
|
395
403
|
continue
|
|
396
404
|
|
|
405
|
+
# Queue addition commands
|
|
406
|
+
lower_input = url_input.lower()
|
|
407
|
+
if lower_input.startswith(("queue ", "q ", "add ")):
|
|
408
|
+
if lower_input.startswith("queue "):
|
|
409
|
+
target_url = url_input[6:].strip()
|
|
410
|
+
elif lower_input.startswith("q "):
|
|
411
|
+
target_url = url_input[2:].strip()
|
|
412
|
+
else:
|
|
413
|
+
target_url = url_input[4:].strip()
|
|
414
|
+
|
|
415
|
+
if not target_url.startswith(("http://", "https://")):
|
|
416
|
+
console.print("[bold red]Error: Please enter a valid HTTP/HTTPS URL to queue.[/bold red]")
|
|
417
|
+
continue
|
|
418
|
+
|
|
419
|
+
download_queue.append(target_url)
|
|
420
|
+
console.print(Panel(
|
|
421
|
+
f"[bold green]✓ Link successfully added to queue![/bold green]\n"
|
|
422
|
+
f"[white]URL:[/white] [cyan]{target_url}[/cyan]\n"
|
|
423
|
+
f"[white]Current Queue Size:[/white] [yellow]{len(download_queue)}[/yellow]",
|
|
424
|
+
border_style="bold green"
|
|
425
|
+
))
|
|
426
|
+
continue
|
|
427
|
+
|
|
428
|
+
if lower_input in ("queue", "q", "queue list", "list queue", "list"):
|
|
429
|
+
if not download_queue:
|
|
430
|
+
console.print("[bold yellow]Queue is empty! Add links using 'queue <URL>'.[/bold yellow]")
|
|
431
|
+
continue
|
|
432
|
+
|
|
433
|
+
q_table = Table(title="[bold yellow]Current Download Queue[/bold yellow]", border_style="bold green")
|
|
434
|
+
q_table.add_column("No.", style="bold cyan", justify="center")
|
|
435
|
+
q_table.add_column("URL / Streaming Link", style="white", justify="left")
|
|
436
|
+
|
|
437
|
+
for idx, q_url in enumerate(download_queue, 1):
|
|
438
|
+
q_table.add_row(f"{idx}", q_url)
|
|
439
|
+
|
|
440
|
+
console.print()
|
|
441
|
+
console.print(q_table)
|
|
442
|
+
console.print()
|
|
443
|
+
continue
|
|
444
|
+
|
|
445
|
+
if lower_input in ("clear", "clear queue"):
|
|
446
|
+
download_queue.clear()
|
|
447
|
+
console.print("[bold green]✓ Download queue successfully cleared![/bold green]")
|
|
448
|
+
continue
|
|
449
|
+
|
|
450
|
+
if lower_input in ("start", "start queue", "run", "run queue"):
|
|
451
|
+
if not download_queue:
|
|
452
|
+
console.print("[bold red]Error: No links in the queue. Add links using 'queue <URL>'.[/bold red]")
|
|
453
|
+
continue
|
|
454
|
+
|
|
455
|
+
total_items = len(download_queue)
|
|
456
|
+
console.print(Panel(
|
|
457
|
+
f"[bold green]Starting sequential queue download ({total_items} items)...[/bold green]",
|
|
458
|
+
border_style="bold green"
|
|
459
|
+
))
|
|
460
|
+
|
|
461
|
+
item_idx = 1
|
|
462
|
+
while download_queue:
|
|
463
|
+
current_url = download_queue[0] # Peek
|
|
464
|
+
console.print(f"\n[bold cyan]Queue Processing [{item_idx}/{total_items}]:[/bold cyan] [cyan]{current_url}[/cyan]")
|
|
465
|
+
|
|
466
|
+
try:
|
|
467
|
+
if is_streaming_url(current_url):
|
|
468
|
+
selected_res = prompt_for_quality(current_url)
|
|
469
|
+
if selected_res:
|
|
470
|
+
download_streaming_video(current_url, None, 8, selected_res)
|
|
471
|
+
else:
|
|
472
|
+
downloader = SpeedyDownloader(url=current_url)
|
|
473
|
+
run_async_downloader(downloader)
|
|
474
|
+
|
|
475
|
+
# Successfully downloaded, pop from queue
|
|
476
|
+
download_queue.pop(0)
|
|
477
|
+
item_idx += 1
|
|
478
|
+
except KeyboardInterrupt:
|
|
479
|
+
console.print("\n[bold yellow]⚠ Queue download paused/interrupted. Storing remaining links in queue.[/bold yellow]")
|
|
480
|
+
break
|
|
481
|
+
except Exception as e:
|
|
482
|
+
console.print(f"\n[bold red]✖ Error downloading {current_url}: {e}[/bold red]")
|
|
483
|
+
choice = console.input("[bold yellow]Do you want to continue to the next item in queue? (y/n) [default: y]: [/bold yellow]").strip().lower()
|
|
484
|
+
if choice == "n":
|
|
485
|
+
break
|
|
486
|
+
# Otherwise pop the failed item and continue
|
|
487
|
+
download_queue.pop(0)
|
|
488
|
+
item_idx += 1
|
|
489
|
+
continue
|
|
490
|
+
|
|
397
491
|
if not url_input.startswith(("http://", "https://")):
|
|
398
|
-
console.print("[bold red]Error: Please enter a valid HTTP/HTTPS URL or 'resume <state_file>'.[/bold red]")
|
|
492
|
+
console.print("[bold red]Error: Please enter a valid HTTP/HTTPS URL, queue commands, or 'resume <state_file>'.[/bold red]")
|
|
399
493
|
continue
|
|
400
494
|
|
|
401
495
|
if is_streaming_url(url_input):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|