refactor: don't fetch steam / lastfm / bsky posts on user request, instead peridocially do it in the background every minute

This commit is contained in:
dusk 2025-02-06 23:57:57 +03:00
parent 4b81de80d5
commit a90bf50558
Signed by: dusk
SSH Key Fingerprint: SHA256:Abmvag+juovVufZTxyWY8KcVgrznxvBjQpJesv071Aw
9 changed files with 57 additions and 38 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -43,8 +43,10 @@
"@neodrag/svelte": "^2.3.0",
"@skyware/bot": "^0.3.8",
"@std/toml": "npm:@jsr/std__toml",
"@types/node-schedule": "^2.1.7",
"base64url": "^3.0.1",
"nanoid": "^5.0.9",
"node-schedule": "^2.1.1",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",
"robots-parser": "^3.0.1",

17
src/hooks.server.ts Normal file
View File

@ -0,0 +1,17 @@
import { updateLastPosts } from '$lib/bluesky';
import { lastFmUpdateNowPlaying } from '$lib/lastfm';
import { steamUpdateNowPlaying } from '$lib/steam'
import { cancelJob, scheduleJob, scheduledJobs } from 'node-schedule'
const UPDATE_LAST_JOB_NAME = "update steam game, lastfm track, bsky posts"
if (UPDATE_LAST_JOB_NAME in scheduledJobs) {
console.log(`${UPDATE_LAST_JOB_NAME} is already running, cancelling so we can start a new one`)
cancelJob(UPDATE_LAST_JOB_NAME)
}
console.log(`starting ${UPDATE_LAST_JOB_NAME} job...`);
scheduleJob(UPDATE_LAST_JOB_NAME, "*/1 * * * *", async () => {
console.log(`running ${UPDATE_LAST_JOB_NAME} job...`)
await Promise.all([steamUpdateNowPlaying(), lastFmUpdateNowPlaying(), updateLastPosts()])
}).invoke() // invoke once immediately

View File

@ -32,4 +32,13 @@ export const getUserPosts = async (did: string, includeReposts: boolean = false,
feedCursor = feedData.cursor
}
return posts
}
}
const lastPosts = writable<Post[]>([])
export const updateLastPosts = async () => {
const posts = await getUserPosts("did:plc:dfl62fgb7wtjj3fcbb72naae", false, 13)
lastPosts.set(posts)
}
export const getLastPosts = () => { return get(lastPosts) }

View File

@ -1,17 +1,11 @@
import { get, writable } from "svelte/store"
const GET_RECENT_TRACKS_ENDPOINT = "https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=yusdacra&api_key=da1911d405b5b37383e200b8f36ee9ec&format=json&limit=1"
const CACHE_EXPIRY_SECONDS = 10
type LastTrack = {name: string, artist: string, image: string | null, link: string}
type CachedLastTrack = {track: LastTrack | null, since: number}
const cachedLastTrack = writable<CachedLastTrack>({track: null, since: 0})
const lastTrack = writable<LastTrack | null>(null)
export const lastFmGetNowPlaying: () => Promise<LastTrack | null> = async () => {
var cached = get(cachedLastTrack)
if (Date.now() - cached.since < CACHE_EXPIRY_SECONDS * 1000) {
return cached.track
}
export const lastFmUpdateNowPlaying = async () => {
try {
var resp = await (await fetch(GET_RECENT_TRACKS_ENDPOINT)).json()
var track = resp.recenttracks.track[0] ?? null
@ -24,11 +18,11 @@ export const lastFmGetNowPlaying: () => Promise<LastTrack | null> = async () =>
image: track.image[2]['#text'] ?? null,
link: track.url,
}
cachedLastTrack.set({track: data, since: Date.now()})
return data
lastTrack.set(data)
} catch(why) {
console.log("could not fetch last fm: ", why)
cachedLastTrack.set({track: null, since: Date.now()})
return null
lastTrack.set(null)
}
}
}
export const getNowPlaying = () => { return get(lastTrack) }

View File

@ -4,42 +4,36 @@ import { get, writable } from "svelte/store";
const STEAM_ID = "76561198106829949"
const GET_PLAYER_SUMMARY_ENDPOINT = `http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${env.STEAM_API_KEY}&steamids=${STEAM_ID}&format=json`
const CACHE_EXPIRY_SECONDS = 10
type LastGame = {name: string, link: string, icon: string, pfp: string}
type CachedLastGame = {game: LastGame | null, since: number}
const steamgriddbClient = writable<SGDB | null>(null);
const cachedLastGame = writable<CachedLastGame>({game: null, since: 0})
const steamgriddbClient = writable<SGDB | null>(null)
const lastGame = writable<LastGame | null>(null)
export const steamGetNowPlaying: () => Promise<LastGame | null> = async () => {
export const steamUpdateNowPlaying = async () => {
var griddbClient = get(steamgriddbClient)
if (griddbClient === null) {
griddbClient = new SGDB(env.STEAMGRIDDB_API_KEY)
steamgriddbClient.set(griddbClient)
}
var cached = get(cachedLastGame)
if (Date.now() - cached.since < CACHE_EXPIRY_SECONDS * 1000) {
return cached.game
}
try {
var profile = (await (await fetch(GET_PLAYER_SUMMARY_ENDPOINT)).json()).response.players[0]
if (!profile.gameid) {
throw "no game is being played"
}
var icons = await griddbClient.getIconsBySteamAppId(profile.gameid, ['official'])
console.log(icons)
var game = {
//console.log(icons)
var game: LastGame = {
name: profile.gameextrainfo,
link: `https://store.steampowered.com/app/${profile.gameid}`,
icon: icons[0].thumb.toString(),
pfp: profile.avatarmedium,
}
cachedLastGame.set({game, since: Date.now()})
return game
lastGame.set(game)
} catch(why) {
console.log("could not fetch steam: ", why)
cachedLastGame.set({game: null, since: Date.now()})
return null
lastGame.set(null)
}
}
}
export const getLastGame = () => { return get(lastGame) }

View File

@ -1,12 +1,13 @@
import { getUserPosts } from "$lib/bluesky.js"
import { lastFmGetNowPlaying } from "$lib/lastfm"
import { steamGetNowPlaying } from "$lib/steam"
import { getLastPosts } from "$lib/bluesky.js"
import { getNowPlaying } from "$lib/lastfm"
import { getLastGame } 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])
const lastTrack = getNowPlaying()
const lastGame = getLastGame()
const lastPosts = getLastPosts()
const lastNote = lastPosts.length > 0 ? noteFromBskyPost(lastPosts[0]) : null
let banners: number[] = []
while (banners.length < 3) {
const no = getBannerNo(banners)

View File

@ -146,6 +146,7 @@
</div>
</Window>
<Window title="status" style="mt-auto" removePadding>
{#if data.lastNote}
<div class="m-1.5 flex flex-col font-monospace">
<div
class="prose prose-ralsei items-center p-1 border-4 text-sm font-bold bg-ralsei-black"
@ -158,6 +159,7 @@
<Note note={data.lastNote} onlyContent/>
</div>
</div>
{/if}
{#if data.lastTrack}
<div class="flex flex-row m-1.5 border-4 border-double bg-ralsei-black">
<!-- svelte-ignore a11y-missing-attribute -->

View File

@ -1,4 +1,4 @@
import { getUserPosts } from '$lib/bluesky.js';
import { getLastPosts, getUserPosts } from '$lib/bluesky.js';
import { noteFromBskyPost } from '../../components/note.svelte';
export const load = async ({ }) => {
@ -7,6 +7,6 @@ export const load = async ({ }) => {
export const _load = async () => {
return {
feedPosts: (await getUserPosts("did:plc:dfl62fgb7wtjj3fcbb72naae", false, 13)).map(noteFromBskyPost),
feedPosts: getLastPosts().map(noteFromBskyPost),
}
}