Adds feature flags, and the ability to do browser playback
This commit is contained in:
@@ -7,6 +7,12 @@ export interface NowPlayingResponse {
|
||||
currentFile: string;
|
||||
}
|
||||
|
||||
export interface Features {
|
||||
video: boolean;
|
||||
screenshare: boolean;
|
||||
browserPlayback: boolean;
|
||||
}
|
||||
|
||||
export interface Metadata {
|
||||
title?: string;
|
||||
description?: string;
|
||||
@@ -57,6 +63,11 @@ export enum ServerEvent {
|
||||
}
|
||||
|
||||
export const API = {
|
||||
async getFeatures(): Promise<Features> {
|
||||
const response = await fetch('/api/features');
|
||||
return response.json();
|
||||
},
|
||||
|
||||
async getPlaylist(): Promise<PlaylistItem[]> {
|
||||
const response = await fetch('/api/playlist');
|
||||
return response.json();
|
||||
|
||||
@@ -4,11 +4,12 @@ import NowPlaying from './NowPlaying';
|
||||
import AddSongPanel from './AddSongPanel';
|
||||
import RenameFavoriteModal from './RenameFavoriteModal';
|
||||
import { TabView, Tab } from './TabView';
|
||||
import { API, getDisplayTitle, PlaylistItem, ServerEvent } from '../api/player';
|
||||
import { API, Features, getDisplayTitle, PlaylistItem, ServerEvent } from '../api/player';
|
||||
import { FaMusic, FaHeart, FaPlus, FaEdit } from 'react-icons/fa';
|
||||
import useWebSocket from 'react-use-websocket';
|
||||
import classNames from 'classnames';
|
||||
import { useScreenShare } from '../hooks/useScreenShare';
|
||||
import AudioPlayer from './AudioPlayer';
|
||||
|
||||
enum Tabs {
|
||||
Playlist = "playlist",
|
||||
@@ -93,6 +94,8 @@ const App: React.FC = () => {
|
||||
const [selectedTab, setSelectedTab] = useState<Tabs>(Tabs.Playlist);
|
||||
const [isRenameModalOpen, setIsRenameModalOpen] = useState(false);
|
||||
const [favoriteToRename, setFavoriteToRename] = useState<PlaylistItem | null>(null);
|
||||
const [audioEnabled, setAudioEnabled] = useState(false);
|
||||
const [features, setFeatures] = useState<Features | null>(null);
|
||||
|
||||
const {
|
||||
isScreenSharing,
|
||||
@@ -124,6 +127,9 @@ const App: React.FC = () => {
|
||||
setIsPlaying(!nowPlaying.isPaused);
|
||||
setVolume(nowPlaying.volume);
|
||||
setIsIdle(nowPlaying.playingItem ? !nowPlaying.playingItem.playing : true);
|
||||
|
||||
const features = await API.getFeatures();
|
||||
setFeatures(features);
|
||||
}, [volumeSettingIsLocked]);
|
||||
|
||||
const handleAddURL = async (url: string) => {
|
||||
@@ -313,6 +319,10 @@ const App: React.FC = () => {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen w-screen bg-black md:py-10">
|
||||
<div className="bg-violet-900 w-full md:max-w-2xl h-full md:max-h-xl md:border md:rounded-2xl flex flex-col">
|
||||
{features?.browserPlayback && (
|
||||
<AudioPlayer isPlaying={isPlaying} enabled={audioEnabled} />
|
||||
)}
|
||||
|
||||
<NowPlaying
|
||||
className="flex flex-row md:rounded-t-2xl"
|
||||
songName={nowPlayingSong || "(Not Playing)"}
|
||||
@@ -330,6 +340,9 @@ const App: React.FC = () => {
|
||||
onVolumeWillChange={() => setVolumeSettingIsLocked(true)}
|
||||
onVolumeDidChange={() => setVolumeSettingIsLocked(false)}
|
||||
isScreenSharingSupported={isScreenSharingSupported}
|
||||
features={features}
|
||||
audioEnabled={audioEnabled}
|
||||
onAudioEnabledChange={setAudioEnabled}
|
||||
/>
|
||||
|
||||
<TabView selectedTab={selectedTab} onTabChange={setSelectedTab}>
|
||||
|
||||
32
frontend/src/components/AudioPlayer.tsx
Normal file
32
frontend/src/components/AudioPlayer.tsx
Normal file
@@ -0,0 +1,32 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
interface AudioPlayerProps {
|
||||
isPlaying: boolean;
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
const AudioPlayer: React.FC<AudioPlayerProps> = ({ isPlaying, enabled }) => {
|
||||
const audioRef = useRef<HTMLAudioElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (enabled && isPlaying) {
|
||||
console.log("Playing audio");
|
||||
audioRef.current?.play().catch((error) => {
|
||||
console.error("Audio playback error:", error);
|
||||
});
|
||||
} else {
|
||||
console.log("Pausing audio");
|
||||
audioRef.current?.pause();
|
||||
}
|
||||
}, [isPlaying, enabled]);
|
||||
|
||||
return (
|
||||
<audio
|
||||
ref={audioRef}
|
||||
src="/stream/audio.m3u8"
|
||||
preload="metadata"
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AudioPlayer;
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { HTMLAttributes } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { FaPlay, FaPause, FaStepForward, FaStepBackward, FaVolumeUp, FaDesktop, FaStop } from 'react-icons/fa';
|
||||
import { Features } from '../api/player';
|
||||
|
||||
interface NowPlayingProps extends HTMLAttributes<HTMLDivElement> {
|
||||
songName: string;
|
||||
@@ -25,6 +26,11 @@ interface NowPlayingProps extends HTMLAttributes<HTMLDivElement> {
|
||||
|
||||
// Sent when the volume has changed
|
||||
onVolumeDidChange: (volume: number) => void;
|
||||
|
||||
features: Features | null;
|
||||
|
||||
audioEnabled: boolean;
|
||||
onAudioEnabledChange: (enabled: boolean) => void;
|
||||
}
|
||||
|
||||
const NowPlaying: React.FC<NowPlayingProps> = (props) => {
|
||||
@@ -80,7 +86,7 @@ const NowPlaying: React.FC<NowPlayingProps> = (props) => {
|
||||
<FaStepForward size={24} />
|
||||
</button>
|
||||
|
||||
{props.isScreenSharingSupported && (
|
||||
{(props.isScreenSharingSupported && props.features?.screenshare) && (
|
||||
<button
|
||||
className={classNames("text-white hover:text-violet-300 transition-colors rounded-full p-2", props.isScreenSharing ? ' bg-violet-800' : '')}
|
||||
onClick={props.onScreenShare}
|
||||
@@ -90,6 +96,20 @@ const NowPlaying: React.FC<NowPlayingProps> = (props) => {
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{props.features?.browserPlayback && (
|
||||
<div>
|
||||
<label className="flex items-center gap-2 text-white text-sm cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={props.audioEnabled}
|
||||
onChange={(e) => props.onAudioEnabledChange(e.target.checked)}
|
||||
className="w-4 h-4 text-violet-600 bg-gray-100 border-gray-300 rounded focus:ring-violet-500 focus:ring-2"
|
||||
/>
|
||||
Enable audio playback in browser
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user