From 2538bb614cf2aa44da504ffa73d8ba96f382ca67 Mon Sep 17 00:00:00 2001 From: dusk Date: Thu, 6 Feb 2025 23:03:00 +0300 Subject: [PATCH] feat: use bsky posts for log instead of custom thing --- bun.lockb | Bin 183056 -> 185888 bytes package.json | 22 ++++----- src/components/note.svelte | 38 ++++++++++++--- src/lib/bluesky.ts | 17 ++++++- src/lib/notes.ts | 68 -------------------------- src/routes/+page.server.ts | 8 +-- src/routes/+page.svelte | 2 +- src/routes/entries/+page.server.ts | 2 +- src/routes/log/+page.server.ts | 43 +++------------- src/routes/log/+page.svelte | 16 ++---- src/routes/log/_rss/+server.ts | 38 --------------- src/routes/log/create/+server.ts | 76 ----------------------------- src/styles/app.css | 4 ++ 13 files changed, 77 insertions(+), 257 deletions(-) delete mode 100644 src/lib/notes.ts delete mode 100644 src/routes/log/_rss/+server.ts delete mode 100644 src/routes/log/create/+server.ts diff --git a/bun.lockb b/bun.lockb index 10d527e86b4d2786d7afdb7f6cf91e1cfe310e3c..4da935d00a35e1e463ccc93c5be7873209f0a366 100755 GIT binary patch delta 24241 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 delta 23139 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 diff --git a/package.json b/package.json index 5a3d77a..f15566d 100644 --- a/package.json +++ b/package.json @@ -13,34 +13,34 @@ }, "devDependencies": { "@sveltejs/enhanced-img": "^0.3.10", - "@sveltejs/kit": "^2.15.1", + "@sveltejs/kit": "^2.17.1", "@sveltejs/vite-plugin-svelte": "^3.1.2", - "@tailwindcss/forms": "^0.5.9", - "@tailwindcss/typography": "^0.5.15", + "@tailwindcss/forms": "^0.5.10", + "@tailwindcss/typography": "^0.5.16", "@types/eslint": "^9.6.1", - "@types/node": "^22.10.3", + "@types/node": "^22.13.1", "autoprefixer": "^10.4.20", - "eslint": "^9.17.0", + "eslint": "^9.19.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-svelte": "^2.46.1", "globals": "^15.14.0", "mdsvex": "^0.12.3", - "postcss": "^8.4.49", + "postcss": "^8.5.1", "prettier": "^3.4.2", - "prettier-plugin-svelte": "^3.3.2", + "prettier-plugin-svelte": "^3.3.3", "svelte": "^4.2.19", "svelte-adapter-bun": "^0.5.2", "svelte-check": "^3.8.6", "sveltekit-rate-limiter": "^0.6.1", "tailwindcss": "^3.4.17", "tslib": "^2.8.1", - "typescript": "^5.7.2", - "typescript-eslint": "^8.19.0", - "vite": "^5.4.11" + "typescript": "^5.7.3", + "typescript-eslint": "^8.23.0", + "vite": "^5.4.14" }, "type": "module", "dependencies": { - "@neodrag/svelte": "^2.2.0", + "@neodrag/svelte": "^2.3.0", "@skyware/bot": "^0.3.8", "@std/toml": "npm:@jsr/std__toml", "base64url": "^3.0.1", diff --git a/src/components/note.svelte b/src/components/note.svelte index 0644807..6941878 100644 --- a/src/components/note.svelte +++ b/src/components/note.svelte @@ -1,9 +1,32 @@ +
-{#if !onlyContent}   {/if} +{#if !onlyContent} {/if} +{#if note.hasMedia}{/if} +{#if note.hasQuote}{/if} {#each note.outgoingLinks ?? [] as {name, link}} {@const color = outgoingLinkColors[name]} {name} diff --git a/src/lib/bluesky.ts b/src/lib/bluesky.ts index 11b8100..0b791d0 100644 --- a/src/lib/bluesky.ts +++ b/src/lib/bluesky.ts @@ -1,5 +1,5 @@ import { env } from '$env/dynamic/private' -import { Bot } from "@skyware/bot"; +import { Bot, Post } from "@skyware/bot"; import { get, writable } from 'svelte/store' const bskyClient = writable(null) @@ -17,4 +17,19 @@ const loginToBsky = async () => { const bot = new Bot({ service: "https://bsky.social" }) await bot.login({ identifier: 'gaze.systems', password: env.BSKY_PASSWORD ?? "" }) return bot +} + +export const getUserPosts = async (did: string, includeReposts: boolean = false, count: number = 10) => { + const client = await getBskyClient() + let feedCursor = undefined; + let posts: Post[] = [] + // fetch requested amount of posts + while (posts.length < count || feedCursor === undefined) { + let feedData = await client.getUserPosts( + did, { limit: count, filter: 'posts_no_replies', cursor: feedCursor } + ) + posts.push(...feedData.posts.filter((post) => !includeReposts && post.author.did === did)) + feedCursor = feedData.cursor + } + return posts } \ No newline at end of file diff --git a/src/lib/notes.ts b/src/lib/notes.ts deleted file mode 100644 index 9b73188..0000000 --- a/src/lib/notes.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { existsSync, readFileSync, writeFileSync } from 'fs' -import { nanoid } from 'nanoid' -import { env } from '$env/dynamic/private' - -export interface OutgoingLinkData { - name: string, - link: string, -} - -export interface Note { - content: string, - published: number, - outgoingLinks?: OutgoingLinkData[], - replyTo?: NoteId, -} -type NoteId = string - -export const notesFolder = `${env.WEBSITE_DATA_DIR}/note` -export const notesListFile = `${env.WEBSITE_DATA_DIR}/notes` -export const noteIdLength = 8; - -export const getNotePath = (id: NoteId) => { return `${notesFolder}/${id}` } -export const genNoteId = () => { - let id = nanoid(noteIdLength) - while (existsSync(getNotePath(id))) { - id = nanoid(noteIdLength) - } - return id -} -export const noteExists = (id: NoteId) => { return existsSync(getNotePath(id)) } -export const readNote = (id: NoteId): Note => { - return JSON.parse(readFileSync(getNotePath(id)).toString()) -} -export const findReplyRoot = (id: NoteId): {rootNote: Note, rootNoteId: NoteId} => { - let noteId: string | null = id - let current: {rootNote?: Note, rootNoteId?: NoteId} = {} - while (noteId !== null) { - current.rootNote = readNote(noteId) - current.rootNoteId = noteId - noteId = current.rootNote.replyTo ?? null - } - if (current.rootNote === undefined || current.rootNoteId === undefined) { - throw "no note with id found" - } - return { - rootNote: current.rootNote, - rootNoteId: current.rootNoteId, - } -} -export const writeNote = (id: NoteId, note: Note) => { - writeFileSync(getNotePath(id), JSON.stringify(note)) - // only append to note list if its not in it yet - let noteList = readNotesList() - if (noteList.indexOf(id) === -1) { - writeNotesList([id].concat(noteList)) - } -} -export const createNote = (id: NoteId, note: Note) => { - writeNote(id, note) - return id -} - -export const readNotesList = (): NoteId[] => { - return JSON.parse(readFileSync(notesListFile).toString()) -} -export const writeNotesList = (note_ids: NoteId[]) => { - writeFileSync(notesListFile, JSON.stringify(note_ids)) -} \ No newline at end of file diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index 3b28ffe..df4eeac 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -1,18 +1,18 @@ +import { getUserPosts } from "$lib/bluesky.js" import { lastFmGetNowPlaying } from "$lib/lastfm" -import { readNote, readNotesList } from "$lib/notes.js" import { steamGetNowPlaying } from "$lib/steam" +import { noteFromBskyPost } from "../components/note.svelte" export const load = async ({}) => { const lastTrack = await lastFmGetNowPlaying() const lastGame = await steamGetNowPlaying() + const lastNote = noteFromBskyPost((await getUserPosts("did:plc:dfl62fgb7wtjj3fcbb72naae", false, 1))[0]) let banners: number[] = [] while (banners.length < 3) { const no = getBannerNo(banners) banners.push(no) } - const lastNoteId = readNotesList()[0] - const lastNote = readNote(lastNoteId) - return {banners, lastTrack, lastGame, lastNote, lastNoteId} + return {banners, lastTrack, lastGame, lastNote} } const getBannerNo = (others: number[]) => { diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 2ccb709..7e5ec96 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -155,7 +155,7 @@ published on {renderDate(data.lastNote.published)}
- +
{#if data.lastTrack} diff --git a/src/routes/entries/+page.server.ts b/src/routes/entries/+page.server.ts index ce806dd..3bc4e89 100644 --- a/src/routes/entries/+page.server.ts +++ b/src/routes/entries/+page.server.ts @@ -10,6 +10,6 @@ export const load = (params) => { if (log_page !== null) { url.searchParams.append("page", log_page) } - var logs_result = load_logs({url}) + var logs_result = load_logs() return logs_result } \ No newline at end of file diff --git a/src/routes/log/+page.server.ts b/src/routes/log/+page.server.ts index 49a3672..021775a 100644 --- a/src/routes/log/+page.server.ts +++ b/src/routes/log/+page.server.ts @@ -1,41 +1,12 @@ -import { noteExists, readNote, readNotesList } from '$lib/notes' +import { getUserPosts } from '$lib/bluesky.js'; +import { noteFromBskyPost } from '../../components/note.svelte'; -const notesPerPage: number = 15 - -export const load = ({ url }) => { - return _load({ url }) +export const load = async ({ }) => { + return _load() } -export const _load = ({ url }: { url: URL }) => { - // get the note id to search for and display the page it is in - const noteId = url.searchParams.get("id") - // get the page no if one is provided, otherwise default to 1 - let page = parseInt(url.searchParams.get("page") || "1") - if (isNaN(page)) { page = 1 } - - // calculate page count - const notesList = readNotesList() - const pageCount = Math.ceil(notesList.length / notesPerPage) - - // find what page the note id if supplied is from - if (noteId !== null && noteExists(noteId)) { - const noteIndex = notesList.lastIndexOf(noteId) - if (noteIndex > -1) { - page = Math.floor(noteIndex / notesPerPage) + 1 - } +export const _load = async () => { + return { + feedPosts: (await getUserPosts("did:plc:dfl62fgb7wtjj3fcbb72naae", false, 13)).map(noteFromBskyPost), } - - // clamp page between our min and max - page = Math.min(page, pageCount) - page = Math.max(page, 1) - - // get the notes from the chosen page - const notes = new Map( - notesList.slice((page - 1) * notesPerPage, page * notesPerPage) - .map( - (id) => { return [id, readNote(id)] } - ) - ) - - return { notes, highlightedNote: noteId, page } } \ No newline at end of file diff --git a/src/routes/log/+page.svelte b/src/routes/log/+page.svelte index 52a26c2..f95dafc 100644 --- a/src/routes/log/+page.svelte +++ b/src/routes/log/+page.svelte @@ -4,17 +4,8 @@ import Note from '../../components/note.svelte'; export let data; - - const highlightedNote = data.notes.get(data.highlightedNote ?? '') ?? null - - {#if highlightedNote !== null} - - - {/if} - -
gazesystems

-{#each data.notes as [id, note], index} -{@const isHighlighted = id === data.highlightedNote} - -{#if index < data.notes.size - 1} +{#each data.feedPosts as note, index} + +{#if index < data.feedPosts.length - 1}
{/if} {/each} diff --git a/src/routes/log/_rss/+server.ts b/src/routes/log/_rss/+server.ts deleted file mode 100644 index e61687f..0000000 --- a/src/routes/log/_rss/+server.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { PUBLIC_BASE_URL } from '$env/static/public'; -import { readNote, readNotesList, type Note } from '$lib/notes.ts'; - -const logUrl = `${PUBLIC_BASE_URL}/log`; - -interface NoteData { - data: Note, - id: string, -} - -export const GET = async ({ }) => { - const log = readNotesList().map((id) => {return { data: readNote(id), id }}) - return new Response( - render(log), - { - headers: { - 'content-type': 'application/xml', - 'cache-control': 'no-store', - } - }) -}; - -const render = (log: NoteData[]) => ` - - - - dusk's notes (@gaze.systems) - ${logUrl} - a collection of random notes i write whenever, aka my microblogging spot - ${log.map((note) => ` - ${logUrl}/?id=${note.id} - ${logUrl}/?id=${note.id} - ${note.data.content} - ${new Date(note.data.published).toUTCString()} - `).join('')} - - - `; \ No newline at end of file diff --git a/src/routes/log/create/+server.ts b/src/routes/log/create/+server.ts deleted file mode 100644 index 03a4e3f..0000000 --- a/src/routes/log/create/+server.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { env } from '$env/dynamic/private'; -import { PUBLIC_BASE_URL } from '$env/static/public'; -import { getBskyClient } from '$lib/bluesky.js'; -import { createNote, findReplyRoot, genNoteId, readNote, type Note } from '$lib/notes'; -import type { Post, PostPayload, PostReference, ReplyRef } from '@skyware/bot'; - -interface NoteData { - content: string, - replyTo?: string, - embedUri?: string, - bskyPosse: boolean, -} - -export const POST = async ({ request }) => { - const token = request.headers.get('authorization') - if (token !== env.GAZEBOT_TOKEN) { - return new Response("rizz failed", { status: 403 }) - } - // get id - const noteId = genNoteId() - // get note data - const noteData: NoteData = await request.json() - console.log(`want to create note #${noteId} with data: `, noteData) - // get a date before we start publishing to other platforms - let note: Note = { - content: noteData.content, - published: Date.now(), - outgoingLinks: [], - replyTo: noteData.replyTo, - } - let errors: string[] = [] - let repliedNote: Note | null = null - if (noteData.replyTo !== undefined) { - repliedNote = readNote(noteData.replyTo) - } - // bridge to bsky if want to bridge - if (noteData.bskyPosse) { - const postContent = `${noteData.content} (${PUBLIC_BASE_URL}/log?id=${noteId})` - try { - const bot = await getBskyClient() - let postPayload: PostPayload = { - text: postContent, - createdAt: new Date(note.published), - external: noteData.embedUri, - } - let postRef: PostReference - // find parent and reply posts - let replyRef: ReplyRef | null = null - if (noteData.replyTo !== undefined && repliedNote !== null) { - const getBskyUri = (note: Note) => { return note.outgoingLinks?.find((v) => {return v.name === "bsky"})?.link } - const parentUri = getBskyUri(repliedNote) - if (parentUri !== undefined) { - const parentPost = await bot.getPost(parentUri) - postRef = await parentPost.reply(postPayload) - } else { - throw "a reply was requested but no reply is found" - } - } else { - postRef = await bot.post(postPayload) - } - note.outgoingLinks?.push({name: "bsky", link: postRef.uri}) - } catch(why) { - console.log(`failed to post note #${noteId} to bsky: `, why) - errors.push(`error while posting to bsky: ${why}`) - } - } - // create note (this should never fail otherwise it would defeat the whole purpose lol) - createNote(noteId, note) - // send back created note id and any errors that occurred - return new Response(JSON.stringify({ noteId, errors }), { - headers: { - 'content-type': 'application/json', - 'cache-control': 'no-store', - } - }) -}; diff --git a/src/styles/app.css b/src/styles/app.css index 0f1e888..e78b868 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -1,5 +1,9 @@ @import './prism-synthwave84.css'; +@import 'bluesky-profile-feed-embed/style.css'; +@import 'bluesky-profile-feed-embed/themes/light.css' (prefers-color-scheme: light); +@import 'bluesky-profile-feed-embed/themes/dim.css' (prefers-color-scheme: dark); + @tailwind base; @tailwind components; @tailwind utilities;