diff --git a/README.md b/README.md index 41fc07f..b28ae21 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,3 @@ # misskey-plugins Collection of plugins for Misskey and associated software. - - ---- -## Getting Started - -Welcome to your new KitsuDev Repo, bunnybeam! Feel free to make this place your own! - -## Make your first push! -Once you're ready to push your files, use these commands to get to your spot! -```bash -git remote add origin https://kitsunes.dev/bunnybeam/misskey-plugins.git -git branch -M main -git push -uf origin main -``` - -Once you're all set, please [Make a README](https://www.makeareadme.com/)! - ---- -Have fun, and happy coding! - --- Kio - -(p.s. and while you're at it, say hi to pearl.) diff --git a/arr-equal.ais b/arr-equal.ais new file mode 100644 index 0000000..0df6206 --- /dev/null +++ b/arr-equal.ais @@ -0,0 +1,51 @@ +@arr_equal(arr1, arr2) { + if arr1.len != arr2.len { + return false + } + for let i,arr1.len { + if arr1[i] != arr2[i] { + return false + } + } + return true +} + +// TESTS + +let unit_tests = [] + +@deftest(test_name, test_func) { + unit_tests.push({name: test_name, func: test_func}) +} + +deftest("arr_equal pos", @() { + return arr_equal([1, 2, 3], [1, 2, 3]) +}) + +deftest("arr_equal neg element", @() { + return !arr_equal([1, 2, 3], [1, 2, 4]) +}) + +deftest("arr_equal neg size", @() { + return !arr_equal([1, 2, 3], [1, 2]) +}) + +@run_all_tests() { + print("Running unit tests...") + var fails = 0 + each let test, unit_tests { + if !test.func() { + fails += 1 + print(`Test {test.name} failed.`) + } + } + if fails == 0 { + print(`All {unit_tests.len} tests successful!`) + return true + } + print(`{fails}/{unit_tests.len} tests failed.`) + Mk:dialog("Load error", "An error occurred while loading the plugin. Please contact the script author.", "error") + return false +} + +run_all_tests() diff --git a/headmate-hopper.ais b/headmate-hopper.ais new file mode 100644 index 0000000..65fb627 --- /dev/null +++ b/headmate-hopper.ais @@ -0,0 +1,174 @@ +/// @ 0.19.0 +### { + name: "Headmate Hopper" + version: "1.0.0" + author: "@bunnybeam@transfem.social" + description: "Adds a tag containing the name of the selected headmate to the end of all new posts." + permissions: ["read:account", "write:account"] + config: { + headmates: { + type: "string" + label: "Headmates" + description: "List of headmate names. Separate with commas." + default: "Headmate 1, Headmate 2" + } + change_name: { + type: "boolean" + label: "Change display name" + description: "If enabled, selecting a headmate will add them to your display name. Requires permission to view and edit account info." + default: false + } + enable_attribution: { + type: "boolean" + label: "Enable attribution" + description: "If enabled, an attribution tag will be inserted into the post, linking back to the plugin page." + default: false + } + tag_template: { + type: "string" + label: "Tag template" + description: "Template for the headmate tag. '%[name]' is replaced with the current headmate name." + default: "- posted by %[name]" + } + note_template: { + type: "string" + label: "Note template" + description: "Template for new notes. %[text] - Raw note contents. %[br] - Line break. %[tag] - Headmate tag. %[attrib] - Attribution tag (or nothing if attribution is disabled)." + default: "%[text]%[br]%[br]%[tag]%[attrib]" + } + attribution_tag: { + type: "string" + label: "Attribution tag" + description: "Content of the attribution tag. Inserted when attribution is enabled. '%[br]' is replaced with a line break." + default: "%[br]?[Headmate Hopper](https://kitsunes.dev/bunnybeam/misskey-plugins/src/branch/main/headmate-hopper.ais)" + } + } +} + +// Format the note, inserting the note text, headmate tag and attribution tag into the template +@format_note(template, note_text, headmate_tag, attribution_tag) { + if Plugin:config.enable_attribution { + template = template.replace("%[attrib]", attribution_tag) + } else { + template = template.replace("%[attrib]", "") + } + template = template.replace("%[br]", Str:lf) + template = template.replace("%[tag]", headmate_tag) + template = template.replace("%[text]", note_text) + return template +} + +// Return the tag template with the headmate name inserted +@make_tag_from_name(headmate_name) { + return Plugin:config.tag_template.replace("%[name]", headmate_name) +} + +// Get the list of headmates by splitting the config line and trimming the results +@get_headmate_list() { + let raw_list = Plugin:config.headmates.split(",") + let new_list = [] + each let name, raw_list { + new_list.push(name.trim()) + } + return new_list +} + +// Check if `text` already contains the headmate tag +@already_tagged(text) { + return text.incl(make_tag_from_name(headmate_name)) +} + +// Attempt to change the display name. Returns true if successful, false otherwise. +@change_display_name(name) { + // Attempt to read the display name + let read_res = Mk:api("i", {}) + if read_res.info != null { + var message = "An unknown error occurred when attempting to read the current display name." + if read_res.info.code == "PERMISSION_DENIED" { + message = "The 'View account information' permission must be enabled in order to change your display name." + } + Mk:dialog("Error reading display name", message, "error") + return false + } + var new_name = read_res.name.replace(` ({headmate_name})`, "") + if name != "" { + new_name = `{new_name} ({name})` + } + + // Attempt to set the display name + let write_res = Mk:api("i/update", {name: new_name}) + if write_res.info != null { + var message = "An unknown error occurred when attempting to edit the current display name." + if write_res.info.code == "PERMISSION_DENIED" { + message = "The 'Edit account information' permission must be enabled in order to change your display name." + } + Mk:dialog("Error setting display name", message, "error") + return false + } + return true +} + +// Select a new headmate name +@select_headmate_name(name) { + if Plugin:config.change_name { + if !change_display_name(name) { + return false + } + } + headmate_name = name + Mk:save("headmate", name) +} + +@arr_equal(arr1, arr2) { + if arr1.len != arr2.len { + return false + } + for let i,arr1.len { + if arr1[i] != arr2[i] { + return false + } + } + return true +} + +Plugin:register_note_post_interruptor(@(note) { + // Filter to only the fields we're allowed to use + let new_note = {} + let keys = Obj:keys(note) + each let key, keys { + if note[key] != null { + new_note[key] = note[key] + } + } + + // Skip if there is no headmate selected + if headmate_name == "" { + return new_note + } + + // Skip if the note already contains the tag + let headmate_tag = make_tag_from_name(headmate_name) + if new_note.text.incl(headmate_tag) { + return new_note + } + + new_note.text = format_note(Plugin:config.note_template, new_note.text, headmate_tag, Plugin:config.attribution_tag) + + return new_note +}) + +// Register post form actions for each headmate +each let name, get_headmate_list() { + Plugin:register_post_form_action(`Switch to {name}`, @(note, rewrite) { + select_headmate_name(name) + }) +} +Plugin:register_post_form_action("Clear fronter", @(note, rewrite) { + select_headmate_name("") +}) + +// Load the persistent selected headmate +var headmate_name = Mk:load("headmate") +if headmate_name == null { + select_headmate_name("") +}