import pino from "pino"; import { MicroBlogBackend } from "./pocketbase"; // custom destination formatter const logger = pino(); const pb = new MicroBlogBackend(logger); const baseURL = process.env.MASTODON_BASE_URL; const accountId = process.env.MASTODON_ACCOUNT_ID; type MastodonPost = { media_attachments: { type: string; //'image', url: string; description: string; // 'Blurry gate', }[]; id: string; content: string; account: { id: string; }; created_at: string; tags: { name: string }[]; }; const getPostUntilId = async ({ lastSavedId, maxId, carryPosts = [], }: { lastSavedId?: string; maxId?: string; carryPosts?: MastodonPost[]; }): Promise => { const params = new URLSearchParams(); params.append("limit", "10"); const urlWithParams = new URL( `${baseURL}/api/v1/accounts/${accountId}/statuses`, ); urlWithParams.search = params.toString(); const res = await fetch(urlWithParams); const posts = (await res.json()) as MastodonPost[]; const containsId = posts.some((post) => post.id === lastSavedId); if (!containsId && posts.length >= 5) { return getPostUntilId({ lastSavedId, carryPosts: carryPosts?.concat(posts), maxId: posts[posts.length - 1]?.id, }); } const allPosts = carryPosts?.concat(posts).reverse(); if (lastSavedId) { const index = allPosts.findIndex((post) => post.id === lastSavedId); return allPosts.slice(index + 1); } return allPosts; }; const savePost = async (post: MastodonPost) => { const postData = { remoteId: post.id, authorId: post.account.id, posted: post.created_at, source: "mastodon" as const, fullPost: post, }; return await pb.savePost(postData); }; const saveTags = async (post: MastodonPost, postId: string) => { logger.info({ tags: post.tags }, "saving tags"); for (const tag of post.tags) { await pb.setTag(tag.name, postId); } }; const saveImages = async (post: MastodonPost, postId: string) => { logger.info({ images: post.media_attachments }, "saving images"); for (const image of post.media_attachments) { await pb.saveAndSetImage( { remoteURL: image.url, alt: image.description }, postId, ); } }; (async () => { const lastSavedPostId = await pb.getLatestPostRemoteIDBySource("mastodon"); console.log({ lastSavedPostId }); const posts = await getPostUntilId({ lastSavedId: lastSavedPostId }); console.log({ posts }); for (const post of posts) { logger.info({ post }, "saving post"); const savedNewPost = await savePost(post); await saveTags(post, savedNewPost.id); await saveImages(post, savedNewPost.id); } })();