feat: INIT

This commit is contained in:
Maurice Renck 2024-01-12 13:30:45 +01:00
parent d4da07733e
commit 6d2887f667
No known key found for this signature in database
GPG Key ID: D0268340AC44A414
6 changed files with 2515 additions and 0 deletions

5
.env.sample Normal file
View File

@ -0,0 +1,5 @@
MASTODON_INSTANCE="https://mastodon.instance"
MASTODON_USER="username"
BLUESKY_ENDPOINT="https://bsky.social"
BLUESKY_HANDLE="USERNAME.bsky.social"
BLUESKY_PASSWORD="PASSWORD"

1
.nvmrc Normal file
View File

@ -0,0 +1 @@
v20.10.0

1
lastProcessedPostId.txt Normal file
View File

@ -0,0 +1 @@
0

88
main.js Normal file
View File

@ -0,0 +1,88 @@
require("dotenv").config();
const fs = require("fs");
const path = require("path");
const { RichText, BskyAgent } = require("@atproto/api");
const axios = require("axios");
// Mastodon credentials
const mastodonInstance = process.env.MASTODON_INSTANCE;
const mastodonUser = process.env.MASTODON_USER;
// Bluesky agent
const agent = new BskyAgent({ service: process.env.BLUESKY_ENDPOINT });
// File to store the last processed Mastodon post ID
const lastProcessedPostIdFile = path.join(__dirname, "lastProcessedPostId.txt");
// Variable to store the last processed Mastodon post ID
let lastProcessedPostId = loadLastProcessedPostId();
// Function to load the last processed post ID from the file
function loadLastProcessedPostId() {
try {
return fs.readFileSync(lastProcessedPostIdFile, "utf8").trim();
} catch (error) {
console.error("Error loading last processed post ID:", error);
return null;
}
}
// Function to save the last processed post ID to the file
function saveLastProcessedPostId() {
try {
fs.writeFileSync(lastProcessedPostIdFile, `${lastProcessedPostId}`);
} catch (error) {
console.error("Error saving last processed post ID:", error);
}
}
async function postToBluesky(text) {
await agent.login({
identifier: process.env.BLUESKY_HANDLE,
password: process.env.BLUESKY_PASSWORD,
});
const richText = new RichText({ text });
await richText.detectFacets(agent);
await agent.post({
text: richText.text,
facets: richText.facets,
});
}
function removeHtmlTags(input) {
return input.replace(/<[^>]*>/g, "");
}
// Function to periodically fetch new Mastodon posts
async function fetchNewPosts() {
const response = await axios.get(`${mastodonInstance}/users/${mastodonUser}/outbox?page=true`);
const reversed = response.data.orderedItems.filter(item => item.object.type === 'Note')
.filter(item => item.object.inReplyTo === null)
.reverse();
let newTimestampId = 0;
reversed.forEach(item => {
const currentTimestampId = Date.parse(item.published);
if(currentTimestampId > newTimestampId) {
newTimestampId = currentTimestampId;
}
if(currentTimestampId > lastProcessedPostId && lastProcessedPostId != 0) {
const text = removeHtmlTags(item.object.content);
postToBluesky(text);
}
})
if(newTimestampId > 0) {
lastProcessedPostId = newTimestampId;
saveLastProcessedPostId();
}
}
fetchNewPosts();
// Fetch new posts every 5 minutes (adjust as needed)
setInterval(fetchNewPosts, 2 * 60 * 1000);

2403
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

17
package.json Normal file
View File

@ -0,0 +1,17 @@
{
"name": "mastodon-to-bluesky",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Maurice Renck <hello@maurice-renck.de>",
"license": "MIT",
"dependencies": {
"@atproto/api": "^0.6.23",
"axios": "^1.6.2",
"dotenv": "^16.3.1",
"mastodon-api": "^1.3.0"
}
}