mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-01 10:23:33 +00:00
fix all imports for new structure
This commit is contained in:
parent
249eaf89f8
commit
930165d006
291 changed files with 2056 additions and 1894 deletions
|
|
@ -1,8 +1,10 @@
|
|||
import { useEffect } from 'react';
|
||||
import { MantineProvider } from '@mantine/core';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import './styles/global.scss';
|
||||
import { useIsDark, useReconnect } from '/@/remote/store';
|
||||
|
||||
import { Shell } from '/@/remote/components/shell';
|
||||
import { useIsDark, useReconnect } from '/@/remote/store';
|
||||
|
||||
export const App = () => {
|
||||
const isDark = useIsDark();
|
||||
|
|
@ -14,8 +16,6 @@ export const App = () => {
|
|||
|
||||
return (
|
||||
<MantineProvider
|
||||
withGlobalStyles
|
||||
withNormalizeCSS
|
||||
theme={{
|
||||
colorScheme: isDark ? 'dark' : 'light',
|
||||
components: {
|
||||
|
|
@ -77,6 +77,8 @@ export const App = () => {
|
|||
xs: '0rem',
|
||||
},
|
||||
}}
|
||||
withGlobalStyles
|
||||
withNormalizeCSS
|
||||
>
|
||||
<Shell />
|
||||
</MantineProvider>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { CiImageOff, CiImageOn } from 'react-icons/ci';
|
||||
|
||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||
import { useShowImage, useToggleShowImage } from '/@/remote/store';
|
||||
|
||||
|
|
@ -9,10 +10,10 @@ export const ImageButton = () => {
|
|||
return (
|
||||
<RemoteButton
|
||||
mr={5}
|
||||
onClick={() => toggleImage()}
|
||||
size="xl"
|
||||
tooltip={showImage ? 'Hide Image' : 'Show Image'}
|
||||
variant="default"
|
||||
onClick={() => toggleImage()}
|
||||
>
|
||||
{showImage ? <CiImageOff size={30} /> : <CiImageOn size={30} />}
|
||||
</RemoteButton>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { RiRestartLine } from 'react-icons/ri';
|
||||
|
||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||
import { useConnected, useReconnect } from '/@/remote/store';
|
||||
import { RiRestartLine } from 'react-icons/ri';
|
||||
|
||||
export const ReconnectButton = () => {
|
||||
const connected = useConnected();
|
||||
|
|
@ -10,10 +11,10 @@ export const ReconnectButton = () => {
|
|||
<RemoteButton
|
||||
$active={!connected}
|
||||
mr={5}
|
||||
onClick={() => reconnect()}
|
||||
size="xl"
|
||||
tooltip={connected ? 'Reconnect' : 'Not connected. Reconnect.'}
|
||||
variant="default"
|
||||
onClick={() => reconnect()}
|
||||
>
|
||||
<RiRestartLine size={30} />
|
||||
</RemoteButton>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import { MouseEvent, ReactNode, Ref, forwardRef } from 'react';
|
||||
import { Button, type ButtonProps as MantineButtonProps } from '@mantine/core';
|
||||
import { Tooltip } from '/@/renderer/components/tooltip';
|
||||
import { Button, type ButtonProps as MantineButtonProps, Tooltip } from '@mantine/core';
|
||||
import { forwardRef, MouseEvent, ReactNode, Ref } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
export interface ButtonProps extends StyledButtonProps {
|
||||
tooltip: string;
|
||||
}
|
||||
|
||||
interface StyledButtonProps extends MantineButtonProps {
|
||||
$active?: boolean;
|
||||
children: ReactNode;
|
||||
|
|
@ -11,10 +14,6 @@ interface StyledButtonProps extends MantineButtonProps {
|
|||
ref: Ref<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
export interface ButtonProps extends StyledButtonProps {
|
||||
tooltip: string;
|
||||
}
|
||||
|
||||
const StyledButton = styled(Button)<StyledButtonProps>`
|
||||
svg {
|
||||
display: flex;
|
||||
|
|
@ -35,12 +34,12 @@ const StyledButton = styled(Button)<StyledButtonProps>`
|
|||
}
|
||||
`;
|
||||
|
||||
export const RemoteButton = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ children, tooltip, ...props }: ButtonProps, ref) => {
|
||||
export const RemoteButton = forwardRef<HTMLButtonElement, any>(
|
||||
({ children, tooltip, ...props }: any, ref) => {
|
||||
return (
|
||||
<Tooltip
|
||||
withinPortal
|
||||
label={tooltip}
|
||||
withinPortal
|
||||
>
|
||||
<StyledButton
|
||||
{...props}
|
||||
|
|
@ -52,9 +51,3 @@ export const RemoteButton = forwardRef<HTMLButtonElement, ButtonProps>(
|
|||
);
|
||||
},
|
||||
);
|
||||
|
||||
RemoteButton.defaultProps = {
|
||||
$active: false,
|
||||
onClick: undefined,
|
||||
onMouseDown: undefined,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { useIsDark, useToggleDark } from '/@/remote/store';
|
||||
import { RiMoonLine, RiSunLine } from 'react-icons/ri';
|
||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||
import { AppTheme } from '/@/renderer/themes/types';
|
||||
import { useEffect } from 'react';
|
||||
import { RiMoonLine, RiSunLine } from 'react-icons/ri';
|
||||
|
||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||
import { useIsDark, useToggleDark } from '/@/remote/store';
|
||||
import { AppTheme } from '/@/shared/types/domain-types';
|
||||
|
||||
export const ThemeButton = () => {
|
||||
const isDark = useIsDark();
|
||||
|
|
@ -16,10 +17,10 @@ export const ThemeButton = () => {
|
|||
return (
|
||||
<RemoteButton
|
||||
mr={5}
|
||||
onClick={() => toggleDark()}
|
||||
size="xl"
|
||||
tooltip="Toggle Theme"
|
||||
variant="default"
|
||||
onClick={() => toggleDark()}
|
||||
>
|
||||
{isDark ? <RiSunLine size={30} /> : <RiMoonLine size={30} />}
|
||||
</RemoteButton>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import { useCallback } from 'react';
|
||||
import { Group, Image, Text, Title } from '@mantine/core';
|
||||
import { useInfo, useSend, useShowImage } from '/@/remote/store';
|
||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||
import { Group, Image, Rating, Text, Title, Tooltip } from '@mantine/core';
|
||||
import formatDuration from 'format-duration';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { useCallback } from 'react';
|
||||
import {
|
||||
RiHeartLine,
|
||||
RiPauseFill,
|
||||
|
|
@ -15,10 +13,11 @@ import {
|
|||
RiSkipForwardFill,
|
||||
RiVolumeUpFill,
|
||||
} from 'react-icons/ri';
|
||||
import { PlayerRepeat, PlayerStatus } from '/@/renderer/types';
|
||||
|
||||
import { RemoteButton } from '/@/remote/components/buttons/remote-button';
|
||||
import { WrapperSlider } from '/@/remote/components/wrapped-slider';
|
||||
import { Tooltip } from '/@/renderer/components/tooltip';
|
||||
import { Rating } from '/@/renderer/components/rating';
|
||||
import { useInfo, useSend, useShowImage } from '/@/remote/store';
|
||||
import { PlayerRepeat, PlayerStatus } from '/@/shared/types/types';
|
||||
|
||||
export const RemoteContainer = () => {
|
||||
const { position, repeat, shuffle, song, status, volume } = useInfo();
|
||||
|
|
@ -62,16 +61,14 @@ export const RemoteContainer = () => {
|
|||
>
|
||||
<RemoteButton
|
||||
disabled={!id}
|
||||
onClick={() => send({ event: 'previous' })}
|
||||
tooltip="Previous track"
|
||||
variant="default"
|
||||
onClick={() => send({ event: 'previous' })}
|
||||
>
|
||||
<RiSkipBackFill size={25} />
|
||||
</RemoteButton>
|
||||
<RemoteButton
|
||||
disabled={!id}
|
||||
tooltip={id && status === PlayerStatus.PLAYING ? 'Pause' : 'Play'}
|
||||
variant="default"
|
||||
onClick={() => {
|
||||
if (status === PlayerStatus.PLAYING) {
|
||||
send({ event: 'pause' });
|
||||
|
|
@ -79,6 +76,8 @@ export const RemoteContainer = () => {
|
|||
send({ event: 'play' });
|
||||
}
|
||||
}}
|
||||
tooltip={id && status === PlayerStatus.PLAYING ? 'Pause' : 'Play'}
|
||||
variant="default"
|
||||
>
|
||||
{id && status === PlayerStatus.PLAYING ? (
|
||||
<RiPauseFill size={25} />
|
||||
|
|
@ -88,9 +87,9 @@ export const RemoteContainer = () => {
|
|||
</RemoteButton>
|
||||
<RemoteButton
|
||||
disabled={!id}
|
||||
onClick={() => send({ event: 'next' })}
|
||||
tooltip="Next track"
|
||||
variant="default"
|
||||
onClick={() => send({ event: 'next' })}
|
||||
>
|
||||
<RiSkipForwardFill size={25} />
|
||||
</RemoteButton>
|
||||
|
|
@ -101,14 +100,15 @@ export const RemoteContainer = () => {
|
|||
>
|
||||
<RemoteButton
|
||||
$active={shuffle || false}
|
||||
onClick={() => send({ event: 'shuffle' })}
|
||||
tooltip={shuffle ? 'Shuffle tracks' : 'Shuffle disabled'}
|
||||
variant="default"
|
||||
onClick={() => send({ event: 'shuffle' })}
|
||||
>
|
||||
<RiShuffleFill size={25} />
|
||||
</RemoteButton>
|
||||
<RemoteButton
|
||||
$active={repeat !== undefined && repeat !== PlayerRepeat.NONE}
|
||||
onClick={() => send({ event: 'repeat' })}
|
||||
tooltip={`Repeat ${
|
||||
repeat === PlayerRepeat.ONE
|
||||
? 'One'
|
||||
|
|
@ -117,7 +117,6 @@ export const RemoteContainer = () => {
|
|||
: 'none'
|
||||
}`}
|
||||
variant="default"
|
||||
onClick={() => send({ event: 'repeat' })}
|
||||
>
|
||||
{repeat === undefined || repeat === PlayerRepeat.ONE ? (
|
||||
<RiRepeatOneLine size={25} />
|
||||
|
|
@ -128,13 +127,13 @@ export const RemoteContainer = () => {
|
|||
<RemoteButton
|
||||
$active={song?.userFavorite}
|
||||
disabled={!id}
|
||||
tooltip={song?.userFavorite ? 'Unfavorite' : 'Favorite'}
|
||||
variant="default"
|
||||
onClick={() => {
|
||||
if (!id) return;
|
||||
|
||||
send({ event: 'favorite', favorite: !song.userFavorite, id });
|
||||
}}
|
||||
tooltip={song?.userFavorite ? 'Unfavorite' : 'Favorite'}
|
||||
variant="default"
|
||||
>
|
||||
<RiHeartLine size={25} />
|
||||
</RemoteButton>
|
||||
|
|
@ -145,10 +144,10 @@ export const RemoteContainer = () => {
|
|||
openDelay={1000}
|
||||
>
|
||||
<Rating
|
||||
sx={{ margin: 'auto' }}
|
||||
value={song.userRating ?? 0}
|
||||
onChange={debouncedSetRating}
|
||||
onDoubleClick={() => debouncedSetRating(0)}
|
||||
sx={{ margin: 'auto' }}
|
||||
value={song.userRating ?? 0}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
@ -159,14 +158,15 @@ export const RemoteContainer = () => {
|
|||
label={(value) => formatDuration(value * 1e3)}
|
||||
leftLabel={formatDuration(position * 1e3)}
|
||||
max={song.duration / 1e3}
|
||||
onChangeEnd={(e) => send({ event: 'position', position: e })}
|
||||
rightLabel={formatDuration(song.duration)}
|
||||
value={position}
|
||||
onChangeEnd={(e) => send({ event: 'position', position: e })}
|
||||
/>
|
||||
)}
|
||||
<WrapperSlider
|
||||
leftLabel={<RiVolumeUpFill size={20} />}
|
||||
max={100}
|
||||
onChangeEnd={(e) => send({ event: 'volume', volume: e })}
|
||||
rightLabel={
|
||||
<Text
|
||||
size="xs"
|
||||
|
|
@ -176,12 +176,11 @@ export const RemoteContainer = () => {
|
|||
</Text>
|
||||
}
|
||||
value={volume ?? 0}
|
||||
onChangeEnd={(e) => send({ event: 'volume', volume: e })}
|
||||
/>
|
||||
{showImage && (
|
||||
<Image
|
||||
src={song?.imageUrl?.replaceAll(/&(size|width|height=\d+)/g, '')}
|
||||
onError={() => send({ event: 'proxy' })}
|
||||
src={song?.imageUrl?.replaceAll(/&(size|width|height=\d+)/g, '')}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ import {
|
|||
Skeleton,
|
||||
Title,
|
||||
} from '@mantine/core';
|
||||
import { ThemeButton } from '/@/remote/components/buttons/theme-button';
|
||||
|
||||
import { ImageButton } from '/@/remote/components/buttons/image-button';
|
||||
import { RemoteContainer } from '/@/remote/components/remote-container';
|
||||
import { ReconnectButton } from '/@/remote/components/buttons/reconnect-button';
|
||||
import { ThemeButton } from '/@/remote/components/buttons/theme-button';
|
||||
import { RemoteContainer } from '/@/remote/components/remote-container';
|
||||
import { useConnected } from '/@/remote/store';
|
||||
|
||||
export const Shell = () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { useState, ReactNode } from 'react';
|
||||
import { SliderProps } from '@mantine/core';
|
||||
import { rem, Slider, SliderProps } from '@mantine/core';
|
||||
import { ReactNode, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { PlayerbarSlider } from '/@/renderer/features/player/components/playerbar-slider';
|
||||
|
||||
const SliderContainer = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -25,6 +24,54 @@ const SliderWrapper = styled.div`
|
|||
height: 100%;
|
||||
`;
|
||||
|
||||
const PlayerbarSlider = ({ ...props }: SliderProps) => {
|
||||
return (
|
||||
<Slider
|
||||
styles={{
|
||||
bar: {
|
||||
backgroundColor: 'var(--playerbar-slider-track-progress-bg)',
|
||||
transition: 'background-color 0.2s ease',
|
||||
},
|
||||
label: {
|
||||
backgroundColor: 'var(--tooltip-bg)',
|
||||
color: 'var(--tooltip-fg)',
|
||||
fontSize: '1.1rem',
|
||||
fontWeight: 600,
|
||||
padding: '0 1rem',
|
||||
},
|
||||
root: {
|
||||
'&:hover': {
|
||||
'& .mantine-Slider-bar': {
|
||||
backgroundColor: 'var(--primary-color)',
|
||||
},
|
||||
'& .mantine-Slider-thumb': {
|
||||
opacity: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
thumb: {
|
||||
backgroundColor: 'var(--slider-thumb-bg)',
|
||||
borderColor: 'var(--primary-color)',
|
||||
borderWidth: rem(1),
|
||||
height: '1rem',
|
||||
opacity: 0,
|
||||
width: '1rem',
|
||||
},
|
||||
track: {
|
||||
'&::before': {
|
||||
backgroundColor: 'var(--playerbar-slider-track-bg)',
|
||||
right: 'calc(0.1rem * -1)',
|
||||
},
|
||||
},
|
||||
}}
|
||||
{...props}
|
||||
onClick={(e) => {
|
||||
e?.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export interface WrappedProps extends Omit<SliderProps, 'onChangeEnd'> {
|
||||
leftLabel?: ReactNode;
|
||||
onChangeEnd: (value: number) => void;
|
||||
|
|
@ -43,9 +90,6 @@ export const WrapperSlider = ({ leftLabel, rightLabel, value, ...props }: Wrappe
|
|||
<PlayerbarSlider
|
||||
{...props}
|
||||
min={0}
|
||||
size={6}
|
||||
value={!isSeeking ? (value ?? 0) : seek}
|
||||
w="100%"
|
||||
onChange={(e) => {
|
||||
setIsSeeking(true);
|
||||
setSeek(e);
|
||||
|
|
@ -54,6 +98,9 @@ export const WrapperSlider = ({ leftLabel, rightLabel, value, ...props }: Wrappe
|
|||
props.onChangeEnd(e);
|
||||
setIsSeeking(false);
|
||||
}}
|
||||
size={6}
|
||||
value={!isSeeking ? (value ?? 0) : seek}
|
||||
w="100%"
|
||||
/>
|
||||
</SliderWrapper>
|
||||
{rightLabel && <SliderValueWrapper $position="right">{rightLabel}</SliderValueWrapper>}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Notifications } from '@mantine/notifications';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
|
||||
import { App } from '/@/remote/app';
|
||||
|
||||
const container = document.getElementById('root')! as HTMLElement;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
/// <reference lib="WebWorker" />
|
||||
|
||||
export type {};
|
||||
// eslint-disable-next-line no-undef
|
||||
|
||||
declare const self: ServiceWorkerGlobalScope;
|
||||
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
const url = new URL(location.toString());
|
||||
const version = url.searchParams.get('version');
|
||||
const prod = url.searchParams.get('prod') === 'true';
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
import { hideNotification, showNotification } from '@mantine/notifications';
|
||||
import type { NotificationProps as MantineNotificationProps } from '@mantine/notifications';
|
||||
|
||||
import { hideNotification, showNotification } from '@mantine/notifications';
|
||||
import merge from 'lodash/merge';
|
||||
import { create } from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
import type { ClientEvent, ServerEvent, SongUpdateSocket } from '/@/remote/types';
|
||||
|
||||
interface StatefulWebSocket extends WebSocket {
|
||||
natural: boolean;
|
||||
import { ClientEvent, ServerEvent, SongUpdateSocket } from '/@/shared/types/remote-types';
|
||||
|
||||
export interface SettingsSlice extends SettingsState {
|
||||
actions: {
|
||||
reconnect: () => void;
|
||||
send: (data: ClientEvent) => void;
|
||||
toggleIsDark: () => void;
|
||||
toggleShowImage: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
interface SettingsState {
|
||||
|
|
@ -18,13 +25,8 @@ interface SettingsState {
|
|||
socket?: StatefulWebSocket;
|
||||
}
|
||||
|
||||
export interface SettingsSlice extends SettingsState {
|
||||
actions: {
|
||||
reconnect: () => void;
|
||||
send: (data: ClientEvent) => void;
|
||||
toggleIsDark: () => void;
|
||||
toggleShowImage: () => void;
|
||||
};
|
||||
interface StatefulWebSocket extends WebSocket {
|
||||
natural: boolean;
|
||||
}
|
||||
|
||||
const initialState: SettingsState = {
|
||||
|
|
@ -106,19 +108,18 @@ export const useRemoteStore = create<SettingsSlice>()(
|
|||
const credentials = await fetch('/credentials');
|
||||
authHeader = await credentials.text();
|
||||
} catch (error) {
|
||||
console.error('Failed to get credentials');
|
||||
console.error('Failed to get credentials', error);
|
||||
}
|
||||
|
||||
set((state) => {
|
||||
const socket = new WebSocket(
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.href.replace('http', 'ws'),
|
||||
) as StatefulWebSocket;
|
||||
|
||||
socket.natural = false;
|
||||
|
||||
socket.addEventListener('message', (message) => {
|
||||
const { event, data } = JSON.parse(message.data) as ServerEvent;
|
||||
const { data, event } = JSON.parse(message.data) as ServerEvent;
|
||||
|
||||
switch (event) {
|
||||
case 'error': {
|
||||
|
|
@ -207,7 +208,6 @@ export const useRemoteStore = create<SettingsSlice>()(
|
|||
|
||||
socket.addEventListener('close', (reason) => {
|
||||
if (reason.code === 4002 || reason.code === 4003) {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
location.reload();
|
||||
} else if (reason.code === 4000) {
|
||||
toast.warn({
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
import type { QueueSong } from '/@/renderer/api/types';
|
||||
import type { PlayerRepeat, PlayerStatus, SongState } from '/@/renderer/types';
|
||||
|
||||
export interface SongUpdateSocket extends Omit<SongState, 'song'> {
|
||||
position?: number;
|
||||
song?: QueueSong | null;
|
||||
}
|
||||
|
||||
export interface ServerError {
|
||||
data: string;
|
||||
event: 'error';
|
||||
}
|
||||
|
||||
export interface ServerFavorite {
|
||||
data: { favorite: boolean; id: string };
|
||||
event: 'favorite';
|
||||
}
|
||||
|
||||
export interface ServerPlayStatus {
|
||||
data: PlayerStatus;
|
||||
event: 'playback';
|
||||
}
|
||||
|
||||
export interface ServerPosition {
|
||||
data: number;
|
||||
event: 'position';
|
||||
}
|
||||
export interface ServerProxy {
|
||||
data: string;
|
||||
event: 'proxy';
|
||||
}
|
||||
|
||||
export interface ServerRating {
|
||||
data: { id: string; rating: number };
|
||||
event: 'rating';
|
||||
}
|
||||
|
||||
export interface ServerRepeat {
|
||||
data: PlayerRepeat;
|
||||
event: 'repeat';
|
||||
}
|
||||
|
||||
export interface ServerShuffle {
|
||||
data: boolean;
|
||||
event: 'shuffle';
|
||||
}
|
||||
|
||||
export interface ServerSong {
|
||||
data: QueueSong | null;
|
||||
event: 'song';
|
||||
}
|
||||
|
||||
export interface ServerState {
|
||||
data: SongState;
|
||||
event: 'state';
|
||||
}
|
||||
|
||||
export interface ServerVolume {
|
||||
data: number;
|
||||
event: 'volume';
|
||||
}
|
||||
|
||||
export type ServerEvent =
|
||||
| ServerError
|
||||
| ServerFavorite
|
||||
| ServerPlayStatus
|
||||
| ServerPosition
|
||||
| ServerRating
|
||||
| ServerRepeat
|
||||
| ServerShuffle
|
||||
| ServerSong
|
||||
| ServerState
|
||||
| ServerProxy
|
||||
| ServerVolume;
|
||||
|
||||
export interface ClientSimpleEvent {
|
||||
event: 'next' | 'pause' | 'play' | 'previous' | 'proxy' | 'repeat' | 'shuffle';
|
||||
}
|
||||
|
||||
export interface ClientFavorite {
|
||||
event: 'favorite';
|
||||
favorite: boolean;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ClientRating {
|
||||
event: 'rating';
|
||||
id: string;
|
||||
rating: number;
|
||||
}
|
||||
|
||||
export interface ClientVolume {
|
||||
event: 'volume';
|
||||
volume: number;
|
||||
}
|
||||
|
||||
export interface ClientAuth {
|
||||
event: 'authenticate';
|
||||
header: string;
|
||||
}
|
||||
|
||||
export interface ClientPosition {
|
||||
event: 'position';
|
||||
position: number;
|
||||
}
|
||||
|
||||
export type ClientEvent =
|
||||
| ClientAuth
|
||||
| ClientPosition
|
||||
| ClientSimpleEvent
|
||||
| ClientFavorite
|
||||
| ClientRating
|
||||
| ClientVolume;
|
||||
Loading…
Add table
Add a link
Reference in a new issue