Refactor to focus on danbooru and support auth properly
This commit is contained in:
parent
be2d09011e
commit
f3601b79eb
13 changed files with 122 additions and 98 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -5,4 +5,5 @@
|
||||||
**/**.png
|
**/**.png
|
||||||
.venv/
|
.venv/
|
||||||
auth/*.secret
|
auth/*.secret
|
||||||
config/*.json
|
config/*.json
|
||||||
|
download/
|
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
10
.idea/fedi-board-bot.iml
generated
Normal file
10
.idea/fedi-board-bot.iml
generated
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.13 (fedi-board-bot) (2)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
21
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
21
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredPackages">
|
||||||
|
<value>
|
||||||
|
<list size="1">
|
||||||
|
<item index="0" class="java.lang.String" itemvalue="gi" />
|
||||||
|
</list>
|
||||||
|
</value>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredIdentifiers">
|
||||||
|
<list>
|
||||||
|
<option value="gi.repository.Gtk" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.13 (fedi-board-bot)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (fedi-board-bot) (2)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/fedi-board-bot.iml" filepath="$PROJECT_DIR$/.idea/fedi-board-bot.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -27,5 +27,3 @@ Run the bot by running
|
||||||
```sh
|
```sh
|
||||||
python3 bot.py <config-name>
|
python3 bot.py <config-name>
|
||||||
```
|
```
|
||||||
|
|
||||||
Use the environment variables `BOARD_API_KEY` and `BOARD_USERNAME` to login with danbooru.
|
|
||||||
|
|
142
bot.py
142
bot.py
|
@ -1,6 +1,6 @@
|
||||||
from dataclasses import dataclass
|
import base64
|
||||||
|
import os.path
|
||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
from os import environ
|
|
||||||
from sys import argv
|
from sys import argv
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -8,13 +8,16 @@ import pathlib
|
||||||
import random
|
import random
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
|
auth: str
|
||||||
block_tags: list[str]
|
block_tags: list[str]
|
||||||
|
danbooru_api_key: str
|
||||||
|
danbooru_username: str
|
||||||
nsfw_tags: list[str]
|
nsfw_tags: list[str]
|
||||||
search_tags: list[str]
|
search_tags: list[str]
|
||||||
text_cw: str
|
text_cw: str
|
||||||
text_filler: list[str]
|
text_filler: list[str]
|
||||||
type: str
|
|
||||||
url: str
|
url: str
|
||||||
|
|
||||||
def __init__(self, config_name: str):
|
def __init__(self, config_name: str):
|
||||||
|
@ -22,18 +25,23 @@ class Config:
|
||||||
config = json.load(file)
|
config = json.load(file)
|
||||||
|
|
||||||
self.block_tags = config["blockTags"]
|
self.block_tags = config["blockTags"]
|
||||||
|
self.danbooru_api_key = config["danbooruApiKey"]
|
||||||
|
self.danbooru_username = config["danbooruUsername"]
|
||||||
self.nsfw_tags = config["nsfwTags"]
|
self.nsfw_tags = config["nsfwTags"]
|
||||||
self.search_tags = config["searchTags"]
|
self.search_tags = config["searchTags"]
|
||||||
self.text_cw = config["textCW"]
|
self.text_cw = config["textCW"]
|
||||||
self.text_filler = config["textFiller"]
|
self.text_filler = config["textFiller"]
|
||||||
self.type = config["type"]
|
|
||||||
self.url = config["url"]
|
self.url = config["url"]
|
||||||
|
|
||||||
def random_image_danbooru(block_tags: list[str], search_tags: list[str], url: str) -> dict | None:
|
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 = []
|
tags = []
|
||||||
for tag in block_tags:
|
for tag in config.block_tags:
|
||||||
tags.append("-" + tag.strip())
|
tags.append("-" + tag.strip())
|
||||||
for tag in search_tags:
|
for tag in config.search_tags:
|
||||||
tags.append(tag.strip())
|
tags.append(tag.strip())
|
||||||
tags = " ".join(tags)
|
tags = " ".join(tags)
|
||||||
|
|
||||||
|
@ -41,49 +49,17 @@ def random_image_danbooru(block_tags: list[str], search_tags: list[str], url: st
|
||||||
"random": "1",
|
"random": "1",
|
||||||
"tags": tags
|
"tags": tags
|
||||||
}
|
}
|
||||||
if environ.get("BOARD_API_KEY") and environ.get("BOARD_USERNAME"):
|
|
||||||
params["api_key"] = environ.get("BOARD_API_KEY")
|
|
||||||
params["login"] = environ.get("BOARD_USERNAME")
|
|
||||||
resp = requests.get(url + "/posts.json", params=params)
|
|
||||||
|
|
||||||
if resp.ok == False:
|
resp = requests.get(config.url + "/posts.json", params=params, headers={"Authorization": config.auth})
|
||||||
|
|
||||||
|
if not resp.ok:
|
||||||
print(resp.json())
|
print(resp.json())
|
||||||
return None
|
return None
|
||||||
elif resp.json() == []:
|
elif not resp.json():
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return random.choice(resp.json())
|
return random.choice(resp.json())
|
||||||
|
|
||||||
def random_image_gelbooru(block_tags: list[str], search_tags: list[str]) -> dict | None:
|
|
||||||
tags = ["sort:random"]
|
|
||||||
for tag in block_tags:
|
|
||||||
tags.append("-" + tag.strip())
|
|
||||||
for tag in search_tags:
|
|
||||||
tags.append(tag.strip())
|
|
||||||
tags = " ".join(tags)
|
|
||||||
|
|
||||||
params = {
|
|
||||||
"page": "dapi",
|
|
||||||
"s": "post",
|
|
||||||
"q": "index",
|
|
||||||
"pid": 0,
|
|
||||||
"json": "1",
|
|
||||||
"limit": "1",
|
|
||||||
"tags": tags
|
|
||||||
}
|
|
||||||
resp = requests.get("https://gelbooru.com/index.php", params=params)
|
|
||||||
|
|
||||||
if resp.ok == False:
|
|
||||||
print(resp.json())
|
|
||||||
return None
|
|
||||||
|
|
||||||
post = resp.json()
|
|
||||||
|
|
||||||
if len(post["post"]) > 0:
|
|
||||||
return random.choice(resp.json()["post"])
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
# Exit if config isn't specified
|
# Exit if config isn't specified
|
||||||
if len(argv) < 2:
|
if len(argv) < 2:
|
||||||
|
@ -92,87 +68,69 @@ if len(argv) < 2:
|
||||||
|
|
||||||
config = Config(argv[1])
|
config = Config(argv[1])
|
||||||
|
|
||||||
match config.type:
|
# Check auth
|
||||||
case "danbooru":
|
auth = requests.get(config.url + "/profile.json", headers={"Authorization": config.auth})
|
||||||
post = random_image_danbooru(config.block_tags, config.search_tags, config.url)
|
|
||||||
case "gelbooru":
|
|
||||||
post = random_image_gelbooru(config.block_tags, config.search_tags)
|
|
||||||
case _:
|
|
||||||
print("'type' in config must be 'danbooru' or 'gelbooru'")
|
|
||||||
exit()
|
|
||||||
|
|
||||||
if post == None:
|
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")
|
print("Couldn't get an image")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
match config.type:
|
filename = f'download/image.{post["file_ext"]}'
|
||||||
case "danbooru":
|
post_url = config.url + "/posts/" + str(post["id"])
|
||||||
characters = post.get("tag_string_character") or ""
|
|
||||||
filename = f'image.{post["file_ext"]}'
|
|
||||||
post_url = config.url + "/posts/" + str(post["id"])
|
|
||||||
case "gelbooru":
|
|
||||||
characters = ""
|
|
||||||
filename = post["image"]
|
|
||||||
post_url = "https://gelbooru.com/index.php?page=post&s=view&id=" + str(post["id"])
|
|
||||||
case _:
|
|
||||||
characters = ""
|
|
||||||
filename = "img.png"
|
|
||||||
post_url = ""
|
|
||||||
|
|
||||||
print(post)
|
print(post)
|
||||||
|
|
||||||
image = requests.get(post["file_url"])
|
image = requests.get(post["file_url"])
|
||||||
|
|
||||||
if image.ok == False:
|
if not image.ok:
|
||||||
print("Couldn't download image")
|
print("Couldn't download image")
|
||||||
exit()
|
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:
|
with open(filename, "wb") as f:
|
||||||
f.write(image.content)
|
f.write(image.content)
|
||||||
|
|
||||||
# Image is NSFW if rated Explicit, Sensitive or Unknown
|
# Image is NSFW if rated Explicit, Sensitive or Unknown
|
||||||
is_nsfw = not post["rating"].startswith("g") or post["rating"] == None
|
is_nsfw = not post["rating"].startswith("g") or post["rating"] == None
|
||||||
|
|
||||||
if is_nsfw == False:
|
if not is_nsfw:
|
||||||
for tag in config.nsfw_tags:
|
for tag in config.nsfw_tags:
|
||||||
# Check if any config defined NSFW tags are present
|
# Check if any config defined NSFW tags are present
|
||||||
match config.type:
|
if tag in post["tag_string"].split():
|
||||||
case "danbooru":
|
is_nsfw = True
|
||||||
if tag in post["tag_string"].split():
|
|
||||||
print(tag)
|
|
||||||
is_nsfw = True
|
|
||||||
break
|
|
||||||
case "gelbooru":
|
|
||||||
if tag in post["tags"].split():
|
|
||||||
print(tag)
|
|
||||||
is_nsfw = True
|
|
||||||
break
|
|
||||||
case _:
|
|
||||||
is_nsfw = True
|
|
||||||
break
|
|
||||||
|
|
||||||
# This sucks but it works :3
|
# This sucks but it works :3
|
||||||
post_content = [
|
post_content = [
|
||||||
random.choice(config.text_filler),
|
random.choice(config.text_filler),
|
||||||
"\n\n",
|
"\n\n",
|
||||||
"Artist: " + post["tag_string_artist"] + "\n" if config.type == "danbooru" and len(post["tag_string_artist"]) > 0 else "",
|
"Artist: " + post["tag_string_artist"] + "\n" if len(post["tag_string_artist"]) > 0 else "",
|
||||||
"Characters: " + characters + "\n" if characters != "" else "",
|
"Characters: " + post["tag_string_character"] + "\n" if len(
|
||||||
|
post["tag_string_character"]) > 0 else "",
|
||||||
"Source: " + post["source"] if len(post["source"]) > 0 else "",
|
"Source: " + post["source"] if len(post["source"]) > 0 else "",
|
||||||
"\n\n" + post_url if post_url != "" else ""
|
"\n\n" + post_url if post_url != "" else ""
|
||||||
]
|
]
|
||||||
|
|
||||||
|
print("".join(post_content))
|
||||||
|
|
||||||
|
exit()
|
||||||
|
|
||||||
mastodon = Mastodon(access_token=f"auth/{argv[1]}.auth.secret")
|
mastodon = Mastodon(access_token=f"auth/{argv[1]}.auth.secret")
|
||||||
|
|
||||||
match config.type:
|
|
||||||
case "danbooru":
|
|
||||||
tags = post["tag_string"]
|
|
||||||
case "gelbooru":
|
|
||||||
tags = post["tags"]
|
|
||||||
case _:
|
|
||||||
tags = "unknown"
|
|
||||||
|
|
||||||
media = mastodon.media_post(
|
media = mastodon.media_post(
|
||||||
description="Automatically posted image. Tagged: " + tags,
|
|
||||||
media_file=filename
|
media_file=filename
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
"blockTags": [
|
"blockTags": [
|
||||||
"List of tags that should be ignored by the bot."
|
"List of tags that should be ignored by the bot."
|
||||||
],
|
],
|
||||||
|
"danbooruApiKey": "",
|
||||||
|
"danbooruUsername": "",
|
||||||
"nsfwTags": [
|
"nsfwTags": [
|
||||||
"If these tags are present the post will be marked as sensitive"
|
"If these tags are present the post will be marked as sensitive"
|
||||||
],
|
],
|
||||||
|
@ -12,6 +14,5 @@
|
||||||
"textFiller": [
|
"textFiller": [
|
||||||
"Flavor text for posts"
|
"Flavor text for posts"
|
||||||
],
|
],
|
||||||
"type": "danbooru or gelbooru",
|
"url": "https://safebooru.donmai.us"
|
||||||
"url": "https://"
|
|
||||||
}
|
}
|
|
@ -1 +1,2 @@
|
||||||
Mastodon.py
|
Mastodon.py
|
||||||
|
requests
|
Loading…
Add table
Reference in a new issue