feat: add now happening that shows lastfm and steam status

This commit is contained in:
dusk 2024-11-19 01:12:33 +03:00
parent c626a322cb
commit 405dacf1c4
Signed by: dusk
SSH Key Fingerprint: SHA256:Abmvag+juovVufZTxyWY8KcVgrznxvBjQpJesv071Aw
6 changed files with 149 additions and 14 deletions

BIN
bun.lockb

Binary file not shown.

View File

@ -46,7 +46,9 @@
"nanoid": "^5.0.8", "nanoid": "^5.0.8",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"typescript-svelte-plugin": "^0.3.42" "steamgriddb": "^2.2.0",
"typescript-svelte-plugin": "^0.3.42",
"xml-js": "^1.6.11"
}, },
"trustedDependencies": [ "trustedDependencies": [
"@sveltejs/kit", "@sveltejs/kit",

View File

@ -1,8 +1,10 @@
import type { Cookies } from '@sveltejs/kit' import type { Cookies } from '@sveltejs/kit'
import { env } from '$env/dynamic/private' import { env } from '$env/dynamic/private'
import { writable } from 'svelte/store' import { get, writable } from 'svelte/store'
import { existsSync, readFileSync } from 'fs' import { existsSync, readFileSync } from 'fs'
import { Agent, CredentialSession } from '@atproto/api' import { Agent, CredentialSession } from '@atproto/api'
import { xml2json } from 'xml-js'
import SGDB from 'steamgriddb'
export const scopeCookies = (cookies: Cookies, path: string) => { export const scopeCookies = (cookies: Cookies, path: string) => {
return { return {
@ -27,3 +29,63 @@ export const loginToBsky = async () => {
return new Agent(creds) return new Agent(creds)
} }
export const bskyClient = writable<null | Agent>(null) export const bskyClient = writable<null | Agent>(null)
const cachedLastTrack = writable<{track: LastTrack | null, since: number}>({track: null, since: 0})
export type LastTrack = {name: string, artist: string, image: string | null, link: string}
export const lastFmGetNowPlaying: () => Promise<LastTrack | null> = async () => {
var cached = get(cachedLastTrack)
if (Date.now() - cached.since < 10 * 1000) {
return cached.track
}
try {
const API_URL = "https://ws.audioscrobbler.com/2.0/?method=user.getrecenttracks&user=yusdacra&api_key=da1911d405b5b37383e200b8f36ee9ec&format=json&limit=1"
var resp = await (await fetch(API_URL)).json()
var track = resp.recenttracks.track[0] ?? null
if (!(track['@attr'].nowplaying ?? null)) {
throw "no nowplaying track found"
}
var data = {
name: track.name,
artist: track.artist['#text'],
image: track.image[2]['#text'] ?? null,
link: track.url,
}
cachedLastTrack.set({track: data, since: Date.now()})
return data
} catch(why) {
console.log("could not fetch last fm: ", why)
cachedLastTrack.set({track: null, since: Date.now()})
return null
}
}
const steamgriddbClient = new SGDB(env.STEAMGRIDDB_API_KEY);
const cachedLastGame = writable<{game: LastGame | null, since: number}>({game: null, since: 0})
export type LastGame = {name: string, link: string, icon: string, pfp: string}
export const steamGetNowPlaying: () => Promise<LastGame | null> = async () => {
var cached = get(cachedLastGame)
if (Date.now() - cached.since < 10 * 1000) {
return cached.game
}
try {
const API_URL = `http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=${env.STEAM_API_KEY}&steamids=76561198106829949&format=json`
var profile = (await (await fetch(API_URL)).json()).response.players[0]
if (!profile.gameid) {
throw "no game is being played"
}
var icons = await steamgriddbClient.getIconsBySteamAppId(profile.gameid, ['official'])
console.log(icons)
var game = {
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
} catch(why) {
console.log("could not fetch steam: ", why)
cachedLastGame.set({game: null, since: Date.now()})
return null
}
}

View File

@ -0,0 +1,7 @@
import { lastFmGetNowPlaying, steamGetNowPlaying } from "$lib"
export const load = async ({}) => {
const lastTrack = await lastFmGetNowPlaying()
const lastGame = await steamGetNowPlaying()
return {lastTrack, lastGame}
}

View File

@ -1,6 +1,8 @@
<script> <script>
import { PUBLIC_BASE_URL } from '$env/static/public'; import { PUBLIC_BASE_URL } from '$env/static/public';
import Window from '../components/window.svelte'; import Window from '../components/window.svelte';
export let data;
</script> </script>
<div class="flex flex-col md:flex-row gap-y-2 lg:gap-y-0 md:h-full h-card"> <div class="flex flex-col md:flex-row gap-y-2 lg:gap-y-0 md:h-full h-card">
@ -61,10 +63,8 @@
<Window title="latest stuff" style="mt-auto"> <Window title="latest stuff" style="mt-auto">
<div class="prose prose-ralsei prose-img:m-0 leading-6"> <div class="prose prose-ralsei prose-img:m-0 leading-6">
<p> <p>
new game prototype thingy <a href="https://yusdacra.itch.io/lightfelt" new game prototype thingy <a href="https://yusdacra.itch.io/lightfelt">at itch.io page</a
>at itch.io page</a >! spent a lot of time learning and designing the environment and scene stuff :3
>!
spent a lot of time learning and designing the environment and scene stuff :3
trenchbroom and func_godot were used mainly! trenchbroom and func_godot were used mainly!
</p> </p>
<img <img
@ -122,13 +122,77 @@
</ul> </ul>
</div> </div>
</Window> </Window>
<Window title="current" iconUri="/icons/entry.png" style="mt-auto"> <Window title="now happening" style="mt-auto" removePadding>
<div class="prose prose-ralsei leading-6"> {#if data.lastTrack}
<ul> <div class="flex flex-row m-2 border-4 border-double">
<li>playing wynncraft, helldivers 2, warframe</li> <!-- svelte-ignore a11y-missing-attribute -->
<li>idk bother me to do stuff</li> {#if data.lastTrack.image}
</ul> <img
</div> class="border-4 w-16 h-16"
style="border-style: none double none none;"
width="64"
height="64"
src={data.lastTrack.image}
/>
{:else}
<img
class="border-4 w-16 h-16 p-2"
style="border-style: none double none none; image-rendering: pixelated;"
src="/icons/cd_audio.png"
/>
{/if}
<div class="flex flex-col max-w-[40ch] p-2 overflow-hidden">
<p
class="text-shadow-green text-ralsei-green-light text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
>
<span class="text-sm text-shadow-white text-ralsei-white">listening to</span>
<a
title={data.lastTrack.name}
href="https://www.last.fm/user/yusdacra"
class="hover:underline">{data.lastTrack.name}</a
>
</p>
<p
class="text-shadow-pink text-ralsei-pink-regular text-sm text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
>
<span class="text-shadow-white text-ralsei-white">by</span>
<span title={data.lastTrack.artist}>{data.lastTrack.artist}</span>
</p>
</div>
</div>
{/if}
{#if data.lastGame}
<div class="flex flex-row m-2 border-4 border-double">
<!-- svelte-ignore a11y-missing-attribute -->
<img
class="border-4 w-16 h-16"
style="border-style: none double none none;"
width="64"
height="64"
src={data.lastGame.icon}
/>
<div class="flex flex-col max-w-[40ch] p-2 gap-1 overflow-hidden">
<p
class="text-shadow-green text-ralsei-green-light text-ellipsis text-nowrap overflow-hidden max-w-[30ch]"
>
<span class="text-sm text-shadow-white text-ralsei-white">playing</span>
<a title={data.lastGame.name} class="hover:underline" href={data.lastGame.link}
>{data.lastGame.name}</a
>
</p>
<!-- svelte-ignore a11y-missing-attribute -->
<a
href="https://steamcommunity.com/id/yusdacra"
class="text-xs hover:underline text-shadow-green text-ralsei-green-light"
><img class="inline w-4" src={data.lastGame.pfp} />
<span class="align-middle">steam profile</span></a
>
</div>
</div>
{/if}
{#if !data.lastGame && !data.lastTrack}
<p class="text-xl m-2">nothing, apparently.</p>
{/if}
</Window> </Window>
</div> </div>
</div> </div>

BIN
static/icons/cd_audio.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 631 B