diff --git a/changelog/v0.1.0-beta3.txt b/changelog/v0.1.0-beta3.txt index 54740d0a..79c2257f 100644 --- a/changelog/v0.1.0-beta3.txt +++ b/changelog/v0.1.0-beta3.txt @@ -62,6 +62,8 @@ AUDIO - The music volume slider follows how loud it sounds, so each step changes the level by a similar amount. Your saved volume plays at the same level after the update. - Music loudness is measured the way Android does it, from the perceptual loudness first, and loud songs are never turned down by more than 20 dB. - An optional crossfade, off by default, fades the next song in over 1 to 12 seconds. Consecutive tracks from the same album and repeat-one keep their gapless joins. +- The equalizer now also applies to videos, including the pop-out player, and opens from the video settings menu. Shorts are left as they are. +- Videos only go through audio processing once the equalizer changes the sound, and only after a short silent self-test shows it works. Where it does not, as on some Linux setups, videos keep playing normally and the menu says the equalizer is not available. MACOS - Flow uses the native macOS window controls and titlebar again. Closing the window hides it and keeps playback and downloads running until you quit, and clicking the Dock icon brings it back. diff --git a/src/components/music/eq/EqualizerDialog.tsx b/src/components/music/eq/EqualizerDialog.tsx index f3907530..530393d7 100644 --- a/src/components/music/eq/EqualizerDialog.tsx +++ b/src/components/music/eq/EqualizerDialog.tsx @@ -35,6 +35,11 @@ export function EqualizerDialog() { const setPreview = useEqStore((s) => s.setPreview); const setBypass = useEqStore((s) => s.setBypass); + useEffect(() => { + useEqStore.setState({ editorHosted: true }); + return () => useEqStore.setState({ editorHosted: false }); + }, []); + useEffect(() => { if (!open) return; const onKey = (event: KeyboardEvent) => { diff --git a/src/components/player/FlowPlayerControls.tsx b/src/components/player/FlowPlayerControls.tsx index 8bf76826..eabc1d9f 100644 --- a/src/components/player/FlowPlayerControls.tsx +++ b/src/components/player/FlowPlayerControls.tsx @@ -22,6 +22,7 @@ import { Volume2, VolumeX, Sliders, + SlidersHorizontal, } from "lucide-react"; import { usePlayerStore, type PlaybackRate } from "../../store/usePlayerStore"; import { useSettingsStore, type SponsorBlockCategory } from "../../store/useSettingsStore"; @@ -51,6 +52,9 @@ import { sponsorBlockCategoryLabel } from "../../lib/sponsorBlockCategories"; import { getString } from "../../lib/i18n/index"; import { SleepTimerLabel } from "../sleep/SleepTimerLabel"; import { SleepTimerPanel } from "../sleep/SleepTimerPanel"; +import { useEqActive } from "../../lib/audio/eq/useEqualizer"; +import { videoEqAvailable } from "../../lib/audio/mediaEqEngine"; +import { useEqStore } from "../../store/useEqStore"; import { Slider } from "../ui/Slider"; import { videoCodecLabel } from "../../lib/settings/playerRuntime"; @@ -478,6 +482,10 @@ export const FlowPlayerControls: React.FC = ({ updateHoverPreview(event.clientX, event.currentTarget); }; + const eqActive = useEqActive(); + const eqEditorHosted = useEqStore((s) => s.editorHosted); + const openEqEditor = useEqStore((s) => s.setEditorOpen); + const renderSettingRow = ( label: string, value: React.ReactNode, @@ -952,6 +960,17 @@ export const FlowPlayerControls: React.FC = ({ , () => setSettingsPane("sleep") )} + {eqEditorHosted && + renderSettingRow( + getString("music_equalizer"), + // Read when the menu draws: the self-test only settles once the equalizer is used. + getString(!videoEqAvailable() ? "eq_state_unavailable" : eqActive ? "eq_state_on" : "eq_state_off"), + , + () => { + setSettingsOpen(false); + openEqEditor(true); + } + )} )} diff --git a/src/components/player/Player.tsx b/src/components/player/Player.tsx index 2f44983c..be879332 100644 --- a/src/components/player/Player.tsx +++ b/src/components/player/Player.tsx @@ -28,6 +28,7 @@ import { import { SubtitleOverlay } from "./SubtitleOverlay"; import { SETTINGS } from "../../lib/settings/schema"; import { loudnessFactor } from "../../lib/loudness"; +import { useVideoEq } from "../../lib/audio/useVideoEq"; import { IS_LINUX_RUNTIME } from "../../lib/platform"; import { AUDIO_DRIFT_TOLERANCE_SECONDS, @@ -595,6 +596,8 @@ export const Player: React.FC = ({ !isHlsPlayback && (hasSelectedAlternateAudio || (!!selectedQuality && !selectedQuality.hasAudio)); + useVideoEq(videoRef, audioRef, usesExternalAudio ? selectedAudioTrack?.localUrl ?? null : null); + const isPipMode = videoPlayerMode === "pip"; const isTheaterSurface = isTheaterMode && !isPipMode; const shouldShowControls = controlsVisible || !isPlaying || settingsOpen || isScrubbing; @@ -2510,6 +2513,8 @@ export const Player: React.FC = ({