chore: lastfm -> listenbrainz
All checks were successful
Publish and deploy / publish (push) Successful in 30s
Publish and deploy / deploy (push) Successful in 6s

This commit is contained in:
alina 🌸 2025-01-25 09:35:56 +03:00
parent e44a9724ff
commit 8c46947144
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
4 changed files with 72 additions and 73 deletions

View file

@ -9,7 +9,6 @@ export const env = zodValidateSync(
UMAMI_HOST: z.string().url(),
UMAMI_TOKEN: z.string(),
UMAMI_SITE_ID: z.string().uuid(),
LASTFM_TOKEN: z.string(),
TG_API_ID: z.coerce.number(),
TG_API_HASH: z.string(),
TG_BOT_TOKEN: z.string(),

View file

@ -2,7 +2,7 @@ import { assertMatches } from '@fuman/utils'
import { bskyLastSeen } from './bsky.ts'
import { githubLastSeen } from './github'
import { lastfm } from './lastfm'
import { lastfm } from './listenbrainz.ts'
import { shikimoriLastSeen } from './shikimori'
import { forgejoLastSeen } from './forgejo.ts'

View file

@ -1,71 +0,0 @@
import { z } from 'zod'
import { AsyncResource } from '@fuman/utils'
import { zodValidate } from '~/utils/zod'
import { env } from '~/backend/env'
import { ffetch } from '../../utils/fetch.ts'
import type { LastSeenItem } from './index.ts'
const LASTFM_TTL = 1000 * 60 * 5 // 5 minutes
const LASTFM_STALE_TTL = 1000 * 60 * 60 // 1 hour
const LASTFM_USERNAME = 'teidesu'
const LASTFM_TOKEN = env.LASTFM_TOKEN
const LastfmTrack = z.object({
'artist': z.object({ 'mbid': z.string(), '#text': z.string() }),
'name': z.string(),
'url': z.string(),
'date': z.object({ uts: z.string() }).optional(),
'@attr': z.object({
nowplaying: z.literal('true'),
}).partial().optional(),
})
const ResponseSchema = z.object({
recenttracks: z.object({
'track': z.array(LastfmTrack),
'@attr': z.object({
user: z.string(),
totalPages: z.string(),
page: z.string(),
perPage: z.string(),
total: z.string(),
}),
}),
})
export const lastfm = new AsyncResource<LastSeenItem | null>({
async fetcher({ current }) {
const res = await ffetch('https://ws.audioscrobbler.com/2.0/', {
query: {
method: 'user.getrecenttracks',
user: LASTFM_USERNAME,
api_key: LASTFM_TOKEN,
format: 'json',
limit: '1',
from: current ? Math.floor(current.time / 1000) : undefined,
},
}).parsedJson(ResponseSchema)
const track = res.recenttracks.track[0]
if (!track.date && track['@attr']?.nowplaying) {
track.date = { uts: Math.floor(Date.now() / 1000).toString() }
} else if (!track.date) {
throw new Error('no track found')
}
return {
data: {
source: 'last.fm',
sourceLink: 'https://last.fm/user/teidesu',
time: Number(track.date!.uts) * 1000,
text: `${track.name} ${track.artist['#text']}`,
link: track.url,
},
expiresIn: LASTFM_TTL,
}
},
swr: true,
swrValidator: ({ currentExpiresAt }) => Date.now() - currentExpiresAt < LASTFM_STALE_TTL,
})

View file

@ -0,0 +1,71 @@
import { z } from 'zod'
import { AsyncResource } from '@fuman/utils'
import { ffetch } from '../../utils/fetch.ts'
import type { LastSeenItem } from './index.ts'
const LB_TTL = 1000 * 60 * 5 // 5 minutes
const LB_STALE_TTL = 1000 * 60 * 60 // 1 hour
const LB_USERNAME = 'teidumb'
const LbListen = z.object({
listened_at: z.number(),
track_metadata: z.object({
artist_name: z.string(),
track_name: z.string(),
additional_info: z.object({
origin_url: z.string().optional(),
}).optional(),
mbid_mapping: z.object({
recording_mbid: z.string().optional(),
}).optional(),
}),
})
const ResponseSchema = z.object({
payload: z.object({
listens: z.array(LbListen),
}),
})
export const lastfm = new AsyncResource<LastSeenItem | null>({
async fetcher({ current }) {
const res = await ffetch(`https://api.listenbrainz.org/1/user/${LB_USERNAME}/listens`, {
query: {
count: 1,
min_ts: current ? Math.floor(current.time / 1000) : '',
},
}).parsedJson(ResponseSchema)
if (!res.payload.listens.length) {
return {
data: current,
expiresIn: 0,
}
}
const listen = res.payload.listens[0]
let url: string | undefined
if (listen.track_metadata.mbid_mapping?.recording_mbid) {
url = `https://musicbrainz.org/recording/${listen.track_metadata.mbid_mapping.recording_mbid}`
} else if (listen.track_metadata.additional_info?.origin_url) {
url = listen.track_metadata.additional_info.origin_url
} else {
url = 'https://listenbrainz.org/user/teidumb/'
}
return {
data: {
source: 'listenbrainz',
sourceLink: 'https://listenbrainz.org/user/teidumb/',
time: listen.listened_at * 1000,
text: `${listen.track_metadata.track_name} ${listen.track_metadata.artist_name}`,
link: url,
},
expiresIn: LB_TTL,
}
},
swr: true,
swrValidator: ({ currentExpiresAt }) => Date.now() - currentExpiresAt < LB_STALE_TTL,
})