mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-10 04:30:25 +02:00
fix missing remote event handlers (#1344)
This commit is contained in:
+170
-5
@@ -3,6 +3,8 @@ import { devtools, persist } from 'zustand/middleware';
|
|||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
import { createWithEqualityFn } from 'zustand/traditional';
|
import { createWithEqualityFn } from 'zustand/traditional';
|
||||||
|
|
||||||
|
import { LogCategory, logFn } from '/@/renderer/utils/logger';
|
||||||
|
import { logMsg } from '/@/renderer/utils/logger-message';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { ClientEvent, ServerEvent, SongUpdateSocket } from '/@/shared/types/remote-types';
|
import { ClientEvent, ServerEvent, SongUpdateSocket } from '/@/shared/types/remote-types';
|
||||||
|
|
||||||
@@ -40,6 +42,9 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
immer((set, get) => ({
|
immer((set, get) => ({
|
||||||
actions: {
|
actions: {
|
||||||
reconnect: async () => {
|
reconnect: async () => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].reconnectInitiated, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
});
|
||||||
const existing = get().socket;
|
const existing = get().socket;
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
@@ -47,6 +52,10 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
existing.readyState === WebSocket.OPEN ||
|
existing.readyState === WebSocket.OPEN ||
|
||||||
existing.readyState === WebSocket.CONNECTING
|
existing.readyState === WebSocket.CONNECTING
|
||||||
) {
|
) {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].closingExistingSocket, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { readyState: existing.readyState },
|
||||||
|
});
|
||||||
existing.natural = true;
|
existing.natural = true;
|
||||||
existing.close(4001);
|
existing.close(4001);
|
||||||
}
|
}
|
||||||
@@ -55,28 +64,63 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
let authHeader: string | undefined;
|
let authHeader: string | undefined;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].fetchingCredentials, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
});
|
||||||
const credentials = await fetch('/credentials');
|
const credentials = await fetch('/credentials');
|
||||||
authHeader = await credentials.text();
|
authHeader = await credentials.text();
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].credentialsFetched, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { hasAuthHeader: !!authHeader },
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to get credentials', error);
|
logFn.error(logMsg[LogCategory.REMOTE].failedToGetCredentials, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { error },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const socket = new WebSocket(
|
const wsUrl = location.href.replace('http', 'ws');
|
||||||
location.href.replace('http', 'ws'),
|
logFn.debug(logMsg[LogCategory.REMOTE].creatingWebSocket, {
|
||||||
) as StatefulWebSocket;
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { url: wsUrl },
|
||||||
|
});
|
||||||
|
const socket = new WebSocket(wsUrl) as StatefulWebSocket;
|
||||||
|
|
||||||
socket.natural = false;
|
socket.natural = false;
|
||||||
|
|
||||||
socket.addEventListener('message', (message) => {
|
socket.addEventListener('message', (message) => {
|
||||||
const { data, event } = JSON.parse(message.data) as ServerEvent;
|
const { data, event } = JSON.parse(message.data) as ServerEvent;
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].webSocketMessageReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { data, event },
|
||||||
|
});
|
||||||
|
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case 'error': {
|
case 'error': {
|
||||||
|
logFn.error(
|
||||||
|
logMsg[LogCategory.REMOTE].webSocketErrorEvent,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { data },
|
||||||
|
},
|
||||||
|
);
|
||||||
toast.error({ message: data, title: 'Socket error' });
|
toast.error({ message: data, title: 'Socket error' });
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'favorite': {
|
case 'favorite': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].favoriteEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
favorite: data.favorite,
|
||||||
|
id: data.id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (state.info.song?.id === data.id) {
|
if (state.info.song?.id === data.id) {
|
||||||
state.info.song.userFavorite = data.favorite;
|
state.info.song.userFavorite = data.favorite;
|
||||||
@@ -85,18 +129,39 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'playback': {
|
case 'playback': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].playbackEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { status: data },
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info.status = data;
|
state.info.status = data;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'position': {
|
case 'position': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].positionEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { position: data },
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info.position = data;
|
state.info.position = data;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'proxy': {
|
case 'proxy': {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].proxyEventReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
dataLength: data?.length,
|
||||||
|
hasData: !!data,
|
||||||
|
},
|
||||||
|
});
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (state.info.song) {
|
if (state.info.song) {
|
||||||
state.info.song.imageUrl = `data:image/jpeg;base64,${data}`;
|
state.info.song.imageUrl = `data:image/jpeg;base64,${data}`;
|
||||||
@@ -105,6 +170,16 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'rating': {
|
case 'rating': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].ratingEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
id: data.id,
|
||||||
|
rating: data.rating,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
if (state.info.song?.id === data.id) {
|
if (state.info.song?.id === data.id) {
|
||||||
state.info.song.userRating = data.rating;
|
state.info.song.userRating = data.rating;
|
||||||
@@ -113,30 +188,68 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'repeat': {
|
case 'repeat': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].repeatEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { repeat: data },
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info.repeat = data;
|
state.info.repeat = data;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'shuffle': {
|
case 'shuffle': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].shuffleEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { shuffle: data },
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info.shuffle = data;
|
state.info.shuffle = data;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'song': {
|
case 'song': {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].songEventReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
artistName: data?.artistName,
|
||||||
|
id: data?.id,
|
||||||
|
name: data?.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info.song = data;
|
state.info.song = data;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'state': {
|
case 'state': {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].stateEventReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
hasSong: !!data.song,
|
||||||
|
position: data.position,
|
||||||
|
status: data.status,
|
||||||
|
volume: data.volume,
|
||||||
|
},
|
||||||
|
});
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info = data;
|
state.info = data;
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'volume': {
|
case 'volume': {
|
||||||
|
logFn.debug(
|
||||||
|
logMsg[LogCategory.REMOTE].volumeEventReceived,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { volume: data },
|
||||||
|
},
|
||||||
|
);
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.info.volume = data;
|
state.info.volume = data;
|
||||||
});
|
});
|
||||||
@@ -145,7 +258,17 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.addEventListener('open', () => {
|
socket.addEventListener('open', () => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].webSocketOpened, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
hasAuthHeader: !!authHeader,
|
||||||
|
readyState: socket.readyState,
|
||||||
|
},
|
||||||
|
});
|
||||||
if (authHeader) {
|
if (authHeader) {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].sendingAuthentication, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
});
|
||||||
socket.send(
|
socket.send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
event: 'authenticate',
|
event: 'authenticate',
|
||||||
@@ -157,14 +280,40 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
});
|
});
|
||||||
|
|
||||||
socket.addEventListener('close', (reason) => {
|
socket.addEventListener('close', (reason) => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].webSocketClosed, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
code: reason.code,
|
||||||
|
natural: socket.natural,
|
||||||
|
reason: reason.reason,
|
||||||
|
wasClean: reason.wasClean,
|
||||||
|
},
|
||||||
|
});
|
||||||
if (reason.code === 4002 || reason.code === 4003) {
|
if (reason.code === 4002 || reason.code === 4003) {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].reloadingPage, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { code: reason.code },
|
||||||
|
});
|
||||||
location.reload();
|
location.reload();
|
||||||
} else if (reason.code === 4000) {
|
} else if (reason.code === 4000) {
|
||||||
|
logFn.warn(logMsg[LogCategory.REMOTE].serverIsDown, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
});
|
||||||
toast.warn({
|
toast.warn({
|
||||||
message: 'Feishin remote server is down',
|
message: 'Feishin remote server is down',
|
||||||
title: 'Connection closed',
|
title: 'Connection closed',
|
||||||
});
|
});
|
||||||
} else if (reason.code !== 4001 && !socket.natural) {
|
} else if (reason.code !== 4001 && !socket.natural) {
|
||||||
|
logFn.error(
|
||||||
|
logMsg[LogCategory.REMOTE].socketClosedUnexpectedly,
|
||||||
|
{
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
code: reason.code,
|
||||||
|
reason: reason.reason,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
toast.error({
|
toast.error({
|
||||||
message: 'Socket closed for unexpected reason',
|
message: 'Socket closed for unexpected reason',
|
||||||
title: 'Connection closed',
|
title: 'Connection closed',
|
||||||
@@ -180,7 +329,23 @@ export const useRemoteStore = createWithEqualityFn<SettingsSlice>()(
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
send: (data: ClientEvent) => {
|
send: (data: ClientEvent) => {
|
||||||
get().socket?.send(JSON.stringify(data));
|
const socket = get().socket;
|
||||||
|
if (socket) {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].sendingEventToServer, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
data: data,
|
||||||
|
event: data.event,
|
||||||
|
readyState: socket.readyState,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
socket.send(JSON.stringify(data));
|
||||||
|
} else {
|
||||||
|
logFn.warn(logMsg[LogCategory.REMOTE].cannotSendEvent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { event: data.event },
|
||||||
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
toggleIsDark: () => {
|
toggleIsDark: () => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import isElectron from 'is-electron';
|
import isElectron from 'is-electron';
|
||||||
import { useEffect } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
|
import { usePlayerEvents } from '/@/renderer/features/player/audio-player/hooks/use-player-events';
|
||||||
import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
import { useCreateFavorite } from '/@/renderer/features/shared/mutations/create-favorite-mutation';
|
||||||
import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
import { useDeleteFavorite } from '/@/renderer/features/shared/mutations/delete-favorite-mutation';
|
||||||
import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
import { useSetRating } from '/@/renderer/features/shared/mutations/set-rating-mutation';
|
||||||
import { usePlayerActions, useRemoteSettings } from '/@/renderer/store';
|
import { usePlayerActions, usePlayerStore, useRemoteSettings } from '/@/renderer/store';
|
||||||
|
import { LogCategory, logFn } from '/@/renderer/utils/logger';
|
||||||
|
import { logMsg } from '/@/renderer/utils/logger-message';
|
||||||
import { toast } from '/@/shared/components/toast/toast';
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { LibraryItem } from '/@/shared/types/domain-types';
|
import { LibraryItem } from '/@/shared/types/domain-types';
|
||||||
import { PlayerShuffle } from '/@/shared/types/types';
|
import { PlayerShuffle } from '/@/shared/types/types';
|
||||||
@@ -14,19 +16,31 @@ const remote = isElectron() ? window.api.remote : null;
|
|||||||
const ipc = isElectron() ? window.api.ipc : null;
|
const ipc = isElectron() ? window.api.ipc : null;
|
||||||
|
|
||||||
export const useRemote = () => {
|
export const useRemote = () => {
|
||||||
const { mediaSkipForward, setTimestamp, setVolume } = usePlayerActions();
|
const { mediaSkipForward, setVolume } = usePlayerActions();
|
||||||
|
const player = usePlayerStore();
|
||||||
|
|
||||||
const remoteSettings = useRemoteSettings();
|
const remoteSettings = useRemoteSettings();
|
||||||
const updateRatingMutation = useSetRating({});
|
const updateRatingMutation = useSetRating({});
|
||||||
const addToFavoritesMutation = useCreateFavorite({});
|
const addToFavoritesMutation = useCreateFavorite({});
|
||||||
const removeFromFavoritesMutation = useDeleteFavorite({});
|
const removeFromFavoritesMutation = useDeleteFavorite({});
|
||||||
|
|
||||||
|
const isRemoteEnabled = remoteSettings.enabled;
|
||||||
|
|
||||||
// Initialize the remote
|
// Initialize the remote
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].initializingRemoteSettings, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
enabled: remoteSettings.enabled,
|
||||||
|
port: remoteSettings.port,
|
||||||
|
username: remoteSettings.username,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
remote
|
remote
|
||||||
?.updateSetting(
|
?.updateSetting(
|
||||||
remoteSettings.enabled,
|
remoteSettings.enabled,
|
||||||
@@ -35,6 +49,10 @@ export const useRemote = () => {
|
|||||||
remoteSettings.password,
|
remoteSettings.password,
|
||||||
)
|
)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
logFn.error(logMsg[LogCategory.REMOTE].failedToEnableRemote, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { error },
|
||||||
|
});
|
||||||
toast.warn({ message: error, title: 'Failed to enable remote' });
|
toast.warn({ message: error, title: 'Failed to enable remote' });
|
||||||
});
|
});
|
||||||
// We only want to fire this once
|
// We only want to fire this once
|
||||||
@@ -42,21 +60,33 @@ export const useRemote = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
remote.requestPosition((_e: unknown, data: { position: number }) => {
|
remote.requestPosition((_e: unknown, data: { position: number }) => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].requestPositionReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { position: data.position },
|
||||||
|
});
|
||||||
const newTime = data.position;
|
const newTime = data.position;
|
||||||
setTimestamp(newTime);
|
player.mediaSeekToTimestamp(newTime);
|
||||||
});
|
});
|
||||||
|
|
||||||
remote.requestSeek((_e: unknown, data: { offset: number }) => {
|
remote.requestSeek((_e: unknown, data: { offset: number }) => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].requestSeekReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { offset: data.offset },
|
||||||
|
});
|
||||||
mediaSkipForward(data.offset);
|
mediaSkipForward(data.offset);
|
||||||
});
|
});
|
||||||
|
|
||||||
remote.requestRating(
|
remote.requestRating(
|
||||||
(_e: unknown, data: { id: string; rating: number; serverId: string }) => {
|
(_e: unknown, data: { id: string; rating: number; serverId: string }) => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].requestRatingReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { id: data.id, rating: data.rating, serverId: data.serverId },
|
||||||
|
});
|
||||||
updateRatingMutation.mutate({
|
updateRatingMutation.mutate({
|
||||||
apiClientProps: { serverId: data.serverId },
|
apiClientProps: { serverId: data.serverId },
|
||||||
query: {
|
query: {
|
||||||
@@ -69,11 +99,19 @@ export const useRemote = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
remote.requestVolume((_e: unknown, data: { volume: number }) => {
|
remote.requestVolume((_e: unknown, data: { volume: number }) => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].requestVolumeReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { volume: data.volume },
|
||||||
|
});
|
||||||
setVolume(data.volume);
|
setVolume(data.volume);
|
||||||
});
|
});
|
||||||
|
|
||||||
remote.requestFavorite(
|
remote.requestFavorite(
|
||||||
(_e: unknown, data: { favorite: boolean; id: string; serverId: string }) => {
|
(_e: unknown, data: { favorite: boolean; id: string; serverId: string }) => {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].requestFavoriteReceived, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { favorite: data.favorite, id: data.id, serverId: data.serverId },
|
||||||
|
});
|
||||||
const mutator = data.favorite
|
const mutator = data.favorite
|
||||||
? addToFavoritesMutation
|
? addToFavoritesMutation
|
||||||
: removeFromFavoritesMutation;
|
: removeFromFavoritesMutation;
|
||||||
@@ -96,63 +134,140 @@ export const useRemote = () => {
|
|||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
addToFavoritesMutation,
|
addToFavoritesMutation,
|
||||||
|
isRemoteEnabled,
|
||||||
mediaSkipForward,
|
mediaSkipForward,
|
||||||
|
player,
|
||||||
removeFromFavoritesMutation,
|
removeFromFavoritesMutation,
|
||||||
setTimestamp,
|
|
||||||
setVolume,
|
setVolume,
|
||||||
updateRatingMutation,
|
updateRatingMutation,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// Send initial song if one is already playing
|
||||||
|
const isInitializedRef = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (isInitializedRef.current || !isRemoteEnabled || !remote) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isInitializedRef.current = true;
|
||||||
|
|
||||||
|
const currentSong = player.getCurrentSong();
|
||||||
|
|
||||||
|
if (currentSong) {
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].sendingInitialSong, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
artistName: currentSong.artistName,
|
||||||
|
id: currentSong.id,
|
||||||
|
name: currentSong.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
remote.updateSong(currentSong);
|
||||||
|
}
|
||||||
|
}, [isRemoteEnabled, player]);
|
||||||
|
|
||||||
usePlayerEvents(
|
usePlayerEvents(
|
||||||
{
|
{
|
||||||
onPlayerProgress: (properties) => {
|
onCurrentSongChange: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updateSongSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
artistName: properties.song?.artistName,
|
||||||
|
id: properties.song?.id,
|
||||||
|
index: properties.index,
|
||||||
|
name: properties.song?.name,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
remote.updateSong(properties.song);
|
||||||
|
},
|
||||||
|
onPlayerProgress: (properties) => {
|
||||||
|
if (!isRemoteEnabled || !remote) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updatePositionSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { timestamp: properties.timestamp },
|
||||||
|
});
|
||||||
remote.updatePosition(properties.timestamp);
|
remote.updatePosition(properties.timestamp);
|
||||||
},
|
},
|
||||||
onPlayerRepeat: (properties) => {
|
onPlayerRepeat: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updateRepeatSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { repeat: properties.repeat },
|
||||||
|
});
|
||||||
remote.updateRepeat(properties.repeat);
|
remote.updateRepeat(properties.repeat);
|
||||||
},
|
},
|
||||||
onPlayerShuffle: (properties) => {
|
onPlayerShuffle: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isShuffleEnabled = properties.shuffle !== PlayerShuffle.NONE;
|
const isShuffleEnabled = properties.shuffle !== PlayerShuffle.NONE;
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updateShuffleSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { isShuffleEnabled, shuffle: properties.shuffle },
|
||||||
|
});
|
||||||
remote.updateShuffle(isShuffleEnabled);
|
remote.updateShuffle(isShuffleEnabled);
|
||||||
},
|
},
|
||||||
onPlayerStatus: (properties) => {
|
onPlayerStatus: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updatePlaybackSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { status: properties.status },
|
||||||
|
});
|
||||||
remote.updatePlayback(properties.status);
|
remote.updatePlayback(properties.status);
|
||||||
},
|
},
|
||||||
onPlayerVolume: (properties) => {
|
onPlayerVolume: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updateVolumeSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: { volume: properties.volume },
|
||||||
|
});
|
||||||
remote.updateVolume(properties.volume);
|
remote.updateVolume(properties.volume);
|
||||||
},
|
},
|
||||||
onUserFavorite: (properties) => {
|
onUserFavorite: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updateFavoriteSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
favorite: properties.favorite,
|
||||||
|
id: properties.id,
|
||||||
|
serverId: properties.serverId,
|
||||||
|
},
|
||||||
|
});
|
||||||
remote.updateFavorite(properties.favorite, properties.serverId, properties.id);
|
remote.updateFavorite(properties.favorite, properties.serverId, properties.id);
|
||||||
},
|
},
|
||||||
onUserRating: (properties) => {
|
onUserRating: (properties) => {
|
||||||
if (!remote) {
|
if (!isRemoteEnabled || !remote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logFn.debug(logMsg[LogCategory.REMOTE].updateRatingSent, {
|
||||||
|
category: LogCategory.REMOTE,
|
||||||
|
meta: {
|
||||||
|
id: properties.id,
|
||||||
|
rating: properties.rating || 0,
|
||||||
|
serverId: properties.serverId,
|
||||||
|
},
|
||||||
|
});
|
||||||
remote.updateRating(properties.rating || 0, properties.serverId, properties.id);
|
remote.updateRating(properties.rating || 0, properties.serverId, properties.id);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -60,6 +60,50 @@ export const logMsg = {
|
|||||||
toggleRepeat: 'Toggle repeat',
|
toggleRepeat: 'Toggle repeat',
|
||||||
toggleShuffle: 'Toggle shuffle',
|
toggleShuffle: 'Toggle shuffle',
|
||||||
},
|
},
|
||||||
|
[LogCategory.REMOTE]: {
|
||||||
|
cannotSendEvent: 'Cannot send event - socket not available',
|
||||||
|
closingExistingSocket: 'Closing existing socket',
|
||||||
|
creatingWebSocket: 'Creating new WebSocket',
|
||||||
|
credentialsFetched: 'Credentials fetched',
|
||||||
|
failedToEnableRemote: 'Failed to enable remote',
|
||||||
|
failedToGetCredentials: 'Failed to get credentials',
|
||||||
|
favoriteEventReceived: 'Favorite event received',
|
||||||
|
fetchingCredentials: 'Fetching credentials',
|
||||||
|
initializingRemoteSettings: 'Initializing remote settings',
|
||||||
|
playbackEventReceived: 'Playback event received',
|
||||||
|
positionEventReceived: 'Position event received',
|
||||||
|
proxyEventReceived: 'Proxy event received (image update)',
|
||||||
|
ratingEventReceived: 'Rating event received',
|
||||||
|
reconnectInitiated: 'Reconnect initiated',
|
||||||
|
reloadingPage: 'Reloading page due to close code',
|
||||||
|
repeatEventReceived: 'Repeat event received',
|
||||||
|
requestFavoriteReceived: 'Request favorite received',
|
||||||
|
requestPositionReceived: 'Request position received',
|
||||||
|
requestRatingReceived: 'Request rating received',
|
||||||
|
requestSeekReceived: 'Request seek received',
|
||||||
|
requestVolumeReceived: 'Request volume received',
|
||||||
|
sendingAuthentication: 'Sending authentication',
|
||||||
|
sendingEventToServer: 'Sending event to server',
|
||||||
|
sendingInitialSong: 'Sending initial song',
|
||||||
|
serverIsDown: 'Server is down',
|
||||||
|
shuffleEventReceived: 'Shuffle event received',
|
||||||
|
socketClosedUnexpectedly: 'Socket closed unexpectedly',
|
||||||
|
songEventReceived: 'Song event received',
|
||||||
|
stateEventReceived: 'State event received (full state update)',
|
||||||
|
updateFavoriteSent: 'Update favorite sent',
|
||||||
|
updatePlaybackSent: 'Update playback sent',
|
||||||
|
updatePositionSent: 'Update position sent',
|
||||||
|
updateRatingSent: 'Update rating sent',
|
||||||
|
updateRepeatSent: 'Update repeat sent',
|
||||||
|
updateShuffleSent: 'Update shuffle sent',
|
||||||
|
updateSongSent: 'Update song sent',
|
||||||
|
updateVolumeSent: 'Update volume sent',
|
||||||
|
volumeEventReceived: 'Volume event received',
|
||||||
|
webSocketClosed: 'WebSocket closed',
|
||||||
|
webSocketErrorEvent: 'WebSocket error event',
|
||||||
|
webSocketMessageReceived: 'WebSocket message received',
|
||||||
|
webSocketOpened: 'WebSocket opened',
|
||||||
|
},
|
||||||
[LogCategory.SCROBBLE]: {
|
[LogCategory.SCROBBLE]: {
|
||||||
scrobbledPause: 'Scrobbled a pause event',
|
scrobbledPause: 'Scrobbled a pause event',
|
||||||
scrobbledStart: 'Scrobbled a start event',
|
scrobbledStart: 'Scrobbled a start event',
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export enum LogCategory {
|
|||||||
GENERAL = 'general',
|
GENERAL = 'general',
|
||||||
OTHER = 'other',
|
OTHER = 'other',
|
||||||
PLAYER = 'player',
|
PLAYER = 'player',
|
||||||
|
REMOTE = 'remote',
|
||||||
SCROBBLE = 'scrobble',
|
SCROBBLE = 'scrobble',
|
||||||
SYSTEM = 'system',
|
SYSTEM = 'system',
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user