Add search command

This commit is contained in:
Ivan Habunek 2017-04-16 15:07:27 +02:00
parent d53849fe4b
commit 64d46955e2
No known key found for this signature in database
GPG Key ID: CDBD63C43A30BB95
5 changed files with 110 additions and 35 deletions

View File

@ -1,6 +1,11 @@
Changelog
---------
**0.5.0 (2016-04-16)**
* Add `search` command
* Migrate from `optparse` to `argparse`
**0.4.0 (2016-04-15)**
* Add `upload` command to post media

View File

@ -4,6 +4,8 @@ Toot - Mastodon CLI interface
Interact with Mastodon social networks from the command line.
.. image:: https://img.shields.io/travis/ihabunek/toot.svg?maxAge=3600&style=flat-square
:target: https://travis-ci.org/ihabunek/toot
.. 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/pdf417-py.svg?maxAge=3600&style=flat-square
@ -21,11 +23,28 @@ Install using pip:
pip install toot
Usage
-----
Firstly, you will need to login to a Mastodon instance:
Running ``toot`` displays a list of available commands.
Running ``toot <command> -h`` shows the documentation for the given command.
=================== ===============================================================
Command Description
=================== ===============================================================
``toot login`` Log into a Mastodon instance, saves access keys for later use.
``toot logout`` Log out, deletes stored access keys.
``toot auth`` Display current login details.
``toot post`` Post a status to your timeline.
``toot search`` Search for accounts or hashtags.
``toot timeline`` Display recent items in your public timeline.
=================== ===============================================================
Authentication
--------------
Before tooting, you need to login to a Mastodon instance:
.. code-block::
@ -51,31 +70,3 @@ And you can logout which will remove the stored access tokens:
.. code-block::
toot logout
Show timeline
~~~~~~~~~~~~~
To show recent items in your public timeline:
.. code-block::
toot timeline
Post status
~~~~~~~~~~~
To post a new status to your timeline:
.. code-block::
toot post "Hello world!"
Optionally attach an image or video to the status:
toot post "Hello world!" --media=path/to/world.jpg
To set post visibility:
toot post "Hello world!" --visibility=unlisted
Possible visibility values are: ``public`` (default), ``unlisted``, ``private``, ``direct``. They are documented `here <https://github.com/tootsuite/documentation/blob/aa20089756c8cf9ff5a52fb35ad1a9472f10970c/Using-Mastodon/User-guide.md#toot-privacy>`_.

View File

@ -3,7 +3,7 @@ import pytest
import requests
from toot import User, App
from toot.console import print_usage, cmd_post_status, cmd_timeline, cmd_upload
from toot.console import print_usage, cmd_post_status, cmd_timeline, cmd_upload, cmd_search
from tests.utils import MockResponse
@ -138,3 +138,35 @@ def test_upload(monkeypatch, capsys):
out, err = capsys.readouterr()
assert "Uploading media" in out
assert __file__ in out
def test_search(monkeypatch, capsys):
def mock_get(url, params, headers=None):
assert url == 'https://habunek.com/api/v1/search'
assert headers == {'Authorization': 'Bearer xxx'}
assert params == {
'q': 'freddy',
'resolve': False,
}
return MockResponse({
'hashtags': ['foo', 'bar', 'baz'],
'accounts': [{
'acct': 'thequeen',
'display_name': 'Freddy Mercury'
}, {
'acct': 'thequeen@other.instance',
'display_name': 'Mercury Freddy'
}],
'statuses': [],
})
monkeypatch.setattr(requests, 'get', mock_get)
cmd_search(app, user, ['freddy'])
out, err = capsys.readouterr()
assert "Hashtags:\n\033[32m#foo\033[0m, \033[32m#bar\033[0m, \033[32m#baz\033[0m" in out
assert "Accounts:" in out
assert "\033[32m@thequeen\033[0m Freddy Mercury" in out
assert "\033[32m@thequeen@other.instance\033[0m Mercury Freddy" in out

View File

@ -108,3 +108,10 @@ def upload_media(app, user, file):
return _post(app, user, '/api/v1/media', files={
'file': file
})
def search(app, user, query, resolve):
return _get(app, user, '/api/v1/search', {
'q': query,
'resolve': resolve,
})

View File

@ -16,7 +16,7 @@ from argparse import ArgumentParser, FileType
from textwrap import TextWrapper
from toot import DEFAULT_INSTANCE
from toot.api import create_app, login, post_status, timeline_home, upload_media
from toot.api import create_app, login, post_status, timeline_home, upload_media, search
from toot.config import save_user, load_user, load_app, save_app, CONFIG_APP_FILE, CONFIG_USER_FILE
@ -84,6 +84,7 @@ def print_usage():
print(" toot logout - log out (delete saved access tokens)")
print(" toot auth - shows currently logged in user and instance")
print(" toot post <msg> - toot a new post to your timeline")
print(" toot search - search for accounts or hashtags")
print(" toot timeline - shows your public timeline")
print("")
print("To get help for each command run:")
@ -233,6 +234,42 @@ def cmd_upload(app, user, args):
print("Text URL: " + green(response['text_url']))
def _print_accounts(accounts):
if not accounts:
return
print("\nAccounts:")
for account in accounts:
acct = green("@{}".format(account['acct']))
display_name = account['display_name']
print("* {} {}".format(acct, display_name))
def _print_hashtags(hashtags):
if not hashtags:
return
print("\nHashtags:")
print(", ".join([green("#" + t) for t in hashtags]))
def cmd_search(app, user, args):
parser = ArgumentParser(prog="toot serach",
description="Search for content",
epilog="https://github.com/ihabunek/toot")
parser.add_argument("query", help="The search query")
parser.add_argument("-r", "--resolve", action='store_true', default=False,
help="Whether to resolve non-local accounts")
args = parser.parse_args(args)
response = search(app, user, args.query, args.resolve)
_print_accounts(response['accounts'])
_print_hashtags(response['hashtags'])
def do_upload(app, user, file):
print("Uploading media: {}".format(green(file.name)))
return upload_media(app, user, file)
@ -251,8 +288,8 @@ def run_command(command, args):
# Commands which require user to be logged in
if not app or not user:
print(red("You are not logged in."))
print(red("Please run `toot login` first."))
print_error("You are not logged in.")
print_error("Please run `toot login` first.")
return
if command == 'logout':
@ -267,7 +304,10 @@ def run_command(command, args):
if command == 'upload':
return cmd_upload(app, user, args)
print(red("Unknown command '{}'\n".format(command)))
if command == 'search':
return cmd_search(app, user, args)
print_error("Unknown command '{}'\n".format(command))
print_usage()