mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
Merge branch 'master' into mpris+tuna-fix
This commit is contained in:
@ -63,7 +63,7 @@
|
|||||||
"npm": "Please use yarn and not npm"
|
"npm": "Please use yarn and not npm"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cliqz/adblocker-electron": "^1.22.6",
|
"@cliqz/adblocker-electron": "^1.23.0",
|
||||||
"@ffmpeg/core": "^0.10.0",
|
"@ffmpeg/core": "^0.10.0",
|
||||||
"@ffmpeg/ffmpeg": "^0.10.0",
|
"@ffmpeg/ffmpeg": "^0.10.0",
|
||||||
"async-mutex": "^0.3.2",
|
"async-mutex": "^0.3.2",
|
||||||
@ -78,11 +78,11 @@
|
|||||||
"electron-localshortcut": "^3.2.1",
|
"electron-localshortcut": "^3.2.1",
|
||||||
"electron-store": "^7.0.3",
|
"electron-store": "^7.0.3",
|
||||||
"electron-unhandled": "^3.0.2",
|
"electron-unhandled": "^3.0.2",
|
||||||
"electron-updater": "^4.4.6",
|
"electron-updater": "^4.6.1",
|
||||||
"filenamify": "^4.3.0",
|
"filenamify": "^4.3.0",
|
||||||
"md5": "^2.3.0",
|
"md5": "^2.3.0",
|
||||||
"mpris-service": "^2.1.2",
|
"mpris-service": "^2.1.2",
|
||||||
"node-fetch": "^2.6.2",
|
"node-fetch": "^2.6.6",
|
||||||
"node-notifier": "^9.0.1",
|
"node-notifier": "^9.0.1",
|
||||||
"ytdl-core": "^4.9.1",
|
"ytdl-core": "^4.9.1",
|
||||||
"ytpl": "^2.2.3"
|
"ytpl": "^2.2.3"
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#nav-bar-background, #header.ytmusic-item-section-renderer {
|
#nav-bar-background,
|
||||||
|
#header.ytmusic-item-section-renderer,
|
||||||
|
ytmusic-tabs {
|
||||||
background: rgba(0, 0, 0, 0.3) !important;
|
background: rgba(0, 0, 0, 0.3) !important;
|
||||||
backdrop-filter: blur(18px) !important;
|
backdrop-filter: blur(8px) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-bar-divider {
|
#nav-bar-divider {
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
document.addEventListener('apiLoaded', () => {
|
document.addEventListener('apiLoaded', apiEvent => {
|
||||||
document.querySelector('video').addEventListener('loadeddata', e => {
|
apiEvent.detail.addEventListener('videodatachange', name => {
|
||||||
|
if (name === 'dataloaded') {
|
||||||
|
apiEvent.detail.pauseVideo();
|
||||||
|
document.querySelector('video').ontimeupdate = e => {
|
||||||
e.target.pause();
|
e.target.pause();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document.querySelector('video').ontimeupdate = null;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}, { once: true, passive: true })
|
}, { once: true, passive: true })
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,25 +1,23 @@
|
|||||||
const { existsSync, mkdirSync } = require("fs");
|
const { existsSync, mkdirSync } = require("fs");
|
||||||
const { join } = require("path");
|
const { join } = require("path");
|
||||||
const { URL } = require("url");
|
|
||||||
|
|
||||||
const { dialog } = require("electron");
|
const { dialog, ipcMain } = require("electron");
|
||||||
const is = require("electron-is");
|
const is = require("electron-is");
|
||||||
const ytpl = require("ytpl");
|
const ytpl = require("ytpl");
|
||||||
const chokidar = require('chokidar');
|
const chokidar = require('chokidar');
|
||||||
|
|
||||||
const { setOptions } = require("../../config/plugins");
|
const { setOptions } = require("../../config/plugins");
|
||||||
const registerCallback = require("../../providers/song-info");
|
|
||||||
const { sendError } = require("./back");
|
const { sendError } = require("./back");
|
||||||
const { defaultMenuDownloadLabel, getFolder } = require("./utils");
|
const { defaultMenuDownloadLabel, getFolder } = require("./utils");
|
||||||
|
|
||||||
let downloadLabel = defaultMenuDownloadLabel;
|
let downloadLabel = defaultMenuDownloadLabel;
|
||||||
let metadataURL = undefined;
|
let playingPlaylistId = undefined;
|
||||||
let callbackIsRegistered = false;
|
let callbackIsRegistered = false;
|
||||||
|
|
||||||
module.exports = (win, options) => {
|
module.exports = (win, options) => {
|
||||||
if (!callbackIsRegistered) {
|
if (!callbackIsRegistered) {
|
||||||
registerCallback((info) => {
|
ipcMain.on("video-src-changed", async (_, data) => {
|
||||||
metadataURL = info.url;
|
playingPlaylistId = JSON.parse(data)?.videoDetails?.playlistId;
|
||||||
});
|
});
|
||||||
callbackIsRegistered = true;
|
callbackIsRegistered = true;
|
||||||
}
|
}
|
||||||
@ -28,17 +26,17 @@ module.exports = (win, options) => {
|
|||||||
{
|
{
|
||||||
label: downloadLabel,
|
label: downloadLabel,
|
||||||
click: async () => {
|
click: async () => {
|
||||||
const currentURL = metadataURL || win.webContents.getURL();
|
const currentPagePlaylistId = new URL(win.webContents.getURL()).searchParams.get("list");
|
||||||
const playlistID = new URL(currentURL).searchParams.get("list");
|
const playlistId = currentPagePlaylistId || playingPlaylistId;
|
||||||
if (!playlistID) {
|
if (!playlistId) {
|
||||||
sendError(win, new Error("No playlist ID found"));
|
sendError(win, new Error("No playlist ID found"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`trying to get playlist ID: '${playlistID}'`);
|
console.log(`trying to get playlist ID: '${playlistId}'`);
|
||||||
let playlist;
|
let playlist;
|
||||||
try {
|
try {
|
||||||
playlist = await ytpl(playlistID, {
|
playlist = await ytpl(playlistId, {
|
||||||
limit: options.playlistMaxItems || Infinity,
|
limit: options.playlistMaxItems || Infinity,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
47
plugins/exponential-volume/front.js
Normal file
47
plugins/exponential-volume/front.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// "Youtube Music fix volume ratio 0.4" by Marco Pfeiffer
|
||||||
|
// https://greasyfork.org/en/scripts/397686-youtube-music-fix-volume-ratio/
|
||||||
|
|
||||||
|
const exponentialVolume = () => {
|
||||||
|
// manipulation exponent, higher value = lower volume
|
||||||
|
// 3 is the value used by pulseaudio, which Barteks2x figured out this gist here: https://gist.github.com/Barteks2x/a4e189a36a10c159bb1644ffca21c02a
|
||||||
|
// 0.05 (or 5%) is the lowest you can select in the UI which with an exponent of 3 becomes 0.000125 or 0.0125%
|
||||||
|
const EXPONENT = 3;
|
||||||
|
|
||||||
|
const storedOriginalVolumes = new WeakMap();
|
||||||
|
const { get, set } = Object.getOwnPropertyDescriptor(
|
||||||
|
HTMLMediaElement.prototype,
|
||||||
|
"volume"
|
||||||
|
);
|
||||||
|
Object.defineProperty(HTMLMediaElement.prototype, "volume", {
|
||||||
|
get() {
|
||||||
|
const lowVolume = get.call(this);
|
||||||
|
const calculatedOriginalVolume = lowVolume ** (1 / EXPONENT);
|
||||||
|
|
||||||
|
// The calculated value has some accuracy issues which can lead to problems for implementations that expect exact values.
|
||||||
|
// To avoid this, I'll store the unmodified volume to return it when read here.
|
||||||
|
// This mostly solves the issue, but the initial read has no stored value and the volume can also change though external influences.
|
||||||
|
// To avoid ill effects, I check if the stored volume is somewhere in the same range as the calculated volume.
|
||||||
|
const storedOriginalVolume = storedOriginalVolumes.get(this);
|
||||||
|
const storedDeviation = Math.abs(
|
||||||
|
storedOriginalVolume - calculatedOriginalVolume
|
||||||
|
);
|
||||||
|
|
||||||
|
const originalVolume =
|
||||||
|
storedDeviation < 0.01
|
||||||
|
? storedOriginalVolume
|
||||||
|
: calculatedOriginalVolume;
|
||||||
|
return originalVolume;
|
||||||
|
},
|
||||||
|
set(originalVolume) {
|
||||||
|
const lowVolume = originalVolume ** EXPONENT;
|
||||||
|
storedOriginalVolumes.set(this, originalVolume);
|
||||||
|
set.call(this, lowVolume);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = () =>
|
||||||
|
document.addEventListener("apiLoaded", exponentialVolume, {
|
||||||
|
once: true,
|
||||||
|
passive: true,
|
||||||
|
});
|
||||||
@ -4,10 +4,13 @@
|
|||||||
font-size: 14px !important;
|
font-size: 14px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fixes nav-bar-background opacity bug and allows clicking scrollbar through it */
|
/* fixes nav-bar-background opacity bug, reposition it, and allows clicking scrollbar through it */
|
||||||
#nav-bar-background {
|
#nav-bar-background {
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
pointer-events: none;
|
pointer-events: none !important;
|
||||||
|
position: sticky !important;
|
||||||
|
top: 0 !important;
|
||||||
|
height: 75px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* remove window dragging for nav bar (conflict with titlebar drag) */
|
/* remove window dragging for nav bar (conflict with titlebar drag) */
|
||||||
@ -17,9 +20,10 @@ ytmusic-pivot-bar-item-renderer {
|
|||||||
-webkit-app-region: unset !important;
|
-webkit-app-region: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* move up item selection renderer by 13 px */
|
/* move up item selection renderers */
|
||||||
ytmusic-item-section-renderer.stuck #header.ytmusic-item-section-renderer {
|
ytmusic-item-section-renderer.stuck #header.ytmusic-item-section-renderer,
|
||||||
top: calc(var(--ytmusic-nav-bar-height) - 13px) !important;
|
ytmusic-tabs.stuck {
|
||||||
|
top: calc(var(--ytmusic-nav-bar-height) - 15px) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fix weird positioning in search screen*/
|
/* fix weird positioning in search screen*/
|
||||||
@ -28,8 +32,7 @@ ytmusic-header-renderer.ytmusic-search-page {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Move navBar downwards */
|
/* Move navBar downwards */
|
||||||
ytmusic-nav-bar[slot="nav-bar"],
|
ytmusic-nav-bar[slot="nav-bar"] {
|
||||||
#nav-bar-background {
|
|
||||||
top: 17px !important;
|
top: 17px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,7 +49,7 @@ const observePopupContainer = () => {
|
|||||||
|
|
||||||
const observeVideo = () => {
|
const observeVideo = () => {
|
||||||
$('video').addEventListener('ratechange', forcePlaybackRate)
|
$('video').addEventListener('ratechange', forcePlaybackRate)
|
||||||
$('video').addEventListener('loadeddata', forcePlaybackRate)
|
$('video').addEventListener('srcChanged', forcePlaybackRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
const setupWheelListener = () => {
|
const setupWheelListener = () => {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
const fetch = require("node-fetch");
|
const fetch = require("node-fetch");
|
||||||
const is = require("electron-is");
|
const is = require("electron-is");
|
||||||
|
const { ipcMain } = require("electron");
|
||||||
|
|
||||||
const defaultConfig = require("../../config/defaults");
|
const defaultConfig = require("../../config/defaults");
|
||||||
const registerCallback = require("../../providers/song-info");
|
|
||||||
const { sortSegments } = require("./segments");
|
const { sortSegments } = require("./segments");
|
||||||
|
|
||||||
let videoID;
|
let videoID;
|
||||||
@ -13,15 +13,10 @@ module.exports = (win, options) => {
|
|||||||
...options,
|
...options,
|
||||||
};
|
};
|
||||||
|
|
||||||
registerCallback(async (info) => {
|
ipcMain.on("video-src-changed", async (_, data) => {
|
||||||
const newURL = info.url || win.webContents.getURL();
|
videoID = JSON.parse(data)?.videoDetails?.videoId;
|
||||||
const newVideoID = new URL(newURL).searchParams.get("v");
|
|
||||||
|
|
||||||
if (videoID !== newVideoID) {
|
|
||||||
videoID = newVideoID;
|
|
||||||
const segments = await fetchSegments(apiURL, categories);
|
const segments = await fetchSegments(apiURL, categories);
|
||||||
win.webContents.send("sponsorblock-skip", segments);
|
win.webContents.send("sponsorblock-skip", segments);
|
||||||
}
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@ function $(selector) { return document.querySelector(selector); }
|
|||||||
|
|
||||||
let options;
|
let options;
|
||||||
|
|
||||||
|
let api;
|
||||||
|
|
||||||
const switchButtonDiv = ElementFromFile(
|
const switchButtonDiv = ElementFromFile(
|
||||||
templatePath(__dirname, "button_template.html")
|
templatePath(__dirname, "button_template.html")
|
||||||
);
|
);
|
||||||
@ -17,7 +19,9 @@ module.exports = (_options) => {
|
|||||||
document.addEventListener('apiLoaded', setup, { once: true, passive: true });
|
document.addEventListener('apiLoaded', setup, { once: true, passive: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function setup() {
|
function setup(e) {
|
||||||
|
api = e.detail;
|
||||||
|
|
||||||
$('ytmusic-player-page').prepend(switchButtonDiv);
|
$('ytmusic-player-page').prepend(switchButtonDiv);
|
||||||
|
|
||||||
$('#song-image.ytmusic-player').style.display = "block"
|
$('#song-image.ytmusic-player').style.display = "block"
|
||||||
@ -35,13 +39,15 @@ function setup() {
|
|||||||
setOptions("video-toggle", options);
|
setOptions("video-toggle", options);
|
||||||
})
|
})
|
||||||
|
|
||||||
$('video').addEventListener('loadedmetadata', videoStarted);
|
$('video').addEventListener('srcChanged', videoStarted);
|
||||||
|
|
||||||
|
observeThumbnail();
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeDisplay(showVideo) {
|
function changeDisplay(showVideo) {
|
||||||
if (!showVideo && $('ytmusic-player').getAttribute('playback-mode') !== "ATV_PREFERRED") {
|
if (!showVideo) {
|
||||||
$('video').style.top = "0";
|
$('video').style.top = "0";
|
||||||
$('ytmusic-player').style.margin = "auto 21.5px";
|
$('ytmusic-player').style.margin = "auto 0px";
|
||||||
$('ytmusic-player').setAttribute('playback-mode', "ATV_PREFERRED");
|
$('ytmusic-player').setAttribute('playback-mode', "ATV_PREFERRED");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,11 +57,8 @@ function changeDisplay(showVideo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function videoStarted() {
|
function videoStarted() {
|
||||||
if (videoExist()) {
|
if (api.getPlayerResponse().videoDetails.musicVideoType === 'MUSIC_VIDEO_TYPE_OMV') { // or `$('#player').videoMode_`
|
||||||
const thumbnails = $('#movie_player').getPlayerResponse()?.videoDetails?.thumbnail?.thumbnails;
|
forceThumbnail($('#song-image img'));
|
||||||
if (thumbnails && thumbnails.length > 0) {
|
|
||||||
$('#song-image img').src = thumbnails[thumbnails.length-1].url;
|
|
||||||
}
|
|
||||||
switchButtonDiv.style.display = "initial";
|
switchButtonDiv.style.display = "initial";
|
||||||
if (!options.hideVideo && $('#song-video.ytmusic-player').style.display === "none") {
|
if (!options.hideVideo && $('#song-video.ytmusic-player').style.display === "none") {
|
||||||
changeDisplay(true);
|
changeDisplay(true);
|
||||||
@ -66,10 +69,6 @@ function videoStarted() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function videoExist() {
|
|
||||||
return $('#player').videoMode_;
|
|
||||||
}
|
|
||||||
|
|
||||||
// on load, after a delay, the page overrides the playback-mode to 'OMV_PREFERRED' which causes weird aspect ratio in the image container
|
// on load, after a delay, the page overrides the playback-mode to 'OMV_PREFERRED' which causes weird aspect ratio in the image container
|
||||||
// this function fix the problem by overriding that override :)
|
// this function fix the problem by overriding that override :)
|
||||||
function forcePlaybackMode() {
|
function forcePlaybackMode() {
|
||||||
@ -83,3 +82,22 @@ function forcePlaybackMode() {
|
|||||||
});
|
});
|
||||||
playbackModeObserver.observe($('ytmusic-player'), { attributeFilter: ["playback-mode"] })
|
playbackModeObserver.observe($('ytmusic-player'), { attributeFilter: ["playback-mode"] })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function observeThumbnail() {
|
||||||
|
const playbackModeObserver = new MutationObserver(mutations => {
|
||||||
|
if (!$('#player').videoMode_) return;
|
||||||
|
|
||||||
|
mutations.forEach(mutation => {
|
||||||
|
if (!mutation.target.src.startsWith('data:')) return;
|
||||||
|
forceThumbnail(mutation.target)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
playbackModeObserver.observe($('#song-image img'), { attributeFilter: ["src"] })
|
||||||
|
}
|
||||||
|
|
||||||
|
function forceThumbnail(img) {
|
||||||
|
const thumbnails = $('#movie_player').getPlayerResponse()?.videoDetails?.thumbnail?.thumbnails;
|
||||||
|
if (thumbnails && thumbnails.length > 0) {
|
||||||
|
img.src = thumbnails[thumbnails.length - 1].url.split("?")[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -13,18 +13,41 @@ ipcRenderer.on("update-song-info", async (_, extractedSongInfo) => {
|
|||||||
global.songInfo.image = await getImage(global.songInfo.imageSrc);
|
global.songInfo.image = await getImage(global.songInfo.imageSrc);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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');
|
||||||
|
|
||||||
module.exports = () => {
|
module.exports = () => {
|
||||||
document.addEventListener('apiLoaded', e => {
|
document.addEventListener('apiLoaded', apiEvent => {
|
||||||
if (config.plugins.isEnabled('tuna-obs')) {
|
if (config.plugins.isEnabled('tuna-obs')) {
|
||||||
setupTimeChangeListener();
|
setupTimeChangeListener();
|
||||||
}
|
}
|
||||||
|
const video = $('video');
|
||||||
|
// name = "dataloaded" and abit later "dataupdated"
|
||||||
|
apiEvent.detail.addEventListener('videodatachange', (name, _dataEvent) => {
|
||||||
|
if (name !== 'dataloaded') return;
|
||||||
|
video.dispatchEvent(srcChangedEvent);
|
||||||
|
sendSongInfo();
|
||||||
|
})
|
||||||
|
|
||||||
$('video').addEventListener('loadedmetadata', () => {
|
for (const status of ['playing', 'pause']) {
|
||||||
const data = e.detail.getPlayerResponse();
|
video.addEventListener(status, e => {
|
||||||
data.videoDetails.album = $('ytmusic-player-page')?.__data?.playerPageWatchMetadata?.albumName?.runs[0].text
|
if (Math.round(e.target.currentTime) > 0) {
|
||||||
ipcRenderer.send("song-info-request", JSON.stringify(data));
|
ipcRenderer.send("playPaused", {
|
||||||
|
isPaused: status === 'pause',
|
||||||
|
elapsedSeconds: Math.floor(e.target.currentTime)
|
||||||
});
|
});
|
||||||
}, { once: true, passive: true })
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendSongInfo() {
|
||||||
|
const data = apiEvent.detail.getPlayerResponse();
|
||||||
|
data.videoDetails.album = $('ytmusic-player-page')?.__data?.playerPageWatchMetadata?.albumName?.runs[0].text
|
||||||
|
data.videoDetails.elapsedSeconds = Math.floor(video.currentTime);
|
||||||
|
data.videoDetails.isPaused = false;
|
||||||
|
ipcRenderer.send("video-src-changed", JSON.stringify(data));
|
||||||
|
}
|
||||||
|
}, { once: true, passive: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
function setupTimeChangeListener() {
|
function setupTimeChangeListener() {
|
||||||
|
|||||||
@ -4,32 +4,6 @@ const fetch = require("node-fetch");
|
|||||||
|
|
||||||
const config = require("../config");
|
const config = require("../config");
|
||||||
|
|
||||||
// Grab the progress using the selector
|
|
||||||
const getProgress = async (win) => {
|
|
||||||
// Get current value of the progressbar element
|
|
||||||
return win.webContents.executeJavaScript(
|
|
||||||
'document.querySelector("#progress-bar").value'
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grab the native image using the src
|
|
||||||
const getImage = async (src) => {
|
|
||||||
const result = await fetch(src);
|
|
||||||
const buffer = await result.buffer();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// To find the paused status, we check if the title contains `-`
|
|
||||||
const getPausedStatus = async (win) => {
|
|
||||||
const title = await win.webContents.executeJavaScript("document.title");
|
|
||||||
return !title.includes("-");
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fill songInfo with empty values
|
// Fill songInfo with empty values
|
||||||
/**
|
/**
|
||||||
* @typedef {songInfo} SongInfo
|
* @typedef {songInfo} SongInfo
|
||||||
@ -45,25 +19,55 @@ const songInfo = {
|
|||||||
songDuration: 0,
|
songDuration: 0,
|
||||||
elapsedSeconds: 0,
|
elapsedSeconds: 0,
|
||||||
url: "",
|
url: "",
|
||||||
album: undefined
|
album: undefined,
|
||||||
|
videoId: "",
|
||||||
|
playlistId: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the native image using the src
|
||||||
|
const getImage = async (src) => {
|
||||||
|
const result = await fetch(src);
|
||||||
|
const buffer = await result.buffer();
|
||||||
|
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) => {
|
||||||
let data = JSON.parse(responseText);
|
const data = JSON.parse(responseText);
|
||||||
songInfo.title = cleanupName(data?.videoDetails?.title);
|
if (!data) return;
|
||||||
songInfo.artist =cleanupName(data?.videoDetails?.author);
|
|
||||||
songInfo.views = data?.videoDetails?.viewCount;
|
const microformat = data.microformat?.microformatDataRenderer;
|
||||||
songInfo.imageSrc = data?.videoDetails?.thumbnail?.thumbnails?.pop()?.url;
|
if (microformat) {
|
||||||
songInfo.songDuration = data?.videoDetails?.lengthSeconds;
|
songInfo.uploadDate = microformat.uploadDate;
|
||||||
songInfo.image = await getImage(songInfo.imageSrc);
|
songInfo.url = microformat.urlCanonical?.split("&")[0];
|
||||||
songInfo.uploadDate = data?.microformat?.microformatDataRenderer?.uploadDate;
|
songInfo.playlistId = new URL(microformat.urlCanonical).searchParams.get("list");
|
||||||
songInfo.url = data?.microformat?.microformatDataRenderer?.urlCanonical?.split("&")[0];
|
// used for options.resumeOnStart
|
||||||
|
config.set("url", microformat.urlCanonical);
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoDetails = data.videoDetails;
|
||||||
|
if (videoDetails) {
|
||||||
|
songInfo.title = cleanupName(videoDetails.title);
|
||||||
|
songInfo.artist = cleanupName(videoDetails.author);
|
||||||
|
songInfo.views = videoDetails.viewCount;
|
||||||
|
songInfo.songDuration = videoDetails.lengthSeconds;
|
||||||
|
songInfo.elapsedSeconds = videoDetails.elapsedSeconds;
|
||||||
|
songInfo.isPaused = videoDetails.isPaused;
|
||||||
|
songInfo.videoId = videoDetails.videoId;
|
||||||
songInfo.album = data?.videoDetails?.album
|
songInfo.album = data?.videoDetails?.album
|
||||||
|
|
||||||
// used for options.resumeOnStart
|
const oldUrl = songInfo.imageSrc;
|
||||||
config.set("url", data?.microformat?.microformatDataRenderer?.urlCanonical);
|
songInfo.imageSrc = videoDetails.thumbnail?.thumbnails?.pop()?.url.split("?")[0];
|
||||||
|
if (oldUrl !== 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));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// This variable will be filled with the callbacks once they register
|
// This variable will be filled with the callbacks once they register
|
||||||
@ -83,26 +87,20 @@ const registerCallback = (callback) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const registerProvider = (win) => {
|
const registerProvider = (win) => {
|
||||||
win.on("page-title-updated", async () => {
|
|
||||||
// Get and set the new data
|
|
||||||
songInfo.isPaused = await getPausedStatus(win);
|
|
||||||
|
|
||||||
const elapsedSeconds = await getProgress(win);
|
|
||||||
songInfo.elapsedSeconds = elapsedSeconds;
|
|
||||||
|
|
||||||
// Trigger the callbacks
|
|
||||||
callbacks.forEach((c) => {
|
|
||||||
c(songInfo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// This will be called when the song-info-front finds a new request with song data
|
// This will be called when the song-info-front finds a new request with song data
|
||||||
ipcMain.on("song-info-request", async (_, responseText) => {
|
ipcMain.on("video-src-changed", async (_, responseText) => {
|
||||||
await handleData(responseText, win);
|
await handleData(responseText, win);
|
||||||
callbacks.forEach((c) => {
|
callbacks.forEach((c) => {
|
||||||
c(songInfo);
|
c(songInfo);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
ipcMain.on("playPaused", (_, { isPaused, elapsedSeconds }) => {
|
||||||
|
songInfo.isPaused = isPaused;
|
||||||
|
songInfo.elapsedSeconds = elapsedSeconds;
|
||||||
|
callbacks.forEach((c) => {
|
||||||
|
c(songInfo);
|
||||||
|
});
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
const suffixesToRemove = [
|
const suffixesToRemove = [
|
||||||
|
|||||||
98
yarn.lock
98
yarn.lock
@ -650,46 +650,46 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@cliqz/adblocker-content@^1.22.7":
|
"@cliqz/adblocker-content@^1.23.0":
|
||||||
version "1.22.7"
|
version "1.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-content/-/adblocker-content-1.22.7.tgz#02bfa1775d8be1efa82e9d5802cc17cfa9dc0712"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-content/-/adblocker-content-1.23.0.tgz#4417a28d6018138956898efa141c9e6f52c9ec34"
|
||||||
integrity sha512-pAGxQ7sKCk7r0g/d7vyxY1MhkLfxfwMzd4WPL9234HmU/blCGCg1QL8wkjLTNYJERXZ+xoJ2dqMOisR/nE0ypA==
|
integrity sha512-X1osDX8pWGE1wGFnJqdY4qnwHI9Kb48Tom8HeZWTYDsf8VN636xUB5e5s4YZCTSfn271tFHYSdXNx3+TZqkkkQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cliqz/adblocker-extended-selectors" "^1.22.7"
|
"@cliqz/adblocker-extended-selectors" "^1.23.0"
|
||||||
|
|
||||||
"@cliqz/adblocker-electron-preload@^1.22.7":
|
"@cliqz/adblocker-electron-preload@^1.23.0":
|
||||||
version "1.22.7"
|
version "1.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.22.7.tgz#1de6c4c3e66d566149cf60785b85d6f3fdb9a9ea"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.23.0.tgz#69b42929fb06f1a3e0af7822813f7d4fb0698c3e"
|
||||||
integrity sha512-1eUQvmmDd5Wi0ka48SRggd80ZBilnA7uRePni/cVGfH5LSecCs5WoIpEhuoc1G333DXeBv9W0sRc1wVlKBsszg==
|
integrity sha512-sLvmoI7sr9dro/zBidVJU8gGrh+8GmS4Bzkbmxl5Wzgr6Q7cAPf1OOO8ixSXltFurJWH7OJCgPss4WC8Q/kc5w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cliqz/adblocker-content" "^1.22.7"
|
"@cliqz/adblocker-content" "^1.23.0"
|
||||||
|
|
||||||
"@cliqz/adblocker-electron@^1.22.6":
|
"@cliqz/adblocker-electron@^1.23.0":
|
||||||
version "1.22.7"
|
version "1.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron/-/adblocker-electron-1.22.7.tgz#bd29cf47835bc5c0c4d146333de3944096d23b4d"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron/-/adblocker-electron-1.23.0.tgz#8ad7f4f705291b9d038356464bde46b310af602c"
|
||||||
integrity sha512-/O5Dskkr7R/8RKOby04VZ7HbnU/OD6Kk+raLxyP858FOYccHOnBjkAcUcUzun2x0UXmHX9Cus8SJ3h8GbrG7ZA==
|
integrity sha512-j7X8B1p4PFHkHA7wOLxPpHUz2smsTkYM04/X8/mQyTUf42jzvqqA14qF0r4EGbavSrdqQxKEkHxeHhw2odHykQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cliqz/adblocker" "^1.22.7"
|
"@cliqz/adblocker" "^1.23.0"
|
||||||
"@cliqz/adblocker-electron-preload" "^1.22.7"
|
"@cliqz/adblocker-electron-preload" "^1.23.0"
|
||||||
tldts-experimental "^5.6.21"
|
tldts-experimental "^5.6.21"
|
||||||
|
|
||||||
"@cliqz/adblocker-extended-selectors@^1.22.7":
|
"@cliqz/adblocker-extended-selectors@^1.23.0":
|
||||||
version "1.22.7"
|
version "1.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-extended-selectors/-/adblocker-extended-selectors-1.22.7.tgz#ca0f219d773af5e8013287e5ddd8b00761359d87"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-extended-selectors/-/adblocker-extended-selectors-1.23.0.tgz#44e54a91ae6f4cbc24f76f5b0ce16ec03851c015"
|
||||||
integrity sha512-eHZWYJsgPZPaiLyQtZF7phDFoEqAzk54eno0P+Daal+QwiNixobsk3V4Uh1AVGFcmFEG/Z2CbC/vdWSHpSlImw==
|
integrity sha512-6Zl/wdGBuRd80ssmThOYS0L9u2t4lZElJXpxRB3Jp7uF6oL4LqSK4OKps4x8BktdQMgej6r5EhCh1avwu/13Bg==
|
||||||
|
|
||||||
"@cliqz/adblocker@^1.22.7":
|
"@cliqz/adblocker@^1.23.0":
|
||||||
version "1.22.7"
|
version "1.23.0"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker/-/adblocker-1.22.7.tgz#e2ee745c663ad6862e627de240973bdb4f1dc100"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker/-/adblocker-1.23.0.tgz#a970d1199d36161a6154e27654cd7eb59a10a497"
|
||||||
integrity sha512-DxHlLJmV1q05F1I6BORqvBaOc43Vqts8c+vZdsjYdfiwfrPtuVRFYVTwZeMlZHBhmWx4HyxnfFakzJ8hw/B09A==
|
integrity sha512-SRgSqEzFSN99zBeW3Or7ZW1uiIn+O2/Ol6KmZnsTZ/Wrn2RAQsm4wEzxPi6BSC3HpdJh2JdKuAwISavpmhuuvA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cliqz/adblocker-content" "^1.22.7"
|
"@cliqz/adblocker-content" "^1.23.0"
|
||||||
"@cliqz/adblocker-extended-selectors" "^1.22.7"
|
"@cliqz/adblocker-extended-selectors" "^1.23.0"
|
||||||
"@remusao/guess-url-type" "^1.1.2"
|
"@remusao/guess-url-type" "^1.1.2"
|
||||||
"@remusao/small" "^1.1.2"
|
"@remusao/small" "^1.1.2"
|
||||||
"@remusao/smaz" "^1.7.1"
|
"@remusao/smaz" "^1.7.1"
|
||||||
"@types/chrome" "^0.0.157"
|
"@types/chrome" "^0.0.159"
|
||||||
"@types/firefox-webext-browser" "^82.0.0"
|
"@types/firefox-webext-browser" "^94.0.0"
|
||||||
tldts-experimental "^5.6.21"
|
tldts-experimental "^5.6.21"
|
||||||
|
|
||||||
"@develar/schema-utils@~2.6.5":
|
"@develar/schema-utils@~2.6.5":
|
||||||
@ -1441,10 +1441,10 @@
|
|||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
"@types/responselike" "*"
|
"@types/responselike" "*"
|
||||||
|
|
||||||
"@types/chrome@^0.0.157":
|
"@types/chrome@^0.0.159":
|
||||||
version "0.0.157"
|
version "0.0.159"
|
||||||
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.157.tgz#5a50bd378f4f632383c6ebbc34c88fb87d501f58"
|
resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.159.tgz#0c1125fbb6d1fd64713e35de9aafbfd5a1b7a33a"
|
||||||
integrity sha512-q5SSmA9nKaDzFi8QkJW9kW8MYwWg9O7PKPUdBxsz+3rPcIF1Kxw0Bexpd70Uq1mU6PN4DBp4qKMXQDybUeiI9w==
|
integrity sha512-WZBkNJGAwZuRgv/an94DANdzFtJK0TvlO/evMpJD/TYnkjIxynIAU6RM7M78e8tyig/vD6weQ9T1Ba7v8nYjXQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/filesystem" "*"
|
"@types/filesystem" "*"
|
||||||
"@types/har-format" "*"
|
"@types/har-format" "*"
|
||||||
@ -1479,10 +1479,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
|
resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.28.tgz#c054e8af4d9dd75db4e63abc76f885168714d4b3"
|
||||||
integrity sha1-wFTor02d11205jq8dviFFocU1LM=
|
integrity sha1-wFTor02d11205jq8dviFFocU1LM=
|
||||||
|
|
||||||
"@types/firefox-webext-browser@^82.0.0":
|
"@types/firefox-webext-browser@^94.0.0":
|
||||||
version "82.0.0"
|
version "94.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/@types/firefox-webext-browser/-/firefox-webext-browser-82.0.0.tgz#4d0f5cfebd7321d2cbf0ccfb6032570f0138b958"
|
resolved "https://registry.yarnpkg.com/@types/firefox-webext-browser/-/firefox-webext-browser-94.0.0.tgz#8a470475ab111e47d34e2599034e227feece09f9"
|
||||||
integrity sha512-zKHePkjMx42KIUUZCPcUiyu1tpfQXH9VR4iDYfns3HvmKVJzt/TAFT+DFVroos8BI9RH78YgF3Hi/wlC6R6cKA==
|
integrity sha512-DU6rySaklQlzc3tnVAFNgK2OGkOKCDze8ZlhQFtx+Ag4w2rzgNFoqlwQHrUqUogRJph7Gxf1M8e9n4mlYlragw==
|
||||||
|
|
||||||
"@types/fs-extra@^9.0.11":
|
"@types/fs-extra@^9.0.11":
|
||||||
version "9.0.12"
|
version "9.0.12"
|
||||||
@ -2397,10 +2397,10 @@ builder-util-runtime@8.7.7:
|
|||||||
debug "^4.3.2"
|
debug "^4.3.2"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
|
|
||||||
builder-util-runtime@8.9.0:
|
builder-util-runtime@8.9.2:
|
||||||
version "8.9.0"
|
version "8.9.2"
|
||||||
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.9.0.tgz#5d8e7ef101c0bf8a54fec3a70f0c551e8fdd58c2"
|
resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-8.9.2.tgz#a9669ae5b5dcabfe411ded26678e7ae997246c28"
|
||||||
integrity sha512-XT7asdRMiSqUj/7EtvSW1mzVARvnhj0Nv4Ei4kD0p8GrKMFJt1Nadm4XwD+PrI2+srrtU+l8JMoBgSe4LX8EmQ==
|
integrity sha512-rhuKm5vh7E0aAmT6i8aoSfEjxzdYEFX7zDApK+eNgOhjofnWb74d9SRJv0H/8nsgOkos0TZ4zxW0P8J4N7xQ2A==
|
||||||
dependencies:
|
dependencies:
|
||||||
debug "^4.3.2"
|
debug "^4.3.2"
|
||||||
sax "^1.2.4"
|
sax "^1.2.4"
|
||||||
@ -3398,13 +3398,13 @@ electron-unhandled@^3.0.2:
|
|||||||
ensure-error "^2.0.0"
|
ensure-error "^2.0.0"
|
||||||
lodash.debounce "^4.0.8"
|
lodash.debounce "^4.0.8"
|
||||||
|
|
||||||
electron-updater@^4.4.6:
|
electron-updater@^4.6.1:
|
||||||
version "4.6.0"
|
version "4.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.6.0.tgz#17fc25a16d28f749cd3980430461bf7e6927d925"
|
resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-4.6.2.tgz#6edd2816a6b3859f55252082f59308b0d314f644"
|
||||||
integrity sha512-evvAwfDn100sIBZ/GLDpcWtWfaug48RGxVuYiSp0foKQkaXJGFyqYy5ADyt+HPML/mSTMPBvUq55cLEW45BroQ==
|
integrity sha512-KAloJQNXwW2j81n0o2KgBsiRsxp2OS15nty4nZLUjZYNuRyJ7yp2zeKPL4fVNGY6Ave491ht7/Dyz5OIykJf9g==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/semver" "^7.3.6"
|
"@types/semver" "^7.3.6"
|
||||||
builder-util-runtime "8.9.0"
|
builder-util-runtime "8.9.2"
|
||||||
fs-extra "^10.0.0"
|
fs-extra "^10.0.0"
|
||||||
js-yaml "^4.1.0"
|
js-yaml "^4.1.0"
|
||||||
lazy-val "^1.0.5"
|
lazy-val "^1.0.5"
|
||||||
@ -6448,10 +6448,10 @@ node-fetch@^2.6.1:
|
|||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
node-fetch@^2.6.2:
|
node-fetch@^2.6.6:
|
||||||
version "2.6.5"
|
version "2.6.6"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.5.tgz#42735537d7f080a7e5f78b6c549b7146be1742fd"
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89"
|
||||||
integrity sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==
|
integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA==
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url "^5.0.0"
|
whatwg-url "^5.0.0"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user