Toot-Mastodon-CLI-TUI-clien.../toot/cli/timelines.py

181 lines
4.9 KiB
Python
Raw Normal View History

2023-12-03 07:07:18 +01:00
import sys
import click
from toot import api
from toot.cli.base import cli, pass_context, Context
from typing import Optional
from toot.cli.validators import validate_instance
from toot.entities import Notification, Status, from_dict
from toot.output import print_notifications, print_timeline
@cli.command()
@click.option(
"--instance", "-i",
callback=validate_instance,
help="""Domain or base URL of the instance from which to read,
e.g. 'mastodon.social' or 'https://mastodon.social'""",
)
@click.option("--account", "-a", help="Show account timeline")
@click.option("--list", help="Show list timeline")
@click.option("--tag", "-t", help="Show hashtag timeline")
@click.option("--public", "-p", is_flag=True, help="Show public timeline")
@click.option(
"--local", "-l", is_flag=True,
help="Show only statuses from the local instance (public and tag timelines only)"
)
@click.option(
"--reverse", "-r", is_flag=True,
help="Reverse the order of the shown timeline (new posts at the bottom)"
)
@click.option(
"--once", "-1", is_flag=True,
help="Only show the first <count> toots, do not prompt to continue"
)
@click.option(
"--count", "-c", type=int, default=10,
help="Number of posts per page (max 20)"
)
@pass_context
def timeline(
ctx: Context,
instance: Optional[str],
account: Optional[str],
list: Optional[str],
tag: Optional[str],
public: bool,
local: bool,
reverse: bool,
once: bool,
count: int,
):
"""Show recent items in a timeline
By default shows the home timeline.
"""
if len([arg for arg in [tag, list, public, account] if arg]) > 1:
raise click.ClickException("Only one of --public, --tag, --account, or --list can be used at one time.")
if local and not (public or tag):
raise click.ClickException("The --local option is only valid alongside --public or --tag.")
if instance and not (public or tag):
raise click.ClickException("The --instance option is only valid alongside --public or --tag.")
list_id = _get_list_id(ctx, list)
"""Show recent statuses in a timeline"""
generator = api.get_timeline_generator(
ctx.app,
ctx.user,
base_url=instance,
account=account,
list_id=list_id,
tag=tag,
public=public,
local=local,
limit=count,
)
_show_timeline(generator, reverse, once)
@cli.command()
@click.option(
"--reverse", "-r", is_flag=True,
help="Reverse the order of the shown timeline (new posts at the bottom)"
)
@click.option(
"--once", "-1", is_flag=True,
help="Only show the first <count> toots, do not prompt to continue"
)
@click.option(
"--count", "-c", type=int, default=10,
help="Number of posts per page (max 20)"
)
@pass_context
def bookmarks(
ctx: Context,
reverse: bool,
once: bool,
count: int,
):
"""Show recent statuses in a timeline"""
generator = api.bookmark_timeline_generator(ctx.app, ctx.user, limit=count)
_show_timeline(generator, reverse, once)
@cli.command()
@click.option("--clear", help="Dismiss all notifications and exit")
@click.option(
"--reverse", "-r", is_flag=True,
help="Reverse the order of the shown notifications (newest on top)"
)
@click.option(
"--mentions", "-m", is_flag=True,
help="Show only mentions"
)
@pass_context
def notifications(
ctx: Context,
clear: bool,
reverse: bool,
mentions: int,
):
"""Show notifications"""
if clear:
api.clear_notifications(ctx.app, ctx.user)
click.secho("✓ Notifications cleared", fg="green")
return
exclude = []
if mentions:
# Filter everything except mentions
# https://docs.joinmastodon.org/methods/notifications/
exclude = ["follow", "favourite", "reblog", "poll", "follow_request"]
notifications = api.get_notifications(ctx.app, ctx.user, exclude_types=exclude)
if not notifications:
click.echo("You have no notifications")
return
if reverse:
notifications = reversed(notifications)
notifications = [from_dict(Notification, n) for n in notifications]
print_notifications(notifications)
def _show_timeline(generator, reverse, once):
while True:
try:
items = next(generator)
except StopIteration:
click.echo("That's all folks.")
return
if reverse:
items = reversed(items)
statuses = [from_dict(Status, item) for item in items]
print_timeline(statuses)
if once or not sys.stdout.isatty():
break
char = input("\nContinue? [Y/n] ")
if char.lower() == "n":
break
def _get_list_id(ctx: Context, value: Optional[str]) -> Optional[str]:
if not value:
return None
lists = api.get_lists(ctx.app, ctx.user)
for list in lists:
if list["id"] == value or list["title"] == value:
return list["id"]