Generate Atom feed
This commit is contained in:
@ -92,84 +92,97 @@ function getMigrations(): Migration[] {
|
||||
}];
|
||||
}
|
||||
|
||||
export function savePost(post: Post): void {
|
||||
console.debug(`Saving post ${post.url}`);
|
||||
const account = post.account;
|
||||
db.run(`
|
||||
INSERT INTO accounts (id, acct, username, display_name, url, avatar, avatar_static)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id)
|
||||
DO UPDATE SET
|
||||
acct=excluded.acct,
|
||||
username=excluded.username,
|
||||
display_name=excluded.display_name,
|
||||
url=excluded.url,
|
||||
avatar=excluded.avatar,
|
||||
avatar_static=excluded.avatar_static;`,
|
||||
[
|
||||
account.id,
|
||||
account.acct,
|
||||
account.username,
|
||||
account.display_name,
|
||||
account.url,
|
||||
account.avatar,
|
||||
account.avatar_static
|
||||
],
|
||||
(err) => {
|
||||
if (err !== null) {
|
||||
console.error(`Could not insert/update account ${account.id}`, err);
|
||||
return;
|
||||
}
|
||||
db.run(`
|
||||
INSERT INTO posts (id, content, created_at, url, account_id)
|
||||
VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET
|
||||
content=excluded.content,
|
||||
created_at=excluded.created_at,
|
||||
url=excluded.url,
|
||||
account_id=excluded.account_id;`,
|
||||
[
|
||||
post.id,
|
||||
post.content,
|
||||
post.created_at,
|
||||
post.url,
|
||||
post.account.id
|
||||
],
|
||||
(postErr) => {
|
||||
if (postErr !== null) {
|
||||
console.error(`Could not insert post ${post.url}`, postErr);
|
||||
return;
|
||||
}
|
||||
|
||||
db.parallelize(() => {
|
||||
for (let tag of post.tags) {
|
||||
db.run(`
|
||||
INSERT INTO tags (url, tag) VALUES (?, ?)
|
||||
ON CONFLICT(url) DO UPDATE SET
|
||||
tag=excluded.tag;`,
|
||||
[
|
||||
tag.url,
|
||||
tag.name
|
||||
],
|
||||
(tagErr) => {
|
||||
if (tagErr !== null) {
|
||||
console.error(`Could not insert/update tag ${tag.url}`, tagErr);
|
||||
return;
|
||||
}
|
||||
db.run('INSERT INTO poststags (post_id, tag_url) VALUES (?, ?)',
|
||||
[post.id, tag.url],
|
||||
(posttagserr) => {
|
||||
if (posttagserr !== null) {
|
||||
console.error(`Could not insert poststags ${tag.url}, ${post.url}`, posttagserr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
export async function savePost(post: Post): Promise<undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.debug(`Saving post ${post.url}`);
|
||||
const account = post.account;
|
||||
db.run(`
|
||||
INSERT INTO accounts (id, acct, username, display_name, url, avatar, avatar_static)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?)
|
||||
ON CONFLICT(id)
|
||||
DO UPDATE SET
|
||||
acct=excluded.acct,
|
||||
username=excluded.username,
|
||||
display_name=excluded.display_name,
|
||||
url=excluded.url,
|
||||
avatar=excluded.avatar,
|
||||
avatar_static=excluded.avatar_static;`,
|
||||
[
|
||||
account.id,
|
||||
account.acct,
|
||||
account.username,
|
||||
account.display_name,
|
||||
account.url,
|
||||
account.avatar,
|
||||
account.avatar_static
|
||||
],
|
||||
(err) => {
|
||||
if (err !== null) {
|
||||
console.error(`Could not insert/update account ${account.id}`, err);
|
||||
reject(err);
|
||||
return;
|
||||
}
|
||||
db.run(`
|
||||
INSERT INTO posts (id, content, created_at, url, account_id)
|
||||
VALUES (?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET
|
||||
content=excluded.content,
|
||||
created_at=excluded.created_at,
|
||||
url=excluded.url,
|
||||
account_id=excluded.account_id;`,
|
||||
[
|
||||
post.id,
|
||||
post.content,
|
||||
post.created_at,
|
||||
post.url,
|
||||
post.account.id
|
||||
],
|
||||
(postErr) => {
|
||||
if (postErr !== null) {
|
||||
console.error(`Could not insert post ${post.url}`, postErr);
|
||||
reject(postErr);
|
||||
return;
|
||||
}
|
||||
|
||||
db.parallelize(() => {
|
||||
let remaining = post.tags.length;
|
||||
for (let tag of post.tags) {
|
||||
db.run(`
|
||||
INSERT INTO tags (url, tag) VALUES (?, ?)
|
||||
ON CONFLICT(url) DO UPDATE SET
|
||||
tag=excluded.tag;`,
|
||||
[
|
||||
tag.url,
|
||||
tag.name
|
||||
],
|
||||
(tagErr) => {
|
||||
if (tagErr !== null) {
|
||||
console.error(`Could not insert/update tag ${tag.url}`, tagErr);
|
||||
reject(tagErr);
|
||||
return;
|
||||
}
|
||||
db.run('INSERT INTO poststags (post_id, tag_url) VALUES (?, ?)',
|
||||
[post.id, tag.url],
|
||||
(posttagserr) => {
|
||||
if (posttagserr !== null) {
|
||||
console.error(`Could not insert poststags ${tag.url}, ${post.url}`, posttagserr);
|
||||
reject(posttagserr);
|
||||
return;
|
||||
}
|
||||
// Don't decrease on fail
|
||||
remaining--;
|
||||
// Only resolve after all have been inserted
|
||||
if (remaining === 0) {
|
||||
resolve(undefined);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getPosts(since: string | null, before: string | null, limit: number) {
|
||||
|
45
src/lib/server/rss.ts
Normal file
45
src/lib/server/rss.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { BASE_URL } from '$env/static/private';
|
||||
import { PUBLIC_MASTODON_INSTANCE_DISPLAY_NAME } from '$env/static/public';
|
||||
import type { Post } from '$lib//mastodon/response';
|
||||
import { Feed } from 'feed';
|
||||
import fs from 'fs/promises';
|
||||
|
||||
export function createFeed(posts: Post[]): Feed {
|
||||
const baseUrl = BASE_URL.endsWith('/') ? BASE_URL : BASE_URL + '/';
|
||||
const feed = new Feed({
|
||||
title: `${PUBLIC_MASTODON_INSTANCE_DISPLAY_NAME} music feed`,
|
||||
description: `Posts about music on ${PUBLIC_MASTODON_INSTANCE_DISPLAY_NAME}`,
|
||||
id: baseUrl,
|
||||
link: baseUrl,
|
||||
language: 'en',
|
||||
//image: "http://example.com/image.png",
|
||||
//favicon: "http://example.com/favicon.ico",
|
||||
copyright: '',
|
||||
generator: 'moshing-mamut',
|
||||
feedLinks: {
|
||||
atom: `${BASE_URL}/feed.atom`
|
||||
},
|
||||
author: {
|
||||
name: '@aymm',
|
||||
link: 'https://metalhead.club/@aymm'
|
||||
},
|
||||
});
|
||||
posts.forEach(p => {
|
||||
feed.addItem({
|
||||
title: p.content,
|
||||
id: p.url,
|
||||
link: p.url,
|
||||
content: p.content,
|
||||
author: [{
|
||||
name: p.account.acct,
|
||||
link: p.account.url
|
||||
}],
|
||||
date: new Date(p.created_at)
|
||||
})
|
||||
});
|
||||
feed.addCategory('Music');
|
||||
return feed;
|
||||
}
|
||||
export async function saveAtomFeed(feed: Feed) {
|
||||
await fs.writeFile('feed.atom', feed.atom1(), { encoding: 'utf8' });
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { HASHTAG_FILTER, MASTODON_INSTANCE, URL_FILTER, YOUTUBE_API_KEY } from '$env/static/private';
|
||||
import type { Post, Tag, TimelineEvent } from '$lib/mastodon/response';
|
||||
import { savePost } from '$lib/server/db';
|
||||
import { getPosts, savePost } from '$lib/server/db';
|
||||
import { createFeed, saveAtomFeed } from '$lib/server/rss';
|
||||
import { WebSocket } from "ws";
|
||||
|
||||
const YOUTUBE_REGEX = new RegExp(/https?:\/\/(www\.)?youtu((be.com\/.*?v=)|(\.be\/))(?<videoId>[a-zA-Z_0-9-]+)/gm);
|
||||
@ -77,9 +78,11 @@ export class TimelineReader {
|
||||
if (found_urls.length === 0 &&
|
||||
found_tags.length === 0 &&
|
||||
!await TimelineReader.checkYoutubeMatches(post.content)) {
|
||||
return;
|
||||
//return;
|
||||
}
|
||||
savePost(post);
|
||||
await savePost(post);
|
||||
const posts = await getPosts(null, null, 100);
|
||||
await saveAtomFeed(createFeed(posts));
|
||||
|
||||
} catch (e) {
|
||||
console.error("error message", event, event.data, e)
|
||||
|
Reference in New Issue
Block a user