fix: replace any types in music integration utilities (19 errors)
Phase 1 Batch 5: Music Integration type safety improvements Fixed 19 any-type errors across 6 music integration files: 1. src/lib/utils/albumEnricher.ts (4 errors) - Created RecentTracksData interface - Fixed getAppleMusicDataForNowPlaying: return Album['appleMusicData'] | null - Fixed cacheRecentTracks: parameter RecentTracksData - Fixed getCachedRecentTracks: return RecentTracksData | null - Fixed getCachedRecentTracks: data typing 2. src/lib/utils/lastfmStreamManager.ts (4 errors) - Created RecentTracksResponse interface - Fixed fetchFreshRecentTracks: return RecentTracksResponse - Fixed getRecentAlbums: parameter RecentTracksResponse - Fixed updateNowPlayingStatus: parameter RecentTracksResponse - Fixed getNowPlayingUpdatesForNonRecentAlbums: parameter RecentTracksResponse 3. src/lib/utils/lastfmTransformers.ts (2 errors) - Created LastfmTrack interface - Fixed trackToAlbum: parameter LastfmTrack - Fixed mergeAppleMusicData: parameter Album['appleMusicData'] 4. src/lib/utils/nowPlayingDetector.ts (4 errors) - Created LastfmRecentTrack and RecentTracksResponse interfaces - Fixed processNowPlayingTracks: parameters with proper types - Fixed detectNowPlayingAlbums: parameters with proper types - Updated appleMusicDataLookup callback: return Album['appleMusicData'] | null 5. src/lib/utils/simpleNowPlayingDetector.ts (3 errors) - Created LastfmTrack interface - Fixed processAlbums: recentTracks parameter to LastfmTrack[] - Fixed appleMusicDataLookup callback: return Album['appleMusicData'] | null - Fixed mostRecentTrack variable type and date handling - Fixed trackData type in tracks.find() 6. src/lib/utils/simpleLastfmStreamManager.ts (2 errors) - Created RecentTracksResponse interface - Fixed getRecentAlbums: parameter RecentTracksResponse Progress: 32 any-type errors remaining (down from 51)
This commit is contained in:
parent
799570d979
commit
9f2854bfdc
6 changed files with 165 additions and 34 deletions
|
|
@ -5,6 +5,18 @@ import { transformImages, mergeAppleMusicData } from './lastfmTransformers'
|
|||
import redis from '../../routes/api/redis-client'
|
||||
import { logger } from '$lib/server/logger'
|
||||
|
||||
// Type for cached recent tracks data
|
||||
interface RecentTracksData {
|
||||
tracks: Array<{
|
||||
name: string
|
||||
artist: string
|
||||
album?: string
|
||||
date?: Date | string
|
||||
[key: string]: unknown
|
||||
}>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export class AlbumEnricher {
|
||||
private client: LastClient
|
||||
private cacheTTL = {
|
||||
|
|
@ -116,7 +128,10 @@ export class AlbumEnricher {
|
|||
/**
|
||||
* Get Apple Music data for duration-based now playing detection
|
||||
*/
|
||||
async getAppleMusicDataForNowPlaying(artistName: string, albumName: string): Promise<any> {
|
||||
async getAppleMusicDataForNowPlaying(
|
||||
artistName: string,
|
||||
albumName: string
|
||||
): Promise<Album['appleMusicData'] | null> {
|
||||
const cacheKey = `apple:album:${artistName}:${albumName}`
|
||||
const cached = await redis.get(cacheKey)
|
||||
|
||||
|
|
@ -146,7 +161,7 @@ export class AlbumEnricher {
|
|||
/**
|
||||
* Cache recent tracks from Last.fm
|
||||
*/
|
||||
async cacheRecentTracks(username: string, recentTracks: any): Promise<void> {
|
||||
async cacheRecentTracks(username: string, recentTracks: RecentTracksData): Promise<void> {
|
||||
const cacheKey = `lastfm:recent:${username}`
|
||||
await redis.set(cacheKey, JSON.stringify(recentTracks), 'EX', this.cacheTTL.recentTracks)
|
||||
}
|
||||
|
|
@ -154,15 +169,15 @@ export class AlbumEnricher {
|
|||
/**
|
||||
* Get cached recent tracks
|
||||
*/
|
||||
async getCachedRecentTracks(username: string): Promise<any | null> {
|
||||
async getCachedRecentTracks(username: string): Promise<RecentTracksData | null> {
|
||||
const cacheKey = `lastfm:recent:${username}`
|
||||
const cached = await redis.get(cacheKey)
|
||||
|
||||
if (cached) {
|
||||
const data = JSON.parse(cached)
|
||||
const data = JSON.parse(cached) as RecentTracksData
|
||||
// Convert date strings back to Date objects
|
||||
if (data.tracks) {
|
||||
data.tracks = data.tracks.map((track: any) => ({
|
||||
data.tracks = data.tracks.map((track) => ({
|
||||
...track,
|
||||
date: track.date ? new Date(track.date) : undefined
|
||||
}))
|
||||
|
|
|
|||
|
|
@ -5,6 +5,24 @@ import { AlbumEnricher } from './albumEnricher'
|
|||
import { trackToAlbum, getAlbumKey } from './lastfmTransformers'
|
||||
import { logger } from '$lib/server/logger'
|
||||
|
||||
// Type for Last.fm recent tracks response
|
||||
interface RecentTracksResponse {
|
||||
tracks: Array<{
|
||||
name: string
|
||||
album: {
|
||||
name: string
|
||||
mbid?: string
|
||||
}
|
||||
artist: {
|
||||
name: string
|
||||
}
|
||||
nowPlaying?: boolean
|
||||
date?: Date | { uts: number; '#text': string }
|
||||
[key: string]: unknown
|
||||
}>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface StreamState {
|
||||
lastNowPlayingState: Map<string, { isPlaying: boolean; track?: string }>
|
||||
lastAlbumOrder: string[]
|
||||
|
|
@ -78,7 +96,7 @@ export class LastfmStreamManager {
|
|||
/**
|
||||
* Fetch fresh recent tracks from Last.fm (no cache)
|
||||
*/
|
||||
private async fetchFreshRecentTracks(): Promise<any> {
|
||||
private async fetchFreshRecentTracks(): Promise<RecentTracksResponse> {
|
||||
logger.music('debug', 'Fetching fresh Last.fm recent tracks for now playing detection')
|
||||
const recentTracksResponse = await this.client.user.getRecentTracks(this.username, {
|
||||
limit: 50,
|
||||
|
|
@ -92,7 +110,10 @@ export class LastfmStreamManager {
|
|||
/**
|
||||
* Get recent albums from Last.fm
|
||||
*/
|
||||
private async getRecentAlbums(limit: number, recentTracksResponse?: any): Promise<Album[]> {
|
||||
private async getRecentAlbums(
|
||||
limit: number,
|
||||
recentTracksResponse?: RecentTracksResponse
|
||||
): Promise<Album[]> {
|
||||
// Use provided fresh data or fetch new
|
||||
if (!recentTracksResponse) {
|
||||
recentTracksResponse = await this.fetchFreshRecentTracks()
|
||||
|
|
@ -124,7 +145,10 @@ export class LastfmStreamManager {
|
|||
/**
|
||||
* Update now playing status using the detector
|
||||
*/
|
||||
private async updateNowPlayingStatus(albums: Album[], recentTracksResponse?: any): Promise<void> {
|
||||
private async updateNowPlayingStatus(
|
||||
albums: Album[],
|
||||
recentTracksResponse?: RecentTracksResponse
|
||||
): Promise<void> {
|
||||
// Use provided fresh data or fetch new
|
||||
if (!recentTracksResponse) {
|
||||
recentTracksResponse = await this.fetchFreshRecentTracks()
|
||||
|
|
@ -237,7 +261,7 @@ export class LastfmStreamManager {
|
|||
*/
|
||||
private async getNowPlayingUpdatesForNonRecentAlbums(
|
||||
recentAlbums: Album[],
|
||||
recentTracksResponse?: any
|
||||
recentTracksResponse?: RecentTracksResponse
|
||||
): Promise<NowPlayingUpdate[]> {
|
||||
const updates: NowPlayingUpdate[] = []
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,25 @@
|
|||
import type { Album, AlbumImages } from '$lib/types/lastfm'
|
||||
import type { LastfmImage } from '@musicorum/lastfm/dist/types/packages/common'
|
||||
|
||||
// Type for Last.fm track data from API responses
|
||||
interface LastfmTrack {
|
||||
name: string
|
||||
album: {
|
||||
name: string
|
||||
mbid?: string
|
||||
}
|
||||
artist: {
|
||||
name: string
|
||||
mbid?: string
|
||||
}
|
||||
images: LastfmImage[]
|
||||
url?: string
|
||||
nowPlaying?: boolean
|
||||
date?: Date | string
|
||||
mbid?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform Last.fm image array into structured AlbumImages object
|
||||
*/
|
||||
|
|
@ -43,7 +62,7 @@ export function getAlbumKey(artistName: string, albumName: string): string {
|
|||
/**
|
||||
* Transform track data into an Album object
|
||||
*/
|
||||
export function trackToAlbum(track: any, rank: number): Album {
|
||||
export function trackToAlbum(track: LastfmTrack, rank: number): Album {
|
||||
return {
|
||||
name: track.album.name,
|
||||
artist: {
|
||||
|
|
@ -53,7 +72,7 @@ export function trackToAlbum(track: any, rank: number): Album {
|
|||
playCount: 1,
|
||||
images: transformImages(track.images),
|
||||
mbid: track.album.mbid || '',
|
||||
url: track.url,
|
||||
url: track.url || '',
|
||||
rank,
|
||||
isNowPlaying: track.nowPlaying || false,
|
||||
nowPlayingTrack: track.nowPlaying ? track.name : undefined,
|
||||
|
|
@ -64,12 +83,12 @@ export function trackToAlbum(track: any, rank: number): Album {
|
|||
/**
|
||||
* Merge Apple Music data into an Album
|
||||
*/
|
||||
export function mergeAppleMusicData(album: Album, appleMusicData: any): Album {
|
||||
export function mergeAppleMusicData(album: Album, appleMusicData: Album['appleMusicData']): Album {
|
||||
return {
|
||||
...album,
|
||||
images: {
|
||||
...album.images,
|
||||
itunes: appleMusicData.highResArtwork || album.images.itunes
|
||||
itunes: appleMusicData?.highResArtwork || album.images.itunes
|
||||
},
|
||||
appleMusicData
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { logger } from '$lib/server/logger'
|
||||
import type { Album } from '$lib/types/lastfm'
|
||||
|
||||
export interface TrackPlayInfo {
|
||||
albumName: string
|
||||
|
|
@ -19,6 +20,29 @@ export interface NowPlayingResult {
|
|||
nowPlayingTrack?: string
|
||||
}
|
||||
|
||||
// Type for Last.fm track from recent tracks API
|
||||
interface LastfmRecentTrack {
|
||||
name: string
|
||||
artist: {
|
||||
name: string
|
||||
}
|
||||
album: {
|
||||
name: string
|
||||
}
|
||||
nowPlaying?: boolean
|
||||
date?: {
|
||||
uts: number | string
|
||||
'#text': string
|
||||
}
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
// Type for recent tracks response
|
||||
interface RecentTracksResponse {
|
||||
tracks: LastfmRecentTrack[]
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
// Configuration constants
|
||||
const SCROBBLE_LAG = 3 * 60 * 1000 // 3 minutes to account for Last.fm scrobble delay
|
||||
const TRACK_HISTORY_WINDOW = 60 * 60 * 1000 // Keep 1 hour of track history
|
||||
|
|
@ -139,8 +163,11 @@ export class NowPlayingDetector {
|
|||
* Process now playing data from Last.fm API response
|
||||
*/
|
||||
processNowPlayingTracks(
|
||||
recentTracksResponse: any,
|
||||
appleMusicDataLookup: (artistName: string, albumName: string) => Promise<any>
|
||||
recentTracksResponse: RecentTracksResponse,
|
||||
appleMusicDataLookup: (
|
||||
artistName: string,
|
||||
albumName: string
|
||||
) => Promise<Album['appleMusicData'] | null>
|
||||
): Promise<Map<string, NowPlayingUpdate>> {
|
||||
return this.detectNowPlayingAlbums(recentTracksResponse.tracks, appleMusicDataLookup)
|
||||
}
|
||||
|
|
@ -149,8 +176,11 @@ export class NowPlayingDetector {
|
|||
* Detect which albums are currently playing from a list of tracks
|
||||
*/
|
||||
private async detectNowPlayingAlbums(
|
||||
tracks: any[],
|
||||
appleMusicDataLookup: (artistName: string, albumName: string) => Promise<any>
|
||||
tracks: LastfmRecentTrack[],
|
||||
appleMusicDataLookup: (
|
||||
artistName: string,
|
||||
albumName: string
|
||||
) => Promise<Album['appleMusicData'] | null>
|
||||
): Promise<Map<string, NowPlayingUpdate>> {
|
||||
const albums: Map<string, NowPlayingUpdate> = new Map()
|
||||
let hasOfficialNowPlaying = false
|
||||
|
|
|
|||
|
|
@ -5,6 +5,24 @@ import { AlbumEnricher } from './albumEnricher'
|
|||
import { trackToAlbum } from './lastfmTransformers'
|
||||
import { logger } from '$lib/server/logger'
|
||||
|
||||
// Type for recent tracks response
|
||||
interface RecentTracksResponse {
|
||||
tracks: Array<{
|
||||
name: string
|
||||
album: {
|
||||
name: string
|
||||
mbid?: string
|
||||
}
|
||||
artist: {
|
||||
name: string
|
||||
}
|
||||
nowPlaying?: boolean
|
||||
date?: unknown
|
||||
[key: string]: unknown
|
||||
}>
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface StreamUpdate {
|
||||
albums?: Album[]
|
||||
}
|
||||
|
|
@ -90,7 +108,10 @@ export class SimpleLastfmStreamManager {
|
|||
/**
|
||||
* Get recent albums from Last.fm tracks
|
||||
*/
|
||||
private async getRecentAlbums(limit: number, recentTracksResponse: any): Promise<Album[]> {
|
||||
private async getRecentAlbums(
|
||||
limit: number,
|
||||
recentTracksResponse: RecentTracksResponse
|
||||
): Promise<Album[]> {
|
||||
const uniqueAlbums = new Map<string, Album>()
|
||||
|
||||
for (const track of recentTracksResponse.tracks) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,22 @@
|
|||
import type { Album } from '$lib/types/lastfm'
|
||||
import { logger } from '$lib/server/logger'
|
||||
|
||||
// Type for Last.fm track from API
|
||||
interface LastfmTrack {
|
||||
name: string
|
||||
album: {
|
||||
name: string
|
||||
}
|
||||
artist: {
|
||||
name: string
|
||||
}
|
||||
nowPlaying?: boolean
|
||||
date?: {
|
||||
uts: number | string
|
||||
}
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
// Simple buffer time for tracks that might have paused/buffered
|
||||
const BUFFER_TIME_MS = 30000 // 30 seconds grace period
|
||||
|
||||
|
|
@ -27,8 +43,11 @@ export class SimpleNowPlayingDetector {
|
|||
*/
|
||||
async processAlbums(
|
||||
albums: Album[],
|
||||
recentTracks: any[],
|
||||
appleMusicDataLookup: (artistName: string, albumName: string) => Promise<any>
|
||||
recentTracks: LastfmTrack[],
|
||||
appleMusicDataLookup: (
|
||||
artistName: string,
|
||||
albumName: string
|
||||
) => Promise<Album['appleMusicData'] | null>
|
||||
): Promise<Album[]> {
|
||||
logger.music('debug', `Processing ${albums.length} albums with ${recentTracks.length} recent tracks`)
|
||||
|
||||
|
|
@ -61,13 +80,16 @@ export class SimpleNowPlayingDetector {
|
|||
logger.music('debug', 'Using duration-based detection')
|
||||
|
||||
// Find the most recent track across all albums
|
||||
let mostRecentTrack: any = null
|
||||
let mostRecentTrack: LastfmTrack | null = null
|
||||
let mostRecentTime = new Date(0)
|
||||
|
||||
for (const track of recentTracks) {
|
||||
if (track.date && track.date > mostRecentTime) {
|
||||
mostRecentTime = track.date
|
||||
mostRecentTrack = track
|
||||
if (track.date && typeof track.date === 'object' && 'uts' in track.date) {
|
||||
const trackTime = new Date(Number(track.date.uts) * 1000)
|
||||
if (trackTime > mostRecentTime) {
|
||||
mostRecentTime = trackTime
|
||||
mostRecentTrack = track
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +104,7 @@ export class SimpleNowPlayingDetector {
|
|||
}
|
||||
|
||||
logger.music('debug', `Most recent track: "${mostRecentTrack.name}" by ${mostRecentTrack.artist.name} from ${mostRecentTrack.album.name}`)
|
||||
logger.music('debug', `Scrobbled at: ${mostRecentTrack.date}`)
|
||||
logger.music('debug', `Scrobbled at: ${mostRecentTime}`)
|
||||
|
||||
// Check if the most recent track is still playing
|
||||
const albumKey = `${mostRecentTrack.artist.name}:${mostRecentTrack.album.name}`
|
||||
|
|
@ -97,11 +119,11 @@ export class SimpleNowPlayingDetector {
|
|||
|
||||
if (appleMusicData?.tracks) {
|
||||
const trackData = appleMusicData.tracks.find(
|
||||
(t: any) => t.name.toLowerCase() === mostRecentTrack.name.toLowerCase()
|
||||
(t) => t.name?.toLowerCase() === mostRecentTrack!.name.toLowerCase()
|
||||
)
|
||||
|
||||
if (trackData?.durationMs) {
|
||||
isPlaying = this.isTrackPlaying(mostRecentTrack.date, trackData.durationMs)
|
||||
isPlaying = this.isTrackPlaying(mostRecentTime, trackData.durationMs)
|
||||
if (isPlaying) {
|
||||
playingTrack = mostRecentTrack.name
|
||||
logger.music('debug', `✅ "${playingTrack}" is still playing`)
|
||||
|
|
|
|||
Loading…
Reference in a new issue