Skip to content

Commit

Permalink
feat: split long posts into replies (#10)
Browse files Browse the repository at this point in the history
* post split text as reply

---------

Co-authored-by: Maurice Renck <maurice@maurice-renck.de>
  • Loading branch information
coding-lemur and mauricerenck authored May 29, 2024
1 parent 598fb3a commit b093c7d
Showing 1 changed file with 120 additions and 80 deletions.
200 changes: 120 additions & 80 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,102 +8,142 @@ const axios = require("axios");
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,
"data",
"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({
async function main() {
// Bluesky agent
const agent = new BskyAgent({ service: process.env.BLUESKY_ENDPOINT });
const loginResponse = await agent.login({
identifier: process.env.BLUESKY_HANDLE,
password: process.env.BLUESKY_PASSWORD,
});
if (!loginResponse.success) console.error("🔒 login failed");

const richText = new RichText({ text });
await richText.detectFacets(agent);
await agent.post({
text: richText.text,
facets: richText.facets,
});
}
// File to store the last processed Mastodon post ID
const lastProcessedPostIdFile = path.join(
__dirname,
"data",
"lastProcessedPostId.txt"
);

function removeHtmlTags(input) {
return input.replace(/<[^>]*>/g, "");
}
// Variable to store the last processed Mastodon post ID
let lastProcessedPostId = loadLastProcessedPostId();

function truncate(text, timestampId) {
if (text.length > 300) {
console.warn(`✂ post '${timestampId}' was truncated`)
return text.substring(0, 299) + '…'
// 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;
}
}

return text
}
// 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);
}
}

// Function to periodically fetch new Mastodon posts
async function fetchNewPosts() {
const response = await axios.get(
`${mastodonInstance}/users/${mastodonUser}/outbox?page=true`
);
async function createBlueskyMessage(text) {
const richText = new RichText({ text });
await richText.detectFacets(agent);

const reversed = response.data.orderedItems
.filter((item) => item.object.type === "Note")
.filter((item) => item.object.inReplyTo === null)
.reverse();
return {
text: richText.text,
facets: richText.facets
};
}

let newTimestampId = 0;
async function postToBluesky(textParts) {
const rootMessageResponse = await agent.post(await createBlueskyMessage(textParts[0]));

if (textParts.length === 1) return;

let replyMessageResponse = null
for (let index = 1; index < textParts.length; index++) {
replyMessageResponse = await agent.post({
...(await createBlueskyMessage(textParts[index])),
reply: {
root: rootMessageResponse,
parent: replyMessageResponse ?? rootMessageResponse,
}
});
}
}

reversed.forEach((item) => {
const currentTimestampId = Date.parse(item.published);
function removeHtmlTags(input) {
return input.replace(/<[^>]*>/g, "");
}

if (currentTimestampId > newTimestampId) {
newTimestampId = currentTimestampId;
function splitText(text, maxLength) {
// Split the text by spaces
const words = text.split(" ");

let result = [];
let currentChunk = "";

for (const word of words) {
// Add the current word to the current chunk
const potentialChunk = `${currentChunk} ${word}`.trim();

if (potentialChunk.length <= maxLength) {
// If the current chunk is still under max length, add the word
currentChunk = potentialChunk;
} else {
// Otherwise, add the current chunk to the result and start a new chunk
result.push(currentChunk);
currentChunk = word;
}
}

if (currentTimestampId > lastProcessedPostId && lastProcessedPostId != 0) {
try {
console.log('📧 posting to BlueSky', currentTimestampId)
const text = truncate(removeHtmlTags(item.object.content), currentTimestampId);
postToBluesky(text);
} catch (error) {
console.error('🔥 can\'t post to Bluesky', currentTimestampId, error)

// Add the last chunk to the result
result.push(currentChunk);

return result;
}

// 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 (newTimestampId > 0) {
lastProcessedPostId = newTimestampId;
saveLastProcessedPostId();
if (currentTimestampId > lastProcessedPostId && lastProcessedPostId != 0) {
try {
console.log('📧 posting to BlueSky', currentTimestampId)
const textParts = splitText(removeHtmlTags(item.object.content), 300);
postToBluesky(textParts);
} catch (error) {
console.error('🔥 can\'t post to Bluesky', currentTimestampId, error)
}
}
});

if (newTimestampId > 0) {
lastProcessedPostId = newTimestampId;
saveLastProcessedPostId();
}
}

fetchNewPosts();
// Fetch new posts every 5 minutes (adjust as needed)
setInterval(fetchNewPosts, (process.env.INTERVAL_MINUTES ?? 5) * 60 * 1000);
}

fetchNewPosts();
// Fetch new posts every 5 minutes (adjust as needed)
setInterval(fetchNewPosts, (process.env.INTERVAL_MINUTES ?? 5) * 60 * 1000);
main()

0 comments on commit b093c7d

Please sign in to comment.