fix: callback for time-changed event (#2577)

Co-authored-by: Derek Alsop <15299183+Azorant@users.noreply.github.com>
This commit is contained in:
JellyBrick
2024-11-03 19:18:06 +09:00
committed by GitHub
parent 516fbff3d7
commit 1e4cd699db
13 changed files with 137 additions and 91 deletions

View File

@ -23,6 +23,8 @@ export const backend = createBackend<BackendType, APIServerConfig>({
this.songInfo = songInfo;
});
ctx.ipc.on('ytmd:player-api-loaded', () => ctx.ipc.send('ytmd:setup-time-changed-listener'));
this.run(config.hostname, config.port);
},
stop() {

View File

@ -1,10 +1,13 @@
import { app, dialog, ipcMain } from 'electron';
import { app, dialog } from 'electron';
import { Client as DiscordClient } from '@xhayper/discord-rpc';
import { dev } from 'electron-is';
import { ActivityType, GatewayActivityButton } from 'discord-api-types/v10';
import registerCallback, { type SongInfo } from '@/providers/song-info';
import registerCallback, {
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import { createBackend, LoggerPrefix } from '@/utils';
import { t } from '@/i18n';
@ -243,25 +246,28 @@ export const backend = createBackend<
// If the page is ready, register the callback
ctx.window.once('ready-to-show', () => {
let lastSongInfo: SongInfo;
registerCallback((songInfo) => {
lastSongInfo = songInfo;
if (this.config) this.updateActivity(songInfo, this.config);
});
connect();
let lastSent = Date.now();
ipcMain.on('ytmd:time-changed', (_, t: number) => {
const currentTime = Date.now();
// if lastSent is more than 5 seconds ago, send the new time
if (currentTime - lastSent > 5000) {
lastSent = currentTime;
if (lastSongInfo) {
lastSongInfo.elapsedSeconds = t;
if (this.config) this.updateActivity(lastSongInfo, this.config);
registerCallback((songInfo, event) => {
if (event !== SongInfoEvent.TimeChanged) {
info.lastSongInfo = songInfo;
if (this.config) this.updateActivity(songInfo, this.config);
} else {
const currentTime = Date.now();
// if lastSent is more than 5 seconds ago, send the new time
if (currentTime - lastSent > 5000) {
lastSent = currentTime;
if (songInfo) {
info.lastSongInfo = songInfo;
if (this.config) this.updateActivity(songInfo, this.config);
}
}
}
});
connect();
});
ctx.ipc.on('ytmd:player-api-loaded', () =>
ctx.ipc.send('ytmd:setup-time-changed-listener'),
);
app.on('window-all-closed', clear);
},
stop() {

View File

@ -30,12 +30,13 @@ import registerCallback, {
getImage,
MediaType,
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import { getNetFetchAsFetch } from '@/plugins/utils/main';
import { t } from '@/i18n';
import { YoutubeFormatList, type Preset, DefaultPresetList } from '../types';
import { DefaultPresetList, type Preset, YoutubeFormatList } from '../types';
import type { DownloaderPluginConfig } from '../index';
@ -68,7 +69,12 @@ const sendError = (error: Error, source?: string) => {
sendFeedback_(win); // Reset feedback
const songNameMessage = source ? `\nin ${source}` : '';
const cause = error.cause ? `\n\n${String(error.cause)}` : '';
const cause = error.cause
? `\n\n${
// eslint-disable-next-line @typescript-eslint/no-base-to-string,@typescript-eslint/restrict-template-expressions
error.cause instanceof Error ? error.cause.toString() : error.cause
}`
: '';
const message = `${error.toString()}${songNameMessage}${cause}`;
console.error(message);
@ -174,7 +180,12 @@ function downloadSongOnFinishSetup({
const defaultDownloadFolder = app.getPath('downloads');
registerCallback((songInfo: SongInfo) => {
registerCallback((songInfo: SongInfo, event) => {
if (event === SongInfoEvent.TimeChanged) {
const elapsedSeconds = songInfo.elapsedSeconds ?? 0;
if (elapsedSeconds > time) time = elapsedSeconds;
return;
}
if (
!songInfo.isPaused &&
songInfo.url !== currentUrl &&
@ -213,10 +224,6 @@ function downloadSongOnFinishSetup({
ipcMain.on('ytmd:player-api-loaded', () => {
ipc.send('ytmd:setup-time-changed-listener');
});
ipcMain.on('ytmd:time-changed', (_, t: number) => {
if (t > time) time = t;
});
}
async function downloadSongUnsafe(

View File

@ -30,7 +30,7 @@ export default createPlugin({
config: {
enabled: false,
},
backend() {
backend({ ipc }) {
const secToMilisec = (t?: number) =>
t ? Math.round(Number(t) * 1e3) : undefined;
const previousStatePaused = null;
@ -65,6 +65,10 @@ export default createPlugin({
});
};
ipc.on('ytmd:player-api-loaded', () =>
ipc.send('ytmd:setup-time-changed-listener'),
);
registerCallback((songInfo) => {
if (!songInfo.title && !songInfo.artist) {
return;

View File

@ -8,7 +8,10 @@ import previousIcon from '@assets/media-icons-black/previous.png?asset&asarUnpac
import { notificationImage, secondsToMinutes, ToastStyles } from './utils';
import getSongControls from '@/providers/song-controls';
import registerCallback, { SongInfo } from '@/providers/song-info';
import registerCallback, {
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import { changeProtocolHandler } from '@/providers/protocol-handler';
import { setTrayOnClick, setTrayOnDoubleClick } from '@/tray';
import { mediaIcons } from '@/types/media-icons';
@ -258,15 +261,14 @@ export default (
let currentSeconds = 0;
on('ytmd:player-api-loaded', () => send('ytmd:setup-time-changed-listener'));
on('ytmd:time-changed', (t: number) => {
currentSeconds = t;
});
let savedSongInfo: SongInfo;
let lastUrl: string | undefined;
// Register songInfoCallback
registerCallback((songInfo) => {
registerCallback((songInfo, event) => {
if (event === SongInfoEvent.TimeChanged) {
currentSeconds = songInfo.elapsedSeconds ?? 0;
}
if (!songInfo.artist && !songInfo.title) {
return;
}

View File

@ -5,7 +5,10 @@ import is from 'electron-is';
import { notificationImage } from './utils';
import interactive from './interactive';
import registerCallback, { type SongInfo } from '@/providers/song-info';
import registerCallback, {
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import type { NotificationsPluginConfig } from './index';
import type { BackendContext } from '@/types/contexts';
@ -30,8 +33,9 @@ const setup = () => {
let oldNotification: Notification;
let currentUrl: string | undefined;
registerCallback((songInfo: SongInfo) => {
registerCallback((songInfo: SongInfo, event) => {
if (
event !== SongInfoEvent.TimeChanged &&
!songInfo.isPaused &&
(songInfo.url !== currentUrl || config.unpauseNotification)
) {

View File

@ -3,6 +3,7 @@ import { BrowserWindow } from 'electron';
import registerCallback, {
MediaType,
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import { createBackend } from '@/utils';
@ -70,7 +71,8 @@ export const backend = createBackend<
await this.createSessions(config, setConfig);
this.setConfig = setConfig;
registerCallback((songInfo: SongInfo) => {
registerCallback((songInfo: SongInfo, event) => {
if (event === SongInfoEvent.TimeChanged) return;
// Set remove the old scrobble timer
clearTimeout(scrobbleTimer);
if (!songInfo.isPaused) {

View File

@ -1,20 +1,23 @@
import { BrowserWindow, ipcMain } from 'electron';
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,
LoopStatus,
PLAYBACK_STATUS_PAUSED,
PLAYBACK_STATUS_PLAYING,
PLAYBACK_STATUS_STOPPED,
type PlayBackStatus,
type PlayerOptions,
type Position,
Track,
} from '@jellybrick/mpris-service';
import registerCallback, { type SongInfo } from '@/providers/song-info';
import registerCallback, {
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import getSongControls from '@/providers/song-controls';
import config from '@/config';
import { LoggerPrefix } from '@/utils';
@ -134,10 +137,6 @@ function registerMPRIS(win: BrowserWindow) {
player.seeked(secToMicro(t));
});
ipcMain.on('ytmd:time-changed', (_, t: number) => {
player.setPosition(secToMicro(t));
});
ipcMain.on('ytmd:repeat-changed', (_, mode: RepeatMode) => {
switch (mode) {
case 'NONE': {
@ -319,7 +318,11 @@ function registerMPRIS(win: BrowserWindow) {
}
});
registerCallback((songInfo: SongInfo) => {
registerCallback((songInfo: SongInfo, event) => {
if (event === SongInfoEvent.TimeChanged) {
player.setPosition(secToMicro(songInfo.elapsedSeconds ?? 0));
return;
}
if (player) {
const data: Track = {
'mpris:length': secToMicro(songInfo.songDuration),

View File

@ -8,7 +8,10 @@ import previousIcon from '@assets/media-icons-black/previous.png?asset&asarUnpac
import { createPlugin } from '@/utils';
import getSongControls from '@/providers/song-controls';
import registerCallback, { type SongInfo } from '@/providers/song-info';
import registerCallback, {
type SongInfo,
SongInfoEvent,
} from '@/providers/song-info';
import { mediaIcons } from '@/types/media-icons';
import { t } from '@/i18n';
@ -102,11 +105,13 @@ export default createPlugin({
]);
};
registerCallback((songInfo) => {
// Update currentsonginfo for win.on('show')
currentSongInfo = songInfo;
// Update thumbar
setThumbar(songInfo);
registerCallback((songInfo, event) => {
if (event !== SongInfoEvent.TimeChanged) {
// Update currentsonginfo for win.on('show')
currentSongInfo = songInfo;
// Update thumbar
setThumbar(songInfo);
}
});
// Need to set thumbar again after win.show

View File

@ -2,7 +2,7 @@ import { nativeImage, type NativeImage, TouchBar } from 'electron';
import { createPlugin } from '@/utils';
import getSongControls from '@/providers/song-controls';
import registerCallback from '@/providers/song-info';
import registerCallback, { SongInfoEvent } from '@/providers/song-info';
import { t } from '@/i18n';
import youtubeMusicIcon from '@assets/youtube-music.png?asset&asarUnpack';
@ -81,7 +81,8 @@ export default createPlugin({
controls = [previous, playPause, next, dislike, like];
// Register the callback
registerCallback((songInfo) => {
registerCallback((songInfo, event) => {
if (event === SongInfoEvent.TimeChanged) return;
// Song information changed, so lets update the touchBar
// Set the song title

View File

@ -28,18 +28,6 @@ export default createPlugin({
},
backend: {
liteMode: false,
data: {
cover: '',
cover_url: '',
title: '',
artists: [] as string[],
status: '',
progress: 0,
duration: 0,
album_url: '',
album: undefined,
url: '',
} as Data,
start({ ipc }) {
const secToMilisec = (t: number) => Math.round(Number(t) * 1e3);
@ -85,31 +73,24 @@ export default createPlugin({
ipc.on('ytmd:player-api-loaded', () =>
ipc.send('ytmd:setup-time-changed-listener'),
);
ipc.on('ytmd:time-changed', (t: number) => {
if (!this.data.title) {
return;
}
this.data.progress = secToMilisec(t);
post(this.data);
});
registerCallback((songInfo) => {
if (!songInfo.title && !songInfo.artist) {
return;
}
this.data.duration = secToMilisec(songInfo.songDuration);
this.data.progress = secToMilisec(songInfo.elapsedSeconds ?? 0);
this.data.cover = songInfo.imageSrc ?? '';
this.data.cover_url = songInfo.imageSrc ?? '';
this.data.album_url = songInfo.imageSrc ?? '';
this.data.title = songInfo.title;
this.data.artists = [songInfo.artist];
this.data.status = songInfo.isPaused ? 'stopped' : 'playing';
this.data.album = songInfo.album;
this.data.url = songInfo.url ?? '';
post(this.data);
post({
duration: secToMilisec(songInfo.songDuration),
progress: secToMilisec(songInfo.elapsedSeconds ?? 0),
cover: songInfo.imageSrc ?? '',
cover_url: songInfo.imageSrc ?? '',
album_url: songInfo.imageSrc ?? '',
title: songInfo.title,
artists: [songInfo.artist],
status: songInfo.isPaused ? 'stopped' : 'playing',
album: songInfo.album,
url: songInfo.url ?? '',
});
});
},
},

View File

@ -149,8 +149,17 @@ const handleData = async (
return songInfo;
};
export enum SongInfoEvent {
VideoSrcChanged = 'ytmd:video-src-changed',
PlayOrPaused = 'ytmd:play-or-paused',
TimeChanged = 'ytmd:time-changed',
}
// This variable will be filled with the callbacks once they register
export type SongInfoCallback = (songInfo: SongInfo, event?: string) => void;
export type SongInfoCallback = (
songInfo: SongInfo,
event: SongInfoEvent,
) => void;
const callbacks: Set<SongInfoCallback> = new Set();
// This function will allow plugins to register callback that will be triggered when data changes
@ -173,7 +182,7 @@ const registerProvider = (win: BrowserWindow) => {
if (tempSongInfo) {
for (const c of callbacks) {
c(tempSongInfo, 'ytmd:video-src-changed');
c(tempSongInfo, SongInfoEvent.VideoSrcChanged);
}
}
});
@ -199,11 +208,29 @@ const registerProvider = (win: BrowserWindow) => {
if (tempSongInfo) {
for (const c of callbacks) {
c(tempSongInfo, 'ytmd:play-or-paused');
c(tempSongInfo, SongInfoEvent.PlayOrPaused);
}
}
},
);
ipcMain.on('ytmd:time-changed', async (_, seconds: number) => {
const tempSongInfo = await dataMutex.runExclusive<SongInfo | null>(() => {
if (!songInfo) {
return null;
}
songInfo.elapsedSeconds = seconds;
return songInfo;
});
if (tempSongInfo) {
for (const c of callbacks) {
c(tempSongInfo, SongInfoEvent.TimeChanged);
}
}
});
};
const suffixesToRemove = [

View File

@ -1,4 +1,4 @@
import { Menu, screen, nativeImage, Tray } from 'electron';
import { Menu, nativeImage, screen, Tray } from 'electron';
import is from 'electron-is';
import defaultTrayIconAsset from '@assets/youtube-music-tray.png?asset&asarUnpack';
@ -7,7 +7,7 @@ import pausedTrayIconAsset from '@assets/youtube-music-tray-paused.png?asset&asa
import config from './config';
import { restart } from './providers/app-controls';
import registerCallback from './providers/song-info';
import registerCallback, { SongInfoEvent } from './providers/song-info';
import getSongControls from './providers/song-controls';
import { t } from '@/i18n';
@ -125,7 +125,9 @@ export const setUpTray = (app: Electron.App, win: Electron.BrowserWindow) => {
const trayMenu = Menu.buildFromTemplate(template);
tray.setContextMenu(trayMenu);
registerCallback((songInfo) => {
registerCallback((songInfo, event) => {
if (event === SongInfoEvent.TimeChanged) return;
if (tray) {
if (typeof songInfo.isPaused === 'undefined') {
tray.setImage(defaultTrayIcon);