aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinnea Gräf <nea@nea.moe>2025-05-12 20:33:57 +0200
committerLinnea Gräf <nea@nea.moe>2025-05-12 20:33:57 +0200
commit4a6ddab6da2bfce1c97a1138ba529f9b9691d998 (patch)
treed2eb64f2b12af7a268cfde5685080db00aef3941
downloadboobbot-4a6ddab6da2bfce1c97a1138ba529f9b9691d998.tar.gz
boobbot-4a6ddab6da2bfce1c97a1138ba529f9b9691d998.tar.bz2
boobbot-4a6ddab6da2bfce1c97a1138ba529f9b9691d998.zip
Initial commit
-rw-r--r--.editorconfig6
-rw-r--r--.envrc4
-rw-r--r--.gitignore18
-rw-r--r--.gitmodules3
-rw-r--r--.vscode/launch.json16
-rw-r--r--.vscode/tasks.json17
-rw-r--r--README.md5
m---------SimpleWordlists0
-rw-r--r--dub-lock.json124
-rw-r--r--dub.sdl8
-rw-r--r--dub.selections.json48
-rw-r--r--flake.lock48
-rw-r--r--flake.nix48
-rw-r--r--source/app.d18
-rw-r--r--source/backronyms.d81
-rw-r--r--source/misskey.d133
16 files changed, 577 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..bf4651d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,6 @@
+root = true
+[*]
+indent_style = tab
+charset = utf-8
+end_of_line = lf
+insert_final_newline = true
diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..07776ce
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,4 @@
+#!/usr/bin/env bash
+watch_file -- flake-modules/*.nix
+use flake . --show-trace
+dotenv
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ffa1041
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,18 @@
+.dub
+docs.json
+__dummy.html
+docs/
+/boobbot
+boobbot.so
+boobbot.dylib
+boobbot.dll
+boobbot.a
+boobbot.lib
+boobbot-test-*
+*.exe
+*.pdb
+*.o
+*.obj
+*.lst
+.env
+
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..fff51df
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "SimpleWordlists"]
+ path = SimpleWordlists
+ url = https://github.com/taikuukaits/SimpleWordlists/
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..d6c5199
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,16 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": "Launch boobbot",
+ "type": "lldb-dap",
+ "cwd": "${workspaceFolder}",
+ "preLaunchTask": "dub: Build boobbot",
+ "program": "${workspaceFolder}/boobbot",
+ "request": "launch"
+ }
+ ]
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..abbfa73
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ // See https://go.microsoft.com/fwlink/?LinkId=733558
+ // for the documentation about the tasks.json format
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "type": "dub",
+ "run": false,
+ "cwd": "${workspaceFolder}",
+ "problemMatcher": [
+ "$dmd"
+ ],
+ "group": "build",
+ "label": "dub: Build boobbot"
+ }
+ ]
+ }
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..857733c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# boobbot
+
+> backronym ordaining & originating bot
+
+comes up with a new backronym once a day \ No newline at end of file
diff --git a/SimpleWordlists b/SimpleWordlists
new file mode 160000
+Subproject b5441204a529c2897d000675d708ba20047ebfd
diff --git a/dub-lock.json b/dub-lock.json
new file mode 100644
index 0000000..197266a
--- /dev/null
+++ b/dub-lock.json
@@ -0,0 +1,124 @@
+{
+ "dependencies": {
+ "automem": {
+ "version": "0.6.11",
+ "sha256": "0l3cbkji47p9myhdpmm83s4j8rjvdwkyln1hinlw1kzph4dgb5wn"
+ },
+ "cachetools": {
+ "version": "0.4.2",
+ "sha256": "0l24y3pwnwxdf1zkx7nxgiscf2ycyj4a4cqhy2qn9syvmdgy6rd4"
+ },
+ "dcd": {
+ "version": "0.16.0-beta.3",
+ "sha256": "0wcsb3zjjfahkaabl4vbcml6wlh4jykdj8xcllyjnzyzf6nbysn5"
+ },
+ "dfmt": {
+ "version": "0.15.2",
+ "sha256": "18dvsikkjifa2y51zg949czklv33hgbx4cgf9iqzqfad3c4gz9d0"
+ },
+ "diet-complete": {
+ "version": "0.0.3",
+ "sha256": "1klzivhzb185m38jvmm957s38mllpa2rkkv8az8ipmwdjj8z6mpv"
+ },
+ "dscanner": {
+ "version": "0.16.0-beta.4",
+ "sha256": "19k22y9lz5mv2irciaimziqny2nss6d0xf2gm3dyj24l8kx727ms"
+ },
+ "dub": {
+ "version": "1.38.1",
+ "sha256": "1dq16qdshdm2l2785h318wyidwvc2d6sigf1sc8dvvhz93a0j4x2"
+ },
+ "emsi_containers": {
+ "version": "0.9.0",
+ "sha256": "1viz1fjh6jhfvl0d25bb1q7aclm1hrs0d7hhcx1d9c0gg5k6lcpm"
+ },
+ "fuzzymatch": {
+ "version": "1.0.0",
+ "sha256": "1avbpn4qqgkqxzg26flhhwzrz0s59xnicvxh72l0yqabaxjnawsj"
+ },
+ "inifiled": {
+ "version": "1.3.3",
+ "sha256": "01hw0lb9n6vwmx6vj5nq2awg54l5pvngqhzxfj2kmg99az84dg6d"
+ },
+ "isfreedesktop": {
+ "version": "0.1.1",
+ "sha256": "0bnjr9avvhl7s09dnbcdr5437yb18jj26fzvm7j292kvd2i8kzqz"
+ },
+ "jsonizer": {
+ "version": "0.7.7",
+ "sha256": "1pz86ff0h6bn3iv0dbc1ps02n7wa3qji7f7xqa2vssw68wn8y4vl"
+ },
+ "libddoc": {
+ "version": "0.8.0",
+ "sha256": "0vxhkd92rxrkrz0svapdnkzh1bdqhws6wakhjj7szmkvykjgwksc"
+ },
+ "libdparse": {
+ "version": "0.23.2",
+ "sha256": "0bcaasam3iiqisilyx4ysxahjmgifn7i8ny155nwg64bjjibd8dk"
+ },
+ "mir-algorithm": {
+ "version": "3.22.3",
+ "sha256": "0z4zdac9jhdlkb67m8jny006pw0j05sbvn21qsiibk5sazf1dzrp"
+ },
+ "mir-core": {
+ "version": "1.7.1",
+ "sha256": "15m1n48fcmh5pw3w4ww5qfzwkdglflpzc3xmxmrlvd30swyyr85j"
+ },
+ "mir-cpuid": {
+ "version": "1.2.11",
+ "sha256": "1gxrnvvy34cfi71p8a0s904z3zp1l7k9qvliacxmhvykxr1nhrsf"
+ },
+ "mir-ion": {
+ "version": "2.3.3",
+ "sha256": "1fvl0gd627i4r9fvaz2pl5g5bqgf538vbnk31mc5xacmln54cwps"
+ },
+ "msgpack-d": {
+ "version": "1.0.5",
+ "sha256": "1gndqjs17pkgmqvwra9wbvvmvlr1kaj443j3x7xl6jb320hk9dbn"
+ },
+ "requests": {
+ "version": "2.1.3",
+ "sha256": "0j7jz1n5g21cj6kw389raj60hpq7rkak17y84ny7yqv2i3pqwvc5"
+ },
+ "rm-rf": {
+ "version": "0.1.0",
+ "sha256": "0yr2jan7m49y0c6vm8nblvmgqqzw1c19g5m3cb412wwa37k12v5d"
+ },
+ "sdlfmt": {
+ "version": "0.1.1",
+ "sha256": "1qmyy5wn3bgd2q5dhy9wyjry2i3mdnaaml8ggvsz4yn23jrs0kr9"
+ },
+ "sdlite": {
+ "version": "1.1.2",
+ "sha256": "0c7ryphvlnb7330gj0h6xv1rmi8f3jfbkqx8jy02a11yc6syizxz"
+ },
+ "serve-d": {
+ "version": "0.8.0-beta.18",
+ "sha256": "0in059xn7pr8fq5x44wxs0iaab1s2wwgxjxjp399vl4csi2z7kc1"
+ },
+ "silly": {
+ "version": "1.1.1",
+ "sha256": "0fz7ib715sfk3w69i6xns5pwd4caahvfqjf32v13daxm1ms8xdzz"
+ },
+ "standardpaths": {
+ "version": "0.8.2",
+ "sha256": "00xjysxlr9rg1wczvijx1bqnq5vb8iiy3jxhh4m10d7814srvlh0"
+ },
+ "taggedalgebraic": {
+ "version": "0.11.23",
+ "sha256": "1bialmbdwjpqhgs95inkwzin7xbhx7sngjf7viq90vzma497l59k"
+ },
+ "test_allocator": {
+ "version": "0.3.4",
+ "sha256": "1xpjz6smxwgm4walrv3xbzi46cddc80q5n4gs7j9gm2yx11sf7gj"
+ },
+ "unit-threaded": {
+ "version": "2.2.3",
+ "sha256": "070qlnr33miyg6w6q8yvry8nnxng23vdklvbr94dmjrbplxb9fy8"
+ },
+ "xdgpaths": {
+ "version": "0.2.5",
+ "sha256": "09l3bkcldv7ckh3d2cmivvj3cbql96a24g3khlz7zp9f1aabfykl"
+ }
+ }
+}
diff --git a/dub.sdl b/dub.sdl
new file mode 100644
index 0000000..0ed1946
--- /dev/null
+++ b/dub.sdl
@@ -0,0 +1,8 @@
+name "boobbot"
+description "Backronym orderly orginating bot"
+authors "Linnea Gräf"
+copyright "Copyright © 2025, Linnea Gräf"
+license "proprietary"
+dependency "requests" version="~>2.1.3"
+dependency "jsonizer" version="~>0.7.7"
+
diff --git a/dub.selections.json b/dub.selections.json
new file mode 100644
index 0000000..cdaf1fb
--- /dev/null
+++ b/dub.selections.json
@@ -0,0 +1,48 @@
+{
+ "fileVersion": 1,
+ "versions": {
+ "automem": "0.6.11",
+ "cachetools": "0.4.2",
+ "dcd": "0.16.0-beta.3",
+ "dfmt": "0.15.2",
+ "diet-complete": "0.0.3",
+ "diet-ng": "1.8.4",
+ "dscanner": "0.16.0-beta.4",
+ "dub": "1.38.1",
+ "emsi_containers": "0.9.0",
+ "eventcore": "0.9.35",
+ "fuzzymatch": "1.0.0",
+ "inifiled": "1.3.3",
+ "isfreedesktop": "0.1.1",
+ "jsonizer": "0.7.7",
+ "libddoc": "0.8.0",
+ "libdparse": "0.23.2",
+ "mir-algorithm": "3.22.3",
+ "mir-core": "1.7.1",
+ "mir-cpuid": "1.2.11",
+ "mir-ion": "2.3.3",
+ "mir-linux-kernel": "1.2.1",
+ "msgpack-d": "1.0.5",
+ "openssl": "3.3.4",
+ "openssl-static": "1.0.5+3.0.8",
+ "requests": "2.1.3",
+ "rm-rf": "0.1.0",
+ "sdlfmt": "0.1.1",
+ "sdlite": "1.1.2",
+ "serve-d": "0.8.0-beta.18",
+ "silly": "1.1.1",
+ "standardpaths": "0.8.2",
+ "stdx-allocator": "2.77.5",
+ "taggedalgebraic": "0.11.23",
+ "test_allocator": "0.3.4",
+ "unit-threaded": "2.2.3",
+ "vibe-container": "1.6.2",
+ "vibe-core": "2.11.0",
+ "vibe-d": "0.10.2",
+ "vibe-http": "1.2.2",
+ "vibe-inet": "1.1.2",
+ "vibe-serialization": "1.1.1",
+ "vibe-stream": "1.1.1",
+ "xdgpaths": "0.2.5"
+ }
+}
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..e7e77db
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,48 @@
+{
+ "nodes": {
+ "flake-parts": {
+ "inputs": {
+ "nixpkgs-lib": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1743550720,
+ "narHash": "sha256-hIshGgKZCgWh6AYJpJmRgFdR3WUbkY04o82X05xqQiY=",
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "rev": "c621e8422220273271f52058f618c94e405bb0f5",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "flake-parts",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1746904237,
+ "narHash": "sha256-3e+AVBczosP5dCLQmMoMEogM57gmZ2qrVSrmq9aResQ=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "d89fc19e405cb2d55ce7cc114356846a0ee5e956",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixos-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-parts": "flake-parts",
+ "nixpkgs": "nixpkgs"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..8214933
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,48 @@
+{
+ inputs = {
+ # dlang-nix.url = "github:PetarKirov/dlang-nix";
+ nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
+ flake-parts = {
+ url = "github:hercules-ci/flake-parts";
+ inputs.nixpkgs-lib.follows = "nixpkgs";
+ };
+ };
+
+ outputs = inputs @ {flake-parts, ...}:
+ flake-parts.lib.mkFlake {inherit inputs;} {
+ systems = ["x86_64-linux" "x86_64-darwin" "aarch64-darwin"];
+ perSystem = {
+ inputs',
+ pkgs,
+ ...
+ }: {
+ packages = {
+ boobbot = pkgs.buildDubPackage {
+ pname = "boobbot";
+ version = "0.0.0";
+ src = ./.;
+ dubLock = ./dub-lock.json;
+ installPhase = ''
+ runHook preInstall
+ install -Dm755 boobbot -t $out/bin
+ runHook postInstall
+ '';
+ buildInputs = [pkgs.openssl];
+ };
+ };
+ formatter = pkgs.alejandra;
+ devShells.default = pkgs.mkShell rec {
+ buildInputs = [
+ pkgs.openssl
+ ];
+ LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs;
+ packages = [
+ pkgs.ldc
+ pkgs.dub
+ pkgs.lldb
+ pkgs.dub-to-nix
+ ];
+ };
+ };
+ };
+}
diff --git a/source/app.d b/source/app.d
new file mode 100644
index 0000000..b60e192
--- /dev/null
+++ b/source/app.d
@@ -0,0 +1,18 @@
+import std.stdio;
+import backronyms;
+import misskey;
+import std.process;
+import std.logger;
+void main()
+{
+ globalLogLevel = LogLevel.trace;
+ info("Hello world");
+ auto generator = BackronymGenerator.load;
+ auto misskey = new MisskeyClient(
+ environment.get("MISSKEY_INSTANCE"),
+ environment.get("MISSKEY_TOKEN")
+ );
+
+ auto boobFormat = "boob is short for\n\n" ~ generator.formatBackronymList("boob");
+ writefln("%s", misskey.createNote(new BasicNote("public", boobFormat)));
+}
diff --git a/source/backronyms.d b/source/backronyms.d
new file mode 100644
index 0000000..7b3c9e6
--- /dev/null
+++ b/source/backronyms.d
@@ -0,0 +1,81 @@
+module backronyms;
+import std.stdio;
+import std.algorithm;
+import std.random;
+import std.conv;
+import std.range;
+import std.typecons;
+
+struct BackronymGenerator
+{
+ WordList nouns;
+ WordList adjectives;
+
+ static BackronymGenerator load()
+ {
+ return BackronymGenerator(
+ WordList.fromFile("SimpleWordlists/Wordlist-Nouns-Common-Audited-Len-3-6.txt"),
+ WordList.fromFile("SimpleWordlists/Wordlist-Adjectives-All.txt"),
+ );
+ }
+
+ string formatBackronymList(string word)
+ {
+ string ret;
+ for (int i = 0; i < word.length; i++)
+ {
+ ret ~= (
+ i + 1 == word.length
+ ? this.nouns : this.adjectives
+ ).findRandomWord(word[i]);
+ ret ~= '\n';
+ }
+ return ret;
+ }
+}
+
+struct WordList
+{
+
+ string[][char] words;
+
+ string[] findBackronym(string word)
+ {
+ string[] ret;
+
+ foreach (c; word)
+ {
+ ret ~= this.findRandomWord(c);
+ }
+
+ return ret;
+ }
+
+ string findRandomWord(char start)
+ {
+ return this.words[start].choice;
+ }
+
+ static WordList fromFile(string filePath)
+ {
+ auto file = File(filePath);
+ return fromLines(file.byLine.map!(to!string));
+ }
+
+ static WordList fromLines(R)(R lines)
+ if (isInputRange!R && is(ElementType!R == string))
+ {
+ WordList ret;
+
+ foreach (line; lines)
+ {
+ if (line.length == 0)
+ continue;
+
+ ret.words[line[0]] ~= line;
+ }
+
+ return ret;
+ }
+
+}
diff --git a/source/misskey.d b/source/misskey.d
new file mode 100644
index 0000000..823dbe0
--- /dev/null
+++ b/source/misskey.d
@@ -0,0 +1,133 @@
+module misskey;
+import requests;
+import std.logger;
+import std.format;
+import std.conv;
+import jsonizer;
+
+class MisskeyException : Exception
+{
+
+ string path;
+ Response response;
+ this(
+ Response response,
+ string path,
+ string msg,
+ string file = __FILE__, size_t line = __LINE__)
+ {
+ super("at path " ~ path ~ ": " ~ msg, file, line);
+ this.response = response;
+ this.path = path;
+ }
+}
+
+class MisskeyClient
+{
+ string instanceUrl;
+ string token;
+ this(string instanceUrl, string token)
+ {
+ this.instanceUrl = instanceUrl;
+ this.token = token;
+ assert(token.length != 0);
+ assert(instanceUrl.length != 0);
+ }
+
+ T request(string method, string path, T, R)(R body)
+ {
+ static assert(path[0] == '/');
+ auto req = Request();
+ req.addHeaders([
+ "user-agent": "boobbot",
+ "authorization": format("Bearer %s", this.token)
+ ]);
+ auto fullPath = format("%s/api%s", this.instanceUrl, path);
+ auto reqBody = toJSONString!R(body);
+ infof("Executing request to %s with headers %s", fullPath, req.headers);
+ Response response = mixin("req." ~ method)(
+ fullPath,
+ reqBody,
+ "application/json"
+ );
+ if (response.code / 100 != 2)
+ throw new MisskeyException(response, path, format("non 200 status code: %s", response
+ .code));
+ return fromJSONString!T(to!string(response.responseBody));
+ }
+
+ CreateNoteResponse createNote(BasicNote note)
+ {
+ return this.request!("post", "/notes/create", CreateNoteResponse, BasicNote)(note);
+ }
+
+}
+
+class BasicNote
+{
+ mixin JsonizeMe;
+
+ @jsonize(Jsonize.opt)
+ {
+ string visibility;
+ string text;
+ string id;
+ }
+
+ this()
+ {
+ }
+
+ this(string visibility, string text)
+ {
+ this.visibility = visibility;
+ this.text = text;
+ this.id = "";
+ }
+
+}
+
+class CreateNoteResponse
+{
+ mixin JsonizeMe;
+
+ @jsonize
+ BasicNote createdNote;
+}
+
+/*
+curl https://sk.amy.rip/api/notes/create \
+ --request POST \
+ --header 'Content-Type: application/json' \
+ --header 'Authorization: Bearer aaaaaaaaaa' \
+ --data '{
+ "visibility": "public",
+ "visibleUserIds": [
+ ""
+ ],
+ "cw": null,
+ "localOnly": false,
+ "reactionAcceptance": null,
+ "noExtractMentions": false,
+ "noExtractHashtags": false,
+ "noExtractEmojis": false,
+ "replyId": null,
+ "renoteId": null,
+ "channelId": null,
+ "text": null,
+ "fileIds": [
+ ""
+ ],
+ "mediaIds": [
+ ""
+ ],
+ "poll": {
+ "choices": [
+ ""
+ ],
+ "multiple": true,
+ "expiresAt": null,
+ "expiredAfter": null
+ }
+}'
+*/