Skip to content

Commit

Permalink
Replace some options with config file
Browse files Browse the repository at this point in the history
  • Loading branch information
fpob committed Feb 22, 2024
1 parent 150bd1a commit dcfbcec
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 47 deletions.
13 changes: 13 additions & 0 deletions docs/cli.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,16 @@ CLI
.. click:: yumemi.cli:main
:prog: yumemi
:nested: full

Configuration
-------------

.. code-block:: toml
[anidb]
# Optional username and password. You can set only the username and leave
# the password unset, so CLI will only prompt you to enter the password.
username = "example"
password = "example"
# Optional encryption key (AniDB > Settings > Account > UDP API Key).
encrypt_key = "example"
2 changes: 1 addition & 1 deletion poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ python = "^3.9"
click = "^8.1"
attrs = "^22.1"
cryptography = ">=41.0.4"
tomli = { version = ">=1.1.0", python = "<3.11" }

[tool.poetry.group.dev.dependencies]
pytest = "^7.2.0"
Expand Down
87 changes: 53 additions & 34 deletions src/yumemi/cli.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime
import multiprocessing
import os
import sys
import time

import click
Expand All @@ -9,9 +10,17 @@
from . import _rhash as rhash


if sys.version_info >= (3, 11):
import tomllib
else:
import tomli as tomllib


CLIENT_NAME = 'yumemi'
CLIENT_VERSION = 4

DEFAULT_CONFIG = os.path.join(click.get_app_dir('yumemi'), 'config.toml')


def ping(ctx, param, value):
if not value or ctx.resilient_parsing:
Expand Down Expand Up @@ -45,6 +54,35 @@ def convert(self, value, param, ctx):
self.fail(f"format must be '{self.format}'")


def load_config(config_path):
if os.path.exists(config_path):
with open(config_path, 'rb') as f:
config = tomllib.load(f)
else:
config = {}

config.setdefault('anidb', {})

return config


def create_client(username=None, password=None, encrypt_key=None):
if not username:
username = click.prompt('Username')
if not password:
password = click.prompt('Password', hide_input=True)

client = Client(CLIENT_NAME, CLIENT_VERSION)
try:
if encrypt_key:
client.encrypt(username, encrypt_key)
client.auth(username, password)
except AnidbError as e:
click.secho(str(e), fg='red', err=True)
raise click.Abort
return client


def mylistadd_file_params(file):
return (
file,
Expand All @@ -56,7 +94,6 @@ def mylistadd_file_params(file):
@click.command(
context_settings=dict(
help_option_names=['-h', '--help'],
auto_envvar_prefix='YUMEMI',
),
)
@click.version_option()
Expand All @@ -69,18 +106,12 @@ def mylistadd_file_params(file):
help='Test connection to AniDB API server.',
)
@click.option(
'-u', '--username',
prompt=True,
)
@click.option(
'-p', '--password',
prompt=True,
hide_input=True,
)
@click.option(
'--encrypt',
default=None,
help='Ecrypt connection. Parameter value is API Key.',
'config_file',
'--config',
default=DEFAULT_CONFIG,
show_default=True,
envvar='YUMEMI_CONFIG',
help='Path to configuration file.',
)
@click.option(
'-w', '--watched',
Expand All @@ -107,40 +138,28 @@ def mylistadd_file_params(file):
default=False,
help='Edit watched state and date of files that are already in mylist.',
)
@click.option(
'-j', '--jobs',
type=int,
default=1,
show_default=True,
help='Number of processes launched to calculate file hashes.',
)
@click.argument(
'files',
nargs=-1,
required=True,
type=click.Path(exists=True, dir_okay=False),
)
def main(username, password, watched, watched_date, deleted, edit, encrypt, jobs,
files):
def main(config_file, watched, watched_date, deleted, edit, files):
"""AniDB client for adding files to mylist."""
config = load_config(config_file)

if watched_date is not None:
watched = True
elif watched:
watched_date = datetime.datetime.now()

client = Client(CLIENT_NAME, CLIENT_VERSION)
try:
if encrypt:
client.encrypt(username, encrypt)
client.auth(username, password)
except AnidbError as e:
msg = str(e)
if e.result and e.result.code in {503, 504}:
msg = 'Client version is no longer supported, please update.'
click.secho(msg, fg='red', err=True)
raise click.Abort
client = create_client(
config['anidb'].get('username'),
config['anidb'].get('password'),
config['anidb'].get('encrypt_key'),
)

mp_pool = multiprocessing.Pool(jobs)
mp_pool = multiprocessing.Pool(1)

try:
files_params = mp_pool.imap(mylistadd_file_params, files)
Expand Down
26 changes: 14 additions & 12 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ def client_mock(mocker):
yield m


@pytest.fixture(autouse=True)
def config_mock(mocker):
mocker.patch('yumemi.cli.load_config').return_value = {
'anidb': {
'username': 'testuser',
'password': 'testpass',
'encrypt_key': 'enckey',
},
}


@pytest.mark.parametrize(
'cli_args, mylistadd_params',
[
Expand Down Expand Up @@ -65,7 +76,7 @@ def test_mylistadd(runner, tmp_path, client_mock, mp_pool_mock,
params={},
code=210,
message='MYLIST ENTRY ADDED',
data=((1,),),
data=(('1',),),
)

mp_pool_mock.imap.return_value = [
Expand All @@ -75,16 +86,7 @@ def test_mylistadd(runner, tmp_path, client_mock, mp_pool_mock,
file = tmp_path / 'test.mkv'
file.write_bytes(b'\x00')

result = runner.invoke(
yumemi.cli.main,
[
'--username', 'testuser',
'--password', 'testpass',
'--encrypt', 'enckey',
*cli_args,
str(file),
],
)
result = runner.invoke(yumemi.cli.main, [*cli_args, str(file)])

assert result.exit_code == 0

Expand All @@ -98,4 +100,4 @@ def test_mylistadd(runner, tmp_path, client_mock, mp_pool_mock,
assert cmd_params['ed2k'] == '47c61a0fa8738ba77308a8a600f88e4b'
assert cmd_params['size'] == 1
for param_key, param_value in mylistadd_params.items():
assert cmd_params[param_key] == param_value
assert cmd_params[param_key] == param_value, param_key

0 comments on commit dcfbcec

Please sign in to comment.