diff --git a/src/components/settings/ConfigPanels/PlayerConfig.tsx b/src/components/settings/ConfigPanels/PlayerConfig.tsx index 9bf7525d..ec09cbc2 100644 --- a/src/components/settings/ConfigPanels/PlayerConfig.tsx +++ b/src/components/settings/ConfigPanels/PlayerConfig.tsx @@ -74,6 +74,9 @@ const PlayerConfig = () => { const [globalMediaHotkeys, setGlobalMediaHotkeys] = useState( Boolean(settings.getSync('globalMediaHotkeys')) ); + const [systemMediaTransportControls, setSystemMediaTransportControls] = useState( + Boolean(settings.getSync('systemMediaTransportControls')) + ); const [scrobble, setScrobble] = useState(Boolean(settings.getSync('scrobble'))); const [audioDevices, setAudioDevices] = useState(); const audioDevicePickerContainerRef = useRef(null); @@ -220,6 +223,10 @@ const PlayerConfig = () => { setGlobalMediaHotkeys(e); if (e) { ipcRenderer.send('enableGlobalHotkeys'); + + settings.setSync('systemMediaTransportControls', !e); + setSystemMediaTransportControls(!e); + ipcRenderer.send('disableSystemMediaTransportControls'); } else { ipcRenderer.send('disableGlobalHotkeys'); } @@ -227,6 +234,35 @@ const PlayerConfig = () => { /> } /> + + Enable or disable the Windows System Media Transport Controls (play/pause, next, + previous, stop). This will show the Windows Media Popup (Windows 10 only) when pressing + a media key. This feauture will override the Global Media Hotkeys option. + + } + option={ + { + settings.setSync('systemMediaTransportControls', e); + setSystemMediaTransportControls(e); + if (e) { + ipcRenderer.send('enableSystemMediaTransportControls'); + + settings.setSync('globalMediaHotkeys', !e); + setGlobalMediaHotkeys(!e); + ipcRenderer.send('disableGlobalHotkeys'); + } else { + ipcRenderer.send('disableSystemMediaTransportControls'); + } + }} + /> + } + /> { settings.setSync('globalMediaHotkeys', false); } + if (force || !settings.hasSync('systemMediaTransportControls')) { + settings.setSync('systemMediaTransportControls', false); + } + if (force || !settings.hasSync('cachePath')) { settings.setSync('cachePath', path.join(path.dirname(settings.file()))); } diff --git a/src/main.dev.js b/src/main.dev.js index af402901..f3a9e597 100644 --- a/src/main.dev.js +++ b/src/main.dev.js @@ -20,6 +20,14 @@ import { autoUpdater } from 'electron-updater'; import log from 'electron-log'; import { configureStore } from '@reduxjs/toolkit'; import { forwardToRenderer, triggerAlias, replayActionMain } from 'electron-redux'; +import { + MediaPlaybackStatus, + MediaPlaybackType, + SystemMediaTransportControlsButton, +} from '@nodert-win10-au/windows.media'; +import { BackgroundMediaPlayer } from '@nodert-win10-au/windows.media.playback'; +import { RandomAccessStreamReference } from '@nodert-win10-au/windows.storage.streams'; +import { Uri } from '@nodert-win10-au/windows.foundation'; import playerReducer, { setStatus } from './redux/playerSlice'; import playQueueReducer, { decrementCurrentIndex, @@ -336,6 +344,99 @@ if (isLinux) { }); } +if (isWindows && isWindows10) { + const Controls = BackgroundMediaPlayer.current.systemMediaTransportControls; + + if (settings.getSync('systemMediaTransportControls')) { + Controls.isEnabled = true; + } else { + Controls.isEnabled = false; + } + + ipcMain.on('enableSystemMediaTransportControls', () => { + Controls.isEnabled = true; + }); + + ipcMain.on('disableSystemMediaTransportControls', () => { + Controls.isEnabled = false; + }); + + Controls.isChannelUpEnabled = false; + Controls.isChannelDownEnabled = false; + Controls.isFastForwardEnabled = false; + Controls.isRewindEnabled = false; + Controls.isRecordEnabled = false; + Controls.isPlayEnabled = true; + Controls.isPauseEnabled = true; + Controls.isStopEnabled = true; + Controls.isNextEnabled = true; + Controls.isPreviousEnabled = true; + + Controls.playbackStatus = MediaPlaybackStatus.closed; + Controls.displayUpdater.type = MediaPlaybackType.music; + + Controls.displayUpdater.musicProperties.title = 'Sonixd'; + Controls.displayUpdater.musicProperties.artist = 'No Track Playing'; + Controls.displayUpdater.musicProperties.albumTitle = 'No Album Playing'; + Controls.displayUpdater.update(); + + Controls.on('buttonpressed', (sender, eventArgs) => { + switch (eventArgs.button) { + case SystemMediaTransportControlsButton.play: + play(); + Controls.playbackStatus = MediaPlaybackStatus.playing; + break; + case SystemMediaTransportControlsButton.pause: + pause(); + Controls.playbackStatus = MediaPlaybackStatus.paused; + break; + case SystemMediaTransportControlsButton.stop: + stop(); + Controls.playbackStatus = MediaPlaybackStatus.stopped; + break; + case SystemMediaTransportControlsButton.next: + nextTrack(); + break; + case SystemMediaTransportControlsButton.previous: + previousTrack(); + break; + default: + break; + } + }); + + ipcMain.on('playpause', (_event, arg) => { + if (arg.status === 'PLAYING') { + Controls.playbackStatus = MediaPlaybackStatus.playing; + } else { + Controls.playbackStatus = MediaPlaybackStatus.paused; + } + }); + + ipcMain.on('current-song', (_event, arg) => { + if (Controls.playbackStatus !== MediaPlaybackStatus.playing) { + Controls.playbackStatus = MediaPlaybackStatus.playing; + } + + Controls.displayUpdater.musicProperties.title = arg.title || 'Unknown Title'; + Controls.displayUpdater.musicProperties.artist = + arg.artist?.length !== 0 + ? arg.artist?.map((artist) => artist.title).join(', ') + : 'Unknown Artist'; + Controls.displayUpdater.musicProperties.albumTitle = arg.album || 'Unknown Album'; + + Controls.displayUpdater.thumbnail = RandomAccessStreamReference.createFromUri( + new Uri( + arg.image.includes('placeholder') + ? 'https://raw.githubusercontent.com/jeffvli/sonixd/main/src/img/placeholder.png' + : arg.image + ) + ); + + Controls.displayUpdater.update(); + }); +} + const createWinThumbarButtons = () => { if (isWindows) { mainWindow.setThumbarButtons([ @@ -405,7 +506,7 @@ const createWindow = async () => { globalShortcut.register('MediaPreviousTrack', () => { previousTrack(); }); - } else { + } else if (!settings.getSync('systemMediaTransportControls')) { electronLocalshortcut.register(mainWindow, 'MediaStop', () => { stop(); }); @@ -424,6 +525,8 @@ const createWindow = async () => { } ipcMain.on('enableGlobalHotkeys', () => { + electronLocalshortcut.unregisterAll(mainWindow); + globalShortcut.register('MediaStop', () => { stop(); }); @@ -443,21 +546,24 @@ const createWindow = async () => { ipcMain.on('disableGlobalHotkeys', () => { globalShortcut.unregisterAll(); - electronLocalshortcut.register(mainWindow, 'MediaStop', () => { - stop(); - }); - electronLocalshortcut.register(mainWindow, 'MediaPlayPause', () => { - playPause(); - }); + if (!settings.getSync('systemMediaTransportControls')) { + electronLocalshortcut.register(mainWindow, 'MediaStop', () => { + stop(); + }); - electronLocalshortcut.register(mainWindow, 'MediaNextTrack', () => { - nextTrack(); - }); + electronLocalshortcut.register(mainWindow, 'MediaPlayPause', () => { + playPause(); + }); - electronLocalshortcut.register(mainWindow, 'MediaPreviousTrack', () => { - previousTrack(); - }); + electronLocalshortcut.register(mainWindow, 'MediaNextTrack', () => { + nextTrack(); + }); + + electronLocalshortcut.register(mainWindow, 'MediaPreviousTrack', () => { + previousTrack(); + }); + } }); mainWindow.loadURL(`file://${__dirname}/index.html#${settings.getSync('startPage')}`); diff --git a/src/shared/mockSettings.ts b/src/shared/mockSettings.ts index 67de614a..b2cb28fd 100644 --- a/src/shared/mockSettings.ts +++ b/src/shared/mockSettings.ts @@ -4,6 +4,7 @@ export const mockSettings = { theme: 'defaultDark', showDebugWindow: false, globalMediaHotkeys: true, + systemMediaTransportControls: false, cachePath: 'C:\\Users\\jli\\AppData\\Roaming\\Electron', legacyAuth: false, volume: 0.93,