Rename toot to witchie
This commit is contained in:
parent
1c5abb8419
commit
41fff21b8d
36 changed files with 157 additions and 166 deletions
6
Makefile
6
Makefile
|
@ -10,7 +10,7 @@ publish :
|
|||
test:
|
||||
pytest -v
|
||||
flake8
|
||||
vermin toot
|
||||
vermin witchie
|
||||
|
||||
coverage:
|
||||
coverage erase
|
||||
|
@ -20,7 +20,7 @@ coverage:
|
|||
|
||||
clean :
|
||||
find . -name "*pyc" | xargs rm -rf $1
|
||||
rm -rf build dist MANIFEST htmlcov toot*.tar.gz
|
||||
rm -rf build dist MANIFEST htmlcov witchie*.tar.gz
|
||||
|
||||
changelog:
|
||||
./scripts/generate_changelog > CHANGELOG.md
|
||||
|
@ -33,4 +33,4 @@ docs-serve:
|
|||
mdbook serve
|
||||
|
||||
docs-deploy: docs
|
||||
rsync --archive --compress --delete --stats book/ bezdomni:web/toot
|
||||
rsync --archive --compress --delete --stats book/ bezdomni:web/witchie
|
||||
|
|
30
README.rst
30
README.rst
|
@ -1,27 +1,16 @@
|
|||
============================
|
||||
Toot - a Mastodon CLI client
|
||||
Witchie - an Akkoma CLI client
|
||||
============================
|
||||
|
||||
.. image:: https://raw.githubusercontent.com/ihabunek/toot/master/trumpet.png
|
||||
|
||||
Toot is a CLI and TUI tool for interacting with Mastodon instances from the command line.
|
||||
|
||||
.. image:: https://img.shields.io/badge/author-%40ihabunek-blue.svg?maxAge=3600&style=flat-square
|
||||
:target: https://mastodon.social/@ihabunek
|
||||
.. image:: https://img.shields.io/github/license/ihabunek/toot.svg?maxAge=3600&style=flat-square
|
||||
:target: https://opensource.org/licenses/GPL-3.0
|
||||
.. image:: https://img.shields.io/pypi/v/toot.svg?maxAge=3600&style=flat-square
|
||||
:target: https://pypi.python.org/pypi/toot
|
||||
Witchie is a CLI and TUI tool for interacting with Akkoma instances from the command line.
|
||||
It is a fork of [ibuhanek's toot](https://github.com/ihabunek/toot) for Mastodon.
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
* Homepage: https://github.com/ihabunek/toot
|
||||
* Issues: https://github.com/ihabunek/toot/issues
|
||||
* Documentation: https://toot.bezdomni.net/
|
||||
* Mailing list for discussion, support and patches:
|
||||
https://lists.sr.ht/~ihabunek/toot-discuss
|
||||
* Informal discussion: #toot IRC channel on `libera.chat <https://libera.chat/>`_
|
||||
* Homepage: https://sr.ht/~huyngo/witchie
|
||||
* Mailing list for discussion: https://lists.sr.ht/~huyngo/witchie
|
||||
* Bugs/feature requests: https://todo.sr.ht/~huyngo/witchie
|
||||
|
||||
Features
|
||||
--------
|
||||
|
@ -30,12 +19,12 @@ Features
|
|||
* Support for media uploads, spoiler text, sensitive content
|
||||
* Search by account or hash tag
|
||||
* Following, muting and blocking accounts
|
||||
* Simple switching between authenticated in Mastodon accounts
|
||||
* Simple switching between authenticated accounts
|
||||
|
||||
Terminal User Interface
|
||||
-----------------------
|
||||
|
||||
toot includes a terminal user interface (TUI). Run it with ``toot tui``.
|
||||
witchie includes a terminal user interface (TUI). Run it with ``witchie tui``.
|
||||
|
||||
.. image :: https://raw.githubusercontent.com/ihabunek/toot/master/docs/images/tui_list.png
|
||||
|
||||
|
@ -45,6 +34,7 @@ toot includes a terminal user interface (TUI). Run it with ``toot tui``.
|
|||
License
|
||||
-------
|
||||
|
||||
Copyright Ivan Habunek <ivan@habunek.com> and contributors.
|
||||
Copyright 2017-2023 Ivan Habunek <ivan@habunek.com> and contributors.
|
||||
Copyright 2023 Ngô Ngọc Đức Huy <huyngo@disroot.org>
|
||||
|
||||
Licensed under `GPLv3 <http://www.gnu.org/licenses/gpl-3.0.html>`_, see `LICENSE <LICENSE>`_.
|
||||
|
|
18
setup.py
18
setup.py
|
@ -3,7 +3,7 @@
|
|||
from setuptools import setup
|
||||
|
||||
long_description = """
|
||||
Toot is a CLI and TUI tool for interacting with Mastodon instances from the
|
||||
Witchie is a CLI and TUI tool for interacting with Akkoma instances from the
|
||||
command line.
|
||||
|
||||
Allows posting text and media to the timeline, searching, following, muting
|
||||
|
@ -11,18 +11,18 @@ and blocking accounts and other actions.
|
|||
"""
|
||||
|
||||
setup(
|
||||
name='toot',
|
||||
name='witchie',
|
||||
version='0.39.0',
|
||||
description='Mastodon CLI client',
|
||||
description='Akkoma CLI client',
|
||||
long_description=long_description.strip(),
|
||||
author='Ivan Habunek',
|
||||
author_email='ivan@habunek.com',
|
||||
url='https://github.com/ihabunek/toot/',
|
||||
author='Ngô Ngọc Đức Huy',
|
||||
author_email='huyngo@disroot.org',
|
||||
url='https://git.sr.ht/~huyngo/witchie/',
|
||||
project_urls={
|
||||
'Documentation': 'https://toot.bezdomni.net/',
|
||||
'Issue tracker': 'https://github.com/ihabunek/toot/issues/',
|
||||
'Issue tracker': 'https://todo.sr.ht/~huyngo/witchie/',
|
||||
},
|
||||
keywords='mastodon toot',
|
||||
keywords='akkoma',
|
||||
license='GPLv3',
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
|
@ -31,7 +31,7 @@ setup(
|
|||
'License :: OSI Approved :: GNU General Public License v3 (GPLv3)',
|
||||
'Programming Language :: Python :: 3',
|
||||
],
|
||||
packages=['toot', 'toot.tui', 'toot.tui.richtext', 'toot.utils'],
|
||||
packages=['akkoma', 'akkoma.tui', 'akkoma.tui.richtext', 'akkoma.utils'],
|
||||
python_requires=">=3.7",
|
||||
install_requires=[
|
||||
"requests>=2.13,<3.0",
|
||||
|
|
BIN
trumpet.png
BIN
trumpet.png
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
|
@ -11,24 +11,24 @@ User = namedtuple('User', ['instance', 'username', 'access_token'])
|
|||
|
||||
DEFAULT_INSTANCE = 'https://mastodon.social'
|
||||
|
||||
CLIENT_NAME = 'toot - a Mastodon CLI client'
|
||||
CLIENT_WEBSITE = 'https://github.com/ihabunek/toot'
|
||||
CLIENT_NAME = 'witchie - an Akkoma CLI client'
|
||||
CLIENT_WEBSITE = 'https://sr.ht/~huyngo/witchie'
|
||||
|
||||
TOOT_CONFIG_DIR_NAME = "toot"
|
||||
CONFIG_DIR_NAME = "witchie"
|
||||
|
||||
|
||||
def get_config_dir():
|
||||
"""Returns the path to toot config directory"""
|
||||
"""Returns the path to witchie config directory"""
|
||||
|
||||
# On Windows, store the config in roaming appdata
|
||||
if sys.platform == "win32" and "APPDATA" in os.environ:
|
||||
return join(os.getenv("APPDATA"), TOOT_CONFIG_DIR_NAME)
|
||||
return join(os.getenv("APPDATA"), CONFIG_DIR_NAME)
|
||||
|
||||
# Respect XDG_CONFIG_HOME env variable if set
|
||||
# https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
||||
if "XDG_CONFIG_HOME" in os.environ:
|
||||
config_home = expanduser(os.environ["XDG_CONFIG_HOME"])
|
||||
return join(config_home, TOOT_CONFIG_DIR_NAME)
|
||||
return join(config_home, CONFIG_DIR_NAME)
|
||||
|
||||
# Default to ~/.config/toot/
|
||||
return join(expanduser("~"), ".config", TOOT_CONFIG_DIR_NAME)
|
||||
# Default to ~/.config/witchie/
|
||||
return join(expanduser("~"), ".config", CONFIG_DIR_NAME)
|
|
@ -7,9 +7,9 @@ from requests import Response
|
|||
from typing import BinaryIO, List, Optional
|
||||
from urllib.parse import urlparse, urlencode, quote
|
||||
|
||||
from toot import App, User, http, CLIENT_NAME, CLIENT_WEBSITE
|
||||
from toot.exceptions import AuthenticationError, ConsoleError
|
||||
from toot.utils import drop_empty_values, str_bool, str_bool_nullable
|
||||
from witchie import App, User, http, CLIENT_NAME, CLIENT_WEBSITE
|
||||
from witchie.exceptions import AuthenticationError, ConsoleError
|
||||
from witchie.utils import drop_empty_values, str_bool, str_bool_nullable
|
||||
|
||||
|
||||
SCOPES = 'read write follow'
|
||||
|
@ -255,7 +255,7 @@ def scheduled_statuses(app, user):
|
|||
def delete_status(app, user, status_id):
|
||||
"""
|
||||
Deletes a status with given ID.
|
||||
https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#deleting-a-status
|
||||
https://docs.joinmastodon.org/methods/statuses/#delete
|
||||
"""
|
||||
return http.delete(app, user, f"/api/v1/statuses/{status_id}")
|
||||
|
|
@ -4,9 +4,9 @@ import webbrowser
|
|||
from builtins import input
|
||||
from getpass import getpass
|
||||
|
||||
from toot import api, config, DEFAULT_INSTANCE, User, App
|
||||
from toot.exceptions import ApiError, ConsoleError
|
||||
from toot.output import print_out
|
||||
from witchie import api, config, DEFAULT_INSTANCE, User, App
|
||||
from witchie.exceptions import ApiError, ConsoleError
|
||||
from witchie.output import print_out
|
||||
from urllib.parse import urlparse
|
||||
|
||||
|
||||
|
@ -104,8 +104,8 @@ def login_interactive(app, email=None):
|
|||
|
||||
|
||||
BROWSER_LOGIN_EXPLANATION = """
|
||||
This authentication method requires you to log into your Mastodon instance
|
||||
in your browser, where you will be asked to authorize <yellow>toot</yellow> to access
|
||||
This authentication method requires you to log into your Akkoma instance
|
||||
in your browser, where you will be asked to authorize <yellow>witchie</yellow> to access
|
||||
your account. When you do, you will be given an <yellow>authorization code</yellow>
|
||||
which you need to paste here.
|
||||
"""
|
|
@ -6,15 +6,15 @@ import platform
|
|||
from datetime import datetime, timedelta, timezone
|
||||
from time import sleep, time
|
||||
|
||||
from toot import api, config, __version__
|
||||
from toot.auth import login_interactive, login_browser_interactive, create_app_interactive
|
||||
from toot.entities import Account, Instance, Notification, Status, from_dict
|
||||
from toot.exceptions import ApiError, ConsoleError
|
||||
from toot.output import (print_lists, print_out, print_instance, print_account, print_acct_list,
|
||||
from witchie import api, config, __version__
|
||||
from witchie.auth import login_interactive, login_browser_interactive, create_app_interactive
|
||||
from witchie.entities import Account, Instance, Notification, Status, from_dict
|
||||
from witchie.exceptions import ApiError, ConsoleError
|
||||
from witchie.output import (print_lists, print_out, print_instance, print_account, print_acct_list,
|
||||
print_search_results, print_status, print_table, print_timeline, print_notifications,
|
||||
print_tag_list, print_list_accounts, print_user_list)
|
||||
from toot.utils import args_get_instance, delete_tmp_status_file, editor_input, multiline_input, EOF_KEY
|
||||
from toot.utils.datetime import parse_datetime
|
||||
from witchie.utils import args_get_instance, delete_tmp_status_file, editor_input, multiline_input, EOF_KEY
|
||||
from witchie.utils.datetime import parse_datetime
|
||||
|
||||
|
||||
def get_timeline_generator(app, user, args):
|
||||
|
@ -85,10 +85,10 @@ def thread(app, user, args):
|
|||
if args.json:
|
||||
print(context_response.text)
|
||||
else:
|
||||
toot = api.fetch_status(app, user, args.status_id).json()
|
||||
post = api.fetch_status(app, user, args.status_id).json()
|
||||
context = context_response.json()
|
||||
|
||||
statuses = chain(context["ancestors"], [toot], context["descendants"])
|
||||
statuses = chain(context["ancestors"], [post], context["descendants"])
|
||||
print_timeline(from_dict(Status, s) for s in statuses)
|
||||
|
||||
|
||||
|
@ -129,9 +129,9 @@ def post(app, user, args):
|
|||
if "scheduled_at" in status:
|
||||
scheduled_at = parse_datetime(status["scheduled_at"])
|
||||
scheduled_at = datetime.strftime(scheduled_at, "%Y-%m-%d %H:%M:%S%z")
|
||||
print_out(f"Toot scheduled for: <green>{scheduled_at}</green>")
|
||||
print_out(f"Post scheduled for: <green>{scheduled_at}</green>")
|
||||
else:
|
||||
print_out(f"Toot posted: <green>{status['url']}")
|
||||
print_out(f"Post posted: <green>{status['url']}")
|
||||
|
||||
delete_tmp_status_file()
|
||||
|
||||
|
@ -146,7 +146,7 @@ def _get_status_text(text, editor, media):
|
|||
if editor:
|
||||
text = editor_input(editor, text)
|
||||
elif not text and not media:
|
||||
print_out("Write or paste your toot. Press <yellow>{}</yellow> to post it.".format(EOF_KEY))
|
||||
print_out("Write or paste your post. Press <yellow>{}</yellow> to post it.".format(EOF_KEY))
|
||||
text = multiline_input()
|
||||
|
||||
return text
|
||||
|
@ -318,7 +318,7 @@ def auth(app, user, args):
|
|||
|
||||
|
||||
def env(app, user, args):
|
||||
print_out(f"toot {__version__}")
|
||||
print_out(f"witchie {__version__}")
|
||||
print_out(f"Python {sys.version}")
|
||||
print_out(platform.platform())
|
||||
|
|
@ -4,17 +4,17 @@ import os
|
|||
from functools import wraps
|
||||
from os.path import dirname, join
|
||||
|
||||
from toot import User, App, get_config_dir
|
||||
from toot.exceptions import ConsoleError
|
||||
from toot.output import print_out
|
||||
from witchie import User, App, get_config_dir
|
||||
from witchie.exceptions import ConsoleError
|
||||
from witchie.output import print_out
|
||||
|
||||
|
||||
TOOT_CONFIG_FILE_NAME = "config.json"
|
||||
WITCHIE_CONFIG_FILE_NAME = "config.json"
|
||||
|
||||
|
||||
def get_config_file_path():
|
||||
"""Returns the path to toot config file."""
|
||||
return join(get_config_dir(), TOOT_CONFIG_FILE_NAME)
|
||||
"""Returns the path to witchie config file."""
|
||||
return join(get_config_dir(), WITCHIE_CONFIG_FILE_NAME)
|
||||
|
||||
|
||||
def user_id(user):
|
||||
|
@ -22,7 +22,7 @@ def user_id(user):
|
|||
|
||||
|
||||
def make_config(path):
|
||||
"""Creates an empty toot configuration file."""
|
||||
"""Creates an empty witchie configuration file."""
|
||||
config = {
|
||||
"apps": {},
|
||||
"users": {},
|
|
@ -7,10 +7,10 @@ import sys
|
|||
from argparse import ArgumentParser, FileType, ArgumentTypeError, Action
|
||||
from collections import namedtuple
|
||||
from itertools import chain
|
||||
from toot import config, commands, CLIENT_NAME, CLIENT_WEBSITE, __version__, settings
|
||||
from toot.exceptions import ApiError, ConsoleError
|
||||
from toot.output import print_out, print_err
|
||||
from toot.settings import get_setting
|
||||
from witchie import config, commands, CLIENT_NAME, CLIENT_WEBSITE, __version__, settings
|
||||
from witchie.exceptions import ApiError, ConsoleError
|
||||
from witchie.output import print_out, print_err
|
||||
from witchie.settings import get_setting
|
||||
|
||||
VISIBILITY_CHOICES = ["public", "unlisted", "private", "direct"]
|
||||
VISIBILITY_CHOICES_STR = ", ".join(f"'{v}'" for v in VISIBILITY_CHOICES)
|
||||
|
@ -62,7 +62,7 @@ class BooleanOptionalAction(Action):
|
|||
|
||||
|
||||
def get_default_visibility():
|
||||
return os.getenv("TOOT_POST_VISIBILITY", "public")
|
||||
return os.getenv("WITCHIE_POST_VISIBILITY", "public")
|
||||
|
||||
|
||||
def language(value):
|
||||
|
@ -94,8 +94,8 @@ def privacy(value):
|
|||
|
||||
def timeline_count(value):
|
||||
n = int(value)
|
||||
if not 0 < n <= 20:
|
||||
raise ArgumentTypeError("Number of toots should be between 1 and 20.")
|
||||
if not 0 < n <= 40:
|
||||
raise ArgumentTypeError("Number of posts should be between 1 and 40.")
|
||||
return n
|
||||
|
||||
|
||||
|
@ -225,7 +225,7 @@ visibility_arg = (["-v", "--visibility"], {
|
|||
"default": get_default_visibility(),
|
||||
"help": f"Post visibility. One of: {VISIBILITY_CHOICES_STR}. Defaults to "
|
||||
f"'{get_default_visibility()}' which can be overridden by setting "
|
||||
"the TOOT_POST_VISIBILITY environment variable",
|
||||
"the WITCHIE_POST_VISIBILITY environment variable",
|
||||
})
|
||||
|
||||
tag_arg = (["tag_name"], {
|
||||
|
@ -239,7 +239,7 @@ json_arg = (["--json"], {
|
|||
"help": "print json instead of plaintext",
|
||||
})
|
||||
|
||||
# Arguments for selecting a timeline (see `toot.commands.get_timeline_generator`)
|
||||
# Arguments for selecting a timeline (see `witchie.commands.get_timeline_generator`)
|
||||
common_timeline_args = [
|
||||
(["-p", "--public"], {
|
||||
"action": "store_true",
|
||||
|
@ -272,7 +272,7 @@ common_timeline_args = [
|
|||
timeline_and_bookmark_args = [
|
||||
(["-c", "--count"], {
|
||||
"type": timeline_count,
|
||||
"help": "number of toots to show per page (1-20, default 10).",
|
||||
"help": "number of posts to show per page (1-40, default 10).",
|
||||
"default": 10,
|
||||
}),
|
||||
(["-r", "--reverse"], {
|
||||
|
@ -283,7 +283,7 @@ timeline_and_bookmark_args = [
|
|||
(["-1", "--once"], {
|
||||
"action": "store_true",
|
||||
"default": False,
|
||||
"help": "Only show the first <count> toots, do not prompt to continue.",
|
||||
"help": "Only show the first <count> posts, do not prompt to continue.",
|
||||
}),
|
||||
]
|
||||
|
||||
|
@ -379,7 +379,7 @@ AUTH_COMMANDS = [
|
|||
TUI_COMMANDS = [
|
||||
Command(
|
||||
name="tui",
|
||||
description="Launches the toot terminal user interface",
|
||||
description="Launches the post terminal user interface",
|
||||
arguments=[
|
||||
(["--relative-datetimes"], {
|
||||
"action": "store_true",
|
||||
|
@ -463,10 +463,10 @@ READ_COMMANDS = [
|
|||
),
|
||||
Command(
|
||||
name="thread",
|
||||
description="Show toot thread items",
|
||||
description="Show post thread items",
|
||||
arguments=[
|
||||
(["status_id"], {
|
||||
"help": "Show thread for toot.",
|
||||
"help": "Show thread for post.",
|
||||
}),
|
||||
json_arg,
|
||||
],
|
||||
|
@ -540,13 +540,13 @@ POST_COMMANDS = [
|
|||
}),
|
||||
(["-l", "--language"], {
|
||||
"type": language,
|
||||
"help": "ISO 639-1 language code of the toot, to skip automatic detection",
|
||||
"help": "ISO 639-1 language code of the post, to skip automatic detection",
|
||||
}),
|
||||
(["-e", "--editor"], {
|
||||
"type": editor,
|
||||
"nargs": "?",
|
||||
"const": os.getenv("EDITOR", ""), # option given without value
|
||||
"help": "Specify an editor to compose your toot, "
|
||||
"help": "Specify an editor to compose your post, "
|
||||
"defaults to editor defined in $EDITOR env variable.",
|
||||
}),
|
||||
(["--scheduled-at"], {
|
||||
|
@ -556,7 +556,7 @@ POST_COMMANDS = [
|
|||
}),
|
||||
(["--scheduled-in"], {
|
||||
"type": duration,
|
||||
"help": f"""Schedule the toot to be posted after a given amount
|
||||
"help": f"""Schedule the post to be posted after a given amount
|
||||
of time, {DURATION_EXAMPLES}. Must be at least 5
|
||||
minutes.""",
|
||||
}),
|
||||
|
@ -876,18 +876,18 @@ def print_usage():
|
|||
|
||||
for cmd in cmds:
|
||||
cmd_name = cmd.name.ljust(max_name_len + 2)
|
||||
print_out(" <yellow>toot {}</yellow> {}".format(cmd_name, cmd.description))
|
||||
print_out(" <yellow>witchie {}</yellow> {}".format(cmd_name, cmd.description))
|
||||
|
||||
print_out("")
|
||||
print_out("To get help for each command run:")
|
||||
print_out(" <yellow>toot \\<command> --help</yellow>")
|
||||
print_out(" <yellow>witchie \\<command> --help</yellow>")
|
||||
print_out("")
|
||||
print_out("<green>{}</green>".format(CLIENT_WEBSITE))
|
||||
|
||||
|
||||
def get_argument_parser(name, command):
|
||||
parser = ArgumentParser(
|
||||
prog='toot %s' % name,
|
||||
prog='witchie %s' % name,
|
||||
description=command.description,
|
||||
epilog=CLIENT_WEBSITE)
|
||||
|
||||
|
@ -918,7 +918,7 @@ def run_command(app, user, name, args):
|
|||
|
||||
if not command:
|
||||
print_err(f"Unknown command '{name}'")
|
||||
print_out("Run <yellow>toot --help</yellow> to show a list of available commands.")
|
||||
print_out("Run <yellow>witchie --help</yellow> to show a list of available commands.")
|
||||
return
|
||||
|
||||
parser = get_argument_parser(name, command)
|
||||
|
@ -932,7 +932,7 @@ def run_command(app, user, name, args):
|
|||
|
||||
if command.require_auth and (not user or not app):
|
||||
print_err("This command requires that you are logged in.")
|
||||
print_err("Please run `toot login` first.")
|
||||
print_err("Please run `witchie login` first.")
|
||||
return
|
||||
|
||||
fn = commands.__dict__.get(name)
|
|
@ -1,7 +1,7 @@
|
|||
"""
|
||||
Dataclasses which represent entities returned by the Mastodon API.
|
||||
|
||||
Data classes my have an optional static method named `__toot_prepare__` which is
|
||||
Data classes my have an optional static method named `__post_prepare__` which is
|
||||
used when constructing the data class using `from_dict`. The method will be
|
||||
called with the dict and may modify it and return a modified dict. This is used
|
||||
to implement any pre-processing which may be required, e.g. to support
|
||||
|
@ -16,9 +16,9 @@ from functools import lru_cache
|
|||
from typing import Any, Dict, List, Optional, Tuple, Type, TypeVar, Union
|
||||
from typing import get_type_hints
|
||||
|
||||
from toot.typing_compat import get_args, get_origin
|
||||
from toot.utils import get_text
|
||||
from toot.utils.datetime import parse_datetime
|
||||
from witchie.typing_compat import get_args, get_origin
|
||||
from witchie.utils import get_text
|
||||
from witchie.utils.datetime import parse_datetime
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -76,7 +76,7 @@ class Account:
|
|||
source: Optional[dict]
|
||||
|
||||
@staticmethod
|
||||
def __toot_prepare__(obj: Dict) -> Dict:
|
||||
def __post_prepare__(obj: Dict) -> Dict:
|
||||
# Pleroma has not yet converted last_status_at from datetime to date
|
||||
# so trim it here so it doesn't break when converting to date.
|
||||
# See: https://git.pleroma.social/pleroma/pleroma/-/issues/1470
|
||||
|
@ -266,7 +266,8 @@ class Status:
|
|||
return self.reblog or self
|
||||
|
||||
@staticmethod
|
||||
def __toot_prepare__(obj: Dict) -> Dict:
|
||||
def __post_prepare__(obj: Dict) -> Dict:
|
||||
# TODO: check this
|
||||
# Pleroma has a bug where created_at is set to an empty string.
|
||||
# To avoid marking created_at as optional, which would require work
|
||||
# because we count on it always existing, set it to current datetime.
|
||||
|
@ -430,8 +431,8 @@ class ConversionError(Exception):
|
|||
|
||||
def from_dict(cls: Type[T], data: Dict) -> T:
|
||||
"""Convert a nested dict into an instance of `cls`."""
|
||||
# Apply __toot_prepare__ if it exists
|
||||
prepare = getattr(cls, '__toot_prepare__', None)
|
||||
# Apply __post_prepare__ if it exists
|
||||
prepare = getattr(cls, '__post_prepare__', None)
|
||||
if prepare:
|
||||
data = prepare(data)
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
from requests import Request, Session
|
||||
from requests.exceptions import RequestException
|
||||
|
||||
from toot import __version__
|
||||
from toot.exceptions import NotFoundError, ApiError
|
||||
from toot.logging import log_request, log_request_exception, log_response
|
||||
from witchie import __version__
|
||||
from witchie.exceptions import NotFoundError, ApiError
|
||||
from witchie.logging import log_request, log_request_exception, log_response
|
||||
|
||||
|
||||
def send_request(request, allow_redirects=True):
|
||||
# Set a user agent string
|
||||
# Required for accessing instances using Cloudfront DDOS protection.
|
||||
request.headers["User-Agent"] = "toot/{}".format(__version__)
|
||||
request.headers["User-Agent"] = "witchie/{}".format(__version__)
|
||||
|
||||
log_request(request)
|
||||
|
|
@ -5,7 +5,7 @@ from logging import getLogger
|
|||
from requests import Request, RequestException, Response
|
||||
from urllib.parse import urlencode
|
||||
|
||||
logger = getLogger("toot")
|
||||
logger = getLogger("witchie")
|
||||
|
||||
VERBOSE = "--verbose" in sys.argv
|
||||
|
|
@ -4,10 +4,10 @@ import sys
|
|||
import textwrap
|
||||
|
||||
from functools import lru_cache
|
||||
from toot import settings
|
||||
from toot.utils import get_text, html_to_paragraphs
|
||||
from toot.entities import Account, Instance, Notification, Poll, Status
|
||||
from toot.wcstring import wc_wrap
|
||||
from witchie import settings
|
||||
from witchie.utils import get_text, html_to_paragraphs
|
||||
from witchie.entities import Account, Instance, Notification, Poll, Status
|
||||
from witchie.wcstring import wc_wrap
|
||||
from typing import Iterable, List
|
||||
from wcwidth import wcswidth
|
||||
|
|
@ -4,17 +4,17 @@ import sys
|
|||
from functools import lru_cache
|
||||
from os.path import exists, join
|
||||
from tomlkit import parse
|
||||
from toot import get_config_dir
|
||||
from witchie import get_config_dir
|
||||
from typing import Optional, Type, TypeVar
|
||||
|
||||
|
||||
DISABLE_SETTINGS = False
|
||||
|
||||
TOOT_SETTINGS_FILE_NAME = "settings.toml"
|
||||
WITCHIE_SETTINGS_FILE_NAME = "settings.toml"
|
||||
|
||||
|
||||
def get_settings_path():
|
||||
return join(get_config_dir(), TOOT_SETTINGS_FILE_NAME)
|
||||
return join(get_config_dir(), WITCHIE_SETTINGS_FILE_NAME)
|
||||
|
||||
|
||||
def load_settings() -> dict:
|
||||
|
@ -72,7 +72,7 @@ def get_debug() -> bool:
|
|||
|
||||
|
||||
def get_debug_file() -> Optional[str]:
|
||||
from_env = os.getenv("TOOT_LOG_FILE")
|
||||
from_env = os.getenv("WITCHIE_LOG_FILE")
|
||||
if from_env:
|
||||
return from_env
|
||||
|
|
@ -4,9 +4,9 @@ import urwid
|
|||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
from toot import api, config, __version__, settings
|
||||
from toot.console import get_default_visibility
|
||||
from toot.exceptions import ApiError
|
||||
from witchie import api, config, __version__, settings
|
||||
from witchie.console import get_default_visibility
|
||||
from witchie.exceptions import ApiError
|
||||
|
||||
from .compose import StatusComposer
|
||||
from .constants import PALETTE
|
||||
|
@ -15,14 +15,14 @@ from .overlays import ExceptionStackTrace, GotoMenu, Help, StatusSource, StatusL
|
|||
from .overlays import StatusDeleteConfirmation, Account
|
||||
from .poll import Poll
|
||||
from .timeline import Timeline
|
||||
from .utils import get_max_toot_chars, parse_content_links, copy_to_clipboard
|
||||
from .utils import get_max_post_chars, parse_content_links, copy_to_clipboard
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
urwid.set_encoding('UTF-8')
|
||||
|
||||
|
||||
DEFAULT_MAX_TOOT_CHARS = 500
|
||||
DEFAULT_MAX_POST_CHARS = 500
|
||||
|
||||
|
||||
class Header(urwid.WidgetWrap):
|
||||
|
@ -32,7 +32,7 @@ class Header(urwid.WidgetWrap):
|
|||
|
||||
self.text = urwid.Text("")
|
||||
self.cols = urwid.Columns([
|
||||
("pack", urwid.Text(('header_bold', 'toot'))),
|
||||
("pack", urwid.Text(('header_bold', 'post'))),
|
||||
("pack", urwid.Text(('header', ' | {}@{}'.format(user.username, app.instance)))),
|
||||
("pack", self.text),
|
||||
])
|
||||
|
@ -124,14 +124,14 @@ class TUI(urwid.Frame):
|
|||
self.executor = ThreadPoolExecutor(max_workers=1)
|
||||
self.timeline_generator = api.home_timeline_generator(app, user, limit=40)
|
||||
|
||||
# Show intro screen while toots are being loaded
|
||||
# Show intro screen while posts are being loaded
|
||||
self.body = self.build_intro()
|
||||
self.header = Header(app, user)
|
||||
self.footer = Footer()
|
||||
self.footer.set_status("Loading...")
|
||||
|
||||
# Default max status length, updated on startup
|
||||
self.max_toot_chars = DEFAULT_MAX_TOOT_CHARS
|
||||
self.max_post_chars = DEFAULT_MAX_POST_CHARS
|
||||
|
||||
self.timeline = None
|
||||
self.overlay = None
|
||||
|
@ -157,7 +157,7 @@ class TUI(urwid.Frame):
|
|||
# NB: Padding with width="clip" will convert the fixed BigText widget
|
||||
# to a flow widget so it can be used in a Pile.
|
||||
|
||||
big_text = "Toot {}".format(__version__)
|
||||
big_text = "Witchie {}".format(__version__)
|
||||
big_text = urwid.BigText(("intro_bigtext", big_text), font)
|
||||
big_text = urwid.Padding(big_text, align="center", width="clip")
|
||||
|
||||
|
@ -170,7 +170,7 @@ class TUI(urwid.Frame):
|
|||
" and contributors"
|
||||
], align="center"),
|
||||
urwid.Divider(),
|
||||
urwid.Text(("intro_smalltext", "Loading toots..."), align="center"),
|
||||
urwid.Text(("intro_smalltext", "Loading posts..."), align="center"),
|
||||
])
|
||||
|
||||
return urwid.Filler(intro)
|
||||
|
@ -296,7 +296,7 @@ class TUI(urwid.Frame):
|
|||
|
||||
def async_load_instance(self):
|
||||
"""
|
||||
Attempt to update max_toot_chars from instance data.
|
||||
Attempt to update max_post_chars from instance data.
|
||||
Does not work on vanilla Mastodon, works on Pleroma.
|
||||
See: https://github.com/tootsuite/mastodon/issues/4915
|
||||
|
||||
|
@ -309,8 +309,8 @@ class TUI(urwid.Frame):
|
|||
return api.get_instance(self.app.base_url).json()
|
||||
|
||||
def _done(instance):
|
||||
self.max_toot_chars = get_max_toot_chars(instance, DEFAULT_MAX_TOOT_CHARS)
|
||||
logger.info(f"Max toot chars set to: {self.max_toot_chars}")
|
||||
self.max_post_chars = get_max_post_chars(instance, DEFAULT_MAX_POST_CHARS)
|
||||
logger.info(f"Max post chars set to: {self.max_post_chars}")
|
||||
|
||||
if "translation" in instance:
|
||||
# instance is advertising translation service
|
||||
|
@ -400,7 +400,7 @@ class TUI(urwid.Frame):
|
|||
def _post(timeline, *args):
|
||||
self.post_status(*args)
|
||||
|
||||
composer = StatusComposer(self.max_toot_chars, self.user.username, in_reply_to)
|
||||
composer = StatusComposer(self.max_post_chars, self.user.username, in_reply_to)
|
||||
urwid.connect_signal(composer, "close", _close)
|
||||
urwid.connect_signal(composer, "post", _post)
|
||||
self.open_overlay(composer, title="Compose status")
|
|
@ -1,7 +1,7 @@
|
|||
import urwid
|
||||
import logging
|
||||
|
||||
from toot.console import get_default_visibility
|
||||
from witchie.console import get_default_visibility
|
||||
|
||||
from .constants import VISIBILITY_OPTIONS
|
||||
from .widgets import Button, EditBox
|
|
@ -1,6 +1,6 @@
|
|||
from collections import namedtuple
|
||||
|
||||
from toot.utils.datetime import parse_datetime
|
||||
from witchie.utils.datetime import parse_datetime
|
||||
|
||||
Author = namedtuple("Author", ["account", "display_name", "username"])
|
||||
|
|
@ -3,11 +3,11 @@ import traceback
|
|||
import urwid
|
||||
import webbrowser
|
||||
|
||||
from toot import __version__
|
||||
from toot import api
|
||||
from toot.tui.utils import highlight_keys
|
||||
from toot.tui.widgets import Button, EditBox, SelectableText
|
||||
from toot.tui.richtext import html_to_widgets
|
||||
from witchie import __version__
|
||||
from witchie import api
|
||||
from witchie.tui.utils import highlight_keys
|
||||
from witchie.tui.widgets import Button, EditBox, SelectableText
|
||||
from witchie.tui.richtext import html_to_widgets
|
||||
|
||||
|
||||
class StatusSource(urwid.Padding):
|
||||
|
@ -198,7 +198,7 @@ class Help(urwid.Padding):
|
|||
def h(text):
|
||||
return highlight_keys(text, "shortcut")
|
||||
|
||||
yield urwid.Text(("bold", "toot {}".format(__version__)))
|
||||
yield urwid.Text(("bold", "witchie {}".format(__version__)))
|
||||
yield urwid.Divider()
|
||||
yield urwid.Text(("bold", "General usage"))
|
||||
yield urwid.Divider()
|
||||
|
@ -209,7 +209,7 @@ class Help(urwid.Padding):
|
|||
yield urwid.Divider()
|
||||
yield urwid.Text(("bold", "General keys"))
|
||||
yield urwid.Divider()
|
||||
yield urwid.Text(h(" [Q] - quit toot"))
|
||||
yield urwid.Text(h(" [Q] - quit witchie"))
|
||||
yield urwid.Text(h(" [G] - go to - switch timelines"))
|
||||
yield urwid.Text(h(" [E] - save/unsave (pin) current timeline"))
|
||||
yield urwid.Text(h(" [,] - refresh current timeline"))
|
||||
|
@ -236,7 +236,7 @@ class Help(urwid.Padding):
|
|||
yield urwid.Text(("bold", "Links"))
|
||||
yield urwid.Divider()
|
||||
yield link("Documentation: ", "https://toot.bezdomni.net/")
|
||||
yield link("Project home: ", "https://github.com/ihabunek/toot/")
|
||||
yield link("Project home: ", "https://sr.ht/~huyngo/witchie")
|
||||
|
||||
|
||||
class Account(urwid.ListBox):
|
|
@ -1,8 +1,8 @@
|
|||
import urwid
|
||||
|
||||
from toot import api
|
||||
from toot.exceptions import ApiError
|
||||
from toot.utils.datetime import parse_datetime
|
||||
from witchie import api
|
||||
from witchie.exceptions import ApiError
|
||||
from witchie.utils.datetime import parse_datetime
|
||||
from .widgets import Button, CheckBox, RadioButton
|
||||
from .richtext import html_to_widgets
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import urwid
|
||||
|
||||
from toot.tui.utils import highlight_hashtags
|
||||
from toot.utils import format_content
|
||||
from witchie.tui.utils import highlight_hashtags
|
||||
from witchie.utils import format_content
|
||||
from typing import List
|
||||
|
||||
try:
|
|
@ -3,8 +3,8 @@ import urwid
|
|||
import unicodedata
|
||||
|
||||
from bs4.element import NavigableString, Tag
|
||||
from toot.tui.constants import PALETTE
|
||||
from toot.utils import parse_html, urlencode_url
|
||||
from witchie.tui.constants import PALETTE
|
||||
from witchie.utils import parse_html, urlencode_url
|
||||
from typing import List, Tuple
|
||||
from urwid.util import decompose_tagmarkup
|
||||
from urwidgets import Hyperlink, TextEmbed
|
|
@ -4,17 +4,17 @@ import webbrowser
|
|||
|
||||
from typing import List, Optional
|
||||
|
||||
from toot.tui import app
|
||||
from toot.tui.richtext import html_to_widgets, url_to_widget
|
||||
from toot.utils.datetime import parse_datetime, time_ago
|
||||
from toot.utils.language import language_name
|
||||
from witchie.tui import app
|
||||
from witchie.tui.richtext import html_to_widgets, url_to_widget
|
||||
from witchie.utils.datetime import parse_datetime, time_ago
|
||||
from witchie.utils.language import language_name
|
||||
|
||||
from toot.entities import Status
|
||||
from toot.tui.scroll import Scrollable, ScrollBar
|
||||
from toot.tui.utils import highlight_keys
|
||||
from toot.tui.widgets import SelectableText, SelectableColumns
|
||||
from witchie.entities import Status
|
||||
from witchie.tui.scroll import Scrollable, ScrollBar
|
||||
from witchie.tui.utils import highlight_keys
|
||||
from witchie.tui.widgets import SelectableText, SelectableColumns
|
||||
|
||||
logger = logging.getLogger("toot")
|
||||
logger = logging.getLogger("witchie")
|
||||
|
||||
|
||||
class Timeline(urwid.Columns):
|
|
@ -88,17 +88,17 @@ def copy_to_clipboard(screen: urwid.raw_display.Screen, text: str):
|
|||
screen.flush()
|
||||
|
||||
|
||||
def get_max_toot_chars(instance, default=500):
|
||||
def get_max_post_chars(instance, default=500):
|
||||
# Mastodon
|
||||
# https://docs.joinmastodon.org/entities/Instance/#max_characters
|
||||
max_toot_chars = deep_get(instance, ["configuration", "statuses", "max_characters"])
|
||||
if isinstance(max_toot_chars, int):
|
||||
return max_toot_chars
|
||||
max_post_chars = deep_get(instance, ["configuration", "statuses", "max_characters"])
|
||||
if isinstance(max_post_chars, int):
|
||||
return max_post_chars
|
||||
|
||||
# Pleroma
|
||||
max_toot_chars = instance.get("max_toot_chars")
|
||||
if isinstance(max_toot_chars, int):
|
||||
return max_toot_chars
|
||||
max_post_chars = instance.get("max_post_chars")
|
||||
if isinstance(max_post_chars, int):
|
||||
return max_post_chars
|
||||
|
||||
return default
|
||||
|
|
@ -9,7 +9,7 @@ import warnings
|
|||
from bs4 import BeautifulSoup
|
||||
from typing import Dict
|
||||
|
||||
from toot.exceptions import ConsoleError
|
||||
from witchie.exceptions import ConsoleError
|
||||
from urllib.parse import urlparse, urlencode, quote, unquote
|
||||
|
||||
|
||||
|
@ -104,7 +104,7 @@ EDITOR_DIVIDER = "------------------------ >8 ------------------------"
|
|||
EDITOR_INPUT_INSTRUCTIONS = f"""
|
||||
{EDITOR_DIVIDER}
|
||||
Do not modify or remove the line above.
|
||||
Enter your toot above it.
|
||||
Enter your post above it.
|
||||
Everything below it will be ignored.
|
||||
"""
|
||||
|
||||
|
@ -145,11 +145,11 @@ def delete_tmp_status_file():
|
|||
|
||||
def _tmp_status_path() -> str:
|
||||
tmp_dir = tempfile.gettempdir()
|
||||
return f"{tmp_dir}/.status.toot"
|
||||
return f"{tmp_dir}/.status.post"
|
||||
|
||||
|
||||
def _use_existing_tmp_file(tmp_path) -> bool:
|
||||
from toot.output import print_out
|
||||
from witchie.output import print_out
|
||||
|
||||
if os.path.exists(tmp_path):
|
||||
print_out(f"<cyan>Found a draft status at: {tmp_path}</cyan>")
|
||||
|
@ -179,15 +179,15 @@ def args_get_instance(instance, scheme, default=None):
|
|||
|
||||
|
||||
def _warn_scheme_deprecated():
|
||||
from toot.output import print_err
|
||||
from witchie.output import print_err
|
||||
|
||||
print_err("\n".join([
|
||||
"--disable-https flag is deprecated and will be removed.",
|
||||
"Please specify the instance as URL instead.",
|
||||
"e.g. instead of writing:",
|
||||
" toot instance unsafehost.com --disable-https",
|
||||
" witchie instance unsafehost.com --disable-https",
|
||||
"instead write:",
|
||||
" toot instance http://unsafehost.com\n"
|
||||
" witchie instance http://unsafehost.com\n"
|
||||
]))
|
||||
|
||||
|
Loading…
Reference in a new issue