mirror of
https://github.com/FoxxMD/multi-scrobbler.git
synced 2026-09-03 05:10:00 +03:00
refactor(ui): Update legacy ui to be compatible with new monitoring structure
This commit is contained in:
+27
-10
@@ -380,7 +380,6 @@ export const setupApi = (app: Express, logger: Logger, appLoggerStream: PassThro
|
||||
players: 'players' in x ? (x as MemorySource).playersToObject() as unknown as Record<string,SourcePlayerJson> : {},
|
||||
sot: ('playerSourceOfTruth' in x) ? x.playerSourceOfTruth as SOURCE_SOT_TYPES : SOURCE_SOT.HISTORY,
|
||||
supportsUpstreamRecentlyPlayed: x.supportsUpstreamRecentlyPlayed,
|
||||
supportsManualListening: true,
|
||||
manualListening: x.monitoringActivity,
|
||||
systemListeningBehavior: x.getSystemMonitoring(),
|
||||
...x.additionalApiData()
|
||||
@@ -427,7 +426,9 @@ export const setupApi = (app: Express, logger: Logger, appLoggerStream: PassThro
|
||||
initialized: x.isReady(),
|
||||
deadLetterScrobbles: x.deadLetterQueued, // x.deadLetterScrobbles.length,
|
||||
deadLetterScrobblesTotal: x.deadLetterLength,
|
||||
queued: x.queuedLength // x.queuedScrobbles.length
|
||||
queued: x.queuedLength, // x.queuedScrobbles.length
|
||||
manualListening: x.monitoringActivity,
|
||||
systemListeningBehavior: x.getSystemMonitoring(),
|
||||
};
|
||||
if (!base.initialized) {
|
||||
if(x.buildOK === false) {
|
||||
@@ -671,19 +672,35 @@ export const setupApi = (app: Express, logger: Logger, appLoggerStream: PassThro
|
||||
}
|
||||
} = req;
|
||||
|
||||
if(!source.supportsManualListening)
|
||||
{
|
||||
source.logger.warn('This source does not support manual Should Scrobble state');
|
||||
res.status(400).send();
|
||||
return;
|
||||
}
|
||||
let listening: boolean | undefined;
|
||||
if(listeningQ !== undefined) {
|
||||
listening = parseBool(listeningQ)
|
||||
}
|
||||
source.logger.verbose(`User requested Should Scrobble status ${listening === undefined ? 'system' : listening}`);
|
||||
source.logger.verbose(`User requested Monitoring status ${listening === undefined ? 'system' : listening}`);
|
||||
|
||||
source.manualListening = listening;
|
||||
source.monitoringActivity = listening;
|
||||
|
||||
res.status(200).json({listening});
|
||||
});
|
||||
|
||||
app.use('/api/client/listen', clientRequiredMiddle);
|
||||
app.post('/api/client/listen', async (req, res) => {
|
||||
// @ts-expect-error TS(2339): Property 'scrobbleSource' does not exist on type '... Remove this comment to see the full error message
|
||||
const client = req.scrobbleClient as AbstractScrobbleClient;
|
||||
|
||||
const {
|
||||
query: {
|
||||
listening: listeningQ
|
||||
}
|
||||
} = req;
|
||||
|
||||
let listening: boolean | undefined;
|
||||
if(listeningQ !== undefined) {
|
||||
listening = parseBool(listeningQ)
|
||||
}
|
||||
client.logger.verbose(`User requested Monitoring status ${listening === undefined ? 'system' : listening}`);
|
||||
|
||||
client.monitoringActivity = listening;
|
||||
|
||||
res.status(200).json({listening});
|
||||
});
|
||||
|
||||
@@ -87,8 +87,6 @@ export default abstract class AbstractSource extends AbstractComponent implement
|
||||
supportsUpstreamNowPlaying: boolean = false;
|
||||
supportsManualListening: boolean = false;
|
||||
|
||||
manualListening?: boolean
|
||||
|
||||
scheduler: ToadScheduler = new ToadScheduler();
|
||||
|
||||
protected SCROBBLE_BACKLOG_COUNT: number = 30;
|
||||
@@ -268,12 +266,12 @@ export default abstract class AbstractSource extends AbstractComponent implement
|
||||
}
|
||||
|
||||
public getRunningState(): ComponentState {
|
||||
const monitoring = (this.canPoll && this.polling) || !this.canPoll;
|
||||
const running = (this.canPoll && this.polling) || !this.canPoll;
|
||||
|
||||
if(monitoring && this.supportsManualListening && this.manualListening === false) {
|
||||
if(running && !this.isMonitoring()) {
|
||||
return COMPONENT_STATE.MUTED;
|
||||
}
|
||||
return monitoring ? COMPONENT_STATE.RUNNING : COMPONENT_STATE.IDLE;
|
||||
return running ? COMPONENT_STATE.RUNNING : COMPONENT_STATE.IDLE;
|
||||
}
|
||||
|
||||
protected getComponentApiData() {
|
||||
|
||||
@@ -37,7 +37,6 @@ export class AzuracastSource extends MemorySource {
|
||||
|
||||
this.requiresAuth = false;
|
||||
this.canPoll = true;
|
||||
this.supportsManualListening = true;
|
||||
}
|
||||
|
||||
protected async doBuildInitData(): Promise<true | string | undefined> {
|
||||
@@ -175,9 +174,9 @@ export class AzuracastSource extends MemorySource {
|
||||
this.logger.debug({labels: `Station ${this.config.data.station}`}, `Currently offline`);
|
||||
return false;
|
||||
}
|
||||
if(this.manualListening === true) {
|
||||
this.logger.debug({labels: `Station ${this.config.data.station}`}, `Using manual listening status ${this.manualListening}`);
|
||||
return this.manualListening;
|
||||
if(this.monitoringActivity !== undefined) {
|
||||
this.logger.debug({labels: `Station ${this.config.data.station}`}, `Using manual listening status ${this.monitoringActivity}`);
|
||||
return this.monitoringActivity;
|
||||
}
|
||||
if(this.config.data.monitorWhenListeners !== undefined) {
|
||||
if(this.config.data.monitorWhenListeners === true && this.wsNowPlaying.listeners.current === 0) {
|
||||
|
||||
@@ -44,7 +44,6 @@ export class IcecastSource extends MemorySource {
|
||||
|
||||
this.requiresAuth = false;
|
||||
this.canPoll = true;
|
||||
this.supportsManualListening = true;
|
||||
}
|
||||
|
||||
protected async doBuildInitData(): Promise<true | string | undefined> {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {clientAdapter} from "../../status/ducks";
|
||||
import type {RootState} from "../../store";
|
||||
import {connect, type ConnectedProps} from "react-redux";
|
||||
import {Link} from "react-router-dom";
|
||||
import {useStartClientMutation} from "./clientDucks";
|
||||
import {useStartClientMutation, useListenClientMutation} from "./clientDucks";
|
||||
|
||||
export interface ClientStatusCardData extends StatusCardSkeletonData, PropsFromRedux {
|
||||
loading?: boolean
|
||||
@@ -40,8 +40,25 @@ const ClientStatusCard = (props: ClientStatusCardData) => {
|
||||
} = props;
|
||||
|
||||
const [startClientPut, startResult] = useStartClientMutation();
|
||||
const [listenPut, listenResult] = useListenClientMutation();
|
||||
|
||||
const tryStart = useCallback((name: string, force?: boolean) => startClientPut({name, force}), [startClientPut]);
|
||||
const tryListen = useCallback((name: string, type: string, currentListening?: boolean) => {
|
||||
// cycle through states
|
||||
let nextListen: boolean | undefined;
|
||||
switch(currentListening) {
|
||||
case true:
|
||||
nextListen = false;
|
||||
break;
|
||||
case false:
|
||||
nextListen = undefined;
|
||||
break;
|
||||
case undefined:
|
||||
nextListen = true;
|
||||
break;
|
||||
}
|
||||
listenPut({name, type, listening: nextListen});
|
||||
}, [listenPut]);
|
||||
|
||||
let header: string | undefined = display;
|
||||
let body = <SkeletonParagraph/>;
|
||||
@@ -50,10 +67,13 @@ const ClientStatusCard = (props: ClientStatusCardData) => {
|
||||
<div onClick={() => tryStart(name)} className="capitalize underline cursor-pointer inline mr-1">{status === 'Running' ? 'Restart' : 'Start'}</div>
|
||||
(<div onClick={() => tryStart(name, true)} className="capitalize underline cursor-pointer inline">Force</div>)
|
||||
</Fragment>)
|
||||
let subtitleElement = startClientElement;
|
||||
if(data !== undefined) {
|
||||
const {
|
||||
hasAuth,
|
||||
hasAuthInteraction,
|
||||
manualListening,
|
||||
systemListeningBehavior,
|
||||
name,
|
||||
type,
|
||||
authed,
|
||||
@@ -61,9 +81,27 @@ const ClientStatusCard = (props: ClientStatusCardData) => {
|
||||
} = data;
|
||||
header = `${display} (Client)`;
|
||||
|
||||
const scrobbled = initialized && (!hasAuth || (hasAuth && authed)) ? <Link to={`/scrobbled?type=${type}&name=${name}`}>Tracks Scrobbled</Link> : <span>Tracks Scrobbled</span>;
|
||||
const ml = useMemo(() => {
|
||||
if(listenResult.status !== 'fulfilled' || listenResult.data === undefined) {
|
||||
return manualListening;
|
||||
}
|
||||
return (listenResult.data as any).listening;
|
||||
}, [manualListening, listenResult]);
|
||||
|
||||
// TODO links
|
||||
const manualListenElement = (<Fragment>
|
||||
<span>Monitoring:</span>
|
||||
<div onClick={() => tryListen(name, type, ml)}
|
||||
className="capitalize underline cursor-pointer inline mr-1 ml-1">
|
||||
{ml !== undefined ? (ml ? 'Yes' : 'No') : null}
|
||||
{ml === undefined ? <span>System {systemListeningBehavior ? '(Yes)' : '(No)'}</span> : null}
|
||||
</div>
|
||||
{/* {ml !== undefined ? <div onClick={() => tryListen(name, type, undefined)}
|
||||
className="capitalize underline cursor-pointer inline">Clear
|
||||
</div> : null} */}
|
||||
</Fragment>);
|
||||
subtitleElement = <Fragment>{startClientElement}</Fragment>;//<Fragment>{manualListenElement} | {startClientElement}</Fragment>;
|
||||
|
||||
const scrobbled = initialized && (!hasAuth || (hasAuth && authed)) ? <Link to={`/scrobbled?type=${type}&name=${name}`}>Tracks Scrobbled</Link> : <span>Tracks Scrobbled</span>;
|
||||
body = (<Fragment>
|
||||
<div>{scrobbled}: {scrobbledCount}</div>
|
||||
<div>Queued Scrobbles: {queued}</div>
|
||||
@@ -77,7 +115,7 @@ const ClientStatusCard = (props: ClientStatusCardData) => {
|
||||
title={header}
|
||||
subtitle={name}
|
||||
status={status}
|
||||
subtitleRight={startClientElement}
|
||||
subtitleRight={subtitleElement}
|
||||
statusType={statusToStatusType(status)}>
|
||||
{body}
|
||||
</StatusCardSkeleton>
|
||||
|
||||
@@ -8,6 +8,9 @@ import {connect, type ConnectedProps} from "react-redux";
|
||||
import Player from "../player/Player";
|
||||
import {useStartSourceMutation, useListenSourceMutation} from "./sourceDucks";
|
||||
import './statusCard.scss';
|
||||
import Tooltip from '../Tooltip';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import {faQuestionCircle} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
const ambiguousTypes = ['lastfm','listenbrainz','koito','librefm','maloja','rocksky'];
|
||||
export interface SourceStatusCardData extends StatusCardSkeletonData, PropsFromRedux {
|
||||
@@ -59,8 +62,6 @@ const SourceStatusCard = (props: SourceStatusCardData) => {
|
||||
}
|
||||
listenPut({name, type, listening: nextListen});
|
||||
}, [listenPut]);
|
||||
let startSourceElement = null;
|
||||
let manualListenElement = null;
|
||||
let subtitleElement = null;
|
||||
|
||||
if(data !== undefined)
|
||||
@@ -78,7 +79,6 @@ const SourceStatusCard = (props: SourceStatusCardData) => {
|
||||
players = {},
|
||||
sot,
|
||||
supportsUpstreamRecentlyPlayed,
|
||||
supportsManualListening,
|
||||
manualListening,
|
||||
systemListeningBehavior
|
||||
} = data;
|
||||
@@ -100,9 +100,13 @@ const SourceStatusCard = (props: SourceStatusCardData) => {
|
||||
return (listenResult.data as any).listening;
|
||||
}, [manualListening, listenResult]);
|
||||
|
||||
if(supportsManualListening) {
|
||||
manualListenElement = (<Fragment>
|
||||
<span>Should Scrobble:</span>
|
||||
const manualListenElement = type !== 'azuracast' && type !== 'icecast' ? null : (<Fragment>
|
||||
<span>Monitoring <Tooltip message="test"
|
||||
style={{
|
||||
display: 'inline-flex'
|
||||
}}>
|
||||
<FontAwesomeIcon color="white" icon={faQuestionCircle}/></Tooltip> :
|
||||
</span>
|
||||
<div onClick={() => tryListen(name, type, ml)}
|
||||
className="capitalize underline cursor-pointer inline mr-1 ml-1">
|
||||
{ml !== undefined ? (ml ? 'Yes' : 'No') : null}
|
||||
@@ -112,9 +116,8 @@ const SourceStatusCard = (props: SourceStatusCardData) => {
|
||||
className="capitalize underline cursor-pointer inline">Clear
|
||||
</div> : null} */}
|
||||
</Fragment>);
|
||||
}
|
||||
|
||||
startSourceElement = (<Fragment>
|
||||
const startSourceElement = (<Fragment>
|
||||
<div onClick={() => tryStart(name, type)}
|
||||
className="capitalize underline cursor-pointer inline mr-1">{startText}
|
||||
</div>
|
||||
|
||||
@@ -16,8 +16,23 @@ export const scrobblerApi = createApi({
|
||||
force: params.force
|
||||
}
|
||||
})
|
||||
}),
|
||||
listenClient: builder.mutation<undefined, {
|
||||
name: string,
|
||||
type: string,
|
||||
listening?: boolean
|
||||
}>({
|
||||
query: (params) => ({
|
||||
url: '/client/listen',
|
||||
method: 'POST',
|
||||
params: {
|
||||
name: params.name,
|
||||
type: params.type,
|
||||
listening: params.listening
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
export const {useStartClientMutation} = scrobblerApi;
|
||||
export const {useStartClientMutation, useListenClientMutation} = scrobblerApi;
|
||||
|
||||
+2
-1
@@ -28,7 +28,6 @@ export interface SourceStatusData {
|
||||
players: Record<string, SourcePlayerJson>
|
||||
sot: SOURCE_SOT_TYPES
|
||||
supportsUpstreamRecentlyPlayed: boolean;
|
||||
supportsManualListening: boolean;
|
||||
manualListening?: boolean
|
||||
systemListeningBehavior?: boolean
|
||||
}
|
||||
@@ -46,6 +45,8 @@ export interface ClientStatusData {
|
||||
hasAuthInteraction: boolean;
|
||||
authed: boolean;
|
||||
initialized: boolean;
|
||||
manualListening?: boolean
|
||||
systemListeningBehavior?: boolean
|
||||
}
|
||||
|
||||
export type PlayObjectIncludeTypes = 'album' | 'time' | 'artist' | 'track' | 'timeFromNow' | 'trackId' | 'comment' | 'platform' | 'session';
|
||||
|
||||
Reference in New Issue
Block a user