Back to APIs list

Mastodon API examples & templates

Use these vals as a playground to view and fork Mastodon API examples and templates on Val Town. Run any example below or find templates that can be used as a pre-built solution.

Auto-tooting anniversary posts from https://crimenesdeodio.info/ to remember hate crimes in Spain between 1990-2020.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { postToMastodon } from "https://esm.town/v/sebdd/postToMastodon";
import { newRSSItems } from "https://esm.town/v/stevekrouse/newRSSItems?v=6";
export async function tootLatestPosts({ lastRunAt }: Interval) {
return Promise.all(
(await newRSSItems({
url: "https://crimenesdeodio.info/es/rss-feed-yearly",
lastRunAt,
}))
.slice(0, 2)
.map((item) =>
postToMastodon(
"https://floss.social/api/v1",
Deno.env.get("mastodonAccessToken"),
`${item.title.charAt(0) === "↗" ? "🔗" : "✍️"} ${item.title.replace("↗ ", "")} ${item.link}`,
)
),
);
}

Create your own Myspace profile, deployed to Val town. https://jdan-myspace.web.val.run

Screenshot 2024-04-27 at 7.20.32 PM.png

Click "..." and select Fork to create your own.

Screenshot 2024-04-27 at 7.18.00 PM.png

From there you can:

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
93
94
95
96
97
98
99
100
import { myspaceHtml } from "https://esm.town/v/jdan/myspaceHtml";
import { Hono } from "npm:hono@3";
// TODO: Fetch from key-value
const profile = {
displayName: "Jordan",
seo: {
title: "Jordan Scales | Myspace.com",
},
info: {
imageUrl: "https://jordanscales.com/me.png",
allImagesUrl: "https://instagram.com/jdanscales",
status:
`<span style="color:purple"><em>~*~ do you realize<br>I could have been the one to change your life? - xcx ~*~</em></span>`,
gender: "Male",
age: 31,
location: ["Hoboken, NEW JERSEY", "United States"],
lastLogin: "04/27/2024",
},
contact: {
sendMessage: "mailto:hello@example.com",
forwardToFriend: "https://twitter.com/intent/tweet?url=https%3A%2F%2Fjordanscales.com",
addToFriends: "https://twitter.com/jdan",
addToFavorites: "https://www.val.town/v/jdan/myspace",
},
interests: {
general: "Reading, surfing the web, video games, long walks with friends, bubble tea, programming, chess, art",
music:
"LIGHTS, Daft Punk, Mr. Oizo, The Chemical Brothers, CHVRCHES, Japanese Breakfast, The Prodigy, PVRIS, The Japanese House, Poppy, blink-182, Chrome Sparks, Ashnikko, Rezz, Grimes, Bag Raiders, Kim Petras, Tegan and Sara, Charli XCX, MARINA",
television: " Boardwalk Empire, The Sopranos, The Office, Parks and Recreation, King of Queens, See, Crashing",
books:
"Three Body Problem (Remembrance of Earth's Past trilogy), Alex's Adventures in Numberland, Things to Make and Do in the Fourth Dimension, Ball Lightning",
},
details: {
status: "Single",
hereFor: "Dating, Serious Relationships, Friends, Networking",
hometown: "Middletown, NJ",
sign: "Cancer",
smokeDrink: "No / Sometimes",
occupation: "Webmaster",
},
schools: [
{
details: [
"Stevens Institute of Technology",
"Hoboken, NEW JERSEY",
"Degree: Bachelor's Degree",
"Major: Computer Science",
"Minor: Mathematics, Science and Technology Studies",
],
start: "2010",
end: "2014",
},
{
details: [
"Middletown High School South",
"Middletown, NEW JERSEY",
"President: Computer Club",
],
start: "2006",
end: "2010",
},
],
links: [
{ url: "https://twitter.com/jdan", text: "Twitter" },
{ url: "https://mastodon.xyz/@jordan", text: "Mastodon" },
{ url: "https://github.com/jdan", text: "GitHub" },
{ url: "https://notes.jordanscales.com/", text: "Blog" },
{ url: "https://hash.jordanscales.com/", text: "Hashart" },
],
blog: {
allPostsUrl: "https://notes.jordanscales.com",
posts: [
{
title: "Is this true?",
url: "https://notes.jordanscales.com/is-this-true",
},
{
title: "Operating on Infinite Lists",
url: "https://notes.jordanscales.com/infinite-lists",
},
{
title: "I Peeked Into My Node_Modules Directory And You Won’t Believe What Happened Next",
url: "https://notes.jordanscales.com/node_modules",
},
],
},
blurbs: {
aboutMe:
`My name is Jordan and I'm not sure what to put on my new profile. I'm a software developer based out of Hoboken, New Jersey and I like to
build things that make people smile.<br><br>
I'm currently trying to get better at <a href="https://lichess.org/@/jordanscales">chess</a> and occasionally making
<a href="https://hash.jordanscales.com/">some art</a>.<br><br>
I write the most words on twitter (<a href="https://twitter.com/jdan">@jdan</a>) and <a href="https://notes.jordanscales.com">my blog</a>.<br><br>
`,
whoIdLikeToMeet: "Tom! Thank you for making the Internet truly good for a while. but most of all, Samy is my hero",
},
top8: {

Create your own Myspace profile, deployed to Val town. https://jdan-myspace.web.val.run

Screenshot 2024-04-27 at 7.20.32 PM.png

Click "..." and select Fork to create your own.

Screenshot 2024-04-27 at 7.18.00 PM.png

From there you can:

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
93
94
95
96
97
98
99
100
import { myspaceHtml } from "https://esm.town/v/jdan/myspaceHtml";
import { Hono } from "npm:hono@3";
// TODO: Fetch from key-value
const profile = {
displayName: "Jordan",
seo: {
title: "Jordan Scales | Myspace.com",
},
info: {
imageUrl: "https://jordanscales.com/me.png",
allImagesUrl: "https://instagram.com/jdanscales",
status:
`<span style="color:purple"><em>~*~ do you realize<br>I could have been the one to change your life? - xcx ~*~</em></span>`,
gender: "Male",
age: 31,
location: ["Hoboken, NEW JERSEY", "United States"],
lastLogin: "04/27/2024",
},
contact: {
sendMessage: "mailto:hello@example.com",
forwardToFriend: "https://twitter.com/intent/tweet?url=https%3A%2F%2Fjordanscales.com",
addToFriends: "https://twitter.com/jdan",
addToFavorites: "https://www.val.town/v/jdan/myspace",
},
interests: {
general: "Reading, surfing the web, video games, long walks with friends, bubble tea, programming, chess, art",
music:
"LIGHTS, Daft Punk, Mr. Oizo, The Chemical Brothers, CHVRCHES, Japanese Breakfast, The Prodigy, PVRIS, The Japanese House, Poppy, blink-182, Chrome Sparks, Ashnikko, Rezz, Grimes, Bag Raiders, Kim Petras, Tegan and Sara, Charli XCX, MARINA",
television: " Boardwalk Empire, The Sopranos, The Office, Parks and Recreation, King of Queens, See, Crashing",
books:
"Three Body Problem (Remembrance of Earth's Past trilogy), Alex's Adventures in Numberland, Things to Make and Do in the Fourth Dimension, Ball Lightning",
},
details: {
status: "Single",
hereFor: "Dating, Serious Relationships, Friends, Networking",
hometown: "Middletown, NJ",
sign: "Cancer",
smokeDrink: "No / Sometimes",
occupation: "Webmaster",
},
schools: [
{
details: [
"Stevens Institute of Technology",
"Hoboken, NEW JERSEY",
"Degree: Bachelor's Degree",
"Major: Computer Science",
"Minor: Mathematics, Science and Technology Studies",
],
start: "2010",
end: "2014",
},
{
details: [
"Middletown High School South",
"Middletown, NEW JERSEY",
"President: Computer Club",
],
start: "2006",
end: "2010",
},
],
links: [
{ url: "https://twitter.com/jdan", text: "Twitter" },
{ url: "https://mastodon.xyz/@jordan", text: "Mastodon" },
{ url: "https://github.com/jdan", text: "GitHub" },
{ url: "https://notes.jordanscales.com/", text: "Blog" },
{ url: "https://hash.jordanscales.com/", text: "Hashart" },
],
blog: {
allPostsUrl: "https://notes.jordanscales.com",
posts: [
{
title: "Is this true?",
url: "https://notes.jordanscales.com/is-this-true",
},
{
title: "Operating on Infinite Lists",
url: "https://notes.jordanscales.com/infinite-lists",
},
{
title: "I Peeked Into My Node_Modules Directory And You Won’t Believe What Happened Next",
url: "https://notes.jordanscales.com/node_modules",
},
],
},
blurbs: {
aboutMe:
`My name is Jordan and I'm not sure what to put on my new profile. I'm a software developer based out of Hoboken, New Jersey and I like to
build things that make people smile.<br><br>
I'm currently trying to get better at <a href="https://lichess.org/@/jordanscales">chess</a> and occasionally making
<a href="https://hash.jordanscales.com/">some art</a>.<br><br>
I write the most words on twitter (<a href="https://twitter.com/jdan">@jdan</a>) and <a href="https://notes.jordanscales.com">my blog</a>.<br><br>
`,
whoIdLikeToMeet: "Tom! Thank you for making the Internet truly good for a while. but most of all, Samy is my hero",
},
top8: {

Create your own Myspace profile, deployed to Val town. https://jdan-myspace.web.val.run

Screenshot 2024-04-27 at 7.20.32 PM.png

Click "..." and select Fork to create your own.

Screenshot 2024-04-27 at 7.18.00 PM.png

From there you can:

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
93
94
95
96
97
98
99
100
import { myspaceHtml } from "https://esm.town/v/jdan/myspaceHtml";
import { Hono } from "npm:hono@3";
// TODO: Fetch from key-value
const profile = {
displayName: "Jordan",
seo: {
title: "Jordan Scales | Myspace.com",
},
info: {
imageUrl: "https://jordanscales.com/me.png",
allImagesUrl: "https://instagram.com/jdanscales",
status:
`<span style="color:purple"><em>~*~ do you realize<br>I could have been the one to change your life? - xcx ~*~</em></span>`,
gender: "Male",
age: 31,
location: ["Hoboken, NEW JERSEY", "United States"],
lastLogin: "04/27/2024",
},
contact: {
sendMessage: "mailto:hello@example.com",
forwardToFriend: "https://twitter.com/intent/tweet?url=https%3A%2F%2Fjordanscales.com",
addToFriends: "https://twitter.com/jdan",
addToFavorites: "https://www.val.town/v/jdan/myspace",
},
interests: {
general: "Reading, surfing the web, video games, long walks with friends, bubble tea, programming, chess, art",
music:
"LIGHTS, Daft Punk, Mr. Oizo, The Chemical Brothers, CHVRCHES, Japanese Breakfast, The Prodigy, PVRIS, The Japanese House, Poppy, blink-182, Chrome Sparks, Ashnikko, Rezz, Grimes, Bag Raiders, Kim Petras, Tegan and Sara, Charli XCX, MARINA",
television: " Boardwalk Empire, The Sopranos, The Office, Parks and Recreation, King of Queens, See, Crashing",
books:
"Three Body Problem (Remembrance of Earth's Past trilogy), Alex's Adventures in Numberland, Things to Make and Do in the Fourth Dimension, Ball Lightning",
},
details: {
status: "Single",
hereFor: "Dating, Serious Relationships, Friends, Networking",
hometown: "Middletown, NJ",
sign: "Cancer",
smokeDrink: "No / Sometimes",
occupation: "Webmaster",
},
schools: [
{
details: [
"Stevens Institute of Technology",
"Hoboken, NEW JERSEY",
"Degree: Bachelor's Degree",
"Major: Computer Science",
"Minor: Mathematics, Science and Technology Studies",
],
start: "2010",
end: "2014",
},
{
details: [
"Middletown High School South",
"Middletown, NEW JERSEY",
"President: Computer Club",
],
start: "2006",
end: "2010",
},
],
links: [
{ url: "https://twitter.com/jdan", text: "Twitter" },
{ url: "https://mastodon.xyz/@jordan", text: "Mastodon" },
{ url: "https://github.com/jdan", text: "GitHub" },
{ url: "https://notes.jordanscales.com/", text: "Blog" },
{ url: "https://hash.jordanscales.com/", text: "Hashart" },
],
blog: {
allPostsUrl: "https://notes.jordanscales.com",
posts: [
{
title: "Is this true?",
url: "https://notes.jordanscales.com/is-this-true",
},
{
title: "Operating on Infinite Lists",
url: "https://notes.jordanscales.com/infinite-lists",
},
{
title: "I Peeked Into My Node_Modules Directory And You Won’t Believe What Happened Next",
url: "https://notes.jordanscales.com/node_modules",
},
],
},
blurbs: {
aboutMe:
`My name is Jordan and I'm not sure what to put on my new profile. I'm a software developer based out of Hoboken, New Jersey and I like to
build things that make people smile.<br><br>
I'm currently trying to get better at <a href="https://lichess.org/@/jordanscales">chess</a> and occasionally making
<a href="https://hash.jordanscales.com/">some art</a>.<br><br>
I write the most words on twitter (<a href="https://twitter.com/jdan">@jdan</a>) and <a href="https://notes.jordanscales.com">my blog</a>.<br><br>
`,
whoIdLikeToMeet: "Tom! Thank you for making the Internet truly good for a while. but most of all, Samy is my hero",
},
top8: {
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
// SPDX-License-Identifier: 0BSD
import { id_rsaEncryption, RSAPublicKey } from "npm:@peculiar/asn1-rsa";
import { AsnParser, AsnSerializer } from "npm:@peculiar/asn1-schema";
import { AlgorithmIdentifier, SubjectPublicKeyInfo } from "npm:@peculiar/asn1-x509";
import ky from "npm:ky";
import { base64pad } from "npm:multiformats/bases/base64";
import * as v from "npm:valibot";
const ActorSchema = v.object({
publicKey: v.object({
id: v.string(),
publicKeyPem: v.string(),
}),
});
const data = await ky.get("https://mastodon.social/@Mastodon.json").json();
const { publicKey } = v.parse(ActorSchema, data);
console.log("keyId=%s\n", publicKey.id);
console.log("Public key in SPKI format:\n%s", publicKey.publicKeyPem.trim());
console.log();
const spki = AsnParser.parse(
parsePem(publicKey.publicKeyPem),
SubjectPublicKeyInfo,
);
console.log("SPKI structure:\n%o", spki);
const expectedAlgo = new AlgorithmIdentifier({
algorithm: id_rsaEncryption,
parameters: null,
});
const actualAlgo = spki.algorithm;
console.assert(expectedAlgo.isEqual(actualAlgo));
console.log();
const pkcs1 = AsnParser.parse(spki.subjectPublicKey, RSAPublicKey);
console.log("PKCS #1 structure (SubjectPublicKeyInfo::subjectPublicKey):\n%o", pkcs1);
console.log();
console.log("Public key in PKCS #1 format:");
const bytes = new Uint8Array(AsnSerializer.serialize(pkcs1));
const rsaPublicKeyPem = [
"-----BEGIN RSA PUBLIC KEY-----",
wrap(base64pad.baseEncode(bytes), 64),
"-----END RSA PUBLIC KEY-----",
].join("\n");
console.log(rsaPublicKeyPem);
function parsePem(pem: string) {
pem = pem.replace(/(?:-----(?:BEGIN|END) PUBLIC KEY-----|\s)/g, "");
return base64pad.baseDecode(pem);
}
function wrap(input: string, columns = 64) {
const reLines = new RegExp(`.{${columns}}`, "g");
return input.replace(reLines, (line) => line + "\n");
}
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
import { postToMastodon } from "https://esm.town/v/sebdd/postToMastodon";
import process from "node:process";
const found = new Set();
export async function tootLatestPosts(interval: Partial<Interval>) {
const { lastRunAt = "2023-04-04T00:00:00" } = interval || {};
const lastRunDate = new Date(lastRunAt);
const out = (await Promise.all([
"https://jaandrle.github.io/feeds/nondev.xml",
"https://jaandrle.github.io/feeds/dev.xml",
].map(fetchRSS)))
.flatMap(rss =>
rss.entry
.filter(e => new Date(e.updated) > lastRunDate)
)
.filter(e => {
const f = !found.has(e.id);
if (f) found.add(e.id);
return f;
});
console.log(out);
return out;
}
import { fetchText } from "https://esm.town/v/stevekrouse/fetchText";
import { parseXML } from "https://esm.town/v/stevekrouse/parseXML";
function fetchRSS(url) {
return fetchText(url)
.then(parseXML)
.then(xml => {
const out = xml.rss || xml.feed;
if (!out) throw new Error("Parsing RSS failed (no `rss` or `feed` entry)\n" + xml);
return out;
});
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { mastodon$sumStats } from "https://esm.town/v/jaandrle/mastodon$sumStats";
import { mastodon$fetchInstanceStats } from "https://esm.town/v/jaandrle/mastodon$fetchInstanceStats";
// https://api.val.town/eval/@jaandrle.mastodon$collectStats(@jaandrle.mastodon$instances_cz, 1)
export async function mastodon$collectStats(instances, weeks = 1) {
const data = await Promise.all(
instances.map(mastodon$fetchInstanceStats)
);
return data
.filter(({ stats }) => Boolean(stats) && Array.isArray(stats))
.map(({ instance, stats }) =>
Object.assign(
{ instance },
mastodon$sumStats(stats.slice(0, weeks + 1))
)
);
}
1
2
3
4
5
6
7
import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
export async function mastodon$fetchInstanceStats(instance) {
const url = "https://" + instance + "/api/v1/instance/activity";
const stats = await fetchJSON(url).catch((e) => e);
return { instance, stats };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import process from "node:process";
import { postToMastodon } from "https://esm.town/v/sebdd/postToMastodon";
import { newRSSItems } from "https://esm.town/v/stevekrouse/newRSSItems?v=6";
export async function tootLatestPosts({ lastRunAt }: Interval) {
return Promise.all(
(await newRSSItems({
url: "https://sebastiandedeyne.com/index.xml",
lastRunAt,
}))
.slice(0, 2)
.map((item) =>
postToMastodon(
"https://mastodon.social/api/v1",
process.env.mastodonAccessToken,
`${item.title.charAt(0) === "↗" ? "🔗" : "✍️"} ${
item.title.replace("↗ ", "")
} ${item.link}`,
)
),
);
}
1
2
3
4
5
6
7
8
9
import { mastodon$sumStats } from "https://esm.town/v/jaandrle/mastodon$sumStats";
import { mastodon$instances_cz_stats_last_week } from "https://esm.town/v/jaandrle/mastodon$instances_cz_stats_last_week";
/* No. of statuses, login (~active users) and new registrations
for all Czech instances of Mastodon last week. */
export const mastodon$stats_cz_week = mastodon$instances_cz_stats_last_week.reduce(
(acc, stats) => mastodon$sumStats([acc, stats]),
{ statuses: 0, logins: 0, registrations: 0 },
);

WebFinger

This is a not-quite-complete ActivityPub implementation based on my blog post about building an AP implementation. It includes enough to look up bot@tmcw-activitypub.web.val.run on Mastodon and get some basic information.

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
export const activitypub = async (req: Request) => {
const { Hono } = await import("npm:hono@3.4.3");
const app = new Hono();
const DOMAIN = "tmcw-activitypub.web.val.run";
const USERS = new Map([
[
`acct:bot@${DOMAIN}`,
{
subject: `acct:bot@${DOMAIN}`,
aliases: [],
links: [
{
rel: "http://webfinger.net/rel/profile-page",
type: "text/html",
href: `https://${DOMAIN}/profile`,
},
{
rel: "self",
type: "application/activity+json",
href: `https://${DOMAIN}/u/bot`,
},
],
},
],
]);
const publicKey = `-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7LBs3Qyuh93lRboTNXLN
hj4n92oK5Qg4oS8Cc81AXh04hD7nQSSKBhtarbHy2yPXeiKA+H3EGbcflsLvZCo2
B3OPNo2nGTCMyJM8HWDf/7JCOHHcy4tZC1ldjrItkb1YDABWwfoXxyBiGTyTVXjL
sBX5ArTGUPwctMSOdxlJp0ttFn5WDIHiPzxbSaEX/fzTy+HKr9RvYPu/hWWpXA/W
8QQRacZjslweupZFGCGPX1zJ+P0FSe81uV6N5cOPpy+vFkBQrvApwCSIyp/n7Rfq
UtU+zi/ru+wSxyvnoZPZa+zOXst8+pk7lIbmI6dyJ2+wijkykAxKt2DnDXWOSUGM
R+aNjc6tt8xp2MwmhAz91f1rIt2+jOhkPZ0m6aLV3B86J3iI0BIHXzQNydDtz5/P
EOj79vnnDwjCrWmbsfsIVCmECQDS7EW6Lzdc98GyiD/vyA4Epg3QgpeN4r7fELZj
8IfJJ7J8Z8nYewRoCVNnfvXpR26y+CLftMUi9LtPP1N78er1IdvZEer/8RIAc58r
S5VmDYBBfEduxPh/l3tn4A5Ri8smue26yG+wPkBj3CSqaOaNFxxZPgXcbI2OePrH
81goKk17g+5O0sZJGv+EAeFM1OQPXKqyu0DLY6PHJKGSho/B/BNWQ34vZnQhQF1r
++VZAcLEeqny/Cn6CHoeu5cCAwEAAQ==
-----END PUBLIC KEY-----`;
app.get("/u/bot", (ctx) => {
return ctx.json({
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
],
id: `https://${DOMAIN}/u/bot`,
type: "Person",
preferredUsername: `bot`,
summary: `Photos from ${DOMAIN}.com`,
inbox: `https://${DOMAIN}/api/inbox`,
followers: `https://${DOMAIN}/u/bot/followers`,
icon: {
type: "Image",
mediaType: "image/jpeg",
url: "https://macwright.com/graphics/about.jpg",
},
publicKey: {
id: `https://${DOMAIN}/u/bot#main-key`,
owner: `https://${DOMAIN}/u/bot`,
publicKeyPem: publicKey,
},
});
});
app.get("/.well-known/webfinger", (ctx) => {
const u = new URL(ctx.req.url);
const resource = u.searchParams.get("resource");
if (resource && USERS.has(resource)) {
return new Response(JSON.stringify(USERS.get(resource)), {
status: 200,
headers: { "Content-Type": "application/jrd+json" },
});
}
return new Response("", {
status: 404,
headers: { "Content-Type": "text/html" },
});
});
return app.fetch(req);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { fetch } from "https://esm.town/v/std/fetch";
export function postToMastodon(mastodonApiUrl, mastodonAccessToken, status) {
return fetch(
`${mastodonApiUrl}/statuses?access_token=${mastodonAccessToken}`,
{
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
method: "POST",
body: JSON.stringify({
status,
}),
}
);
}
1
2
3
4
5
6
export function mastodon$sumStats(arr) {
const out = { statuses: 0, logins: 0, registrations: 0 };
for (const key of Object.keys(out))
for (const s of arr) out[key] += Number(s[key]);
return out;
}
1
2
3
4
5
6
import { mastodon$instances_cz } from "https://esm.town/v/jaandrle/mastodon$instances_cz";
import { mastodon$collectStats } from "https://esm.town/v/jaandrle/mastodon$collectStats";
/* No. of statuses, login (~active users) and new registrations
in Czech instances of Mastodon last week. */
export const mastodon$instances_cz_stats_last_week = await mastodon$collectStats(mastodon$instances_cz, 1);
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
export const mastodon$instances_cz = [
"mastodonczech.cz",
"mastodon.arch-linux.cz",
"nasface.cz",
"witter.cz",
"cztwitter.cz",
"mastodon.pirati.cz",
"gomastodon.cz",
"f.cz",
"mastodon.macsnet.cz",
"toot.whatever.cz",
"lgbtcz.social",
"kompost.cz",
"boskovice.social",
"propulse.club",
"mastodon.1984.cz",
"mastodon.rozhlas.cz",
"mastodon.queerclub.cz",
"fediverse.cz",
"kocour.club",
"mastodon.urbancloud.cz",
"mastodon.telekomunikace.cz",
"ajtaci.club",
"mastodon.darksheep.social",
"mastodon.posvic.cz",
"social.filik.eu",
"social.meyer.cz",
"mastodon.vyboh.net",
"mastodon.starnet.cz",
"social.gwei.cz",
"blogator.com",
"hatedon.1984.cz",
"spondr.cz",
"mastodon.loutaci.cz",
"social.toxwat.cz",
"mastodon.hinata.cz",
"hlidacstatu.social",
"mastodon.train.cz",
"mastodon.stan.cz",
"mastodon.haxo.cz",
"mastodon.kiklhorn.cz",
"mastodon.skorpil.cz",
"mastodon.starlink.cz",
"kiklhorn.cz",
"social.bobek.cz",
"mutant.cz",
"social.taborsky.cz",
//"petrzprahy.cz", --- 404 Not Found
"social.lukacern.cz",
"mastodon.zs-studanka.cz",
"rodina-sucha.cz",
];
1
Next