Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
Something went wrong. Try again.
8.4 kB · 190 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190import { type ArtistCredit, type ArtMeta, isPlayObject, type ObjectPlayData, type PlayObject, type TrackMeta } from "../../../core/Atomic.ts";import type {AtomicStageConfig, StageConfig} from "../../../core/Transform.ts";import AbstractTransformer from "./AbstractTransformer.ts";
//export type GenericAtomicStageConfig<A> =
export default abstract class AtomicPartsTransformer<Y, T = any, Z extends AtomicStageConfig<Y> = StageConfig> extends AbstractTransformer<T, Z> {
protected async doHandle(parts: Z, play: PlayObject, transformData: T): Promise<PlayObject> { const { throwOnFailure = false, } = this.config.options || {}; const transformedPlayData: Partial<ObjectPlayData> = {}; if (parts.title !== undefined) { try { const title = await this.handleTitle(play, parts.title, transformData); transformedPlayData.track = title; } catch (e) { const err = new Error(`Failed to transform title: ${play.data.track}`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('title'))) { throw err; } else { this.logger.warn(err); } } } if (parts.artists !== undefined) { try { const artists = await this.handleArtists(play, parts.artists, transformData); transformedPlayData.artists = artists; } catch (e) { const err = new Error(`Failed to transform artists`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('artists'))) { throw err; } else { this.logger.warn(err); } } }
if(parts.albumArtists !== undefined) { try { const albumArtists = await this.handleAlbumArtists(play, parts.albumArtists, transformData); transformedPlayData.albumArtists = albumArtists; } catch (e) { const err = new Error(`Failed to transform album artists`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('albumArtists'))) { throw err; } else { this.logger.warn(err); } } } if (parts.album !== undefined) { try { const album = await this.handleAlbum(play, parts.album, transformData); transformedPlayData.album = album; } catch (e) { const err = new Error(`Failed to transform album: ${play.data.album}`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('album'))) { throw err; } else { this.logger.warn(err); } } }
if (parts.duration !== undefined) { try { const duration = await this.handleDuration(play, parts.duration, transformData); transformedPlayData.duration = duration; } catch (e) { const err = new Error(`Failed to transform duration: ${play.data.duration}`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('duration'))) { throw err; } else { this.logger.warn(err); } } }
let mergedMeta: TrackMeta; if (parts.meta !== undefined) { try { const meta = await this.handleMeta(play, parts.duration, transformData);
if (meta !== undefined) { mergedMeta = { ...(play.data.meta ?? {}) }; for (const [k, v] of Object.entries(meta)) { if (mergedMeta[k] !== undefined) { mergedMeta[k] = { ...mergedMeta[k], ...v } } else { mergedMeta[k] = v; } } } } catch (e) { const err = new Error(`Failed to transform meta: ${play.data.meta}`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('meta'))) { throw err; } else { this.logger.warn(err); } } }
let mergedArt: ArtMeta; if (parts.art !== undefined) { try { const art = await this.handleArt(play, parts.art, transformData);
if (art !== undefined) { mergedArt = { ...(play.meta?.art ?? {}) }; for (const [k, v] of Object.entries(art)) { if (mergedArt[k] !== undefined) { mergedArt[k] = { ...mergedMeta[k], ...v } } else { mergedArt[k] = v; } } } } catch (e) { const err = new Error(`Failed to transform art: ${JSON.stringify(play.meta?.art)}`, { cause: e }); if (throwOnFailure === true || (throwOnFailure !== false && throwOnFailure.includes('art'))) { throw err; } else { this.logger.warn(err); } } }
const transformedPlay = { ...play, data: { ...play.data, ...transformedPlayData, } }
if(mergedMeta !== undefined) { transformedPlay.data.meta = mergedMeta; } if(mergedArt !== undefined) { transformedPlay.meta.art = mergedArt; }
if(typeof transformData === 'object' && isPlayObject(transformData) && transformData.meta?.lifecycleInputs !== undefined) { const { meta: { lifecycleInputs = [], } = {}, } = transformedPlay; transformedPlay.meta.lifecycleInputs = lifecycleInputs.concat(transformData.meta?.lifecycleInputs); }
return transformedPlay; } protected abstract handleTitle(play: PlayObject, parts: Y, transformData: T): Promise<string | undefined>; protected abstract handleArtists(play: PlayObject, parts: Y, transformData: T): Promise<ArtistCredit[] | undefined>; protected abstract handleAlbumArtists(play: PlayObject, parts: Y, transformData: T): Promise<ArtistCredit[] | undefined>; protected abstract handleAlbum(play: PlayObject, parts: Y, transformData: T): Promise<string | undefined>; protected async handleDuration(play: PlayObject, parts: Y, transformData: T): Promise<number | undefined> { return play.data.duration; } protected async handleMeta(play: PlayObject, parts: Y, transformData: T): Promise<TrackMeta | undefined> { return undefined; }
protected async handleArt(play: PlayObject, parts: Y, transformData: T): Promise<ArtMeta | undefined> { return undefined; }
}