mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-10 10:11:46 +00:00
fix: fix #1621
This commit is contained in:
@ -32,7 +32,7 @@ export const onRendererLoad = ({
|
||||
|
||||
let unregister: (() => void) | null = null;
|
||||
|
||||
on('update-song-info', (extractedSongInfo: SongInfo) => {
|
||||
on('ytmd:update-song-info', (extractedSongInfo: SongInfo) => {
|
||||
unregister?.();
|
||||
|
||||
setTimeout(async () => {
|
||||
|
||||
@ -10,10 +10,7 @@ import type { VideoDataChanged } from '@/types/video-data-changed';
|
||||
let songInfo: SongInfo = {} as SongInfo;
|
||||
export const getSongInfo = () => songInfo;
|
||||
|
||||
const $ = <E extends Element = Element>(s: string): E | null =>
|
||||
document.querySelector<E>(s);
|
||||
|
||||
window.ipcRenderer.on('update-song-info', (_, extractedSongInfo: SongInfo) => {
|
||||
window.ipcRenderer.on('ytmd:update-song-info', (_, extractedSongInfo: SongInfo) => {
|
||||
songInfo = extractedSongInfo;
|
||||
});
|
||||
|
||||
@ -21,7 +18,7 @@ window.ipcRenderer.on('update-song-info', (_, extractedSongInfo: SongInfo) => {
|
||||
const srcChangedEvent = new CustomEvent('ytmd:src-changed');
|
||||
|
||||
export const setupSeekedListener = singleton(() => {
|
||||
$('video')?.addEventListener('seeked', (v) => {
|
||||
document.querySelector('video')?.addEventListener('seeked', (v) => {
|
||||
if (v.target instanceof HTMLVideoElement) {
|
||||
window.ipcRenderer.send('ytmd:seeked', v.target.currentTime);
|
||||
}
|
||||
@ -36,7 +33,7 @@ export const setupTimeChangedListener = singleton(() => {
|
||||
songInfo.elapsedSeconds = Number(target.value);
|
||||
}
|
||||
});
|
||||
const progressBar = $('#progress-bar');
|
||||
const progressBar = document.querySelector('#progress-bar');
|
||||
if (progressBar) {
|
||||
progressObserver.observe(progressBar, { attributeFilter: ['value'] });
|
||||
}
|
||||
@ -56,7 +53,7 @@ export const setupRepeatChangedListener = singleton(() => {
|
||||
).__dataHost.getState().queue.repeatMode,
|
||||
);
|
||||
});
|
||||
repeatObserver.observe($('#right-controls .repeat')!, {
|
||||
repeatObserver.observe(document.querySelector('#right-controls .repeat')!, {
|
||||
attributeFilter: ['title'],
|
||||
});
|
||||
|
||||
@ -64,7 +61,7 @@ export const setupRepeatChangedListener = singleton(() => {
|
||||
// provided by YouTube Music
|
||||
window.ipcRenderer.send(
|
||||
'ytmd:repeat-changed',
|
||||
$<
|
||||
document.querySelector<
|
||||
HTMLElement & {
|
||||
getState: () => GetState;
|
||||
}
|
||||
@ -73,7 +70,7 @@ export const setupRepeatChangedListener = singleton(() => {
|
||||
});
|
||||
|
||||
export const setupVolumeChangedListener = singleton((api: YoutubePlayer) => {
|
||||
$('video')?.addEventListener('volumechange', () => {
|
||||
document.querySelector('video')?.addEventListener('volumechange', () => {
|
||||
window.ipcRenderer.send('ytmd:volume-changed', api.getVolume());
|
||||
});
|
||||
// Emit the initial value as well; as it's persistent between launches.
|
||||
@ -134,7 +131,7 @@ export default (api: YoutubePlayer) => {
|
||||
waitingEvent.delete(videoData.videoId);
|
||||
sendSongInfo(videoData);
|
||||
} else if (name === 'dataloaded') {
|
||||
const video = $<HTMLVideoElement>('video');
|
||||
const video = document.querySelector<HTMLVideoElement>('video');
|
||||
video?.dispatchEvent(srcChangedEvent);
|
||||
|
||||
for (const status of ['playing', 'pause'] as const) {
|
||||
@ -146,9 +143,12 @@ export default (api: YoutubePlayer) => {
|
||||
}
|
||||
});
|
||||
|
||||
const video = $('video')!;
|
||||
for (const status of ['playing', 'pause'] as const) {
|
||||
video.addEventListener(status, playPausedHandlers[status]);
|
||||
const video = document.querySelector('video');
|
||||
|
||||
if (video) {
|
||||
for (const status of ['playing', 'pause'] as const) {
|
||||
video.addEventListener(status, playPausedHandlers[status]);
|
||||
}
|
||||
}
|
||||
|
||||
function sendSongInfo(videoData: VideoDataChangeValue) {
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
import { BrowserWindow, ipcMain, nativeImage, net } from 'electron';
|
||||
|
||||
import { cache } from './decorators';
|
||||
import { Mutex } from 'async-mutex';
|
||||
|
||||
import { cache } from './decorators';
|
||||
import config from '@/config';
|
||||
|
||||
import type { GetPlayerResponse } from '@/types/get-player-response';
|
||||
@ -22,23 +23,6 @@ export interface SongInfo {
|
||||
playlistId?: string;
|
||||
}
|
||||
|
||||
// Fill songInfo with empty values
|
||||
export const songInfo: SongInfo = {
|
||||
title: '',
|
||||
artist: '',
|
||||
views: 0,
|
||||
uploadDate: '',
|
||||
imageSrc: '',
|
||||
image: null,
|
||||
isPaused: undefined,
|
||||
songDuration: 0,
|
||||
elapsedSeconds: 0,
|
||||
url: '',
|
||||
album: undefined,
|
||||
videoId: '',
|
||||
playlistId: '',
|
||||
};
|
||||
|
||||
// Grab the native image using the src
|
||||
export const getImage = cache(
|
||||
async (src: string): Promise<Electron.NativeImage> => {
|
||||
@ -57,11 +41,28 @@ export const getImage = cache(
|
||||
const handleData = async (
|
||||
data: GetPlayerResponse,
|
||||
win: Electron.BrowserWindow,
|
||||
) => {
|
||||
): Promise<SongInfo | null> => {
|
||||
if (!data) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fill songInfo with empty values
|
||||
const songInfo: SongInfo = {
|
||||
title: '',
|
||||
artist: '',
|
||||
views: 0,
|
||||
uploadDate: '',
|
||||
imageSrc: '',
|
||||
image: null,
|
||||
isPaused: undefined,
|
||||
songDuration: 0,
|
||||
elapsedSeconds: 0,
|
||||
url: '',
|
||||
album: undefined,
|
||||
videoId: '',
|
||||
playlistId: '',
|
||||
} satisfies SongInfo;
|
||||
|
||||
const microformat = data.microformat?.microformatDataRenderer;
|
||||
if (microformat) {
|
||||
songInfo.uploadDate = microformat.uploadDate;
|
||||
@ -87,8 +88,10 @@ const handleData = async (
|
||||
songInfo.imageSrc = thumbnails.at(-1)?.url.split('?')[0];
|
||||
if (songInfo.imageSrc) songInfo.image = await getImage(songInfo.imageSrc);
|
||||
|
||||
win.webContents.send('update-song-info', songInfo);
|
||||
win.webContents.send('ytmd:update-song-info', songInfo);
|
||||
}
|
||||
|
||||
return songInfo;
|
||||
};
|
||||
|
||||
// This variable will be filled with the callbacks once they register
|
||||
@ -100,35 +103,47 @@ const registerCallback = (callback: SongInfoCallback) => {
|
||||
callbacks.add(callback);
|
||||
};
|
||||
|
||||
let handlingData = false;
|
||||
|
||||
const registerProvider = (win: BrowserWindow) => {
|
||||
const dataMutex = new Mutex();
|
||||
let songInfo: SongInfo | null = null;
|
||||
|
||||
// This will be called when the song-info-front finds a new request with song data
|
||||
ipcMain.on('ytmd:video-src-changed', async (_, data: GetPlayerResponse) => {
|
||||
handlingData = true;
|
||||
await handleData(data, win);
|
||||
handlingData = false;
|
||||
for (const c of callbacks) {
|
||||
c(songInfo, 'ytmd:video-src-changed');
|
||||
const tempSongInfo = await dataMutex.runExclusive<SongInfo | null>(async () => {
|
||||
songInfo = await handleData(data, win);
|
||||
return songInfo;
|
||||
});
|
||||
|
||||
if (tempSongInfo) {
|
||||
for (const c of callbacks) {
|
||||
c(tempSongInfo, 'ytmd:video-src-changed');
|
||||
}
|
||||
}
|
||||
});
|
||||
ipcMain.on(
|
||||
'ytmd:play-or-paused',
|
||||
(
|
||||
async (
|
||||
_,
|
||||
{
|
||||
isPaused,
|
||||
elapsedSeconds,
|
||||
}: { isPaused: boolean; elapsedSeconds: number },
|
||||
) => {
|
||||
songInfo.isPaused = isPaused;
|
||||
songInfo.elapsedSeconds = elapsedSeconds;
|
||||
if (handlingData) {
|
||||
return;
|
||||
}
|
||||
const tempSongInfo = await dataMutex.runExclusive<SongInfo | null>(() => {
|
||||
if (!songInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const c of callbacks) {
|
||||
c(songInfo, 'ytmd:play-or-paused');
|
||||
songInfo.isPaused = isPaused;
|
||||
songInfo.elapsedSeconds = elapsedSeconds;
|
||||
|
||||
return songInfo;
|
||||
});
|
||||
|
||||
if (tempSongInfo) {
|
||||
for (const c of callbacks) {
|
||||
c(tempSongInfo, 'ytmd:play-or-paused');
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user