fedi-board-bot/bot.py

142 lines
3.6 KiB
Python

import base64
import os.path
from mastodon import Mastodon
from sys import argv
import json
import pathlib
import random
import requests
class Config:
auth: str
block_tags: list[str]
danbooru_api_key: str
danbooru_username: str
nsfw_tags: list[str]
search_tags: list[str]
text_cw: str
text_filler: list[str]
url: str
def __init__(self, config_name: str):
with open(f"config/{config_name}.json") as file:
config = json.load(file)
self.block_tags = config["blockTags"]
self.danbooru_api_key = config["danbooruApiKey"]
self.danbooru_username = config["danbooruUsername"]
self.nsfw_tags = config["nsfwTags"]
self.search_tags = config["searchTags"]
self.text_cw = config["textCW"]
self.text_filler = config["textFiller"]
self.url = config["url"]
self.auth = "Basic " + base64.b64encode(
bytes(self.danbooru_username + ":" + self.danbooru_api_key, "utf-8")).decode("utf-8")
def random_image(config: Config) -> dict | None:
tags = []
for tag in config.block_tags:
tags.append("-" + tag.strip())
for tag in config.search_tags:
tags.append(tag.strip())
tags = " ".join(tags)
params = {
"random": "1",
"tags": tags
}
resp = requests.get(config.url + "/posts.json", params=params, headers={"Authorization": config.auth})
if not resp.ok:
print(resp.json())
return None
elif not resp.json():
return None
return random.choice(resp.json())
# Exit if config isn't specified
if len(argv) < 2:
print(f"Usage: python3 {argv[0]} <config-name>")
exit()
config = Config(argv[1])
# Check auth
auth = requests.get(config.url + "/profile.json", headers={"Authorization": config.auth})
print(auth.status_code)
print(auth.json())
if not auth.ok or auth.json()["id"] is None:
print("Authentication failed")
exit()
post = random_image(config)
if post is None:
print("Couldn't get an image")
exit()
filename = f'download/image.{post["file_ext"]}'
post_url = config.url + "/posts/" + str(post["id"])
print(post)
image = requests.get(post["file_url"])
if not image.ok:
print("Couldn't download image")
exit()
if not os.path.isdir("download"):
if not os.path.exists("download"):
os.makedirs("download")
else:
print("\"download\" exists but isn't a directory")
exit()
with open(filename, "wb") as f:
f.write(image.content)
# Image is NSFW if rated Explicit, Sensitive or Unknown
is_nsfw = not post["rating"].startswith("g") or post["rating"] == None
if not is_nsfw:
for tag in config.nsfw_tags:
# Check if any config defined NSFW tags are present
if tag in post["tag_string"].split():
is_nsfw = True
# This sucks but it works :3
post_content = [
random.choice(config.text_filler),
"\n\n",
"Artist: " + post["tag_string_artist"] + "\n" if len(post["tag_string_artist"]) > 0 else "",
"Characters: " + post["tag_string_character"] + "\n" if len(
post["tag_string_character"]) > 0 else "",
"Source: " + post["source"] if len(post["source"]) > 0 else "",
"\n\n" + post_url if post_url != "" else ""
]
mastodon = Mastodon(access_token=f"auth/{argv[1]}.auth.secret")
media = mastodon.media_post(
media_file=filename
)
status = mastodon.status_post(
"".join(post_content),
media_ids=[media["id"]],
sensitive=is_nsfw,
spoiler_text="(NSFW) " + config.text_cw if is_nsfw else config.text_cw,
visibility="unlisted"
)
print(status["url"])
pathlib.Path(filename).unlink()