diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a7af302 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +npm-debug.log +.env +Dockerfile +.dockerignore \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0d7900c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM node:21-bookworm-slim + +WORKDIR /usr/src/app + +COPY package*.json ./ +RUN npm install + +COPY . . + +CMD [ "node", "main.js" ] diff --git a/lastProcessedPostId.txt b/data/lastProcessedPostId.txt similarity index 100% rename from lastProcessedPostId.txt rename to data/lastProcessedPostId.txt diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3e1a2e6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' +services: + app: + image: host/mastodon-to-bluesky:latest + container_name: mastodon-to-bluesky + environment: + MASTODON_INSTANCE: 'https://mastodon.instance' + MASTODON_USER: 'username' + BLUESKY_ENDPOINT: 'https://bsky.social' + BLUESKY_HANDLE: 'USERNAME.bsky.social' + BLUESKY_PASSWORD: 'PASSWORD' + INTERVAL_MINUTES: 5 + volumes: + - mastodon-to-bluesky:/usr/src/app/data + restart: unless-stopped + +volumes: + mastodon-to-bluesky: + external: true \ No newline at end of file diff --git a/main.js b/main.js index 9d12ae3..4d1b26e 100644 --- a/main.js +++ b/main.js @@ -12,7 +12,11 @@ const mastodonUser = process.env.MASTODON_USER; 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"); +const lastProcessedPostIdFile = path.join( + __dirname, + "data", + "lastProcessedPostId.txt" +); // Variable to store the last processed Mastodon post ID let lastProcessedPostId = loadLastProcessedPostId(); @@ -56,28 +60,31 @@ function removeHtmlTags(input) { // Function to periodically fetch new Mastodon posts async function fetchNewPosts() { - const response = await axios.get(`${mastodonInstance}/users/${mastodonUser}/outbox?page=true`); + 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(); + const reversed = response.data.orderedItems + .filter((item) => item.object.type === "Note") + .filter((item) => item.object.inReplyTo === null) + .reverse(); let newTimestampId = 0; - - reversed.forEach(item => { + + reversed.forEach((item) => { const currentTimestampId = Date.parse(item.published); - if(currentTimestampId > newTimestampId) { + if (currentTimestampId > newTimestampId) { newTimestampId = currentTimestampId; } - if(currentTimestampId > lastProcessedPostId && lastProcessedPostId != 0) { + if (currentTimestampId > lastProcessedPostId && lastProcessedPostId != 0) { const text = removeHtmlTags(item.object.content); postToBluesky(text); } - }) + }); - if(newTimestampId > 0) { + if (newTimestampId > 0) { lastProcessedPostId = newTimestampId; saveLastProcessedPostId(); } @@ -85,4 +92,4 @@ async function fetchNewPosts() { fetchNewPosts(); // Fetch new posts every 5 minutes (adjust as needed) -setInterval(fetchNewPosts, 2 * 60 * 1000); +setInterval(fetchNewPosts, (process.env.INTERVAL_MINUTES ?? 5) * 60 * 1000);