From 5a5bcf2943cf8225a1179e97c98e33b949af0968 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sun, 18 Dec 2022 19:25:07 -0800 Subject: [PATCH] mass DM example :) --- .env.sample | 3 + README.md | 4 +- masto_tools/__init__.py | 1 + masto_tools/config.py | 12 ++ masto_tools/constants.py | 58 ++++++++ masto_tools/creds.py | 0 masto_tools/init.py | 15 ++ masto_tools/logging.py | 0 masto_tools/script.py | 35 +++++ masto_tools/scripts/__init__.py | 0 masto_tools/scripts/mass_dm.py | 89 +++++++++++ poetry.lock | 255 ++++++++++++++++++++++++++++++++ pyproject.toml | 19 +++ 13 files changed, 490 insertions(+), 1 deletion(-) create mode 100644 .env.sample create mode 100644 masto_tools/__init__.py create mode 100644 masto_tools/config.py create mode 100644 masto_tools/constants.py create mode 100644 masto_tools/creds.py create mode 100644 masto_tools/init.py create mode 100644 masto_tools/logging.py create mode 100644 masto_tools/script.py create mode 100644 masto_tools/scripts/__init__.py create mode 100644 masto_tools/scripts/mass_dm.py create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..313c984 --- /dev/null +++ b/.env.sample @@ -0,0 +1,3 @@ +MASTO_URL= +MASTO_TOKEN= +LOGDIR= \ No newline at end of file diff --git a/README.md b/README.md index bd372dd..2378e4b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # masto-tools -Lil scripts and stuff to do admin stuff on masto \ No newline at end of file +Lil scripts and stuff to do admin stuff on masto + +## Permissions required diff --git a/masto_tools/__init__.py b/masto_tools/__init__.py new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/masto_tools/__init__.py @@ -0,0 +1 @@ + diff --git a/masto_tools/config.py b/masto_tools/config.py new file mode 100644 index 0000000..985bad2 --- /dev/null +++ b/masto_tools/config.py @@ -0,0 +1,12 @@ +from pathlib import Path +from typing import Optional +from pydantic import BaseSettings, AnyHttpUrl, EmailStr + +class Config(BaseSettings): + MASTO_URL:AnyHttpUrl + MASTO_TOKEN: Optional[str] = None + LOGDIR:Path = Path().home() / '.mastotools' + + class Config: + env_file = '.env' + env_file_encoding = 'utf-8' \ No newline at end of file diff --git a/masto_tools/constants.py b/masto_tools/constants.py new file mode 100644 index 0000000..c3c35a5 --- /dev/null +++ b/masto_tools/constants.py @@ -0,0 +1,58 @@ +from enum import Enum, auto + +class StrEnum(str, Enum): + pass + +BASE_SCOPES =( + "", + "accounts", + "blocks", + "bookmarks", + "favourites", + "filters", + "follows", + "lists", + "mutes", + "notifictions", + "search", + "statuses", +) + +ADMIN_SCOPES = ( + "", + "accounts", + "canonical_email_blocks", + "domin_allows", + "domain_blocks", + "email_domain_blocks", + "ip_blocks", + "reports" +) + +EXTRA_SCOPES = ( + "follow", + "push", + "crypto" +) + +SCOPES = tuple( + item for tup in ( + (":".join(["read", scope]) for scope in BASE_SCOPES), + (":".join(["write", scope]) for scope in BASE_SCOPES), + (":".join(["admin", "read", scope]) for scope in ADMIN_SCOPES), + (":".join(["admin", "write", scope]) for scope in ADMIN_SCOPES), + EXTRA_SCOPES + ) for item in tup +) + +# +# class SCOPES(StrEnum): +# read = BASE_SCOPES() +# write = BASE_SCOPES() +# follow = auto() +# push = auto() +# crypto = auto() +# +# class admin(StrEnum): +# read = ADMIN_SCOPES +# write = ADMIN_SCOPES diff --git a/masto_tools/creds.py b/masto_tools/creds.py new file mode 100644 index 0000000..e69de29 diff --git a/masto_tools/init.py b/masto_tools/init.py new file mode 100644 index 0000000..b30d6cf --- /dev/null +++ b/masto_tools/init.py @@ -0,0 +1,15 @@ +from typing import Optional +from masto_tools.config import Config + +from mastodon import Mastodon + +def log_in(config:Optional[Config]=None) -> Mastodon: + if config is None: + config = Config() + + client = Mastodon( + access_token=config.MASTO_TOKEN, + api_base_url=config.MASTO_URL + ) + + return client \ No newline at end of file diff --git a/masto_tools/logging.py b/masto_tools/logging.py new file mode 100644 index 0000000..e69de29 diff --git a/masto_tools/script.py b/masto_tools/script.py new file mode 100644 index 0000000..c0bb9b5 --- /dev/null +++ b/masto_tools/script.py @@ -0,0 +1,35 @@ +from abc import ABC +from pydantic import BaseModel +from typing import Optional, Tuple + +from mastodon import Mastodon + +from masto_tools.init import log_in + +from masto_tools.config import Config + +class Result(BaseModel): + """ + Result of a script step + """ + + +class Script(ABC): + """ + Metaclass for organizing + """ + name:str = "" + # TODO Typ + scopes: Tuple[str] = () + + def __init__(self, config:Optional[Config]=None): + + # TODO: Logging + + if config is None: + config = Config() + + self.config = config + + self.client = log_in(config) + diff --git a/masto_tools/scripts/__init__.py b/masto_tools/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/masto_tools/scripts/mass_dm.py b/masto_tools/scripts/mass_dm.py new file mode 100644 index 0000000..64190cc --- /dev/null +++ b/masto_tools/scripts/mass_dm.py @@ -0,0 +1,89 @@ +""" +DM All +""" + +# from masto_tools.script import Script + +# class MassDM(Script): +# """ +# Send a message to everyone on the instance :) +# +# fuck it getting tired come back to making formal script mode later +# just do functional mode for now +# """ +from typing import List, Optional +from argparse import ArgumentParser, Namespace +from masto_tools.init import log_in +from warnings import warn + +from mastodon import Mastodon + +def get_accounts(client) -> List[dict]: + # get first page of accounts + first_accounts = client.admin_accounts() + # then paginate + accounts = client.fetch_remaining(first_accounts) + return accounts + +def filter_accounts(accounts:List[dict]) -> List[dict]: + # filter by approval and suspensions status + accounts = [a for a in accounts if \ + a['approved'] is True and \ + a['disabled'] is False and \ + a['suspended'] is False and \ + a['silenced'] is False] + + return accounts + +def send_dm(client:Mastodon, message:str, account:dict) -> dict: + # prepend @ to message + message = f"@{account['username']}\n" + message + response = client.status_post(message, visibility='direct') + return response + + +def send_to_all(client:Mastodon, message:str, accounts:List[dict], message_id:str, message_tag:str="DMAnnouncement") -> List[dict]: + """ + Send message to all, returning dictionary of account IDs and + + :param message: The message to send + :param accounts: List of accounts to send to + :param message_id: Unique ID to label messages with (to be able to find this specific message later + :param message_tag: General tag to label all mass DMs with + :return: + """ + # Postpend the tags to the message + message += "\n\n" + f"#{message_tag.replace(' ', '_')} " + f"#{message_id.replace(' ', '_')}" + + responses = [] + for account in accounts: + try: + response = send_dm(client, message, account) + responses.append(response) + except Exception as e: + # TODO: Logging and error handling lmao + warn(f"Could not send dm to username: {account['username']}: {str(e)}") + + return responses + +def argparser() -> ArgumentParser: + parser = ArgumentParser() + parser.add_argument('-m', '--message', help="The Message to send", type=str) + parser.add_argument('-i', '--id', help="Unique message ID") + parser.add_argument('-t', '--tag', help="Tag for all mass DMs", type=str, default="DMAnnouncement") + + return parser + + +def main() -> List[dict]: + args = argparser().parse_args() + + client = log_in() + accounts = get_accounts(client) + accounts = filter_accounts(accounts) + responses = send_to_all(client, args.message, accounts, message_id=args.id, message_tag=args.tag) + return responses + + +if __name__ == "__main__": + responses = main() diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..56ec7d5 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,255 @@ +[[package]] +name = "blurhash" +version = "1.1.4" +description = "Pure-Python implementation of the blurhash algorithm." +category = "main" +optional = false +python-versions = "*" + +[package.extras] +test = ["Pillow", "numpy", "pytest"] + +[[package]] +name = "certifi" +version = "2022.12.7" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.6.0" + +[package.extras] +unicode-backport = ["unicodedata2"] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "mastodon-py" +version = "1.8.0" +description = "Python wrapper for the Mastodon API" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +blurhash = ">=1.1.4" +decorator = ">=4.0.0" +python-dateutil = "*" +python-magic = "*" +requests = ">=2.4.2" +six = "*" + +[package.extras] +blurhash = ["blurhash (>=1.1.4)"] +test = ["blurhash (>=1.1.4)", "cryptography (>=1.6.0)", "http-ece (>=1.0.5)", "pytest", "pytest-cov", "pytest-mock", "pytest-runner", "pytest-vcr", "pytz", "requests-mock", "vcrpy"] +webpush = ["cryptography (>=1.6.0)", "http-ece (>=1.0.5)"] + +[[package]] +name = "pydantic" +version = "1.10.2" +description = "Data validation and settings management using python type hints" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +typing-extensions = ">=4.1.0" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "python-dotenv" +version = "0.21.0" +description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +cli = ["click (>=5.0)"] + +[[package]] +name = "python-magic" +version = "0.4.27" +description = "File type identification using libmagic" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "requests" +version = "2.28.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=3.7, <4" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<3" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "typing-extensions" +version = "4.4.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.13" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + +[metadata] +lock-version = "1.1" +python-versions = "^3.9" +content-hash = "da2ce267aafd656dbc97392d84ec3e6e17922c57102df9ff639c8bf78c10184e" + +[metadata.files] +blurhash = [ + {file = "blurhash-1.1.4-py2.py3-none-any.whl", hash = "sha256:7611c1bc41383d2349b6129208587b5d61e8792ce953893cb49c38beeb400d1d"}, + {file = "blurhash-1.1.4.tar.gz", hash = "sha256:da56b163e5a816e4ad07172f5639287698e09d7f3dc38d18d9726d9c1dbc4cee"}, +] +certifi = [ + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] +decorator = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] +idna = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] +mastodon-py = [ + {file = "Mastodon.py-1.8.0-py2.py3-none-any.whl", hash = "sha256:31624c881318682577b76c082a9e8e4114a42e80ad3652c6bc00e5c658cea1a7"}, + {file = "Mastodon.py-1.8.0.tar.gz", hash = "sha256:f5af3bb16df6409bed0bb8b97543d7979237a6a2a2a4bc484dec261c36918668"}, +] +pydantic = [ + {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, + {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, + {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, + {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, + {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, + {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, + {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, + {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, + {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, + {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, + {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, + {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, + {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, + {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, + {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, + {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, + {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, + {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, + {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, + {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, + {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, + {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, + {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, +] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +python-dotenv = [ + {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, + {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, +] +python-magic = [ + {file = "python-magic-0.4.27.tar.gz", hash = "sha256:c1ba14b08e4a5f5c31a302b7721239695b2f0f058d125bd5ce1ee36b9d9d3c3b"}, + {file = "python_magic-0.4.27-py2.py3-none-any.whl", hash = "sha256:c212960ad306f700aa0d01e5d7a325d20548ff97eb9920dcd29513174f0294d3"}, +] +requests = [ + {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"}, + {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"}, +] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] +typing-extensions = [ + {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, + {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, +] +urllib3 = [ + {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"}, + {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"}, +] diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..c0611f6 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "masto-tools" +version = "0.1.0" +description = "Lil scripts for doing masto admin stuff" +authors = ["sneakers-the-rat "] +license = "AGPL-3.0" +readme = "README.md" +packages = [{include = "masto_tools"}] + +[tool.poetry.dependencies] +python = "^3.9" +mastodon-py = "^1.8.0" +pydantic = "^1.10.2" +python-dotenv = "^0.21.0" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api"