Home Firefish Plugin - Share to Mastodon
Post
Cancel

Firefish Plugin - Share to Mastodon

Share a note to Mastodon from your Firefish timeline. Syndication

I’m having a lot of fun building these plugins. Ever wanted to share a Firefish post to your Mastodon account? I’ve got something for you. And, if you’re interested in how the Plugin works, check the bottom of the post and we’ll go through some of the more interesting bits I learned from working on the plugin, namely syntax, api and local storage.

Let’s get this installed!


Overview

This plugin offers a way to share notes on your Firefish server to your Mastodon account. After installation and setup, on any note in your Firefish timeline, open the “More…” dialog along the bottom of a note. The last item in the list will be “Share to Mastodon”. Click it, and your Mastodon instance’s /share page will be opened with a reference to the Firefish note and the author. If you haven’t logged in to your Mastodon instance yet, you’ll need to do that first.

If the note you chose to share is not identified as a public note, or is a public note marked as local only, you’ll get a dialog alerting you to this issue, and the sharing website action won’t proceed.

Share to Mastodon Menu Item Mastodon Share Card

Settings

The plugin has a single setting you can configure to customize your experience.

In the new plugin item called “Share to Mastodon” found in Settings > Plugins, choose the Settings button, then enter your Mastodon domain, complete with https:// at the beginning of the URL. Click the Check mark on the top right of the modal, and you’re done with configuration.

Setting Description
Mastodon Server Url The Url of your Mastodon instance. For example, https://mastodon.social

The Mastodon Server Url setting is required. If you try to use the “Share to Mastodon” action without it, you’ll get a nice little message telling you to go back and add it. So do it now so you don’t have to come back. 😀

Installation

If you’re on a Firefish server, you can install this plugin by copying the code below into the Settings > Plugins section. You can read more about installing plugins here or watch a video demonstration of the process here.

On your Firefish instance’s website, go to Settings > Plugins, then choose “Install Plugins”.

As it states, only install plugins from trusted sources.

You trust me, right?

Paste the code from below into the textarea, and click Install. Initially, you won’t see anything. Click the Settings > Plugins menu item again and you should see the new plugin installed.

Click the Settings button and enter your Mastodon server’s url, then click the Check mark on the top right of the modal. You’re done!

Share to Mastodon Plugin Overview and Settings Dialogs

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/// @ 0.11.1
### {
  name: "Share to Mastodon"
  version: "0.11.1.0.001"
  author: "@box464@calckey.social"
  description: "Share a Firefish post to your Mastodon account using Mastodon's share url. Will only share posts marked as public and not restricted to local viewing."
  permission: []
  config: {
    mastodon_server: {
      type: "string"
      label: "Mastodon Server Url (in the form: https://mastodon.social)"
      default: ""
    }
  }
}

@handler(note) {
  $noteText <- ""
  $canDisplay <- yes

  $mastodonServer <- Plugin:config.mastodon_server
  $calckeyServer <- Mk:load("ShareToMastodon_CalckeyServer")

  ? ((calckeyServer = _) | (calckeyServer = "")) {
    // This API call does not require any permissions, it's a public endpoint and does not contain any personal data
    #metaData = Mk:api("meta", {})
    calckeyServer <- metaData.uri

    // This saves to local storage with the naming convention of "aiscript:plugins:[PluginGuid]:[MkSaveKey]"
    // This will save to the local storage key: "aiscript:plugins:[PluginGuid]:ShareToMastodon_CalckeyServer"
    Mk:save("ShareToMastodon_CalckeyServer" calckeyServer)
  }

  ? ((mastodonServer = _ ) | (Str:len(mastodonServer) = 0)) {
    canDisplay <- no
      noteText <- "Add your Mastodon Server Url to the Share to Mastodon Plugin Settings"
  } . {
    mastodonServer <- Str:replace(mastodonServer, "http://", "https://")

    ? (Str:index_of(mastodonServer, "https") = 0) {
      mastodonServer <- Arr:join("https://" mastodonServer)
    }
  }

  ? ((canDisplay = yes) & (note.visibility != "public")) {
    canDisplay <- no
    ? (Str:len(noteText) > 0) {
      noteText <- Arr:join([noteText Str:lf "The note was not shared to public audiences."])
    } . {
      noteText <- "The note was not shared to public audiences."
    }
  }

  ? ((canDisplay = yes) & (note.localOnly = yes)) {
    canDisplay <- no
    ? (Str:len(noteText) > 0) {
      noteText <- Arr:join([noteText Str:lf "The note was only shared to the local server."])
    } . {
      noteText <- "The note was only shared to the local server."
    }
  }

  ? (canDisplay = yes) {
    effect(note, calckeyServer)
  } . {
   Mk:dialog("Note can't be shared." noteText)
  }

  note
}

@effect(note_, calckeyServer_) {
  $userHost <- note_.user.host
  $noteUrl <- note_.url
  ? (userHost = _) {
    userHost <- Str:replace(calckeyServer_, "https://", "")
  }

  ? (noteUrl = _) {
    noteUrl <- Arr:join([calckeyServer_ "/notes/" note_.id])
  }

  $noteText <- Str:replace(Str:replace(Arr:join(["Sharing a post from @" note_.user.username "@" userHost]) "/" "%2F") "#" "%23")

  noteText <- Arr:join([noteText "%0A%0A" noteUrl])

  Plugin:open_url(Arr:join([Plugin:config.mastodon_server "/share?text=" noteText]))

  note_
}

Plugin:register_note_action("Share to Mastodon" handler)

Digging Deeper

This plugin used some features that were new to me, and I was excited to see them work.

Mk:api

This function is custom to Misskey / Calckey. It’s not part of the stock AiScript language. It’s a function that provides you access to the entire Firefish API. Yes, that’s right - you can utilize any user accessible API endpoint from AiScript! So, if you’re not an admin, you wouldn’t be able to access the Admin endpoints, for example. It’s whatever the logged in user has access to do.

This is both GREAT but also a bit SCARY because if I wanted to be a bad actor, I guess I could use it to post something to the timeline the user isn’t expecting.

That’s why it’s important to understand how plugins works. Or, at least only install plugins from trusted sources!

The call I’m making from this plugin is as follows:

Mk:api("meta", {})

This calls a public endpoint to receive the metatdata for the server. It contains no user data and you can’t write back to the account or make new posts, etc. So, in this specific instance, I do not have to set permissions in my plugin to access the endpoint.

Mk:save and Mk:load

I was a little worried about making calls to the API everytime I needed to grab the current server’s metadata. So I found a way to save the content to local storage! I only have to make a single call the first time the plugin is used. Then I just pull the content locally. Sweet!

Here’s some detail about it.

I need the Firefish Server url because for whatever reason, local posts do not contain this information in the note itself. Notes from external servers do.

In any case, after I make the API call, I then call Mk:save as follows:

Mk:save("ShareToMastodon_CalckeyServer" calckeyServer)

This stores the value in your browser’s local storage. It sticks around even if you log out. It’s very sticky. I think you have to clear the browser cache to get rid of it.

A suggestion here, name your local storage key with the plugin name in it. I used “ShareToMastodon_CalckeyServer” because I wanted to make sure it was identifiable when I was looking in the Developer’s Console.

I just noticed that it also sticks around after you uninstall the plugin…might open an issue about that one. While harmless, it would be good to do some cleanup, especially if Plugins take off and we have tons of them using local storage.

Firefish Local Storage

Now I can check local storage FIRST for the value before calling the API every time. Nice!

` $calckeyServer <- Mk:load(“ShareToMastodon_CalckeyServer”)`

Conditional Logic Puzzles

This is really confusing and there is no documentation about this exact coding structure, so I hope I can save you some pain here.

When you have more than one conditional check in a single IF statement, there’s a few things to consider.

  • If you’re using an AND conditional, you use &, not &&
  • If you’re using an OR conditional, you use |, not ||

I made that mistake SO. MANY. TIMES. Coming from C# and Javascript, it’s just.. natural.

Second, this got me for a few hours unfortunately. When you have more than one condition, it appears you need to wrap each condition in their own parentheses or it won’t work for some reason.

I assume if you had even more complex conditionals, you’d have to keep adding parentheses around each individual condition PLUS the group of conditionals you need.

So instead of this in javascript:

1
2
3
4
5
6
7
if (bEnabled == true && bWriteAccess == true) {
	// do something
}

if (bEnabled == true || bUserIsLoggedIn == true) {
	// do something
}

You’ve got to write:

1
2
3
4
5
6
7
? ((bEnabled = yes) & (bWriteAccess = true)) {
	// do something
}

? ((bEnabled = yes) | (bUserIsLoggedIn = yes)) {
	// do something
}
This post is licensed under CC BY 4.0 by the author.