Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Build

on:
pull_request:

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- run: uv build

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v5

- run: uv run --group dev ruff check .
- run: uv run --group dev ruff format --check .
116 changes: 84 additions & 32 deletions nyaacli/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import logging
import sys
from typing import List

from rich import print
from rich.logging import RichHandler
Expand All @@ -19,48 +18,91 @@
install(show_locals=True)


def entries_autocomplete(ctx, args: List[str], incomplete: str):
def entries_autocomplete(ctx, param, incomplete):
"""
Auto-complete choices for --number / -n argument
"""

text = 'Selection Entries'
text = "Selection Entries"

entries = [
('5', f'5 {text}'),
('10', f'10 {text} (default)'),
('15', f'15 {text}'),
('20', f'20 {text}')
("5", f"5 {text}"),
("10", f"10 {text} (default)"),
("15", f"15 {text}"),
("20", f"20 {text}"),
]

return [c for c in entries if incomplete in c[0]]
return [
click.shell_completion.CompletionItem(v, help=h)
for v, h in entries
if incomplete in v
]


def sort_mode_autocomplete(ctx, args: List[str], incomplete: str):
def sort_mode_autocomplete(ctx, param, incomplete):
"""
Auto-complete choices for --sort-by / -s argument
"""

entries = [
('seeders', 'Sort by number of torrent seeders (default)'),
('date', 'Sort by upload date'),
('size', 'Sort by file size'),
('comments', 'Sort by number of comments')
("seeders", "Sort by number of torrent seeders (default)"),
("date", "Sort by upload date"),
("size", "Sort by file size"),
("comments", "Sort by number of comments"),
]

return [c for c in entries if incomplete in c[0]]
return [
click.shell_completion.CompletionItem(v, help=h)
for v, h in entries
if incomplete in v
]


@click.command()
@click.argument('anime')
@click.argument('episode', type=int, default=None, required=False)
@click.option('--output', '-o', default='~/Videos/Anime', help=green('Output Folder'), type=click.Path(), show_default=True)
@click.option('--number', '-n', default=10, help=green('Number of entries'), show_default=True, autocompletion=entries_autocomplete)
@click.option('--sort-by', '-s', default='seeders', help=green('Sort by'), show_default=True, autocompletion=sort_mode_autocomplete)
@click.option('--trusted', '-t', default=False, help=green('Only search trusted uploads'), is_flag=True)
@click.option('--debug', '-d', default=False, help=green('Debug Mode'), is_flag=True)
@click.option('--client', '-c', default=False, help=green('Use Torrent Client'), is_flag=True)
@click.option('--player', '-p', default=False, help=green('Open in Video Player after download'), is_flag=True)
@click.argument("anime")
@click.argument("episode", type=int, default=None, required=False)
@click.option(
"--output",
"-o",
default="~/Videos/Anime",
help=green("Output Folder"),
type=click.Path(),
show_default=True,
)
@click.option(
"--number",
"-n",
default=10,
help=green("Number of entries"),
show_default=True,
shell_complete=entries_autocomplete,
)
@click.option(
"--sort-by",
"-s",
default="seeders",
help=green("Sort by"),
show_default=True,
shell_complete=sort_mode_autocomplete,
)
@click.option(
"--trusted",
"-t",
default=False,
help=green("Only search trusted uploads"),
is_flag=True,
)
@click.option("--debug", "-d", default=False, help=green("Debug Mode"), is_flag=True)
@click.option(
"--client", "-c", default=False, help=green("Use Torrent Client"), is_flag=True
)
@click.option(
"--player",
"-p",
default=False,
help=green("Open in Video Player after download"),
is_flag=True,
)
def main(
anime: str,
episode: int,
Expand All @@ -70,7 +112,7 @@ def main(
trusted: bool = False,
player: bool = False,
number: int = 10,
sort_by: str = 'seeders',
sort_by: str = "seeders",
):
"""
Search for Anime on https://nyaa.si and downloads it
Expand All @@ -96,15 +138,25 @@ def main(
try:
from nyaacli.torrenting import download_torrent
except ModuleNotFoundError:
print("[bold red]You need to have the 'libtorrent' library (with the Python API) installed to user nyaa-cli.[/bold red]\n")

print('- Install with apt: [bold green]sudo apt install python3-libtorrent[/bold green]')
print('- Install with pacman: [bold green]sudo pacman -S libtorrent-rasterbar[/bold green]')

print('\nAlternatively pass the flag [bold green]--client[/bold green] to use your default torrenting client instead.')
print(
"[bold red]You need to have the 'libtorrent' library (with the Python API) installed to use nyaa-cli.[/bold red]\n"
)

print(
"- Install with apt: [bold green]sudo apt install python3-libtorrent[/bold green]"
)
print(
"- Install with pacman: [bold green]sudo pacman -S libtorrent-rasterbar[/bold green]"
)

print(
"\nAlternatively pass the flag [bold green]--client[/bold green] to use your default torrenting client instead."
)
sys.exit(1)

torrent_search = search_torrent(anime, episode, number=number, trusted_only=trusted, sort_by=sort_by)
torrent_search = search_torrent(
anime, episode, number=number, trusted_only=trusted, sort_by=sort_by
)

if torrent_search:
torrent_path, result_name = torrent_search
Expand All @@ -114,7 +166,7 @@ def main(
else:
output_path = download_torrent(torrent_path, result_name, base_path=output)

print(f'Finished download at: [green]\'{output_path}\'[/green] ')
print(f"Finished download at: [green]'{output_path}'[/green] ")

if player:
xdg_open(output_path)
Expand Down
26 changes: 14 additions & 12 deletions nyaacli/colors.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ def blue(text: str) -> str:
return Fore.BLUE + text + Style.RESET_ALL


prompt_style = styles.Style([
('qmark', 'fg:#5F819D bold'),
('question', 'fg:#289c64 bold'),
('answer', 'fg:#48b5b5 bold'),
('pointer', 'fg:#48b5b5 bold'),
('highlighted', 'fg:#07d1e8'),
('selected', 'fg:#48b5b5 bold'),
('separator', 'fg:#6C6C6C'),
('instruction', 'fg:#77a371'),
('text', ''),
('disabled', 'fg:#858585 italic')
])
prompt_style = styles.Style(
[
("qmark", "fg:#5F819D bold"),
("question", "fg:#289c64 bold"),
("answer", "fg:#48b5b5 bold"),
("pointer", "fg:#48b5b5 bold"),
("highlighted", "fg:#07d1e8"),
("selected", "fg:#48b5b5 bold"),
("separator", "fg:#6C6C6C"),
("instruction", "fg:#77a371"),
("text", ""),
("disabled", "fg:#858585 italic"),
]
)
Loading
Loading