diff --git a/config/defaults.js b/config/defaults.js
index e92a5711..863e8b25 100644
--- a/config/defaults.js
+++ b/config/defaults.js
@@ -55,8 +55,10 @@ const defaultConfig = {
enabled: false,
unpauseNotification: false,
urgency: "normal", //has effect only on Linux
- interactive: true, //has effect only on Windows
- smallInteractive: false //has effect only on Windows
+ // the following has effect only on Windows
+ interactive: true,
+ toastStyle: 1, // see plugins/notifications/utils for more info
+ hideButtonText: false
},
"precise-volume": {
enabled: false,
diff --git a/index.js b/index.js
index 7b414352..eed0c040 100644
--- a/index.js
+++ b/index.js
@@ -75,6 +75,7 @@ function onClosed() {
mainWindow = null;
}
+/** @param {Electron.BrowserWindow} win */
function loadPlugins(win) {
injectCSS(win.webContents, path.join(__dirname, "youtube-music.css"));
// Load user CSS
diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js
index 98dde0f8..419e27d3 100644
--- a/plugins/notifications/back.js
+++ b/plugins/notifications/back.js
@@ -2,8 +2,9 @@ const { Notification } = require("electron");
const is = require("electron-is");
const registerCallback = require("../../providers/song-info");
const { notificationImage } = require("./utils");
+const config = require("./config");
-const notify = (info, options) => {
+const notify = (info) => {
// Fill the notification with content
const notification = {
@@ -11,7 +12,7 @@ const notify = (info, options) => {
body: info.artist,
icon: notificationImage(info),
silent: true,
- urgency: options.urgency,
+ urgency: config.get('urgency'),
};
// Send the notification
@@ -21,24 +22,26 @@ const notify = (info, options) => {
return currentNotification;
};
-const setup = (options) => {
+const setup = () => {
let oldNotification;
let currentUrl;
registerCallback(songInfo => {
- if (!songInfo.isPaused && (songInfo.url !== currentUrl || options.unpauseNotification)) {
+ if (!songInfo.isPaused && (songInfo.url !== currentUrl || config.get('unpauseNotification'))) {
// Close the old notification
oldNotification?.close();
currentUrl = songInfo.url;
// This fixes a weird bug that would cause the notification to be updated instead of showing
- setTimeout(() => { oldNotification = notify(songInfo, options) }, 10);
+ setTimeout(() => { oldNotification = notify(songInfo) }, 10);
}
});
}
+/** @param {Electron.BrowserWindow} win */
module.exports = (win, options) => {
+ config.init(options);
// Register the callback for new song information
is.windows() && options.interactive ?
- require("./interactive")(win, options) :
- setup(options);
+ require("./interactive")(win) :
+ setup();
};
diff --git a/plugins/notifications/config.js b/plugins/notifications/config.js
new file mode 100644
index 00000000..dfba8ca5
--- /dev/null
+++ b/plugins/notifications/config.js
@@ -0,0 +1,22 @@
+const { setOptions, setMenuOptions } = require("../../config/plugins");
+
+let config;
+
+module.exports.init = (options) => {
+ config = options;
+}
+
+module.exports.setAndMaybeRestart = (option, value) => {
+ config[option] = value;
+ setMenuOptions("notifications", config);
+}
+
+module.exports.set = (option, value) => {
+ config[option] = value;
+ setOptions("notifications", config);
+}
+
+module.exports.get = (option) => {
+ let res = config[option];
+ return res;
+}
diff --git a/plugins/notifications/interactive.js b/plugins/notifications/interactive.js
index 1b3d434f..dac18700 100644
--- a/plugins/notifications/interactive.js
+++ b/plugins/notifications/interactive.js
@@ -1,31 +1,38 @@
-const { notificationImage, icons, save_temp_icons } = require("./utils");
+const { notificationImage, icons, save_temp_icons, secondsToMinutes, ToastStyles } = require("./utils");
const getSongControls = require('../../providers/song-controls');
const registerCallback = require("../../providers/song-info");
const { changeProtocolHandler } = require("../../providers/protocol-handler");
-const { Notification, app } = require("electron");
+const { Notification, app, ipcMain } = require("electron");
const path = require('path');
-let songControls;
-let config;
-let savedNotification;
+const config = require("./config");
-module.exports = (win, _config) => {
+let songControls;
+let savedNotification;
+// TODO create banner function
+/** @param {Electron.BrowserWindow} win */
+module.exports = (win) => {
songControls = getSongControls(win);
- config = _config;
- if (app.isPackaged && !config.smallInteractive) save_temp_icons();
+
+ let currentSeconds = 0;
+ ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener'));
+
+ ipcMain.on('timeChanged', (_, t) => currentSeconds = t);
+
+ if (app.isPackaged) save_temp_icons();
let lastSongInfo = { url: undefined };
// Register songInfoCallback
registerCallback(songInfo => {
- if (!songInfo.isPaused && (songInfo.url !== lastSongInfo.url || config.unpauseNotification)) {
+ if (!songInfo.isPaused && (songInfo.url !== lastSongInfo.url || config.get("unpauseNotification"))) {
lastSongInfo = { ...songInfo };
sendXML(songInfo);
}
});
- //TODO on app before close, close notification
+ // TODO on app before close, close notification
app.once("before-quit", () => {
savedNotification?.close();
});
@@ -34,9 +41,9 @@ module.exports = (win, _config) => {
(cmd) => {
if (Object.keys(songControls).includes(cmd)) {
songControls[cmd]();
- if (cmd === 'pause' || (cmd === 'play' && !config.unpauseNotification)) {
+ if (cmd === 'pause' || (cmd === 'play' && !config.get("unpauseNotification"))) {
setImmediate(() =>
- sendXML({ ...lastSongInfo, isPaused: cmd === 'pause' })
+ sendXML({ ...lastSongInfo, isPaused: cmd === 'pause', elapsedSeconds: currentSeconds })
);
}
}
@@ -45,20 +52,20 @@ module.exports = (win, _config) => {
}
function sendXML(songInfo) {
- const imgSrc = notificationImage(songInfo, true);
+ const iconSrc = notificationImage(songInfo);
savedNotification?.close();
savedNotification = new Notification({
title: songInfo.title || "Playing",
body: songInfo.artist,
- icon: imgSrc,
+ icon: iconSrc,
silent: true,
// https://learn.microsoft.com/en-us/uwp/schemas/tiles/toastschema/schema-root
// https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-schema
// https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/adaptive-interactive-toasts?tabs=xml
// https://learn.microsoft.com/en-us/uwp/api/windows.ui.notifications.toasttemplatetype
- toastXml: get_xml_custom(),
+ toastXml: get_xml(songInfo, iconSrc),
});
savedNotification.on("close", (_) => {
@@ -68,209 +75,131 @@ function sendXML(songInfo) {
savedNotification.show();
}
+const get_xml = (songInfo, iconSrc) => {
+ switch (config.get("style")) {
+ default:
+ case ToastStyles.logo:
+ case ToastStyles.legacy:
+ return xml_logo(songInfo, iconSrc);
+ case ToastStyles.banner_top_custom:
+ return xml_banner_top_custom(songInfo, iconSrc);
+ case ToastStyles.hero:
+ return xml_hero(songInfo, iconSrc);
+ case ToastStyles.banner_bottom:
+ return xml_banner_bottom(songInfo, iconSrc);
+ case ToastStyles.banner_centered_bottom:
+ return xml_banner_centered_bottom(songInfo, iconSrc);
+ case ToastStyles.banner_centered_top:
+ return xml_banner_centered_top(songInfo, iconSrc);
+ };
+}
+
const iconLocation = app.isPackaged ?
path.resolve(app.getPath("userData"), 'icons') :
path.resolve(__dirname, '..', '..', 'assets/media-icons-black');
+const display = (kind) => {
+ if (config.get("style") === ToastStyles.legacy ) {
+ return `content="${icons[kind]}"`;
+ } else {
+ return `\
+ content="${kind.charAt(0).toUpperCase() + kind.slice(1)}"\
+ imageUri="file:///${path.resolve(__dirname, iconLocation, `${kind}.png`)}"
+ `;
+ }
+}
-const getButton = (kind) =>
+const getButton = (kind) =>
``;
-const display = (kind) =>
- config.smallInteractive ?
- `content="${icons[kind]}"` :
- `content="${kind.charAt(0).toUpperCase() + kind.slice(1)}" imageUri="file:///${path.resolve(__dirname, iconLocation, `${kind}.png`)}"`;
-
-
-const get_xml = (songInfo, options, imgSrc) => `
-
-
-
-
-
- ${songInfo.title}
- ${songInfo.artist}
-
-
-
+const getButtons = (isPaused) => `\
${getButton('previous')}
- ${songInfo.isPaused ? getButton('play') : getButton('pause')}
+ ${isPaused ? getButton('play') : getButton('pause')}
${getButton('next')}
-
-`
+ \
+`;
-// **************************************************** //
-// PREMADE TEMPLATES FOR TESTING
-// DELETE AFTER TESTING
-// **************************************************** //
-
-const get_xml_custom = () => xml_banner_centered_top;
-
-const xml_logo_ascii = `
-
+const toast = (content, isPaused) => `\
+
-
- The Last Stand of Frej
- Amon Amarth
+ ${content}
-
-
-
-
-
-
-`;
+ ${getButtons(isPaused)}
+`;
+const xml_logo = ({title, artist, isPaused}, imgSrc) => toast(`\
+
+ ${title}
+ ${artist}\
+`, isPaused);
-const xml_logo_icons_notext =`
-
-
-
-
-
- The Last Stand of Frej
- Amon Amarth
-
-
+const xml_hero = ({title, artist, isPaused}, imgSrc) => toast(`\
+
+ ${title}
+ ${artist}\
+`, isPaused);
-
-
-
-
-
-
-`;
+const xml_banner_bottom = ({title, artist, isPaused}, imgSrc) => toast(`\
+
+ ${title}
+ ${artist}\
+`, isPaused);
-const buttons_icons = `
-
-
-
-
-
-`;
-
-const xml_logo_icons = `
-
-
-
-
-
- The Last Stand of Frej
- Amon Amarth
-
-
-
- ${buttons_icons}
-
-`;
-
-const xml_hero = `
-
-
-
-
-
- The Last Stand of Frej
- Amon Amarth
-
-
-
- ${buttons_icons}
-
-`;
-
-const xml_banner_bottom = `
-
-
-
-
-
- The Last Stand of Frej
- Amon Amarth
-
-
-
- ${buttons_icons}
-
-`;
-
-const xml_banner_top_custom = `
-
-
-
-
-
+const xml_banner_top_custom = (songInfo, imgSrc) => toast(`\
+
ㅤ
- The Last Stand of Frej
- Amon Amarth
+ ${songInfo.title}
+ ${songInfo.artist}
-
- Surtur Rising
- 2011
-
-
-
-
+ ${xml_more_data(songInfo)}
+ \
+`, songInfo.isPaused);
- ${buttons_icons}
-
+const xml_more_data = ({ album, elapsedSeconds, songDuration })=> `\
+
+ ${album ?
+ `${album}` : ''}
+ ${secondsToMinutes(elapsedSeconds)} / ${secondsToMinutes(songDuration)}
+\
`;
-const xml_banner_centered_bottom = `
-
-
-
-
+const xml_banner_centered_bottom = ({title, artist, isPaused}, imgSrc) => toast(`\
ㅤ
- The Last Stand of Frej
- Amon Amarth
+ ${title}
+ ${artist}
-
-
-
+ \
+`, isPaused);
- ${buttons_icons}
-
-`;
-
-const xml_banner_centered_top = `
-
-
-
-
-
+const xml_banner_centered_top = ({title, artist, isPaused}, imgSrc) => toast(`\
+
ㅤ
- The Last Stand of Frej
- Amon Amarth
+ ${title}
+ ${artist}
-
-
-
+ \
+`, isPaused);
- ${buttons_icons}
-
-`;
+const titleFontPicker = (title) => {
+ if (title.length <= 13) {
+ return 'Header';
+ } else if (title.length <= 22) {
+ return 'Subheader';
+ } else if (title.length <= 26) {
+ return 'Title';
+ } else {
+ return 'Subtitle';
+ }
+}
diff --git a/plugins/notifications/menu.js b/plugins/notifications/menu.js
index 7c2776f8..6d238dd7 100644
--- a/plugins/notifications/menu.js
+++ b/plugins/notifications/menu.js
@@ -1,5 +1,6 @@
-const { urgencyLevels, setOption } = require("./utils");
+const { urgencyLevels, ToastStyles, snakeToCamel } = require("./utils");
const is = require("electron-is");
+const config = require("./config");
module.exports = (_win, options) => [
...(is.linux()
@@ -10,7 +11,7 @@ module.exports = (_win, options) => [
label: level.name,
type: "radio",
checked: options.urgency === level.value,
- click: () => setOption(options, "urgency", level.value),
+ click: () => config.set("urgency", level.value),
})),
},
]
@@ -21,13 +22,12 @@ module.exports = (_win, options) => [
label: "Interactive Notifications",
type: "checkbox",
checked: options.interactive,
- click: (item) => setOption(options, "interactive", item.checked),
+ // doesn't update until restart
+ click: (item) => config.setAndMaybeRestart("interactive", item.checked),
},
{
- label: "Smaller Interactive Notifications",
- type: "checkbox",
- checked: options.smallInteractive,
- click: (item) => setOption(options, "smallInteractive", item.checked),
+ label: "Toast Style",
+ submenu: getToastStyleMenuItems(options)
},
]
: []),
@@ -35,6 +35,29 @@ module.exports = (_win, options) => [
label: "Show notification on unpause",
type: "checkbox",
checked: options.unpauseNotification,
- click: (item) => setOption(options, "unpauseNotification", item.checked),
+ click: (item) => config.set("unpauseNotification", item.checked),
},
];
+
+function getToastStyleMenuItems(options) {
+ const arr = new Array(Object.keys(ToastStyles).length + 1);
+
+ arr[0] = {
+ label: "Hide Button Text",
+ type: "checkbox",
+ checked: options.hideButtonText,
+ click: (item) => config.set("hideButtonText", item.checked),
+ }
+
+ // ToastStyles index starts from 1
+ for (const [name, index] of Object.entries(ToastStyles)) {
+ arr[index] = {
+ label: snakeToCamel(name),
+ type: "radio",
+ checked: options.style === index,
+ click: () => config.set("style", index),
+ };
+ }
+
+ return arr;
+}
diff --git a/plugins/notifications/utils.js b/plugins/notifications/utils.js
index 64309c02..5e531ecc 100644
--- a/plugins/notifications/utils.js
+++ b/plugins/notifications/utils.js
@@ -1,11 +1,22 @@
-const { setMenuOptions } = require("../../config/plugins");
const path = require("path");
const { app } = require("electron");
const fs = require("fs");
+const config = require("./config");
const icon = "assets/youtube-music.png";
const userData = app.getPath("userData");
const tempIcon = path.join(userData, "tempIcon.png");
+const tempBanner = path.join(userData, "tempBanner.png");
+
+module.exports.ToastStyles = {
+ logo: 1,
+ banner_centered_top: 2,
+ hero: 3,
+ banner_top_custom: 4,
+ banner_centered_bottom: 5,
+ banner_bottom: 6,
+ legacy: 7
+}
module.exports.icons = {
play: "\u{1405}", // ᐅ
@@ -14,37 +25,47 @@ module.exports.icons = {
previous: "\u{1438}" // ᐸ
}
-module.exports.setOption = (options, option, value) => {
- options[option] = value;
- setMenuOptions("notifications", options)
-}
-
module.exports.urgencyLevels = [
{ name: "Low", value: "low" },
{ name: "Normal", value: "normal" },
{ name: "High", value: "critical" },
];
-module.exports.notificationImage = (songInfo, saveIcon = false) => {
- //return local path to temp icon
- if (saveIcon && !!songInfo.image) {
- try {
- fs.writeFileSync(tempIcon,
- centerNativeImage(songInfo.image)
- .toPNG()
- );
- } catch (err) {
- console.log(`Error writing song icon to disk:\n${err.toString()}`)
- return icon;
- }
- return tempIcon;
- }
- //else: return image
- return songInfo.image
- ? centerNativeImage(songInfo.image)
- : icon
+module.exports.notificationImage = (songInfo) => {
+ if (!songInfo.image) return icon;
+ if (!config.get("interactive")) return nativeImageToLogo(songInfo.image);
+
+ switch(config.get("style")) {
+ case module.exports.ToastStyles.logo:
+ case module.exports.ToastStyles.legacy:
+ return this.saveImage(nativeImageToLogo(songInfo.image), tempIcon);
+ default:
+ return this.saveImage(songInfo.image, tempBanner);
+ };
};
+module.exports.saveImage = (img, save_path) => {
+ try {
+ fs.writeFileSync(save_path, img.toPNG());
+ } catch (err) {
+ console.log(`Error writing song icon to disk:\n${err.toString()}`)
+ return icon;
+ }
+ 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 = () => {
for (const kind of Object.keys(module.exports.icons)) {
const destinationPath = path.join(userData, 'icons', `${kind}.png`);
@@ -55,13 +76,16 @@ module.exports.save_temp_icons = () => {
}
};
-function centerNativeImage(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.snakeToCamel = (str) => {
+ return str.replace(/([-_][a-z]|^[a-z])/g, (group) =>
+ group.toUpperCase()
+ .replace('-', ' ')
+ .replace('_', ' ')
+ );
+}
+
+module.exports.secondsToMinutes = (seconds) => {
+ const minutes = Math.floor(seconds / 60);
+ const secondsLeft = seconds % 60;
+ return `${minutes}:${secondsLeft < 10 ? '0' : ''}${secondsLeft}`;
}
diff --git a/plugins/shortcuts/mpris.js b/plugins/shortcuts/mpris.js
index bf427b58..d84f655e 100644
--- a/plugins/shortcuts/mpris.js
+++ b/plugins/shortcuts/mpris.js
@@ -18,6 +18,7 @@ function setupMPRIS() {
return player;
}
+/** @param {Electron.BrowserWindow} win */
function registerMPRIS(win) {
const songControls = getSongControls(win);
const { playPause, next, previous, volumeMinus10, volumePlus10 } = songControls;
@@ -30,6 +31,13 @@ function registerMPRIS(win) {
const player = setupMPRIS();
+ ipcMain.on("apiLoaded", () => {
+ win.webContents.send("setupSeekedListener", "mpris");
+ win.webContents.send("setupTimeChangedListener", "mpris");
+ win.webContents.send("setupRepeatChangedListener", "mpris");
+ win.webContents.send("setupVolumeChangedListener", "mpris");
+ });
+
ipcMain.on('seeked', (_, t) => player.seeked(secToMicro(t)));
let currentSeconds = 0;
diff --git a/plugins/tuna-obs/back.js b/plugins/tuna-obs/back.js
index 0a2bc3a3..29ed9dd8 100644
--- a/plugins/tuna-obs/back.js
+++ b/plugins/tuna-obs/back.js
@@ -27,7 +27,9 @@ const post = async (data) => {
fetch(url, { method: 'POST', headers, body: JSON.stringify({ data }) }).catch(e => console.log(`Error: '${e.code || e.errno}' - when trying to access obs-tuna webserver at port ${port}`));
}
+/** @param {Electron.BrowserWindow} win */
module.exports = async (win) => {
+ ipcMain.on('apiLoaded', () => win.webContents.send('setupTimeChangedListener'));
ipcMain.on('timeChanged', async (_, t) => {
if (!data.title) return;
data.progress = secToMilisec(t);
diff --git a/preload.js b/preload.js
index 3f1d23a5..6c6abae9 100644
--- a/preload.js
+++ b/preload.js
@@ -95,6 +95,8 @@ function listenForApiLoad() {
function onApiLoaded() {
document.dispatchEvent(new CustomEvent('apiLoaded', { detail: api }));
+ //setImmediate()
+ ipcRenderer.send('apiLoaded');
// Remove upgrade button
if (config.get("options.removeUpgradeButton")) {
diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js
index 07c50542..4bc33274 100644
--- a/providers/song-controls-front.js
+++ b/providers/song-controls-front.js
@@ -1,13 +1,8 @@
const { ipcRenderer } = require("electron");
-const config = require("../config");
-const is = require("electron-is");
module.exports.setupSongControls = () => {
document.addEventListener('apiLoaded', e => {
ipcRenderer.on("seekTo", (_, t) => e.detail.seekTo(t));
ipcRenderer.on("seekBy", (_, t) => e.detail.seekBy(t));
- if (is.linux() && config.plugins.isEnabled('shortcuts')) { // MPRIS Enabled
- document.querySelector('video').addEventListener('seeked', v => ipcRenderer.send('seeked', v.target.currentTime));
- }
}, { once: true, passive: true })
};
diff --git a/providers/song-info-front.js b/providers/song-info-front.js
index 03cf2957..8a57eda2 100644
--- a/providers/song-info-front.js
+++ b/providers/song-info-front.js
@@ -1,9 +1,6 @@
const { ipcRenderer } = require("electron");
-const is = require('electron-is');
const { getImage } = require("./song-info");
-const config = require("../config");
-
global.songInfo = {};
const $ = s => document.querySelector(s);
@@ -17,14 +14,63 @@ 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)
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(() => {
+ document.querySelector('video')?.addEventListener('seeked', v => ipcRenderer.send('seeked', v.target.currentTime));
+});
+
+module.exports.setupTimeChangedListener = singleton(() => {
+ const progressObserver = new MutationObserver(mutations => {
+ ipcRenderer.send('timeChanged', mutations[0].target.value);
+ global.songInfo.elapsedSeconds = mutations[0].target.value;
+ });
+ progressObserver.observe($('#progress-bar'), { attributeFilter: ["value"] });
+});
+
+module.exports.setupRepeatChangedListener = singleton(() => {
+ const repeatObserver = new MutationObserver(mutations => {
+ ipcRenderer.send('repeatChanged', mutations[0].target.title);
+ });
+ repeatObserver.observe($('#right-controls .repeat'), { attributeFilter: ["title"] });
+
+ // Emit the initial value as well; as it's persistent between launches.
+ ipcRenderer.send('repeatChanged', $('#right-controls .repeat').title);
+});
+
+module.exports.setupVolumeChangedListener = singleton((api) => {
+ $('video').addEventListener('volumechange', (_) => {
+ ipcRenderer.send('volumeChanged', api.getVolume());
+ });
+ // Emit the initial value as well; as it's persistent between launches.
+ ipcRenderer.send('volumeChanged', api.getVolume());
+});
+
module.exports = () => {
document.addEventListener('apiLoaded', apiEvent => {
- if (config.plugins.isEnabled('tuna-obs') ||
- (is.linux() && config.plugins.isEnabled('shortcuts'))) {
- setupTimeChangeListener();
- setupRepeatChangeListener();
- setupVolumeChangeListener(apiEvent.detail);
- }
+ ipcRenderer.on("setupTimeChangedListener", async () => {
+ this.setupTimeChangedListener();
+ });
+
+ ipcRenderer.on("setupRepeatChangedListener", async () => {
+ this.setupRepeatChangedListener();
+ });
+
+ ipcRenderer.on("setupVolumeChangedListener", async () => {
+ this.setupVolumeChangedListener(apiEvent.detail);
+ });
+
+ ipcRenderer.on("setupSeekedListener", async () => {
+ this.setupSeekedListener();
+ });
+
const video = $('video');
// name = "dataloaded" and abit later "dataupdated"
apiEvent.detail.addEventListener('videodatachange', (name, _dataEvent) => {
@@ -57,29 +103,3 @@ module.exports = () => {
}
}, { once: true, passive: true });
};
-
-function setupTimeChangeListener() {
- const progressObserver = new MutationObserver(mutations => {
- ipcRenderer.send('timeChanged', mutations[0].target.value);
- global.songInfo.elapsedSeconds = mutations[0].target.value;
- });
- progressObserver.observe($('#progress-bar'), { attributeFilter: ["value"] })
-}
-
-function setupRepeatChangeListener() {
- const repeatObserver = new MutationObserver(mutations => {
- ipcRenderer.send('repeatChanged', mutations[0].target.title);
- });
- repeatObserver.observe($('#right-controls .repeat'), { attributeFilter: ["title"] });
-
- // Emit the initial value as well; as it's persistent between launches.
- ipcRenderer.send('repeatChanged', $('#right-controls .repeat').title);
-}
-
-function setupVolumeChangeListener(api) {
- $('video').addEventListener('volumechange', (_) => {
- ipcRenderer.send('volumeChanged', api.getVolume());
- });
- // Emit the initial value as well; as it's persistent between launches.
- ipcRenderer.send('volumeChanged', api.getVolume());
-}
diff --git a/providers/song-info.js b/providers/song-info.js
index 8181e6ad..1e26b99c 100644
--- a/providers/song-info.js
+++ b/providers/song-info.js
@@ -61,7 +61,8 @@ const handleData = async (responseText, win) => {
songInfo.album = data?.videoDetails?.album; // Will be undefined if video exist
const oldUrl = songInfo.imageSrc;
- songInfo.imageSrc = videoDetails.thumbnail?.thumbnails?.pop()?.url.split("?")[0];
+ const thumbnails = videoDetails.thumbnail?.thumbnails;
+ songInfo.imageSrc = thumbnails[thumbnails.length - 1]?.url.split("?")[0];
if (oldUrl !== songInfo.imageSrc) {
songInfo.image = await getImage(songInfo.imageSrc);
}