summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.idea/.gitignore8
-rw-r--r--.idea/deployment.xml15
-rw-r--r--.idea/derp.iml12
-rw-r--r--.idea/discord.xml7
-rw-r--r--.idea/inspectionProfiles/Project_Default.xml12
-rw-r--r--.idea/misc.xml4
-rw-r--r--.idea/modules.xml8
-rw-r--r--config/__pycache__/raindrops.cpython-310.pycbin0 -> 471 bytes
-rw-r--r--config/raindrops.py33
-rw-r--r--derp.sh3
-rw-r--r--main.py135
12 files changed, 240 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..24f4c4d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+auth.txt
+token-*.txt
+list-*.txt \ No newline at end of file
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/deployment.xml b/.idea/deployment.xml
new file mode 100644
index 0000000..c2acf39
--- /dev/null
+++ b/.idea/deployment.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="PublishConfigData" autoUpload="Always" serverName="bridlewood" remoteFilesAllowedToDisappearOnAutoupload="false">
+ <serverData>
+ <paths name="bridlewood">
+ <serverdata>
+ <mappings>
+ <mapping deploy="/opt/derp" local="$PROJECT_DIR$" web="/" />
+ </mappings>
+ </serverdata>
+ </paths>
+ </serverData>
+ <option name="myAutoUpload" value="ALWAYS" />
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/derp.iml b/.idea/derp.iml
new file mode 100644
index 0000000..8f6a3ea
--- /dev/null
+++ b/.idea/derp.iml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="WEB_MODULE" version="4">
+ <component name="NewModuleRootManager">
+ <content url="file://$MODULE_DIR$">
+ <excludeFolder url="file://$MODULE_DIR$/.tmp" />
+ <excludeFolder url="file://$MODULE_DIR$/temp" />
+ <excludeFolder url="file://$MODULE_DIR$/tmp" />
+ </content>
+ <orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ </component>
+</module> \ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
new file mode 100644
index 0000000..d8e9561
--- /dev/null
+++ b/.idea/discord.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="DiscordProjectSettings">
+ <option name="show" value="PROJECT_FILES" />
+ <option name="description" value="" />
+ </component>
+</project> \ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..34b1592
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,12 @@
+<component name="InspectionProjectProfileManager">
+ <profile version="1.0">
+ <option name="myName" value="Project Default" />
+ <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
+ <option name="ignoredIdentifiers">
+ <list>
+ <option value="config" />
+ </list>
+ </option>
+ </inspection_tool>
+ </profile>
+</component> \ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..dc9ea49
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
+</project> \ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..3f23d1c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+ <component name="ProjectModuleManager">
+ <modules>
+ <module fileurl="file://$PROJECT_DIR$/.idea/derp.iml" filepath="$PROJECT_DIR$/.idea/derp.iml" />
+ </modules>
+ </component>
+</project> \ No newline at end of file
diff --git a/config/__pycache__/raindrops.cpython-310.pyc b/config/__pycache__/raindrops.cpython-310.pyc
new file mode 100644
index 0000000..4cfaa76
--- /dev/null
+++ b/config/__pycache__/raindrops.cpython-310.pyc
Binary files differ
diff --git a/config/raindrops.py b/config/raindrops.py
new file mode 100644
index 0000000..53b62dc
--- /dev/null
+++ b/config/raindrops.py
@@ -0,0 +1,33 @@
+# Derp configuration file
+
+# ---------------------------
+# Paths to the data files for this configuration file
+sent_list_path = "list-raindrops.txt"
+token_path = "token-raindrops.txt"
+
+# ---------------------------
+# The tags to show in the notification, considered high-importance tags
+
+triggers = {"explicit", "suggestive", "grimdark", "semi-grimdark", "grotesque", "questionable", "foalcon", "male", "intersex", "bondage", "close-up", "tentacles"}
+
+# ---------------------------
+# The query to send to Derpibooru when looking for new images
+
+query = "my:watched"
+
+# ---------------------------
+# If you want to use a Derpibooru filter when fetching images, enter its ID here
+
+filter_id = 206751 # 56027 is the "Everything" filter, meaning nothing is filtered
+
+# ---------------------------
+# The size the images should be cropped at when they are attached to the notification.
+
+resolution = (1000, 500) # Recommended for Android 12+
+#resolution = (1300, 400) # Recommended for Android 9-11
+
+# ---------------------------
+# The user name associated with the Derpibooru account
+# Notifications are sent to the 'derpibooru-<username>' channel
+
+user_name = "RaindropsSys" \ No newline at end of file
diff --git a/derp.sh b/derp.sh
new file mode 100644
index 0000000..ec49988
--- /dev/null
+++ b/derp.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+python main.py \ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..c1fd0ec
--- /dev/null
+++ b/main.py
@@ -0,0 +1,135 @@
+import requests
+from PIL import Image, ImageFilter, ImageEnhance, ImageOps
+from io import BytesIO
+
+import config.raindrops as config
+
+DERPI_ENDPOINT = "https://derpibooru.org/api/v1/json/search/images"
+NOTIFY_ENDPOINT = f"https://notifications.equestria.dev/derpibooru-{config.user_name}"
+
+
+def should_notify(target_post, sent_list):
+ return target_post['id'] not in sent_list and target_post['processed'] and not target_post["deletion_reason"]
+
+
+def do_request(query, filter_id):
+ params = {"key": api_key, "q": query, "filter_id": filter_id, "per_page": 50}
+
+ return requests.get(DERPI_ENDPOINT, params=params)
+
+
+def get_artists(tags):
+ artists = filter(lambda tag: tag.startswith("artist:"), tags)
+ artists = map(lambda tag: tag.removeprefix("artist:"), artists)
+ artists = format_artists(list(artists))
+
+ return artists
+
+
+def format_artists(artists):
+ if len(artists) == 1:
+ return artists[0]
+
+ return ", ".join(artists[:-1]) + " and " + artists[-1]
+
+
+def get_censored_tags(tags, trigger_tags):
+ overlap = tags.intersection(trigger_tags)
+ return overlap
+
+
+def get_thumbnail(image_url, censor, resolution, target_post):
+ if not target_post['mime_type'].startswith("image/"):
+ return None
+
+ image = Image.open(BytesIO(requests.get(image_url).content))
+ image = image.convert("RGBA")
+
+ thumb = image.resize(resolution)
+ thumb = thumb.filter(ImageFilter.GaussianBlur(80))
+ thumb = ImageEnhance.Brightness(thumb).enhance(0.5)
+
+ if censor:
+ image.filter(ImageFilter.GaussianBlur(40))
+
+ #image = ImageOps.pad(image, config.resolution, color=(0, 0, 0, 0))
+ #thumb.paste(image, (0, 0), image)
+
+ image = ImageOps.contain(image, resolution)
+ thumb.paste(image, ((resolution[0] - image.size[0]) // 2, 0))
+
+ buffer = BytesIO()
+ thumb.save(buffer, format="PNG")
+
+ return buffer
+
+
+def get_prefix(censored_tags):
+ if len(censored_tags) > 0:
+ prefix = "⚠️ " + ", ".join(censored_tags)
+ else:
+ prefix = "safe"
+
+ return prefix
+
+
+def get_description(target_post):
+ if not target_post["description"]:
+ return None
+
+ return target_post["description"].replace("\r", " ").replace("\n", " ").strip()
+
+
+def get_notify_data(target_post, thumb_res, trigger_tags):
+ post_id = target_post["id"]
+ width = target_post["width"]
+ height = target_post["height"]
+ tags = target_post["tags"]
+ censor_tags = get_censored_tags(set(tags), trigger_tags)
+ artists = get_artists(tags)
+
+ prefix = get_prefix(censor_tags)
+ description = get_description(target_post)
+
+ title = f"#{post_id} - by {artists}"
+ message = f"{prefix} - {width}x{height}"
+ censor = len(censor_tags) > 0
+
+ if description:
+ message += f" - {description}"
+
+ click = f"https://derpibooru.org/images/{post_id}"
+ thumb = get_thumbnail(target_post['representations']['medium'], censor, thumb_res, target_post)
+ notify_data = {"title": title, "message": message, "click": click, "thumb": thumb}
+
+ return notify_data
+
+
+def send_notification(notify_data, auth):
+ requests.post(NOTIFY_ENDPOINT, data=notify_data["thumb"].getvalue() if notify_data["thumb"] else None,
+ headers={"Authorization": f"Basic {auth}", "User-Agent": "Mozilla/5.0 (+Derp/0.0)",
+ "Tags": "derpibooru", "Title": notify_data["title"].encode("utf-8"),
+ "Message": notify_data["message"].encode("utf-8"),
+ "Click": notify_data["click"].encode("utf-8"),
+ "Icon": "https://derpicdn.net/img/view/2020/7/23/2406370.png"})
+
+
+api_key = open(config.token_path, "r").read().strip()
+ntfy_auth = open("auth.txt", "r").read().strip()
+
+response = do_request(config.query, config.filter_id if config.filter_id >= 0 else None)
+data = response.json()
+
+with open(config.sent_list_path, "r+") as f:
+ sent = [int(image_id.strip()) for image_id in f.readlines()]
+
+ for post in reversed(data['images']):
+ if not should_notify(post, sent):
+ continue
+
+ post_notify_data = get_notify_data(post, config.resolution, config.triggers)
+ send_notification(post_notify_data, ntfy_auth)
+
+ print(post['id'])
+ sent.append(post['id'])
+ f.write(f"{post['id']}\n")