your personal website on atproto - mirror blento.app
at fix-cached-posts 80 lines 3.0 kB view raw
1import type { CardDefinition } from '../../../types'; 2import CreateLastFMCardModal from '../CreateLastFMCardModal.svelte'; 3import LastFMRecentTracksCard from './LastFMRecentTracksCard.svelte'; 4import { fetchLastFM } from '../api.remote'; 5 6export const LastFMRecentTracksCardDefinition = { 7 type: 'lastfmRecentTracks', 8 contentComponent: LastFMRecentTracksCard, 9 creationModalComponent: CreateLastFMCardModal, 10 createNew: (card) => { 11 card.w = 4; 12 card.mobileW = 8; 13 card.h = 3; 14 card.mobileH = 6; 15 }, 16 loadData: async (items) => { 17 const allData: Record<string, unknown> = {}; 18 for (const item of items) { 19 const username = item.cardData.lastfmUsername; 20 if (!username) continue; 21 try { 22 const data = await fetchLastFM({ method: 'user.getRecentTracks', user: username }); 23 if (data) allData[`lastfmRecentTracks:${username}`] = data?.recenttracks?.track ?? []; 24 } catch (error) { 25 console.error('Failed to fetch Last.fm recent tracks:', error); 26 } 27 } 28 return allData; 29 }, 30 loadDataServer: async (items) => { 31 const allData: Record<string, unknown> = {}; 32 for (const item of items) { 33 const username = item.cardData.lastfmUsername; 34 if (!username) continue; 35 try { 36 const data = await fetchLastFM({ method: 'user.getRecentTracks', user: username }); 37 if (data) allData[`lastfmRecentTracks:${username}`] = data?.recenttracks?.track ?? []; 38 } catch (error) { 39 console.error('Failed to fetch Last.fm recent tracks:', error); 40 } 41 } 42 return allData; 43 }, 44 onUrlHandler: (url, item) => { 45 const username = getLastFMUsername(url); 46 if (!username) return null; 47 48 item.cardData.lastfmUsername = username; 49 item.cardData.href = `https://www.last.fm/user/${username}`; 50 item.w = 4; 51 item.mobileW = 8; 52 item.h = 3; 53 item.mobileH = 6; 54 item.cardType = 'lastfmRecentTracks'; 55 return item; 56 }, 57 urlHandlerPriority: 5, 58 minW: 3, 59 minH: 2, 60 canHaveLabel: true, 61 name: 'Last.fm Recent Tracks', 62 keywords: ['music', 'scrobble', 'listening', 'songs', 'lastfm', 'last.fm'], 63 groups: ['Media'], 64 icon: `<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="size-4"><path stroke-linecap="round" stroke-linejoin="round" d="m9 9 10.5-3m0 6.553v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 1 1-.99-3.467l2.31-.66a2.25 2.25 0 0 0 1.632-2.163Zm0 0V2.25L9 5.25v10.303m0 0v3.75a2.25 2.25 0 0 1-1.632 2.163l-1.32.377a1.803 1.803 0 0 1-.99-3.467l2.31-.66A2.25 2.25 0 0 0 9 15.553Z" /></svg>` 65} as CardDefinition & { type: 'lastfmRecentTracks' }; 66 67function getLastFMUsername(url: string | undefined): string | undefined { 68 if (!url) return; 69 try { 70 const parsed = new URL(url); 71 if (!/^(www\.)?last\.fm$/.test(parsed.hostname)) return undefined; 72 const segments = parsed.pathname.split('/').filter(Boolean); 73 if (segments.length >= 2 && segments[0] === 'user') { 74 return segments[1]; 75 } 76 return undefined; 77 } catch { 78 return undefined; 79 } 80}