1
0
mirror of https://github.com/ihabunek/toot synced 2025-01-25 13:08:35 +01:00

Add support for custom instance domains

The instance domain can be different from their base url, for example
the instance at https://social.vivaldi.net uses the vivaldi.net domain,
sans 'social'.

This commit requires the user to provide the base url of the instance,
instead of domain name. The domain is then fetched from the server.

fixes #217
This commit is contained in:
Ivan Habunek 2023-03-07 10:37:03 +01:00
parent 9baa0823f9
commit d5b5c89996
No known key found for this signature in database
GPG Key ID: F5F0623FF5EBCB3D
6 changed files with 70 additions and 32 deletions

View File

@ -5,7 +5,7 @@ __version__ = '0.35.0'
App = namedtuple('App', ['instance', 'base_url', 'client_id', 'client_secret']) App = namedtuple('App', ['instance', 'base_url', 'client_id', 'client_secret'])
User = namedtuple('User', ['instance', 'username', 'access_token']) User = namedtuple('User', ['instance', 'username', 'access_token'])
DEFAULT_INSTANCE = 'mastodon.social' DEFAULT_INSTANCE = 'https://mastodon.social'
CLIENT_NAME = 'toot - a Mastodon CLI client' CLIENT_NAME = 'toot - a Mastodon CLI client'
CLIENT_WEBSITE = 'https://github.com/ihabunek/toot' CLIENT_WEBSITE = 'https://github.com/ihabunek/toot'

View File

@ -28,8 +28,8 @@ def _tag_action(app, user, tag_name, action):
return http.post(app, user, url).json() return http.post(app, user, url).json()
def create_app(domain, scheme='https'): def create_app(base_url):
url = f"{scheme}://{domain}/api/v1/apps" url = f"{base_url}/api/v1/apps"
json = { json = {
'client_name': CLIENT_NAME, 'client_name': CLIENT_NAME,
@ -504,6 +504,6 @@ def clear_notifications(app, user):
http.post(app, user, '/api/v1/notifications/clear') http.post(app, user, '/api/v1/notifications/clear')
def get_instance(domain, scheme="https"): def get_instance(base_url):
url = f"{scheme}://{domain}/api/v1/instance" url = f"{base_url}/api/v1/instance"
return http.anon_get(url).json() return http.anon_get(url).json()

View File

@ -9,21 +9,13 @@ from toot.exceptions import ApiError, ConsoleError
from toot.output import print_out from toot.output import print_out
def register_app(domain, scheme='https'): def register_app(domain, base_url):
print_out("Looking up instance info...")
instance = api.get_instance(domain, scheme)
print_out("Found instance <blue>{}</blue> running Mastodon version <yellow>{}</yellow>".format(
instance['title'], instance['version']))
try: try:
print_out("Registering application...") print_out("Registering application...")
response = api.create_app(domain, scheme) response = api.create_app(base_url)
except ApiError: except ApiError:
raise ConsoleError("Registration failed.") raise ConsoleError("Registration failed.")
base_url = scheme + '://' + domain
app = App(domain, base_url, response['client_id'], response['client_secret']) app = App(domain, base_url, response['client_id'], response['client_secret'])
config.save_app(app) config.save_app(app)
@ -32,14 +24,30 @@ def register_app(domain, scheme='https'):
return app return app
def create_app_interactive(instance=None, scheme='https'): def create_app_interactive(base_url):
if not instance: if not base_url:
print_out("Choose an instance [<green>{}</green>]: ".format(DEFAULT_INSTANCE), end="") print_out(f"Enter instance URL [<green>{DEFAULT_INSTANCE}</green>]: ", end="")
instance = input() base_url = input()
if not instance: if not base_url:
instance = DEFAULT_INSTANCE base_url = DEFAULT_INSTANCE
return config.load_app(instance) or register_app(instance, scheme) domain = get_instance_domain(base_url)
return config.load_app(domain) or register_app(domain, base_url)
def get_instance_domain(base_url):
print_out("Looking up instance info...")
instance = api.get_instance(base_url)
print_out(
f"Found instance <blue>{instance['title']}</blue> "
f"running Mastodon version <yellow>{instance['version']}</yellow>"
)
# NB: when updating to v2 instance endpoint, this field has been renamed to `domain`
return instance["uri"]
def create_user(app, access_token): def create_user(app, access_token):

View File

@ -10,7 +10,7 @@ from toot.output import (print_out, print_instance, print_account, print_acct_li
print_search_results, print_timeline, print_notifications, print_search_results, print_timeline, print_notifications,
print_tag_list) print_tag_list)
from toot.tui.utils import parse_datetime from toot.tui.utils import parse_datetime
from toot.utils import delete_tmp_status_file, editor_input, multiline_input, EOF_KEY from toot.utils import args_get_instance, delete_tmp_status_file, editor_input, multiline_input, EOF_KEY
def get_timeline_generator(app, user, args): def get_timeline_generator(app, user, args):
@ -305,7 +305,8 @@ def update_account(app, user, args):
def login_cli(app, user, args): def login_cli(app, user, args):
app = create_app_interactive(instance=args.instance, scheme=args.scheme) base_url = args_get_instance(args.instance, args.scheme)
app = create_app_interactive(base_url)
login_interactive(app, args.email) login_interactive(app, args.email)
print_out() print_out()
@ -313,7 +314,8 @@ def login_cli(app, user, args):
def login(app, user, args): def login(app, user, args):
app = create_app_interactive(instance=args.instance, scheme=args.scheme) base_url = args_get_instance(args.instance, args.scheme)
app = create_app_interactive(base_url)
login_browser_interactive(app) login_browser_interactive(app)
print_out() print_out()
@ -452,17 +454,19 @@ def whois(app, user, args):
def instance(app, user, args): def instance(app, user, args):
name = args.instance or (app and app.instance) default = app.base_url if app else None
if not name: base_url = args_get_instance(args.instance, args.scheme, default)
raise ConsoleError("Please specify instance name.")
if not base_url:
raise ConsoleError("Please specify an instance.")
try: try:
instance = api.get_instance(name, args.scheme) instance = api.get_instance(base_url)
print_instance(instance) print_instance(instance)
except ApiError: except ApiError:
raise ConsoleError( raise ConsoleError(
"Instance not found at {}.\n" f"Instance not found at {base_url}.\n"
"The given domain probably does not host a Mastodon instance.".format(name) "The given domain probably does not host a Mastodon instance."
) )

View File

@ -336,7 +336,7 @@ class TUI(urwid.Frame):
See: https://github.com/mastodon/mastodon/issues/19328 See: https://github.com/mastodon/mastodon/issues/19328
""" """
def _load_instance(): def _load_instance():
return api.get_instance(self.app.instance) return api.get_instance(self.app.base_url)
def _done(instance): def _done(instance):
if "max_toot_chars" in instance: if "max_toot_chars" in instance:

View File

@ -160,3 +160,29 @@ def _use_existing_tmp_file(tmp_path) -> bool:
def drop_empty_values(data: Dict) -> Dict: def drop_empty_values(data: Dict) -> Dict:
"""Remove keys whose values are null""" """Remove keys whose values are null"""
return {k: v for k, v in data.items() if v is not None} return {k: v for k, v in data.items() if v is not None}
def args_get_instance(instance, scheme, default=None):
if not instance:
return default
if scheme == "http":
_warn_scheme_deprecated()
if instance.startswith("http"):
return instance.rstrip("/")
else:
return f"{scheme}://{instance}"
def _warn_scheme_deprecated():
from toot.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",
"instead write:",
" toot instance http://unsafehost.com\n"
]))