mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-17 05:02:06 +00:00
Merge pull request #125 from th-ch/refactor-providers
Refactor providers
This commit is contained in:
11
index.js
11
index.js
@ -28,8 +28,6 @@ if (config.get("options.disableHardwareAcceleration")) {
|
|||||||
// Adds debug features like hotkeys for triggering dev tools and reload
|
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||||
require("electron-debug")();
|
require("electron-debug")();
|
||||||
|
|
||||||
// these are the providers for the plugins, this shouldn't be hardcoded but it's temporarily
|
|
||||||
const providers = ["song-info"];
|
|
||||||
// Prevent window being garbage collected
|
// Prevent window being garbage collected
|
||||||
let mainWindow;
|
let mainWindow;
|
||||||
autoUpdater.autoDownload = false;
|
autoUpdater.autoDownload = false;
|
||||||
@ -56,15 +54,6 @@ function loadPlugins(win) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
providers.forEach(provider => {
|
|
||||||
console.log("Loaded provider - " + provider);
|
|
||||||
const providerPath = path.join(__dirname, "providers", provider, "back.js");
|
|
||||||
fileExists(providerPath, () => {
|
|
||||||
const handle = require(providerPath);
|
|
||||||
handle(win);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
config.plugins.getEnabled().forEach(([plugin, options]) => {
|
config.plugins.getEnabled().forEach(([plugin, options]) => {
|
||||||
console.log("Loaded plugin - " + plugin);
|
console.log("Loaded plugin - " + plugin);
|
||||||
const pluginPath = path.join(__dirname, "plugins", plugin, "back.js");
|
const pluginPath = path.join(__dirname, "plugins", plugin, "back.js");
|
||||||
|
|||||||
@ -1,41 +1,51 @@
|
|||||||
const Discord = require('discord-rpc');
|
const Discord = require("discord-rpc");
|
||||||
|
|
||||||
|
const getSongInfo = require("../../providers/song-info");
|
||||||
|
|
||||||
const rpc = new Discord.Client({
|
const rpc = new Discord.Client({
|
||||||
transport: 'ipc'
|
transport: "ipc",
|
||||||
});
|
});
|
||||||
|
|
||||||
const clientId = '790655993809338398';
|
// Application ID registered by @semvis123
|
||||||
|
const clientId = "790655993809338398";
|
||||||
|
|
||||||
|
module.exports = (win) => {
|
||||||
|
const registerCallback = getSongInfo(win);
|
||||||
|
|
||||||
module.exports = win => {
|
|
||||||
// If the page is ready, register the callback
|
// If the page is ready, register the callback
|
||||||
win.on('ready-to-show', () => {
|
win.on("ready-to-show", () => {
|
||||||
// Startup the rpc client
|
rpc.on("ready", () => {
|
||||||
rpc.login({
|
// Register the callback
|
||||||
clientId
|
registerCallback((songInfo) => {
|
||||||
}).catch(console.error);
|
// Song information changed, so lets update the rich presence
|
||||||
|
const activityInfo = {
|
||||||
|
details: songInfo.title,
|
||||||
|
state: songInfo.artist,
|
||||||
|
largeImageKey: "logo",
|
||||||
|
largeImageText: songInfo.views + " - " + songInfo.likes,
|
||||||
|
};
|
||||||
|
|
||||||
// Register the callback
|
if (songInfo.isPaused) {
|
||||||
global.songInfo.onNewData(songInfo => {
|
// Add an idle icon to show that the song is paused
|
||||||
// Song information changed, so lets update the rich presence
|
activityInfo.smallImageKey = "idle";
|
||||||
|
activityInfo.smallImageText = "idle/paused";
|
||||||
|
} else {
|
||||||
|
// Add the start and end time of the song
|
||||||
|
const songStartTime = Date.now() - songInfo.elapsedSeconds * 1000;
|
||||||
|
activityInfo.startTimestamp = songStartTime;
|
||||||
|
activityInfo.endTimestamp =
|
||||||
|
songStartTime + songInfo.songDuration * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
const activityInfo = {
|
rpc.setActivity(activityInfo);
|
||||||
details: songInfo.title,
|
});
|
||||||
state: songInfo.artist,
|
|
||||||
largeImageKey: 'logo',
|
|
||||||
largeImageText: songInfo.views + ' - ' + songInfo.likes
|
|
||||||
};
|
|
||||||
|
|
||||||
if (songInfo.isPaused) {
|
|
||||||
// Add an idle icon to show that the song is paused
|
|
||||||
activityInfo.smallImageKey = 'idle';
|
|
||||||
activityInfo.smallImageText = 'idle/paused';
|
|
||||||
} else {
|
|
||||||
// Add the start and end time of the song
|
|
||||||
const songStartTime = Date.now() - (songInfo.elapsedSeconds * 1000);
|
|
||||||
activityInfo.startTimestamp = songStartTime;
|
|
||||||
activityInfo.endTimestamp = songStartTime + (songInfo.songDuration * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
rpc.setActivity(activityInfo);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Startup the rpc client
|
||||||
|
rpc
|
||||||
|
.login({
|
||||||
|
clientId,
|
||||||
|
})
|
||||||
|
.catch(console.error);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,27 +1,31 @@
|
|||||||
const {Notification} = require('electron');
|
const { Notification } = require("electron");
|
||||||
|
|
||||||
const notify = info => {
|
const getSongInfo = require("../../providers/song-info");
|
||||||
let notificationImage = 'assets/youtube-music.png';
|
|
||||||
|
const notify = (info) => {
|
||||||
|
let notificationImage = "assets/youtube-music.png";
|
||||||
|
|
||||||
if (info.image) {
|
if (info.image) {
|
||||||
notificationImage = info.image.resize({height: 256, width: 256});
|
notificationImage = info.image.resize({ height: 256, width: 256 });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the notification with content
|
// Fill the notification with content
|
||||||
const notification = {
|
const notification = {
|
||||||
title: info.title || 'Playing',
|
title: info.title || "Playing",
|
||||||
body: info.artist,
|
body: info.artist,
|
||||||
icon: notificationImage,
|
icon: notificationImage,
|
||||||
silent: true
|
silent: true,
|
||||||
};
|
};
|
||||||
// Send the notification
|
// Send the notification
|
||||||
new Notification(notification).show();
|
new Notification(notification).show();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = win => {
|
module.exports = (win) => {
|
||||||
win.on('ready-to-show', () => {
|
const registerCallback = getSongInfo(win);
|
||||||
|
|
||||||
|
win.on("ready-to-show", () => {
|
||||||
// Register the callback for new song information
|
// Register the callback for new song information
|
||||||
global.songInfo.onNewData(songInfo => {
|
registerCallback((songInfo) => {
|
||||||
// If song is playing send notification
|
// If song is playing send notification
|
||||||
if (!songInfo.isPaused) {
|
if (!songInfo.isPaused) {
|
||||||
notify(songInfo);
|
notify(songInfo);
|
||||||
|
|||||||
@ -1,12 +1,7 @@
|
|||||||
const { globalShortcut } = require("electron");
|
const { globalShortcut } = require("electron");
|
||||||
const electronLocalshortcut = require("electron-localshortcut");
|
const electronLocalshortcut = require("electron-localshortcut");
|
||||||
|
|
||||||
const {
|
const getSongControls = require("../../providers/song-controls");
|
||||||
playPause,
|
|
||||||
nextTrack,
|
|
||||||
previousTrack,
|
|
||||||
startSearch
|
|
||||||
} = require("./youtube.js");
|
|
||||||
|
|
||||||
function _registerGlobalShortcut(webContents, shortcut, action) {
|
function _registerGlobalShortcut(webContents, shortcut, action) {
|
||||||
globalShortcut.register(shortcut, () => {
|
globalShortcut.register(shortcut, () => {
|
||||||
@ -21,11 +16,13 @@ function _registerLocalShortcut(win, shortcut, action) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function registerShortcuts(win) {
|
function registerShortcuts(win) {
|
||||||
|
const { playPause, next, previous, search } = getSongControls(win);
|
||||||
|
|
||||||
_registerGlobalShortcut(win.webContents, "MediaPlayPause", playPause);
|
_registerGlobalShortcut(win.webContents, "MediaPlayPause", playPause);
|
||||||
_registerGlobalShortcut(win.webContents, "MediaNextTrack", nextTrack);
|
_registerGlobalShortcut(win.webContents, "MediaNextTrack", next);
|
||||||
_registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previousTrack);
|
_registerGlobalShortcut(win.webContents, "MediaPreviousTrack", previous);
|
||||||
_registerLocalShortcut(win, "CommandOrControl+F", startSearch);
|
_registerLocalShortcut(win, "CommandOrControl+F", search);
|
||||||
_registerLocalShortcut(win, "CommandOrControl+L", startSearch);
|
_registerLocalShortcut(win, "CommandOrControl+L", search);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = registerShortcuts;
|
module.exports = registerShortcuts;
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
function _keyboardInput(webContents, key) {
|
|
||||||
return webContents.sendInputEvent({
|
|
||||||
type : "keydown",
|
|
||||||
keyCode: key
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function playPause(webContents) {
|
|
||||||
return _keyboardInput(webContents, "Space");
|
|
||||||
}
|
|
||||||
|
|
||||||
function nextTrack(webContents) {
|
|
||||||
return _keyboardInput(webContents, "j");
|
|
||||||
}
|
|
||||||
|
|
||||||
function previousTrack(webContents) {
|
|
||||||
return _keyboardInput(webContents, "k");
|
|
||||||
}
|
|
||||||
|
|
||||||
function startSearch(webContents) {
|
|
||||||
return _keyboardInput(webContents, "/");
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
playPause : playPause,
|
|
||||||
nextTrack : nextTrack,
|
|
||||||
previousTrack: previousTrack,
|
|
||||||
startSearch : startSearch
|
|
||||||
};
|
|
||||||
@ -1,15 +1,18 @@
|
|||||||
const {TouchBar} = require('electron');
|
const { TouchBar } = require("electron");
|
||||||
const {
|
const {
|
||||||
TouchBarButton,
|
TouchBarButton,
|
||||||
TouchBarLabel,
|
TouchBarLabel,
|
||||||
TouchBarSpacer,
|
TouchBarSpacer,
|
||||||
TouchBarSegmentedControl,
|
TouchBarSegmentedControl,
|
||||||
TouchBarScrubber
|
TouchBarScrubber,
|
||||||
} = TouchBar;
|
} = TouchBar;
|
||||||
|
|
||||||
|
const getSongInfo = require("../../providers/song-info");
|
||||||
|
const getSongControls = require("../../providers/song-controls");
|
||||||
|
|
||||||
// Songtitle label
|
// Songtitle label
|
||||||
const songTitle = new TouchBarLabel({
|
const songTitle = new TouchBarLabel({
|
||||||
label: ''
|
label: "",
|
||||||
});
|
});
|
||||||
// This will store the song controls once available
|
// This will store the song controls once available
|
||||||
let controls = [];
|
let controls = [];
|
||||||
@ -22,23 +25,23 @@ const pausePlayButton = new TouchBarButton();
|
|||||||
|
|
||||||
// The song control buttons (control functions are in the same order)
|
// The song control buttons (control functions are in the same order)
|
||||||
const buttons = new TouchBarSegmentedControl({
|
const buttons = new TouchBarSegmentedControl({
|
||||||
mode: 'buttons',
|
mode: "buttons",
|
||||||
segments: [
|
segments: [
|
||||||
new TouchBarButton({
|
new TouchBarButton({
|
||||||
label: '⏮'
|
label: "⏮",
|
||||||
}),
|
}),
|
||||||
pausePlayButton,
|
pausePlayButton,
|
||||||
new TouchBarButton({
|
new TouchBarButton({
|
||||||
label: '⏭'
|
label: "⏭",
|
||||||
}),
|
}),
|
||||||
new TouchBarButton({
|
new TouchBarButton({
|
||||||
label: '👎'
|
label: "👎",
|
||||||
}),
|
}),
|
||||||
new TouchBarButton({
|
new TouchBarButton({
|
||||||
label: '👍'
|
label: "👍",
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
change: i => controls[i]()
|
change: (i) => controls[i](),
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is the touchbar object, this combines everything with proper layout
|
// This is the touchbar object, this combines everything with proper layout
|
||||||
@ -46,38 +49,37 @@ const touchBar = new TouchBar({
|
|||||||
items: [
|
items: [
|
||||||
new TouchBarScrubber({
|
new TouchBarScrubber({
|
||||||
items: [songImage, songTitle],
|
items: [songImage, songTitle],
|
||||||
continuous: false
|
continuous: false,
|
||||||
}),
|
}),
|
||||||
new TouchBarSpacer({
|
new TouchBarSpacer({
|
||||||
size: 'flexible'
|
size: "flexible",
|
||||||
}),
|
}),
|
||||||
buttons
|
buttons,
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = win => {
|
module.exports = (win) => {
|
||||||
|
const registerCallback = getSongInfo(win);
|
||||||
|
const { playPause, next, previous, like, dislike } = getSongControls(win);
|
||||||
|
|
||||||
// If the page is ready, register the callback
|
// If the page is ready, register the callback
|
||||||
win.on('ready-to-show', () => {
|
win.on("ready-to-show", () => {
|
||||||
controls = [
|
controls = [previous, playPause, next, like, dislike];
|
||||||
global.songControls.previous,
|
|
||||||
global.songControls.pause,
|
|
||||||
global.songControls.next,
|
|
||||||
global.songControls.like,
|
|
||||||
global.songControls.dislike
|
|
||||||
];
|
|
||||||
|
|
||||||
// Register the callback
|
// Register the callback
|
||||||
global.songInfo.onNewData(songInfo => {
|
registerCallback((songInfo) => {
|
||||||
// Song information changed, so lets update the touchBar
|
// Song information changed, so lets update the touchBar
|
||||||
|
|
||||||
// Set the song title
|
// Set the song title
|
||||||
songTitle.label = songInfo.title;
|
songTitle.label = songInfo.title;
|
||||||
|
|
||||||
// Changes the pause button if paused
|
// Changes the pause button if paused
|
||||||
pausePlayButton.label = songInfo.isPaused ? '▶️' : '⏸';
|
pausePlayButton.label = songInfo.isPaused ? "▶️" : "⏸";
|
||||||
|
|
||||||
// Get image source
|
// Get image source
|
||||||
songImage.icon = songInfo.image ? songInfo.image.resize({height: 23}) : null;
|
songImage.icon = songInfo.image
|
||||||
|
? songInfo.image.resize({ height: 23 })
|
||||||
|
: null;
|
||||||
|
|
||||||
win.setTouchBar(touchBar);
|
win.setTouchBar(touchBar);
|
||||||
});
|
});
|
||||||
|
|||||||
18
providers/song-controls.js
Normal file
18
providers/song-controls.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// This is used for to control the songs
|
||||||
|
const pressKey = (window, key) => {
|
||||||
|
window.webContents.sendInputEvent({
|
||||||
|
type: "keydown",
|
||||||
|
keyCode: key,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = (win) => {
|
||||||
|
return {
|
||||||
|
previous: () => pressKey(win, "k"),
|
||||||
|
next: () => pressKey(win, "j"),
|
||||||
|
playPause: () => pressKey(win, "space"),
|
||||||
|
like: () => pressKey(win, "_"),
|
||||||
|
dislike: () => pressKey(win, "+"),
|
||||||
|
search: () => pressKey(win, "/"),
|
||||||
|
};
|
||||||
|
};
|
||||||
137
providers/song-info.js
Normal file
137
providers/song-info.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
const { nativeImage } = require("electron");
|
||||||
|
|
||||||
|
const fetch = require("node-fetch");
|
||||||
|
|
||||||
|
// This selects the song title
|
||||||
|
const titleSelector = ".title.style-scope.ytmusic-player-bar";
|
||||||
|
|
||||||
|
// This selects the song image
|
||||||
|
const imageSelector =
|
||||||
|
"#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > img";
|
||||||
|
|
||||||
|
// This selects the song subinfo, this includes artist, views, likes
|
||||||
|
const subInfoSelector =
|
||||||
|
"#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span";
|
||||||
|
|
||||||
|
// This selects the progress bar, used for songlength and current progress
|
||||||
|
const progressSelector = "#progress-bar";
|
||||||
|
|
||||||
|
// Grab the title using the selector
|
||||||
|
const getTitle = (win) => {
|
||||||
|
return win.webContents
|
||||||
|
.executeJavaScript(
|
||||||
|
"document.querySelector('" + titleSelector + "').innerText"
|
||||||
|
)
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the image src using the selector
|
||||||
|
const getImageSrc = (win) => {
|
||||||
|
return win.webContents
|
||||||
|
.executeJavaScript("document.querySelector('" + imageSelector + "').src")
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the subinfo using the selector
|
||||||
|
const getSubInfo = async (win) => {
|
||||||
|
// Get innerText of subinfo element
|
||||||
|
const subInfoString = await win.webContents.executeJavaScript(
|
||||||
|
'document.querySelector("' + subInfoSelector + '").innerText'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Split and clean the string
|
||||||
|
const splittedSubInfo = subInfoString.replaceAll("\n", "").split(" • ");
|
||||||
|
|
||||||
|
// Make sure we always return 3 elements in the aray
|
||||||
|
const subInfo = [];
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
// Fill array with empty string if not defined
|
||||||
|
subInfo.push(splittedSubInfo[i] || "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return subInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the progress using the selector
|
||||||
|
const getProgress = async (win) => {
|
||||||
|
// Get max value of the progressbar element
|
||||||
|
const songDuration = await win.webContents.executeJavaScript(
|
||||||
|
'document.querySelector("' + progressSelector + '").max'
|
||||||
|
);
|
||||||
|
// Get current value of the progressbar element
|
||||||
|
const elapsedSeconds = await win.webContents.executeJavaScript(
|
||||||
|
'document.querySelector("' + progressSelector + '").value'
|
||||||
|
);
|
||||||
|
|
||||||
|
return { songDuration, elapsedSeconds };
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the native image using the src
|
||||||
|
const getImage = async (src) => {
|
||||||
|
const result = await fetch(src);
|
||||||
|
const buffer = await result.buffer();
|
||||||
|
return nativeImage.createFromBuffer(buffer);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPausedStatus = async (win) => {
|
||||||
|
const title = await win.webContents.executeJavaScript("document.title");
|
||||||
|
return !title.includes("-");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fill songInfo with empty values
|
||||||
|
const songInfo = {
|
||||||
|
title: "",
|
||||||
|
artist: "",
|
||||||
|
views: "",
|
||||||
|
likes: "",
|
||||||
|
imageSrc: "",
|
||||||
|
image: null,
|
||||||
|
isPaused: true,
|
||||||
|
songDuration: 0,
|
||||||
|
elapsedSeconds: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const registerProvider = (win) => {
|
||||||
|
// This variable will be filled with the callbacks once they register
|
||||||
|
const callbacks = [];
|
||||||
|
|
||||||
|
// This function will allow plugins to register callback that will be triggered when data changes
|
||||||
|
const registerCallback = (callback) => {
|
||||||
|
callbacks.push(callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
win.on("page-title-updated", async () => {
|
||||||
|
// Save the old title temporarily
|
||||||
|
const oldTitle = songInfo.title;
|
||||||
|
// Get and set the new data
|
||||||
|
songInfo.title = await getTitle(win);
|
||||||
|
songInfo.isPaused = await getPausedStatus(win);
|
||||||
|
|
||||||
|
const { songDuration, elapsedSeconds } = await getProgress(win);
|
||||||
|
songInfo.songDuration = songDuration;
|
||||||
|
songInfo.elapsedSeconds = elapsedSeconds;
|
||||||
|
|
||||||
|
// If title changed then we do need to update other info
|
||||||
|
if (oldTitle !== songInfo.title) {
|
||||||
|
const subInfo = await getSubInfo(win);
|
||||||
|
songInfo.artist = subInfo[0];
|
||||||
|
songInfo.views = subInfo[1];
|
||||||
|
songInfo.likes = subInfo[2];
|
||||||
|
songInfo.imageSrc = await getImageSrc(win);
|
||||||
|
songInfo.image = await getImage(songInfo.imageSrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger the callbacks
|
||||||
|
callbacks.forEach((c) => {
|
||||||
|
c(songInfo);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return registerCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = registerProvider;
|
||||||
@ -1,141 +0,0 @@
|
|||||||
const {nativeImage} = require('electron');
|
|
||||||
const fetch = require('node-fetch');
|
|
||||||
|
|
||||||
// This selects the song title
|
|
||||||
const titleSelector = '.title.style-scope.ytmusic-player-bar';
|
|
||||||
|
|
||||||
// This selects the song image
|
|
||||||
const imageSelector = '#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > img';
|
|
||||||
|
|
||||||
// This selects the song subinfo, this includes artist, views, likes
|
|
||||||
const subInfoSelector = '#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > div.content-info-wrapper.style-scope.ytmusic-player-bar > span';
|
|
||||||
|
|
||||||
// This selects the progress bar, used for songlength and current progress
|
|
||||||
const progressSelector = '#progress-bar';
|
|
||||||
|
|
||||||
// This is used for to control the songs
|
|
||||||
const presskey = (window, key) => {
|
|
||||||
window.webContents.sendInputEvent({
|
|
||||||
type: 'keydown',
|
|
||||||
keyCode: key
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grab the title using the selector
|
|
||||||
const getTitle = win => {
|
|
||||||
return win.webContents.executeJavaScript(
|
|
||||||
'document.querySelector(\'' + titleSelector + '\').innerText'
|
|
||||||
).catch(error => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grab the image src using the selector
|
|
||||||
const getImageSrc = win => {
|
|
||||||
return win.webContents.executeJavaScript(
|
|
||||||
'document.querySelector(\'' + imageSelector + '\').src'
|
|
||||||
).catch(error => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grab the subinfo using the selector
|
|
||||||
const getSubInfo = async win => {
|
|
||||||
// Get innerText of subinfo element
|
|
||||||
const subInfoString = await win.webContents.executeJavaScript(
|
|
||||||
'document.querySelector("' + subInfoSelector + '").innerText');
|
|
||||||
|
|
||||||
// Split and clean the string
|
|
||||||
const splittedSubInfo = subInfoString.replaceAll('\n', '').split(' • ');
|
|
||||||
|
|
||||||
// Make sure we always return 3 elements in the aray
|
|
||||||
const subInfo = [];
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
// Fill array with empty string if not defined
|
|
||||||
subInfo.push(splittedSubInfo[i] || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return subInfo;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grab the progress using the selector
|
|
||||||
const getProgress = async win => {
|
|
||||||
// Get max value of the progressbar element
|
|
||||||
const songDuration = await win.webContents.executeJavaScript(
|
|
||||||
'document.querySelector("' + progressSelector + '").max');
|
|
||||||
// Get current value of the progressbar element
|
|
||||||
const elapsedSeconds = await win.webContents.executeJavaScript(
|
|
||||||
'document.querySelector("' + progressSelector + '").value');
|
|
||||||
|
|
||||||
return {songDuration, elapsedSeconds};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Grab the native image using the src
|
|
||||||
const getImage = async src => {
|
|
||||||
const result = await fetch(src);
|
|
||||||
const buffer = await result.buffer();
|
|
||||||
return nativeImage.createFromBuffer(buffer);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getPausedStatus = async win => {
|
|
||||||
const title = await win.webContents.executeJavaScript('document.title');
|
|
||||||
return !title.includes('-');
|
|
||||||
};
|
|
||||||
|
|
||||||
// This variable will be filled with the callbacks once they register
|
|
||||||
const callbacks = [];
|
|
||||||
|
|
||||||
module.exports = win => {
|
|
||||||
// Fill songInfo with empty values
|
|
||||||
global.songInfo = {
|
|
||||||
title: '',
|
|
||||||
artist: '',
|
|
||||||
views: '',
|
|
||||||
likes: '',
|
|
||||||
imageSrc: '',
|
|
||||||
image: null,
|
|
||||||
isPaused: true,
|
|
||||||
songDuration: 0,
|
|
||||||
elapsedSeconds: 0
|
|
||||||
};
|
|
||||||
// The song control functions
|
|
||||||
global.songControls = {
|
|
||||||
previous: () => presskey(win, 'k'),
|
|
||||||
next: () => presskey(win, 'j'),
|
|
||||||
pause: () => presskey(win, 'space'),
|
|
||||||
like: () => presskey(win, '_'),
|
|
||||||
dislike: () => presskey(win, '+')
|
|
||||||
};
|
|
||||||
|
|
||||||
// This function will allow plugins to register callback that will be triggered when data changes
|
|
||||||
global.songInfo.onNewData = callback => {
|
|
||||||
callbacks.push(callback);
|
|
||||||
};
|
|
||||||
|
|
||||||
win.on('page-title-updated', async () => {
|
|
||||||
// Save the old title temporarily
|
|
||||||
const oldTitle = global.songInfo.title;
|
|
||||||
// Get and set the new data
|
|
||||||
global.songInfo.title = await getTitle(win);
|
|
||||||
global.songInfo.isPaused = await getPausedStatus(win);
|
|
||||||
|
|
||||||
const {songDuration, elapsedSeconds} = await getProgress(win);
|
|
||||||
global.songInfo.songDuration = songDuration;
|
|
||||||
global.songInfo.elapsedSeconds = elapsedSeconds;
|
|
||||||
|
|
||||||
// If title changed then we do need to update other info
|
|
||||||
if (oldTitle !== global.songInfo.title) {
|
|
||||||
const subInfo = await getSubInfo(win);
|
|
||||||
global.songInfo.artist = subInfo[0];
|
|
||||||
global.songInfo.views = subInfo[1];
|
|
||||||
global.songInfo.likes = subInfo[2];
|
|
||||||
global.songInfo.imageSrc = await getImageSrc(win);
|
|
||||||
global.songInfo.image = await getImage(global.songInfo.imageSrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trigger the callbacks
|
|
||||||
callbacks.forEach(c => {
|
|
||||||
c(global.songInfo);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user