diff --git a/bun.lockb b/bun.lockb index 4da935d..ce7f926 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index f15566d..3e6809c 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..918c690 --- /dev/null +++ b/src/hooks.server.ts @@ -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 \ No newline at end of file diff --git a/src/lib/bluesky.ts b/src/lib/bluesky.ts index 0b791d0..29f5fe7 100644 --- a/src/lib/bluesky.ts +++ b/src/lib/bluesky.ts @@ -32,4 +32,13 @@ export const getUserPosts = async (did: string, includeReposts: boolean = false, feedCursor = feedData.cursor } return posts -} \ No newline at end of file +} + +const lastPosts = writable([]) + +export const updateLastPosts = async () => { + const posts = await getUserPosts("did:plc:dfl62fgb7wtjj3fcbb72naae", false, 13) + lastPosts.set(posts) +} + +export const getLastPosts = () => { return get(lastPosts) } \ No newline at end of file diff --git a/src/lib/lastfm.ts b/src/lib/lastfm.ts index 25425e5..8e34248 100644 --- a/src/lib/lastfm.ts +++ b/src/lib/lastfm.ts @@ -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({track: null, since: 0}) +const lastTrack = writable(null) -export const lastFmGetNowPlaying: () => Promise = 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 = 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) } -} \ No newline at end of file +} + +export const getNowPlaying = () => { return get(lastTrack) } \ No newline at end of file diff --git a/src/lib/steam.ts b/src/lib/steam.ts index cefcc96..f82041e 100644 --- a/src/lib/steam.ts +++ b/src/lib/steam.ts @@ -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(null); -const cachedLastGame = writable({game: null, since: 0}) +const steamgriddbClient = writable(null) +const lastGame = writable(null) -export const steamGetNowPlaying: () => Promise = 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) } -} \ No newline at end of file +} + +export const getLastGame = () => { return get(lastGame) } \ No newline at end of file diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index df4eeac..4333997 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -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) diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 7e5ec96..42a9362 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -146,6 +146,7 @@ + {#if data.lastNote}
+ {/if} {#if data.lastTrack}
diff --git a/src/routes/log/+page.server.ts b/src/routes/log/+page.server.ts index 021775a..49b2ef3 100644 --- a/src/routes/log/+page.server.ts +++ b/src/routes/log/+page.server.ts @@ -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), } } \ No newline at end of file