2023-11-29 07:21:03 +01:00
|
|
|
import click
|
2023-12-14 14:10:53 +01:00
|
|
|
import json as pyjson
|
2023-11-29 07:21:03 +01:00
|
|
|
|
2023-12-14 10:11:09 +01:00
|
|
|
from toot import api, config
|
2023-12-14 14:10:53 +01:00
|
|
|
from toot.cli import Context, cli, pass_context, json_option
|
2024-03-09 09:32:38 +01:00
|
|
|
from toot.entities import from_dict_list, List
|
2023-12-13 16:14:46 +01:00
|
|
|
from toot.output import print_list_accounts, print_lists, print_warning
|
2023-11-29 07:21:03 +01:00
|
|
|
|
|
|
|
|
2023-12-13 16:14:46 +01:00
|
|
|
@cli.group(invoke_without_command=True)
|
|
|
|
@click.pass_context
|
|
|
|
def lists(ctx: click.Context):
|
|
|
|
"""Display and manage lists"""
|
|
|
|
if ctx.invoked_subcommand is None:
|
2023-12-27 10:16:19 +01:00
|
|
|
print_warning("`toot lists` is deprecated in favour of `toot lists list`.\n" +
|
|
|
|
"Run `toot lists -h` to see other list-related commands.")
|
2023-12-13 16:14:46 +01:00
|
|
|
|
2023-12-14 10:11:09 +01:00
|
|
|
user, app = config.get_active_user_app()
|
|
|
|
if not user or not app:
|
|
|
|
raise click.ClickException("This command requires you to be logged in.")
|
|
|
|
|
2024-03-09 09:32:38 +01:00
|
|
|
data = api.get_lists(app, user)
|
|
|
|
lists = from_dict_list(List, data)
|
2023-12-13 16:14:46 +01:00
|
|
|
if lists:
|
|
|
|
print_lists(lists)
|
|
|
|
else:
|
|
|
|
click.echo("You have no lists defined.")
|
|
|
|
|
|
|
|
|
|
|
|
@lists.command()
|
2023-12-14 14:10:53 +01:00
|
|
|
@json_option
|
2023-12-14 10:11:09 +01:00
|
|
|
@pass_context
|
2023-12-14 14:10:53 +01:00
|
|
|
def list(ctx: Context, json: bool):
|
2023-12-13 16:14:46 +01:00
|
|
|
"""List all your lists"""
|
2024-03-09 09:32:38 +01:00
|
|
|
data = api.get_lists(ctx.app, ctx.user)
|
2023-11-29 07:21:03 +01:00
|
|
|
|
2023-12-14 14:10:53 +01:00
|
|
|
if json:
|
2024-03-09 09:32:38 +01:00
|
|
|
click.echo(pyjson.dumps(data))
|
2023-11-29 07:21:03 +01:00
|
|
|
else:
|
2024-03-09 09:32:38 +01:00
|
|
|
if data:
|
|
|
|
lists = from_dict_list(List, data)
|
2023-12-14 14:10:53 +01:00
|
|
|
print_lists(lists)
|
|
|
|
else:
|
|
|
|
click.echo("You have no lists defined.")
|
2023-11-29 07:21:03 +01:00
|
|
|
|
|
|
|
|
2023-12-13 16:14:46 +01:00
|
|
|
@lists.command()
|
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
2023-12-14 14:10:53 +01:00
|
|
|
@json_option
|
2023-12-13 16:14:46 +01:00
|
|
|
@pass_context
|
2023-12-14 14:10:53 +01:00
|
|
|
def accounts(ctx: Context, title: str, id: str, json: bool):
|
2023-12-13 16:14:46 +01:00
|
|
|
"""List the accounts in a list"""
|
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
response = api.get_list_accounts(ctx.app, ctx.user, list_id)
|
2023-12-14 14:10:53 +01:00
|
|
|
|
|
|
|
if json:
|
|
|
|
click.echo(pyjson.dumps(response))
|
|
|
|
else:
|
|
|
|
print_list_accounts(response)
|
2023-12-13 16:14:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
@lists.command()
|
|
|
|
@click.argument("title")
|
|
|
|
@click.option(
|
|
|
|
"--replies-policy",
|
|
|
|
type=click.Choice(["followed", "list", "none"]),
|
|
|
|
default="none",
|
|
|
|
help="Replies policy"
|
|
|
|
)
|
2023-12-14 14:10:53 +01:00
|
|
|
@json_option
|
2023-12-13 16:14:46 +01:00
|
|
|
@pass_context
|
2023-12-14 14:10:53 +01:00
|
|
|
def create(ctx: Context, title: str, replies_policy: str, json: bool):
|
2023-12-13 16:14:46 +01:00
|
|
|
"""Create a list"""
|
2023-12-14 14:10:53 +01:00
|
|
|
response = api.create_list(ctx.app, ctx.user, title=title, replies_policy=replies_policy)
|
|
|
|
if json:
|
|
|
|
print(response.text)
|
|
|
|
else:
|
|
|
|
click.secho(f"✓ List \"{title}\" created.", fg="green")
|
2023-12-13 16:14:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
@lists.command()
|
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
2023-12-14 14:10:53 +01:00
|
|
|
@json_option
|
2023-12-13 16:14:46 +01:00
|
|
|
@pass_context
|
2023-12-14 14:10:53 +01:00
|
|
|
def delete(ctx: Context, title: str, id: str, json: bool):
|
2023-12-13 16:14:46 +01:00
|
|
|
"""Delete a list"""
|
|
|
|
list_id = _get_list_id(ctx, title, id)
|
2023-12-14 14:10:53 +01:00
|
|
|
response = api.delete_list(ctx.app, ctx.user, list_id)
|
|
|
|
if json:
|
|
|
|
click.echo(response.text)
|
|
|
|
else:
|
|
|
|
click.secho(f"✓ List \"{title if title else id}\" deleted.", fg="green")
|
2023-12-13 16:14:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
@lists.command()
|
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.argument("account")
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
2023-12-14 14:10:53 +01:00
|
|
|
@json_option
|
2023-12-13 16:14:46 +01:00
|
|
|
@pass_context
|
2023-12-14 14:10:53 +01:00
|
|
|
def add(ctx: Context, title: str, account: str, id: str, json: bool):
|
2023-12-13 16:14:46 +01:00
|
|
|
"""Add an account to a list"""
|
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
found_account = api.find_account(ctx.app, ctx.user, account)
|
|
|
|
|
|
|
|
try:
|
2023-12-14 14:10:53 +01:00
|
|
|
response = api.add_accounts_to_list(ctx.app, ctx.user, list_id, [found_account["id"]])
|
|
|
|
if json:
|
|
|
|
click.echo(response.text)
|
|
|
|
else:
|
|
|
|
click.secho(f"✓ Added account \"{account}\"", fg="green")
|
2023-12-13 16:14:46 +01:00
|
|
|
except Exception:
|
|
|
|
# TODO: this is slow, improve
|
|
|
|
# if we failed to add the account, try to give a
|
|
|
|
# more specific error message than "record not found"
|
|
|
|
my_accounts = api.followers(ctx.app, ctx.user, found_account["id"])
|
|
|
|
found = False
|
|
|
|
if my_accounts:
|
|
|
|
for my_account in my_accounts:
|
|
|
|
if my_account["id"] == found_account["id"]:
|
|
|
|
found = True
|
|
|
|
break
|
|
|
|
if found is False:
|
|
|
|
raise click.ClickException(f"You must follow @{account} before adding this account to a list.")
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
@lists.command()
|
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.argument("account")
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
2023-12-14 14:10:53 +01:00
|
|
|
@json_option
|
2023-12-13 16:14:46 +01:00
|
|
|
@pass_context
|
2023-12-14 14:10:53 +01:00
|
|
|
def remove(ctx: Context, title: str, account: str, id: str, json: bool):
|
2023-12-13 16:14:46 +01:00
|
|
|
"""Remove an account from a list"""
|
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
found_account = api.find_account(ctx.app, ctx.user, account)
|
2023-12-14 14:10:53 +01:00
|
|
|
response = api.remove_accounts_from_list(ctx.app, ctx.user, list_id, [found_account["id"]])
|
|
|
|
if json:
|
|
|
|
click.echo(response.text)
|
|
|
|
else:
|
|
|
|
click.secho(f"✓ Removed account \"{account}\"", fg="green")
|
|
|
|
|
|
|
|
|
|
|
|
# -- Deprecated commands -------------------------------------------------------
|
2023-12-13 16:14:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
@cli.command(name="list_accounts", hidden=True)
|
2023-11-29 07:21:03 +01:00
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
|
|
|
@pass_context
|
|
|
|
def list_accounts(ctx: Context, title: str, id: str):
|
|
|
|
"""List the accounts in a list"""
|
2023-12-13 16:14:46 +01:00
|
|
|
print_warning("`toot list_accounts` is deprecated in favour of `toot lists accounts`")
|
2023-11-29 07:21:03 +01:00
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
response = api.get_list_accounts(ctx.app, ctx.user, list_id)
|
|
|
|
print_list_accounts(response)
|
|
|
|
|
|
|
|
|
2023-12-13 16:14:46 +01:00
|
|
|
@cli.command(name="list_create", hidden=True)
|
2023-11-29 07:21:03 +01:00
|
|
|
@click.argument("title")
|
|
|
|
@click.option(
|
|
|
|
"--replies-policy",
|
|
|
|
type=click.Choice(["followed", "list", "none"]),
|
|
|
|
default="none",
|
|
|
|
help="Replies policy"
|
|
|
|
)
|
|
|
|
@pass_context
|
|
|
|
def list_create(ctx: Context, title: str, replies_policy: str):
|
|
|
|
"""Create a list"""
|
2023-12-13 16:14:46 +01:00
|
|
|
print_warning("`toot list_create` is deprecated in favour of `toot lists create`")
|
2023-11-29 07:21:03 +01:00
|
|
|
api.create_list(ctx.app, ctx.user, title=title, replies_policy=replies_policy)
|
|
|
|
click.secho(f"✓ List \"{title}\" created.", fg="green")
|
|
|
|
|
|
|
|
|
2023-12-13 16:14:46 +01:00
|
|
|
@cli.command(name="list_delete", hidden=True)
|
2023-11-29 07:21:03 +01:00
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
|
|
|
@pass_context
|
|
|
|
def list_delete(ctx: Context, title: str, id: str):
|
|
|
|
"""Delete a list"""
|
2023-12-13 16:14:46 +01:00
|
|
|
print_warning("`toot list_delete` is deprecated in favour of `toot lists delete`")
|
2023-11-29 07:21:03 +01:00
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
api.delete_list(ctx.app, ctx.user, list_id)
|
|
|
|
click.secho(f"✓ List \"{title if title else id}\" deleted.", fg="green")
|
|
|
|
|
|
|
|
|
2023-12-13 16:14:46 +01:00
|
|
|
@cli.command(name="list_add", hidden=True)
|
2023-11-29 07:21:03 +01:00
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.argument("account")
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
|
|
|
@pass_context
|
|
|
|
def list_add(ctx: Context, title: str, account: str, id: str):
|
|
|
|
"""Add an account to a list"""
|
2023-12-13 16:14:46 +01:00
|
|
|
print_warning("`toot list_add` is deprecated in favour of `toot lists add`")
|
2023-11-29 07:21:03 +01:00
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
found_account = api.find_account(ctx.app, ctx.user, account)
|
|
|
|
|
|
|
|
try:
|
|
|
|
api.add_accounts_to_list(ctx.app, ctx.user, list_id, [found_account["id"]])
|
|
|
|
except Exception:
|
|
|
|
# if we failed to add the account, try to give a
|
|
|
|
# more specific error message than "record not found"
|
|
|
|
my_accounts = api.followers(ctx.app, ctx.user, found_account["id"])
|
|
|
|
found = False
|
|
|
|
if my_accounts:
|
|
|
|
for my_account in my_accounts:
|
|
|
|
if my_account["id"] == found_account["id"]:
|
|
|
|
found = True
|
|
|
|
break
|
|
|
|
if found is False:
|
|
|
|
raise click.ClickException(f"You must follow @{account} before adding this account to a list.")
|
|
|
|
raise
|
|
|
|
|
|
|
|
click.secho(f"✓ Added account \"{account}\"", fg="green")
|
|
|
|
|
|
|
|
|
2023-12-13 16:14:46 +01:00
|
|
|
@cli.command(name="list_remove", hidden=True)
|
2023-11-29 07:21:03 +01:00
|
|
|
@click.argument("title", required=False)
|
|
|
|
@click.argument("account")
|
|
|
|
@click.option("--id", help="List ID if not title is given")
|
|
|
|
@pass_context
|
|
|
|
def list_remove(ctx: Context, title: str, account: str, id: str):
|
|
|
|
"""Remove an account from a list"""
|
2023-12-13 16:14:46 +01:00
|
|
|
print_warning("`toot list_remove` is deprecated in favour of `toot lists remove`")
|
2023-11-29 07:21:03 +01:00
|
|
|
list_id = _get_list_id(ctx, title, id)
|
|
|
|
found_account = api.find_account(ctx.app, ctx.user, account)
|
|
|
|
api.remove_accounts_from_list(ctx.app, ctx.user, list_id, [found_account["id"]])
|
|
|
|
click.secho(f"✓ Removed account \"{account}\"", fg="green")
|
|
|
|
|
|
|
|
|
|
|
|
def _get_list_id(ctx: Context, title, list_id):
|
2023-12-13 16:14:46 +01:00
|
|
|
if not list_id and not title:
|
|
|
|
raise click.ClickException("Please specify list title or ID")
|
|
|
|
|
|
|
|
lists = api.get_lists(ctx.app, ctx.user)
|
|
|
|
matched_ids = [
|
|
|
|
list["id"] for list in lists
|
|
|
|
if list["title"].lower() == title.lower() or list["id"] == list_id
|
|
|
|
]
|
|
|
|
|
|
|
|
if not matched_ids:
|
2023-11-29 07:21:03 +01:00
|
|
|
raise click.ClickException("List not found")
|
2023-12-13 16:14:46 +01:00
|
|
|
|
|
|
|
if len(matched_ids) > 1:
|
|
|
|
raise click.ClickException("Found multiple lists with the same title, please specify the ID instead")
|
|
|
|
|
|
|
|
return matched_ids[0]
|