mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
fix: fix bugs in MPRIS, and improve MPRIS (#1760)
Co-authored-by: JellyBrick <shlee1503@naver.com> Co-authored-by: Totto <32566573+Totto16@users.noreply.github.com>
This commit is contained in:
@ -6,7 +6,7 @@ import { t } from '@/i18n';
|
||||
import { createPlugin } from '@/utils';
|
||||
import promptOptions from '@/providers/prompt-options';
|
||||
|
||||
import { type AppElement, getDefaultProfile, type Permission, type Profile, type VideoData } from './types';
|
||||
import { getDefaultProfile, type Permission, type Profile, type VideoData } from './types';
|
||||
import { Queue } from './queue';
|
||||
import { Connection, type ConnectionEventUnion } from './connection';
|
||||
import { createHostPopup } from './ui/host';
|
||||
@ -19,6 +19,7 @@ import style from './style.css?inline';
|
||||
import type { YoutubePlayer } from '@/types/youtube-player';
|
||||
import type { RendererContext } from '@/types/contexts';
|
||||
import type { VideoDataChanged } from '@/types/video-data-changed';
|
||||
import type { AppElement } from '@/types/queue';
|
||||
|
||||
type RawAccountData = {
|
||||
accountName: {
|
||||
|
||||
@ -4,8 +4,9 @@ import { mapQueueItem } from './utils';
|
||||
import { t } from '@/i18n';
|
||||
|
||||
import type { ConnectionEventUnion } from '@/plugins/music-together/connection';
|
||||
import type { Profile, QueueElement, VideoData } from '../types';
|
||||
import type { Profile, VideoData } from '../types';
|
||||
import type { QueueItem } from '@/types/datahost-get-state';
|
||||
import type { QueueElement } from '@/types/queue';
|
||||
|
||||
const getHeaderPayload = (() => {
|
||||
let payload: {
|
||||
|
||||
@ -1,44 +1,3 @@
|
||||
import type { YoutubePlayer } from '@/types/youtube-player';
|
||||
import type { GetState, QueueItem } from '@/types/datahost-get-state';
|
||||
|
||||
type StoreState = GetState;
|
||||
type Store = {
|
||||
dispatch: (obj: {
|
||||
type: string;
|
||||
payload?: {
|
||||
items?: QueueItem[];
|
||||
};
|
||||
}) => void;
|
||||
|
||||
getState: () => StoreState;
|
||||
replaceReducer: (param1: unknown) => unknown;
|
||||
subscribe: (callback: () => void) => unknown;
|
||||
}
|
||||
|
||||
export type QueueElement = HTMLElement & {
|
||||
dispatch(obj: {
|
||||
type: string;
|
||||
payload?: unknown;
|
||||
}): void;
|
||||
queue: QueueAPI;
|
||||
};
|
||||
export type QueueAPI = {
|
||||
getItems(): unknown[];
|
||||
store: {
|
||||
store: Store,
|
||||
};
|
||||
continuation?: string;
|
||||
autoPlaying?: boolean;
|
||||
};
|
||||
export type AppElement = HTMLElement & AppAPI;
|
||||
export type AppAPI = {
|
||||
queue_: QueueAPI;
|
||||
playerApi_: YoutubePlayer;
|
||||
openToast: (message: string) => void;
|
||||
|
||||
// TODO: Add more
|
||||
};
|
||||
|
||||
export type Profile = {
|
||||
id: string;
|
||||
handleId: string;
|
||||
|
||||
@ -307,9 +307,9 @@ export default (
|
||||
savedNotification?.close();
|
||||
});
|
||||
|
||||
changeProtocolHandler((cmd) => {
|
||||
changeProtocolHandler((cmd, args) => {
|
||||
if (Object.keys(songControls).includes(cmd)) {
|
||||
songControls[cmd as keyof typeof songControls]();
|
||||
songControls[cmd as keyof typeof songControls](args as never);
|
||||
if (
|
||||
config().refreshOnPlayPause &&
|
||||
(cmd === 'pause' || (cmd === 'play' && !config().unpauseNotification))
|
||||
|
||||
110
src/plugins/shortcuts/mpris-service.d.ts
vendored
110
src/plugins/shortcuts/mpris-service.d.ts
vendored
@ -4,10 +4,10 @@ declare module '@jellybrick/mpris-service' {
|
||||
import { interface as dbusInterface } from 'dbus-next';
|
||||
|
||||
interface RootInterfaceOptions {
|
||||
identity: string;
|
||||
supportedUriSchemes: string[];
|
||||
supportedMimeTypes: string[];
|
||||
desktopEntry: string;
|
||||
identity?: string;
|
||||
supportedUriSchemes?: string[];
|
||||
supportedMimeTypes?: string[];
|
||||
desktopEntry?: string;
|
||||
}
|
||||
|
||||
export interface Track {
|
||||
@ -35,6 +35,32 @@ declare module '@jellybrick/mpris-service' {
|
||||
'xesam:userRating'?: number;
|
||||
}
|
||||
|
||||
export type PlayBackStatus = 'Playing' | 'Paused' | 'Stopped';
|
||||
|
||||
export type LoopStatus = 'None' | 'Track' | 'Playlist';
|
||||
|
||||
export const PLAYBACK_STATUS_PLAYING: 'Playing';
|
||||
export const PLAYBACK_STATUS_PAUSED: 'Paused';
|
||||
export const PLAYBACK_STATUS_STOPPED: 'Stopped';
|
||||
|
||||
export const LOOP_STATUS_NONE: 'None';
|
||||
export const LOOP_STATUS_TRACK: 'Track';
|
||||
export const LOOP_STATUS_PLAYLIST: 'Playlist';
|
||||
|
||||
export type Interfaces = 'player' | 'trackList' | 'playlists';
|
||||
|
||||
export interface AdditionalPlayerOptions {
|
||||
name: string;
|
||||
supportedInterfaces: Interfaces[];
|
||||
}
|
||||
|
||||
export type PlayerOptions = RootInterfaceOptions & AdditionalPlayerOptions;
|
||||
|
||||
export interface Position {
|
||||
trackId: string;
|
||||
position: number;
|
||||
}
|
||||
|
||||
declare class Player extends EventEmitter {
|
||||
constructor(opts: {
|
||||
name: string;
|
||||
@ -43,18 +69,44 @@ declare module '@jellybrick/mpris-service' {
|
||||
supportedInterfaces?: string[];
|
||||
});
|
||||
|
||||
//RootInterface
|
||||
on(event: 'quit', listener: () => void): this;
|
||||
on(event: 'raise', listener: () => void): this;
|
||||
on(
|
||||
event: 'fullscreen',
|
||||
listener: (fullscreenEnabled: boolean) => void,
|
||||
): this;
|
||||
|
||||
emit(type: string, ...args: unknown[]): unknown;
|
||||
|
||||
name: string;
|
||||
identity: string;
|
||||
fullscreen: boolean;
|
||||
fullscreen?: boolean;
|
||||
supportedUriSchemes: string[];
|
||||
supportedMimeTypes: string[];
|
||||
canQuit: boolean;
|
||||
canRaise: boolean;
|
||||
canSetFullscreen: boolean;
|
||||
canSetFullscreen?: boolean;
|
||||
desktopEntry?: string;
|
||||
hasTrackList: boolean;
|
||||
desktopEntry: string;
|
||||
playbackStatus: string;
|
||||
loopStatus: string;
|
||||
|
||||
// PlayerInterface
|
||||
on(event: 'next', listener: () => void): this;
|
||||
on(event: 'previous', listener: () => void): this;
|
||||
on(event: 'pause', listener: () => void): this;
|
||||
on(event: 'playpause', listener: () => void): this;
|
||||
on(event: 'stop', listener: () => void): this;
|
||||
on(event: 'play', listener: () => void): this;
|
||||
on(event: 'seek', listener: (offset: number) => void): this;
|
||||
on(event: 'open', listener: ({ uri: string }) => void): this;
|
||||
on(event: 'loopStatus', listener: (status: LoopStatus) => void): this;
|
||||
on(event: 'rate', listener: () => void): this;
|
||||
on(event: 'shuffle', listener: (enableShuffle: boolean) => void): this;
|
||||
on(event: 'volume', listener: (newVolume: number) => void): this;
|
||||
on(event: 'position', listener: (position: Position) => void): this;
|
||||
|
||||
playbackStatus: PlayBackStatus;
|
||||
loopStatus: LoopStatus;
|
||||
shuffle: boolean;
|
||||
metadata: Track;
|
||||
volume: number;
|
||||
@ -67,9 +119,40 @@ declare module '@jellybrick/mpris-service' {
|
||||
rate: number;
|
||||
minimumRate: number;
|
||||
maximumRate: number;
|
||||
playlists: unknown[];
|
||||
|
||||
abstract getPosition(): number;
|
||||
|
||||
seeked(position: number): void;
|
||||
|
||||
// TracklistInterface
|
||||
on(event: 'addTrack', listener: () => void): this;
|
||||
on(event: 'removeTrack', listener: () => void): this;
|
||||
on(event: 'goTo', listener: () => void): this;
|
||||
|
||||
tracks: Track[];
|
||||
canEditTracks: boolean;
|
||||
|
||||
on(event: '*', a: unknown[]): this;
|
||||
|
||||
addTrack(track: string): void;
|
||||
|
||||
removeTrack(trackId: string): void;
|
||||
|
||||
// PlaylistsInterface
|
||||
on(event: 'activatePlaylist', listener: () => void): this;
|
||||
|
||||
playlists: Playlist[];
|
||||
activePlaylist: string;
|
||||
|
||||
setPlaylists(playlists: Playlist[]): void;
|
||||
|
||||
setActivePlaylist(playlistId: string): void;
|
||||
|
||||
// Player methods
|
||||
constructor(opts: PlayerOptions);
|
||||
|
||||
on(event: 'error', listener: (error: Error) => void): this;
|
||||
|
||||
init(opts: RootInterfaceOptions): void;
|
||||
|
||||
objectPath(subpath?: string): string;
|
||||
@ -91,13 +174,6 @@ declare module '@jellybrick/mpris-service' {
|
||||
setPlaylists(playlists: Track[]): void;
|
||||
|
||||
setActivePlaylist(playlistId: string): void;
|
||||
|
||||
static PLAYBACK_STATUS_PLAYING: 'Playing';
|
||||
static PLAYBACK_STATUS_PAUSED: 'Paused';
|
||||
static PLAYBACK_STATUS_STOPPED: 'Stopped';
|
||||
static LOOP_STATUS_NONE: 'None';
|
||||
static LOOP_STATUS_TRACK: 'Track';
|
||||
static LOOP_STATUS_PLAYLIST: 'Playlist';
|
||||
}
|
||||
|
||||
interface MprisInterface extends dbusInterface.Interface {
|
||||
|
||||
@ -1,12 +1,27 @@
|
||||
import { BrowserWindow, ipcMain } from 'electron';
|
||||
|
||||
import MprisPlayer, { Track } from '@jellybrick/mpris-service';
|
||||
import MprisPlayer, {
|
||||
Track,
|
||||
LoopStatus,
|
||||
type PlayBackStatus,
|
||||
type PlayerOptions,
|
||||
PLAYBACK_STATUS_STOPPED,
|
||||
PLAYBACK_STATUS_PAUSED,
|
||||
PLAYBACK_STATUS_PLAYING,
|
||||
LOOP_STATUS_NONE,
|
||||
LOOP_STATUS_PLAYLIST,
|
||||
LOOP_STATUS_TRACK,
|
||||
type Position,
|
||||
} from '@jellybrick/mpris-service';
|
||||
|
||||
import registerCallback, { type SongInfo } from '@/providers/song-info';
|
||||
import getSongControls from '@/providers/song-controls';
|
||||
import config from '@/config';
|
||||
import { LoggerPrefix } from '@/utils';
|
||||
|
||||
import type { RepeatMode } from '@/types/datahost-get-state';
|
||||
import type { QueueResponse } from '@/types/youtube-music-desktop-internal';
|
||||
|
||||
class YTPlayer extends MprisPlayer {
|
||||
/**
|
||||
* @type {number} The current position in microseconds
|
||||
@ -14,12 +29,7 @@ class YTPlayer extends MprisPlayer {
|
||||
*/
|
||||
private currentPosition: number;
|
||||
|
||||
constructor(opts: {
|
||||
name: string;
|
||||
identity: string;
|
||||
supportedMimeTypes?: string[];
|
||||
supportedInterfaces?: string[];
|
||||
}) {
|
||||
constructor(opts: PlayerOptions) {
|
||||
super(opts);
|
||||
|
||||
this.currentPosition = 0;
|
||||
@ -33,35 +43,38 @@ class YTPlayer extends MprisPlayer {
|
||||
return this.currentPosition;
|
||||
}
|
||||
|
||||
setLoopStatus(status: string) {
|
||||
setLoopStatus(status: LoopStatus) {
|
||||
this.loopStatus = status;
|
||||
}
|
||||
|
||||
isPlaying(): boolean {
|
||||
return this.playbackStatus === YTPlayer.PLAYBACK_STATUS_PLAYING;
|
||||
return this.playbackStatus === PLAYBACK_STATUS_PLAYING;
|
||||
}
|
||||
|
||||
isPaused(): boolean {
|
||||
return this.playbackStatus === YTPlayer.PLAYBACK_STATUS_PAUSED;
|
||||
return this.playbackStatus === PLAYBACK_STATUS_PAUSED;
|
||||
}
|
||||
|
||||
isStopped(): boolean {
|
||||
return this.playbackStatus === YTPlayer.PLAYBACK_STATUS_STOPPED;
|
||||
return this.playbackStatus === PLAYBACK_STATUS_STOPPED;
|
||||
}
|
||||
|
||||
setPlaybackStatus(status: string) {
|
||||
setPlaybackStatus(status: PlayBackStatus) {
|
||||
this.playbackStatus = status;
|
||||
}
|
||||
}
|
||||
|
||||
function setupMPRIS() {
|
||||
const instance = new YTPlayer({
|
||||
name: 'youtube-music',
|
||||
name: 'YoutubeMusic',
|
||||
identity: 'YouTube Music',
|
||||
supportedMimeTypes: ['audio/mpeg'],
|
||||
supportedInterfaces: ['player'],
|
||||
});
|
||||
|
||||
instance.canRaise = true;
|
||||
instance.canQuit = false;
|
||||
instance.canSetFullscreen = true;
|
||||
instance.supportedUriSchemes = ['http', 'https'];
|
||||
instance.desktopEntry = 'youtube-music';
|
||||
return instance;
|
||||
@ -73,21 +86,27 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
playPause,
|
||||
next,
|
||||
previous,
|
||||
volumeMinus10,
|
||||
volumePlus10,
|
||||
setVolume,
|
||||
shuffle,
|
||||
switchRepeat,
|
||||
setFullscreen,
|
||||
requestFullscreenInformation,
|
||||
requestQueueInformation,
|
||||
} = songControls;
|
||||
try {
|
||||
let currentSongInfo: SongInfo | null = null;
|
||||
const secToMicro = (n: number) => Math.round(Number(n) * 1e6);
|
||||
const microToSec = (n: number) => Math.round(Number(n) / 1e6);
|
||||
|
||||
const seekTo = (event: {
|
||||
trackId: string;
|
||||
position: number;
|
||||
}) => {
|
||||
if (event.trackId === currentSongInfo?.videoId) {
|
||||
const correctId = (videoId: string) => {
|
||||
return videoId.replace('-', '_MINUS_');
|
||||
};
|
||||
|
||||
const seekTo = (event: Position) => {
|
||||
if (
|
||||
currentSongInfo?.videoId &&
|
||||
event.trackId.endsWith(correctId(currentSongInfo.videoId))
|
||||
) {
|
||||
win.webContents.send('ytmd:seek-to', microToSec(event.position ?? 0));
|
||||
}
|
||||
};
|
||||
@ -101,6 +120,10 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
win.webContents.send('ytmd:setup-time-changed-listener', 'mpris');
|
||||
win.webContents.send('ytmd:setup-repeat-changed-listener', 'mpris');
|
||||
win.webContents.send('ytmd:setup-volume-changed-listener', 'mpris');
|
||||
win.webContents.send('ytmd:setup-fullscreen-changed-listener', 'mpris');
|
||||
win.webContents.send('ytmd:setup-autoplay-changed-listener', 'mpris');
|
||||
requestFullscreenInformation();
|
||||
requestQueueInformation();
|
||||
});
|
||||
|
||||
ipcMain.on('ytmd:seeked', (_, t: number) => player.seeked(secToMicro(t)));
|
||||
@ -109,29 +132,85 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
player.setPosition(secToMicro(t));
|
||||
});
|
||||
|
||||
ipcMain.on('ytmd:repeat-changed', (_, mode: string) => {
|
||||
ipcMain.on('ytmd:repeat-changed', (_, mode: RepeatMode) => {
|
||||
switch (mode) {
|
||||
case 'NONE': {
|
||||
player.setLoopStatus(YTPlayer.LOOP_STATUS_NONE);
|
||||
player.setLoopStatus(LOOP_STATUS_NONE);
|
||||
break;
|
||||
}
|
||||
case 'ONE': {
|
||||
player.setLoopStatus(YTPlayer.LOOP_STATUS_TRACK);
|
||||
player.setLoopStatus(LOOP_STATUS_TRACK);
|
||||
break;
|
||||
}
|
||||
case 'ALL': {
|
||||
player.setLoopStatus(YTPlayer.LOOP_STATUS_PLAYLIST);
|
||||
player.setLoopStatus(LOOP_STATUS_PLAYLIST);
|
||||
// No default
|
||||
break;
|
||||
}
|
||||
}
|
||||
requestQueueInformation();
|
||||
});
|
||||
player.on('loopStatus', (status: string) => {
|
||||
|
||||
ipcMain.on('ytmd:fullscreen-changed', (_, changedTo: boolean) => {
|
||||
if (player.fullscreen === undefined || !player.canSetFullscreen) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.fullscreen =
|
||||
changedTo !== undefined ? changedTo : !player.fullscreen;
|
||||
});
|
||||
|
||||
ipcMain.on(
|
||||
'ytmd:set-fullscreen',
|
||||
(_, isFullscreen: boolean | undefined) => {
|
||||
if (!player.canSetFullscreen || isFullscreen === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
player.fullscreen = isFullscreen;
|
||||
},
|
||||
);
|
||||
|
||||
ipcMain.on(
|
||||
'ytmd:fullscreen-changed-supported',
|
||||
(_, isFullscreenSupported: boolean) => {
|
||||
player.canSetFullscreen = isFullscreenSupported;
|
||||
},
|
||||
);
|
||||
ipcMain.on('ytmd:autoplay-changed', (_) => {
|
||||
requestQueueInformation();
|
||||
});
|
||||
|
||||
ipcMain.on('ytmd:get-queue-response', (_, queue: QueueResponse) => {
|
||||
if (!queue) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentPosition = queue.items?.findIndex((it) =>
|
||||
it?.playlistPanelVideoRenderer?.selected ||
|
||||
it?.playlistPanelVideoWrapperRenderer?.primaryRenderer?.playlistPanelVideoRenderer?.selected
|
||||
) ?? 0;
|
||||
player.canGoPrevious = currentPosition !== 0;
|
||||
|
||||
let hasNext: boolean;
|
||||
if (queue.autoPlaying) {
|
||||
hasNext = true;
|
||||
} else if (player.loopStatus === LOOP_STATUS_PLAYLIST) {
|
||||
hasNext = true;
|
||||
} else {
|
||||
// Example: currentPosition = 0, queue.items.length = 29 -> hasNext = true
|
||||
hasNext = !!(currentPosition - (queue?.items?.length ?? 0 - 1));
|
||||
}
|
||||
|
||||
player.canGoNext = hasNext;
|
||||
});
|
||||
|
||||
player.on('loopStatus', (status: LoopStatus) => {
|
||||
// SwitchRepeat cycles between states in that order
|
||||
const switches = [
|
||||
YTPlayer.LOOP_STATUS_NONE,
|
||||
YTPlayer.LOOP_STATUS_PLAYLIST,
|
||||
YTPlayer.LOOP_STATUS_TRACK,
|
||||
LOOP_STATUS_NONE,
|
||||
LOOP_STATUS_PLAYLIST,
|
||||
LOOP_STATUS_TRACK,
|
||||
];
|
||||
const currentIndex = switches.indexOf(player.loopStatus);
|
||||
const targetIndex = switches.indexOf(status);
|
||||
@ -142,33 +221,44 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
});
|
||||
|
||||
player.on('raise', () => {
|
||||
if (!player.canRaise) {
|
||||
return;
|
||||
}
|
||||
|
||||
win.setSkipTaskbar(false);
|
||||
win.show();
|
||||
});
|
||||
|
||||
player.on('fullscreen', (fullscreenEnabled: boolean) => {
|
||||
setFullscreen(fullscreenEnabled);
|
||||
});
|
||||
|
||||
player.on('play', () => {
|
||||
if (!player.isPlaying()) {
|
||||
player.setPlaybackStatus(YTPlayer.PLAYBACK_STATUS_PLAYING);
|
||||
player.setPlaybackStatus(PLAYBACK_STATUS_PLAYING);
|
||||
playPause();
|
||||
}
|
||||
});
|
||||
player.on('pause', () => {
|
||||
if (player.playbackStatus !== YTPlayer.PLAYBACK_STATUS_PAUSED) {
|
||||
player.setPlaybackStatus(YTPlayer.PLAYBACK_STATUS_PAUSED);
|
||||
if (!player.isPaused()) {
|
||||
player.setPlaybackStatus(PLAYBACK_STATUS_PAUSED);
|
||||
playPause();
|
||||
}
|
||||
});
|
||||
player.on('playpause', () => {
|
||||
player.setPlaybackStatus(
|
||||
player.isPlaying()
|
||||
? YTPlayer.PLAYBACK_STATUS_PAUSED
|
||||
: YTPlayer.PLAYBACK_STATUS_PLAYING
|
||||
player.isPlaying() ? PLAYBACK_STATUS_PAUSED : PLAYBACK_STATUS_PLAYING,
|
||||
);
|
||||
playPause();
|
||||
});
|
||||
|
||||
player.on('next', next);
|
||||
player.on('previous', previous);
|
||||
player.on('next', () => {
|
||||
next();
|
||||
});
|
||||
|
||||
player.on('previous', () => {
|
||||
previous();
|
||||
});
|
||||
|
||||
player.on('seek', seekBy);
|
||||
player.on('position', seekTo);
|
||||
@ -176,10 +266,18 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
player.on('shuffle', (enableShuffle) => {
|
||||
if (enableShuffle) {
|
||||
shuffle();
|
||||
requestQueueInformation();
|
||||
}
|
||||
});
|
||||
player.on('open', (args: { uri: string }) => {
|
||||
win.loadURL(args.uri);
|
||||
win.loadURL(args.uri).then(() => {
|
||||
requestQueueInformation();
|
||||
});
|
||||
});
|
||||
|
||||
player.on('error', (error: Error) => {
|
||||
console.error(LoggerPrefix, 'Error in MPRIS');
|
||||
console.trace(error);
|
||||
});
|
||||
|
||||
let mprisVolNewer = false;
|
||||
@ -198,7 +296,7 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
}
|
||||
});
|
||||
|
||||
player.on('volume', (newVolume) => {
|
||||
player.on('volume', (newVolume: number) => {
|
||||
if (config.plugins.isEnabled('precise-volume')) {
|
||||
// With precise volume we can set the volume to the exact value.
|
||||
const newVol = ~~(newVolume * 100);
|
||||
@ -208,31 +306,23 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
win.webContents.send('setVolume', newVol);
|
||||
}
|
||||
} else {
|
||||
// With keyboard shortcuts we can only change the volume in increments of 10, so round it.
|
||||
let deltaVolume = Math.round((newVolume - player.volume) * 10);
|
||||
while (deltaVolume !== 0 && deltaVolume > 0) {
|
||||
volumePlus10();
|
||||
player.volume += 0.1;
|
||||
deltaVolume--;
|
||||
}
|
||||
|
||||
while (deltaVolume !== 0 && deltaVolume < 0) {
|
||||
volumeMinus10();
|
||||
player.volume -= 0.1;
|
||||
deltaVolume++;
|
||||
}
|
||||
setVolume(newVolume * 100);
|
||||
}
|
||||
});
|
||||
|
||||
registerCallback((songInfo) => {
|
||||
registerCallback((songInfo: SongInfo) => {
|
||||
if (player) {
|
||||
const data: Track = {
|
||||
'mpris:length': secToMicro(songInfo.songDuration),
|
||||
'mpris:artUrl': songInfo.imageSrc ?? undefined,
|
||||
...(songInfo.imageSrc
|
||||
? { 'mpris:artUrl': songInfo.imageSrc }
|
||||
: undefined),
|
||||
'xesam:title': songInfo.title,
|
||||
'xesam:url': songInfo.url,
|
||||
'xesam:artist': [songInfo.artist],
|
||||
'mpris:trackid': songInfo.videoId,
|
||||
'mpris:trackid': player.objectPath(
|
||||
`Track/${correctId(songInfo.videoId)}`,
|
||||
),
|
||||
};
|
||||
if (songInfo.album) {
|
||||
data['xesam:album'] = songInfo.album;
|
||||
@ -241,22 +331,20 @@ function registerMPRIS(win: BrowserWindow) {
|
||||
|
||||
player.metadata = data;
|
||||
|
||||
const currentElapsedMicroSeconds = secToMicro(songInfo.elapsedSeconds ?? 0);
|
||||
const currentElapsedMicroSeconds = secToMicro(
|
||||
songInfo.elapsedSeconds ?? 0,
|
||||
);
|
||||
player.setPosition(currentElapsedMicroSeconds);
|
||||
player.seeked(currentElapsedMicroSeconds);
|
||||
|
||||
player.setPlaybackStatus(
|
||||
songInfo.isPaused ?
|
||||
YTPlayer.PLAYBACK_STATUS_PAUSED :
|
||||
YTPlayer.PLAYBACK_STATUS_PLAYING
|
||||
songInfo.isPaused ? PLAYBACK_STATUS_PAUSED : PLAYBACK_STATUS_PLAYING,
|
||||
);
|
||||
}
|
||||
requestQueueInformation();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(
|
||||
LoggerPrefix,
|
||||
'Error in MPRIS'
|
||||
);
|
||||
console.error(LoggerPrefix, 'Error in MPRIS');
|
||||
console.trace(error);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user