[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
0

Configure Feed

Select the types of activity you want to include in your feed.

feat: Add more identying data to lifecycle step

FoxxMD (Jun 10, 2026, 1:54 AM UTC) e13d86b1 f7577c43

+17 -8
+9 -5
src/backend/common/AbstractComponent.ts
··· 338 338 } 339 339 } 340 340 steps.forEach((s, index) => { 341 - const existingStepIndex = transformedPlay.meta.lifecycle.steps.findIndex(x => x.name === 'hookType' && x.source === this.getIdentifier()); 341 + const existingStepIndex = transformedPlay.meta.lifecycle.steps.findIndex(x => x.stageName === s.stageName && x.stageType && s.stageType && x.hook === s.hook && x.source === this.getIdentifier()); 342 342 if(existingStepIndex !== -1) { 343 343 transformedPlay.meta.lifecycle.steps[existingStepIndex] = s; 344 344 } else { ··· 347 347 348 348 if(shouldLog === 'all') { 349 349 if(s.patch === undefined) { 350 - historyToDiff.push({name: `${s.source}-${s.name}`}); 350 + historyToDiff.push({name: `${s.source}-${s.hook}-${s.stageType}-${s.stageName}`}); 351 351 } else { 352 352 const patched = patchObject(historyToDiff[historyToDiff.length - 1].data, s.patch); 353 - historyToDiff.push({name: `${s.source}-${s.name}${s.cached ? ' (Cached)' : ''}`, data: patched}); 353 + historyToDiff.push({name: `${s.source}-${s.hook}-${s.stageType}-${s.stageName} ${s.cached ? ' (Cached)' : ''}`, data: patched}); 354 354 } 355 355 } 356 356 }); ··· 413 413 } = opts; 414 414 415 415 const stepName = `${hookType} - ${hookItem.type} - ${hookItem.name}` 416 - const existingStepIndex = playTruth.meta.lifecycle.steps.findIndex(x => x.name === stepName && x.source === this.getIdentifier()); 416 + const existingStepIndex = playTruth.meta.lifecycle.steps.findIndex(x => x.hook === hookType && hookItem.name === x.stageName && x.stageType === hookItem.type && x.source === this.getIdentifier()); 417 417 const step: LifecycleStep = existingStepIndex !== -1 && playTruth.meta.lifecycle.steps[existingStepIndex] !== undefined ? playTruth.meta.lifecycle.steps[existingStepIndex] : { 418 - name: stepName, 418 + stageName: hookItem.name, 419 + hook: hookType, 420 + stageType: hookItem.type, 419 421 source: this.getIdentifier(), 420 422 createdAt: dayjs().toString() 421 423 } ··· 432 434 stageName = e.stageName; 433 435 } 434 436 } 437 + 438 + step.stageName = stageName; 435 439 436 440 if (err !== undefined) { 437 441 const merged = mergeSimpleError(err);
+4 -2
src/core/Atomic.ts
··· 5 5 import { MarkOptional } from "ts-essentials"; 6 6 import { ErrorObject } from "serialize-error"; 7 7 import { PlayPlatformIdStr } from "../backend/common/infrastructure/Atomic.js"; 8 - import { FlowControlTerm } from "../backend/common/infrastructure/Transform.js"; 8 + import { FlowControlTerm, TransformHook } from "../backend/common/infrastructure/Transform.js"; 9 9 import { Changeset } from "json-diff-ts"; 10 10 11 11 export interface SourceStatusData { ··· 319 319 } 320 320 321 321 export interface LifecycleStep { 322 - name: string 322 + stageName: string 323 + stageType: string 324 + hook: TransformHook 323 325 source: string 324 326 cached?: boolean 325 327 returnPartial?: boolean
+4 -1
src/core/tests/utils/fixtures.ts
··· 11 11 import { playToListenPayload } from '../../../backend/common/vendor/listenbrainz/lzUtils.js'; 12 12 import { mergeSimpleError, SimpleError, SkipTransformStageError, StagePrerequisiteError } from '../../../backend/common/errors/MSErrors.js'; 13 13 import dayjs, { Dayjs } from 'dayjs'; 14 + import { TransformHook } from '../../../backend/common/infrastructure/Transform.js'; 14 15 15 16 export interface ScrobbleMatchOptions { 16 17 match?: boolean ··· 172 173 const inputs = faker.helpers.multiple(() => generateLifecycleInput(), { count: inputCount ?? { min: 0, max: 2 } }); 173 174 174 175 const step: LifecycleStep = { 175 - name, 176 + hook: name as TransformHook, 177 + stageType: faker.helpers.arrayElement(['musicbrainz','native','user']), 178 + stageName: faker.word.noun({length: {min: 1, max: 3}}), 176 179 source, 177 180 flowResult: 'continue', 178 181 inputs,