mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
use pseudo decorators
This commit is contained in:
@ -4,13 +4,14 @@ const { setMenuOptions } = require("../../config/plugins");
|
|||||||
const promptOptions = require("../../providers/prompt-options");
|
const promptOptions = require("../../providers/prompt-options");
|
||||||
const { clear, connect, registerRefresh, isConnected } = require("./back");
|
const { clear, connect, registerRefresh, isConnected } = require("./back");
|
||||||
|
|
||||||
let hasRegisterred = false;
|
const { singleton } = require("../../providers/decorators")
|
||||||
|
|
||||||
|
const registerRefreshOnce = singleton((refreshMenu) => {
|
||||||
|
registerRefresh(refreshMenu);
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = (win, options, refreshMenu) => {
|
module.exports = (win, options, refreshMenu) => {
|
||||||
if (!hasRegisterred) {
|
registerRefreshOnce(refreshMenu);
|
||||||
registerRefresh(refreshMenu);
|
|
||||||
hasRegisterred = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,6 +8,8 @@ const userData = app.getPath("userData");
|
|||||||
const tempIcon = path.join(userData, "tempIcon.png");
|
const tempIcon = path.join(userData, "tempIcon.png");
|
||||||
const tempBanner = path.join(userData, "tempBanner.png");
|
const tempBanner = path.join(userData, "tempBanner.png");
|
||||||
|
|
||||||
|
const { cache } = require("../../providers/decorators")
|
||||||
|
|
||||||
module.exports.ToastStyles = {
|
module.exports.ToastStyles = {
|
||||||
logo: 1,
|
logo: 1,
|
||||||
banner_centered_top: 2,
|
banner_centered_top: 2,
|
||||||
@ -31,6 +33,18 @@ module.exports.urgencyLevels = [
|
|||||||
{ name: "High", value: "critical" },
|
{ name: "High", value: "critical" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const nativeImageToLogo = cache((nativeImage) => {
|
||||||
|
const tempImage = nativeImage.resize({ height: 256 });
|
||||||
|
const margin = Math.max(tempImage.getSize().width - 256, 0);
|
||||||
|
|
||||||
|
return tempImage.crop({
|
||||||
|
x: Math.round(margin / 2),
|
||||||
|
y: 0,
|
||||||
|
width: 256,
|
||||||
|
height: 256,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
module.exports.notificationImage = (songInfo) => {
|
module.exports.notificationImage = (songInfo) => {
|
||||||
if (!songInfo.image) return icon;
|
if (!songInfo.image) return icon;
|
||||||
if (!config.get("interactive")) return nativeImageToLogo(songInfo.image);
|
if (!config.get("interactive")) return nativeImageToLogo(songInfo.image);
|
||||||
@ -44,7 +58,7 @@ module.exports.notificationImage = (songInfo) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.saveImage = (img, save_path) => {
|
module.exports.saveImage = cache((img, save_path) => {
|
||||||
try {
|
try {
|
||||||
fs.writeFileSync(save_path, img.toPNG());
|
fs.writeFileSync(save_path, img.toPNG());
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -52,19 +66,7 @@ module.exports.saveImage = (img, save_path) => {
|
|||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
return save_path;
|
return save_path;
|
||||||
}
|
});
|
||||||
|
|
||||||
|
|
||||||
function nativeImageToLogo(nativeImage) {
|
|
||||||
const tempImage = nativeImage.resize({ height: 256 });
|
|
||||||
const margin = Math.max((tempImage.getSize().width - 256), 0);
|
|
||||||
|
|
||||||
return tempImage.crop({
|
|
||||||
x: Math.round(margin / 2),
|
|
||||||
y: 0,
|
|
||||||
width: 256, height: 256
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.save_temp_icons = () => {
|
module.exports.save_temp_icons = () => {
|
||||||
for (const kind of Object.keys(module.exports.icons)) {
|
for (const kind of Object.keys(module.exports.icons)) {
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
const { getSongMenu } = require("../../providers/dom-elements");
|
const { getSongMenu } = require("../../providers/dom-elements");
|
||||||
const { ElementFromFile, templatePath } = require("../utils");
|
const { ElementFromFile, templatePath } = require("../utils");
|
||||||
|
const { singleton } = require("../../providers/decorators")
|
||||||
|
|
||||||
function $(selector) { return document.querySelector(selector); }
|
function $(selector) { return document.querySelector(selector); }
|
||||||
|
|
||||||
@ -22,7 +23,16 @@ const updatePlayBackSpeed = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let menu;
|
let menu;
|
||||||
let observingSlider = false;
|
|
||||||
|
const setupSliderListener = singleton(() => {
|
||||||
|
$('#playback-speed-slider').addEventListener('immediate-value-changed', e => {
|
||||||
|
playbackSpeed = e.detail.value || MIN_PLAYBACK_SPEED;
|
||||||
|
if (isNaN(playbackSpeed)) {
|
||||||
|
playbackSpeed = 1;
|
||||||
|
}
|
||||||
|
updatePlayBackSpeed();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
const observePopupContainer = () => {
|
const observePopupContainer = () => {
|
||||||
const observer = new MutationObserver(() => {
|
const observer = new MutationObserver(() => {
|
||||||
@ -32,10 +42,7 @@ const observePopupContainer = () => {
|
|||||||
|
|
||||||
if (menu && menu.parentElement.eventSink_?.matches('ytmusic-menu-renderer.ytmusic-player-bar') && !menu.contains(slider)) {
|
if (menu && menu.parentElement.eventSink_?.matches('ytmusic-menu-renderer.ytmusic-player-bar') && !menu.contains(slider)) {
|
||||||
menu.prepend(slider);
|
menu.prepend(slider);
|
||||||
if (!observingSlider) {
|
setupSliderListener();
|
||||||
setupSliderListener();
|
|
||||||
observingSlider = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -68,16 +75,6 @@ const setupWheelListener = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupSliderListener() {
|
|
||||||
$('#playback-speed-slider').addEventListener('immediate-value-changed', e => {
|
|
||||||
playbackSpeed = e.detail.value || MIN_PLAYBACK_SPEED;
|
|
||||||
if (isNaN(playbackSpeed)) {
|
|
||||||
playbackSpeed = 1;
|
|
||||||
}
|
|
||||||
updatePlayBackSpeed();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function forcePlaybackRate(e) {
|
function forcePlaybackRate(e) {
|
||||||
if (e.target.playbackRate !== playbackSpeed) {
|
if (e.target.playbackRate !== playbackSpeed) {
|
||||||
e.target.playbackRate = playbackSpeed
|
e.target.playbackRate = playbackSpeed
|
||||||
|
|||||||
@ -4,6 +4,8 @@ const { setOptions, setMenuOptions, isEnabled } = require("../../config/plugins"
|
|||||||
|
|
||||||
function $(selector) { return document.querySelector(selector); }
|
function $(selector) { return document.querySelector(selector); }
|
||||||
|
|
||||||
|
const { debounce } = require("../../providers/decorators");
|
||||||
|
|
||||||
let api, options;
|
let api, options;
|
||||||
|
|
||||||
module.exports = (_options) => {
|
module.exports = (_options) => {
|
||||||
@ -16,7 +18,27 @@ module.exports = (_options) => {
|
|||||||
}, { once: true, passive: true })
|
}, { once: true, passive: true })
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.moveVolumeHud = moveVolumeHud;
|
//without this function it would rewrite config 20 time when volume change by 20
|
||||||
|
const writeOptions = debounce(() => {
|
||||||
|
setOptions("precise-volume", options);
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
module.exports.moveVolumeHud = debounce((showVideo) => {
|
||||||
|
const volumeHud = $("#volumeHud");
|
||||||
|
if (!volumeHud) return;
|
||||||
|
volumeHud.style.top = showVideo
|
||||||
|
? `${($("ytmusic-player").clientHeight - $("video").clientHeight) / 2}px`
|
||||||
|
: 0;
|
||||||
|
}, 250);
|
||||||
|
|
||||||
|
const hideVolumeHud = debounce((volumeHud) => {
|
||||||
|
volumeHud.style.opacity = 0;
|
||||||
|
}, 2000);
|
||||||
|
|
||||||
|
const hideVolumeSlider = debounce((slider) => {
|
||||||
|
slider.classList.remove("on-hover");
|
||||||
|
}, 2500);
|
||||||
|
|
||||||
|
|
||||||
/** Restore saved volume and setup tooltip */
|
/** Restore saved volume and setup tooltip */
|
||||||
function firstRun() {
|
function firstRun() {
|
||||||
@ -67,33 +89,14 @@ function injectVolumeHud(noVid) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let hudMoveTimeout;
|
|
||||||
function moveVolumeHud(showVideo) {
|
|
||||||
clearTimeout(hudMoveTimeout);
|
|
||||||
const volumeHud = $('#volumeHud');
|
|
||||||
if (!volumeHud) return;
|
|
||||||
hudMoveTimeout = setTimeout(() => {
|
|
||||||
volumeHud.style.top = showVideo ? `${($('ytmusic-player').clientHeight - $('video').clientHeight) / 2}px` : 0;
|
|
||||||
}, 250)
|
|
||||||
}
|
|
||||||
|
|
||||||
let hudFadeTimeout;
|
|
||||||
|
|
||||||
function showVolumeHud(volume) {
|
function showVolumeHud(volume) {
|
||||||
let volumeHud = $("#volumeHud");
|
const volumeHud = $("#volumeHud");
|
||||||
if (!volumeHud) return;
|
if (!volumeHud) return;
|
||||||
|
|
||||||
volumeHud.textContent = volume + '%';
|
volumeHud.textContent = `${volume}%`;
|
||||||
volumeHud.style.opacity = 1;
|
volumeHud.style.opacity = 1;
|
||||||
|
|
||||||
if (hudFadeTimeout) {
|
hideVolumeHud(volumeHud);
|
||||||
clearTimeout(hudFadeTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
hudFadeTimeout = setTimeout(() => {
|
|
||||||
volumeHud.style.opacity = 0;
|
|
||||||
hudFadeTimeout = null;
|
|
||||||
}, 2000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add onwheel event to video player */
|
/** Add onwheel event to video player */
|
||||||
@ -110,17 +113,6 @@ function saveVolume(volume) {
|
|||||||
writeOptions();
|
writeOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
//without this function it would rewrite config 20 time when volume change by 20
|
|
||||||
let writeTimeout;
|
|
||||||
function writeOptions() {
|
|
||||||
if (writeTimeout) clearTimeout(writeTimeout);
|
|
||||||
|
|
||||||
writeTimeout = setTimeout(() => {
|
|
||||||
setOptions("precise-volume", options);
|
|
||||||
writeTimeout = null;
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add onwheel event to play bar and also track if play bar is hovered*/
|
/** Add onwheel event to play bar and also track if play bar is hovered*/
|
||||||
function setupPlaybar() {
|
function setupPlaybar() {
|
||||||
const playerbar = $("ytmusic-player-bar");
|
const playerbar = $("ytmusic-player-bar");
|
||||||
@ -199,23 +191,12 @@ function updateVolumeSlider() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let volumeHoverTimeoutID;
|
|
||||||
|
|
||||||
function showVolumeSlider() {
|
function showVolumeSlider() {
|
||||||
const slider = $("#volume-slider");
|
const slider = $("#volume-slider");
|
||||||
// This class display the volume slider if not in minimized mode
|
// This class display the volume slider if not in minimized mode
|
||||||
slider.classList.add("on-hover");
|
slider.classList.add("on-hover");
|
||||||
// Reset timeout if previous one hasn't completed
|
|
||||||
if (volumeHoverTimeoutID) {
|
hideVolumeSlider(slider);
|
||||||
clearTimeout(volumeHoverTimeoutID);
|
|
||||||
}
|
|
||||||
// Timeout to remove volume preview after 3 seconds if playbar isn't hovered
|
|
||||||
volumeHoverTimeoutID = setTimeout(() => {
|
|
||||||
volumeHoverTimeoutID = null;
|
|
||||||
if (!$("ytmusic-player-bar").classList.contains("on-hover")) {
|
|
||||||
slider.classList.remove("on-hover");
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set new volume as tooltip for volume slider and icon + expanding slider (appears when window size is small)
|
// Set new volume as tooltip for volume slider and icon + expanding slider (appears when window size is small)
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
const { ipcRenderer } = require("electron");
|
const { ipcRenderer } = require("electron");
|
||||||
const { getImage } = require("./song-info");
|
const { getImage } = require("./song-info");
|
||||||
|
const { singleton } = require("../providers/decorators");
|
||||||
|
|
||||||
global.songInfo = {};
|
global.songInfo = {};
|
||||||
|
|
||||||
@ -14,17 +15,8 @@ ipcRenderer.on("update-song-info", async (_, extractedSongInfo) => {
|
|||||||
// used because 'loadeddata' or 'loadedmetadata' weren't firing on song start for some users (https://github.com/th-ch/youtube-music/issues/473)
|
// used because 'loadeddata' or 'loadedmetadata' weren't firing on song start for some users (https://github.com/th-ch/youtube-music/issues/473)
|
||||||
const srcChangedEvent = new CustomEvent('srcChanged');
|
const srcChangedEvent = new CustomEvent('srcChanged');
|
||||||
|
|
||||||
const singleton = (fn) => {
|
|
||||||
let called = false;
|
|
||||||
return (...args) => {
|
|
||||||
if (called) return;
|
|
||||||
called = true;
|
|
||||||
return fn(...args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.setupSeekedListener = singleton(() => {
|
module.exports.setupSeekedListener = singleton(() => {
|
||||||
document.querySelector('video')?.addEventListener('seeked', v => ipcRenderer.send('seeked', v.target.currentTime));
|
$('video')?.addEventListener('seeked', v => ipcRenderer.send('seeked', v.target.currentTime));
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports.setupTimeChangedListener = singleton(() => {
|
module.exports.setupTimeChangedListener = singleton(() => {
|
||||||
|
|||||||
@ -4,6 +4,8 @@ const fetch = require("node-fetch");
|
|||||||
|
|
||||||
const config = require("../config");
|
const config = require("../config");
|
||||||
|
|
||||||
|
const { cache } = require("../providers/decorators")
|
||||||
|
|
||||||
// Fill songInfo with empty values
|
// Fill songInfo with empty values
|
||||||
/**
|
/**
|
||||||
* @typedef {songInfo} SongInfo
|
* @typedef {songInfo} SongInfo
|
||||||
@ -25,16 +27,21 @@ const songInfo = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Grab the native image using the src
|
// Grab the native image using the src
|
||||||
const getImage = async (src) => {
|
const getImage = cache (
|
||||||
const result = await fetch(src);
|
/**
|
||||||
const buffer = await result.buffer();
|
* @returns {Promise<Electron.NativeImage>}
|
||||||
const output = nativeImage.createFromBuffer(buffer);
|
*/
|
||||||
if (output.isEmpty() && !src.endsWith(".jpg") && src.includes(".jpg")) { // fix hidden webp files (https://github.com/th-ch/youtube-music/issues/315)
|
async (src) => {
|
||||||
return getImage(src.slice(0, src.lastIndexOf(".jpg") + 4));
|
const result = await fetch(src);
|
||||||
} else {
|
const buffer = await result.buffer();
|
||||||
return output;
|
const output = nativeImage.createFromBuffer(buffer);
|
||||||
|
if (output.isEmpty() && !src.endsWith(".jpg") && src.includes(".jpg")) { // fix hidden webp files (https://github.com/th-ch/youtube-music/issues/315)
|
||||||
|
return getImage(src.slice(0, src.lastIndexOf(".jpg") + 4));
|
||||||
|
} else {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
);
|
||||||
|
|
||||||
const handleData = async (responseText, win) => {
|
const handleData = async (responseText, win) => {
|
||||||
const data = JSON.parse(responseText);
|
const data = JSON.parse(responseText);
|
||||||
@ -60,13 +67,10 @@ const handleData = async (responseText, win) => {
|
|||||||
songInfo.videoId = videoDetails.videoId;
|
songInfo.videoId = videoDetails.videoId;
|
||||||
songInfo.album = data?.videoDetails?.album; // Will be undefined if video exist
|
songInfo.album = data?.videoDetails?.album; // Will be undefined if video exist
|
||||||
|
|
||||||
const oldUrl = songInfo.imageSrc;
|
|
||||||
const thumbnails = videoDetails.thumbnail?.thumbnails;
|
const thumbnails = videoDetails.thumbnail?.thumbnails;
|
||||||
songInfo.imageSrc = thumbnails[thumbnails.length - 1]?.url.split("?")[0];
|
songInfo.imageSrc = thumbnails[thumbnails.length - 1]?.url.split("?")[0];
|
||||||
if (oldUrl !== songInfo.imageSrc) {
|
songInfo.image = await getImage(songInfo.imageSrc);
|
||||||
songInfo.image = await getImage(songInfo.imageSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
win.webContents.send("update-song-info", JSON.stringify(songInfo));
|
win.webContents.send("update-song-info", JSON.stringify(songInfo));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user