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.
9.6 kB · 190 lines
TypeScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191import { loggerTest } from "@foxxmd/logging";import { expect } from 'chai';import EventEmitter from "events";import { describe, it } from 'mocha';import type {PlayMeta} from "../../../core/Atomic.ts";
import validSessionResponse from './validSession.json' with { type: "json" };import { generatePlay } from "../../../core/tests/utils/PlayTestUtils.ts";import type {PlayerStateDataMaybePlay} from "../../common/infrastructure/Atomic.ts";import type {PlexApiData} from "../../common/infrastructure/config/source/plex.ts";import PlexApiSource from "../../sources/PlexApiSource.ts";import type {GetSessionsMetadata} from "@lukehagar/plexjs/sdk/models/operations/getsessions.js";
const validSession = validSessionResponse.object.mediaContainer.metadata[0];
const createSource = async (data: PlexApiData, authedUser: string | false = 'MyUser'): Promise<PlexApiSource> => { const source = new PlexApiSource('Test', { id: `test-${Date.now()}`, data, options: {} }, { localUrl: new URL('http://test'), configDir: 'test', logger: loggerTest, version: 'test' }, new EventEmitter()); source.libraries = [{name: 'Music', collectionType: 'artist', uuid: 'dfsdf'}]; source.plexUser = 'MyUser'; await source.buildInitData(); if(authedUser !== false && source.usersAllow.length === 0 && data.usersAllow !== true) { source.usersAllow.push(authedUser.toLocaleLowerCase()); } return source;}
const defaultCreds = {url: 'http://example.com', token: '1234'};
const validPlayerState: PlayerStateDataMaybePlay = { platformId: ['1234', 'MyUser'], play: generatePlay({}, {mediaType: 'track', user: 'MyUser', deviceId: '1234', library: 'Music'})}const playWithMeta = (meta: PlayMeta): PlayerStateDataMaybePlay => { const {user, deviceId} = meta; const platformId = validPlayerState.platformId; return { ...validPlayerState, platformId: [deviceId ?? platformId[0], user ?? platformId[1]], play: { ...validPlayerState.play, meta: { ...validPlayerState.play?.meta, ...meta } }}}// ({...validPlayerState, meta: {...validPlayerState.meta, ...meta}});
const nowPlayingSession = (data: object = {}): GetSessionsMetadata => ({...validSession, ...data});
describe("Plex API Source", function() { describe('Parses config allow/block correctly', function () { it('Should parse users, devices, and libraries, and library types as lowercase from config', async function () { const s = await createSource({ usersAllow: ['MyUser', 'AnotherUser'], usersBlock: ['SomeUser'], devicesAllow: ['Web Player'], devicesBlock: ['Bad Player'], librariesAllow: ['MuSiCoNe'], librariesBlock: ['MuSiCbAd'], ...defaultCreds});
expect(s.usersAllow).to.be.eql(['myuser', 'anotheruser']); expect(s.usersBlock).to.be.eql(['someuser']); expect(s.devicesAllow).to.be.eql(['web player']); expect(s.devicesBlock).to.be.eql(['bad player']); expect(s.librariesAllow).to.be.eql(['musicone']); expect(s.librariesBlock).to.be.eql(['musicbad']); await s.destroy(); });
it('Should include authenticating user as allowed when no others are set', async function () { const s = await createSource({...defaultCreds});
expect(s.usersAllow).to.be.eql(['myuser']); await s.destroy(); });
it('Should set allowed users to empty array (allow all) when usersAllow is true', async function () { const s = await createSource({...defaultCreds, usersAllow: true}, false);
expect(s.usersAllow).to.be.empty; await s.destroy(); });
it('Should set allowed users to empty array (allow all) when usersAllow is an array with only one value equal to true', async function () { const s = await createSource({...defaultCreds, usersAllow: ['true']}, false);
expect(s.usersAllow).to.be.empty; await s.destroy(); }); });
describe('Correctly detects activity as valid/invalid', function() {
describe('Filters from Configuration', function() {
it('Should allow activity based on user allow', async function () { const s = await createSource({...defaultCreds}); expect(s.isActivityValid(playWithMeta({user: 'SomeOtherUser'}), validSession)).to.not.be.true; expect(s.isActivityValid(validPlayerState, validSession)).to.be.true; expect(s.isActivityValid(playWithMeta({user: 'myuser'}), validSession)).to.be.true; await s.destroy(); }); it('Should disallow activity based on user block', async function () { const s = await createSource({...defaultCreds, usersBlock: ['BadUser']}); expect(s.isActivityValid(playWithMeta({user: 'BadUser'}), validSession)).to.not.be.true; expect(s.isActivityValid(validPlayerState, validSession)).to.be.true; expect(s.isActivityValid(playWithMeta({user: 'myuser'}), validSession)).to.be.true; await s.destroy(); }); it('Should allow activity based on devices allow', async function () { const s = await createSource({...defaultCreds, devicesAllow: ['WebPlayer']}); expect(s.isActivityValid(validPlayerState, validSession)).to.not.be.true; expect(s.isActivityValid(playWithMeta({deviceId: 'WebPlayer'}), validSession)).to.be.true; await s.destroy(); }); it('Should disallow activity based on devices block', async function () { const s = await createSource({...defaultCreds, devicesBlock: ['WebPlayer']}); expect(s.isActivityValid(validPlayerState, validSession)).to.be.true; expect(s.isActivityValid(playWithMeta({deviceId: 'WebPlayer'}), validSession)).to.not.be.true; await s.destroy(); });
it('Should allow activity based on libraries allow', async function () { const s = await createSource({...defaultCreds, librariesAllow: ['music']}); s.libraries.push({name: 'SomeOtherLibrary', collectionType: 'artist', uuid: '43543'}); s.libraries.push({name: 'Study Music', collectionType: 'artist', uuid: '435437'}); s.libraries.push({name: 'Music', collectionType: 'artist', uuid: '4354378'}); expect(s.isActivityValid(validPlayerState, validSession)).to.be.true; expect(s.isActivityValid(playWithMeta({library: 'SomeOtherLibrary'}), nowPlayingSession({librarySectionTitle: 'SomeOtherLibrary'}))).to.not.be.true; expect(s.isActivityValid(playWithMeta({library: 'Study Music'}), nowPlayingSession({librarySectionTitle: 'Study Music'}))).to.not.be.true; expect(s.isActivityValid(playWithMeta({library: 'Music'}), nowPlayingSession({librarySectionTitle: 'Music'}))).to.be.true; await s.destroy(); }); it('Should disallow activity based on libraries block', async function () { const s = await createSource({...defaultCreds, librariesBlock: ['music']}); s.libraries.push({name: 'CoolVideos', collectionType: 'artist', uuid: '43543'}); s.libraries.push({name: 'Study Music', collectionType: 'artist', uuid: '435437'}); s.libraries.push({name: 'Music', collectionType: 'artist', uuid: '4354378'}); expect(s.isActivityValid(validPlayerState, validSession)).to.not.be.true; expect(s.isActivityValid(playWithMeta({library: 'CoolVideos'}), nowPlayingSession({librarySectionTitle: 'CoolVideos'}))).to.be.true; expect(s.isActivityValid(playWithMeta({library: 'Study Music'}), nowPlayingSession({librarySectionTitle: 'Study Music'}))).to.be.true; expect(s.isActivityValid(playWithMeta({library: 'Music'}), nowPlayingSession({librarySectionTitle: 'Music'}))).to.not.be.true; await s.destroy(); });
});
describe('Detection by Session/Media/Library Type', function() {
it('Should allow activity with valid MediaType and valid Library', async function () { const s = await createSource({...defaultCreds}); expect(s.isActivityValid(validPlayerState, validSession)).to.be.true; await s.destroy(); });
it('Should disallow activity with invalid library type', async function () { const s = await createSource({...defaultCreds}); s.libraries.push({name: 'CoolVideos', uuid: '64564', collectionType: 'shows'}); expect(s.isActivityValid(playWithMeta({library: 'CoolVideos'}), nowPlayingSession({librarySectionTitle: 'CoolVideos'}))).to.not.be.true; await s.destroy(); }); it('Should disallow Play that is not valid MediaType', async function () { const s = await createSource({...defaultCreds}); expect(s.isActivityValid(playWithMeta({mediaType: 'book'}), validSession)).to.not.be.true; await s.destroy(); });
}); });});