diff options
| author | Linnea Gräf <nea@nea.moe> | 2025-05-12 20:33:57 +0200 |
|---|---|---|
| committer | Linnea Gräf <nea@nea.moe> | 2025-05-12 20:33:57 +0200 |
| commit | 4a6ddab6da2bfce1c97a1138ba529f9b9691d998 (patch) | |
| tree | d2eb64f2b12af7a268cfde5685080db00aef3941 | |
| download | boobbot-4a6ddab6da2bfce1c97a1138ba529f9b9691d998.tar.gz boobbot-4a6ddab6da2bfce1c97a1138ba529f9b9691d998.tar.bz2 boobbot-4a6ddab6da2bfce1c97a1138ba529f9b9691d998.zip | |
Initial commit
| -rw-r--r-- | .editorconfig | 6 | ||||
| -rw-r--r-- | .envrc | 4 | ||||
| -rw-r--r-- | .gitignore | 18 | ||||
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | .vscode/launch.json | 16 | ||||
| -rw-r--r-- | .vscode/tasks.json | 17 | ||||
| -rw-r--r-- | README.md | 5 | ||||
| m--------- | SimpleWordlists | 0 | ||||
| -rw-r--r-- | dub-lock.json | 124 | ||||
| -rw-r--r-- | dub.sdl | 8 | ||||
| -rw-r--r-- | dub.selections.json | 48 | ||||
| -rw-r--r-- | flake.lock | 48 | ||||
| -rw-r--r-- | flake.nix | 48 | ||||
| -rw-r--r-- | source/app.d | 18 | ||||
| -rw-r--r-- | source/backronyms.d | 81 | ||||
| -rw-r--r-- | source/misskey.d | 133 |
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 @@ -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" + } + } +} @@ -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 + } +}' +*/ |
