initial commit
This commit is contained in:
commit
c70fc72952
143 changed files with 13594 additions and 0 deletions
149
workers/mastodon/index.js
Normal file
149
workers/mastodon/index.js
Normal file
|
@ -0,0 +1,149 @@
|
|||
import { XMLParser } from "fast-xml-parser";
|
||||
import { convert } from "html-to-text";
|
||||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
const BASE_URL = "https://coryd.dev";
|
||||
|
||||
export default {
|
||||
async scheduled(event, env) {
|
||||
await handleMastodonPost(env);
|
||||
},
|
||||
};
|
||||
|
||||
async function handleMastodonPost(env) {
|
||||
const mastodonApiUrl = "https://follow.coryd.dev/api/v1/statuses";
|
||||
const accessToken = env.MASTODON_ACCESS_TOKEN;
|
||||
const rssFeedUrl = "https://coryd.dev/feeds/syndication";
|
||||
const supabaseUrl = env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
try {
|
||||
const latestItems = await fetchRSSFeed(rssFeedUrl);
|
||||
|
||||
for (let i = latestItems.length - 1; i >= 0; i--) {
|
||||
const item = latestItems[i];
|
||||
const existingPost = await env.RSS_TO_MASTODON_NAMESPACE.get(item.link);
|
||||
|
||||
if (existingPost) continue;
|
||||
|
||||
const title = item.title;
|
||||
const link = item.link;
|
||||
const maxLength = 500;
|
||||
const plainTextDescription = convert(item.description, {
|
||||
wordwrap: false,
|
||||
selectors: [
|
||||
{ selector: "a", options: { ignoreHref: true } },
|
||||
{ selector: "h1", options: { uppercase: false } },
|
||||
{ selector: "h2", options: { uppercase: false } },
|
||||
{ selector: "h3", options: { uppercase: false } },
|
||||
{ selector: "*", format: "block" },
|
||||
],
|
||||
});
|
||||
|
||||
const cleanedDescription = plainTextDescription
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
const content = truncateContent(
|
||||
title,
|
||||
cleanedDescription,
|
||||
link,
|
||||
maxLength
|
||||
);
|
||||
|
||||
const mastodonPostUrl = await postToMastodon(
|
||||
mastodonApiUrl,
|
||||
accessToken,
|
||||
content
|
||||
);
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
await env.RSS_TO_MASTODON_NAMESPACE.put(link, timestamp);
|
||||
|
||||
if (link.includes("coryd.dev/posts")) {
|
||||
const slug = link.replace(BASE_URL, "");
|
||||
await addMastodonUrlToPost(supabase, slug, mastodonPostUrl);
|
||||
}
|
||||
|
||||
console.log(`Posted stored URL: ${link}`);
|
||||
}
|
||||
|
||||
console.log("RSS processed successfully");
|
||||
} catch (error) {
|
||||
console.error("Error in scheduled event:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function addMastodonUrlToPost(supabase, slug, mastodonPostUrl) {
|
||||
const { data, error } = await supabase
|
||||
.from("posts")
|
||||
.update({ mastodon_url: mastodonPostUrl })
|
||||
.eq("slug", slug);
|
||||
|
||||
if (error) {
|
||||
console.error("Error updating post:", error);
|
||||
} else {
|
||||
console.log(`Updated post with Mastodon URL: ${mastodonPostUrl}`);
|
||||
}
|
||||
}
|
||||
|
||||
function truncateContent(title, description, link, maxLength) {
|
||||
const baseLength = `${title}\n\n${link}`.length;
|
||||
const availableSpace = maxLength - baseLength - 4;
|
||||
let truncatedDescription = description;
|
||||
|
||||
if (description.length > availableSpace)
|
||||
truncatedDescription =
|
||||
description
|
||||
.substring(0, availableSpace)
|
||||
.split(" ")
|
||||
.slice(0, -1)
|
||||
.join(" ") + "...";
|
||||
|
||||
truncatedDescription = truncatedDescription.replace(/\s+([.,!?;:])/g, "$1");
|
||||
|
||||
return `${title}\n\n${truncatedDescription}\n\n${link}`;
|
||||
}
|
||||
|
||||
async function fetchRSSFeed(rssFeedUrl) {
|
||||
const response = await fetch(rssFeedUrl);
|
||||
const rssText = await response.text();
|
||||
const parser = new XMLParser();
|
||||
const rssData = parser.parse(rssText);
|
||||
const items = rssData.rss.channel.item;
|
||||
|
||||
let latestItems = [];
|
||||
|
||||
items.forEach((item) => {
|
||||
const title = item.title;
|
||||
const link = item.link;
|
||||
const description = item.description;
|
||||
latestItems.push({ title, link, description });
|
||||
});
|
||||
|
||||
return latestItems;
|
||||
}
|
||||
|
||||
async function postToMastodon(apiUrl, accessToken, content) {
|
||||
const response = await fetch(apiUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ status: content }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(
|
||||
`Error posting to Mastodon: ${response.statusText} - ${errorText}`
|
||||
);
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
console.log("Posted to Mastodon successfully.");
|
||||
|
||||
return responseData.url;
|
||||
}
|
21
workers/mastodon/wrangler.template.toml
Normal file
21
workers/mastodon/wrangler.template.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
name = "rss-to-mastodon-worker"
|
||||
main = "./index.js"
|
||||
compatibility_date = "2023-01-01"
|
||||
|
||||
account_id = "${CF_ACCOUNT_ID}"
|
||||
workers_dev = true
|
||||
|
||||
[observability]
|
||||
enabled = true
|
||||
|
||||
[[kv_namespaces]]
|
||||
binding = "RSS_TO_MASTODON_NAMESPACE"
|
||||
id = "${RSS_TO_MASTODON_KV_NAMESPACE_ID}"
|
||||
|
||||
[env.production]
|
||||
name = "rss-to-mastodon-worker-production"
|
||||
triggers = { crons = ["*/15 * * * *"] }
|
||||
|
||||
[[env.production.kv_namespaces]]
|
||||
binding = "RSS_TO_MASTODON_NAMESPACE"
|
||||
id = "${RSS_TO_MASTODON_KV_NAMESPACE_ID}"
|
Reference in a new issue