mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-13 19:31:46 +00:00
Merge branch 'master' into lastfm
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
const { writeFileSync } = require("fs");
|
||||
const { join } = require("path");
|
||||
|
||||
const ID3Writer = require("browser-id3-writer");
|
||||
const { dialog, ipcMain } = require("electron");
|
||||
const { dialog } = require("electron");
|
||||
|
||||
const getSongInfo = require("../../providers/song-info");
|
||||
const { injectCSS, listenAction } = require("../utils");
|
||||
@ -40,35 +38,6 @@ function handle(win) {
|
||||
console.log("Unknown action: " + action);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on("add-metadata", (event, filePath, songBuffer) => {
|
||||
let fileBuffer = songBuffer;
|
||||
|
||||
try {
|
||||
const writer = new ID3Writer(songBuffer);
|
||||
if (metadata.image) {
|
||||
const coverBuffer = metadata.image.toPNG();
|
||||
|
||||
// Create the metadata tags
|
||||
writer
|
||||
.setFrame("TIT2", metadata.title)
|
||||
.setFrame("TPE1", [metadata.artist])
|
||||
.setFrame("APIC", {
|
||||
type: 3,
|
||||
data: coverBuffer,
|
||||
description: "",
|
||||
});
|
||||
writer.addTag();
|
||||
}
|
||||
fileBuffer = Buffer.from(writer.arrayBuffer);
|
||||
} catch (error) {
|
||||
sendError(win, error);
|
||||
}
|
||||
|
||||
writeFileSync(filePath, fileBuffer);
|
||||
// Notify the youtube-dl file
|
||||
event.reply("add-metadata-done");
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = handle;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
const { contextBridge } = require("electron");
|
||||
|
||||
const { defaultConfig } = require("../../config");
|
||||
const { getSongMenu } = require("../../providers/dom-elements");
|
||||
const { ElementFromFile, templatePath, triggerAction } = require("../utils");
|
||||
const { ACTIONS, CHANNEL } = require("./actions.js");
|
||||
@ -31,11 +32,19 @@ const reinit = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const baseUrl = defaultConfig.url;
|
||||
|
||||
// TODO: re-enable once contextIsolation is set to true
|
||||
// contextBridge.exposeInMainWorld("downloader", {
|
||||
// download: () => {
|
||||
global.download = () => {
|
||||
const videoUrl = window.location.href;
|
||||
let videoUrl = getSongMenu()
|
||||
.querySelector("ytmusic-menu-navigation-item-renderer")
|
||||
.querySelector("#navigation-endpoint")
|
||||
.getAttribute("href");
|
||||
videoUrl = !videoUrl
|
||||
? global.songInfo.url || window.location.href
|
||||
: baseUrl + videoUrl;
|
||||
|
||||
downloadVideoToMP3(
|
||||
videoUrl,
|
||||
@ -51,7 +60,8 @@ global.download = () => {
|
||||
reinit();
|
||||
},
|
||||
reinit,
|
||||
pluginOptions
|
||||
pluginOptions,
|
||||
global.songInfo
|
||||
);
|
||||
};
|
||||
// });
|
||||
|
||||
@ -2,62 +2,89 @@ const { existsSync, mkdirSync } = require("fs");
|
||||
const { join } = require("path");
|
||||
const { URL } = require("url");
|
||||
|
||||
const { ipcMain } = require("electron");
|
||||
const { dialog, ipcMain } = require("electron");
|
||||
const is = require("electron-is");
|
||||
const ytpl = require("ytpl");
|
||||
|
||||
const { setOptions } = require("../../config/plugins");
|
||||
const getSongInfo = require("../../providers/song-info");
|
||||
const { sendError } = require("./back");
|
||||
const { defaultMenuDownloadLabel, getFolder } = require("./utils");
|
||||
|
||||
let downloadLabel = defaultMenuDownloadLabel;
|
||||
let metadataURL = undefined;
|
||||
let callbackIsRegistered = false;
|
||||
|
||||
module.exports = (win, options, refreshMenu) => [
|
||||
{
|
||||
label: downloadLabel,
|
||||
click: async () => {
|
||||
const currentURL = win.webContents.getURL();
|
||||
const playlistID = new URL(currentURL).searchParams.get("list");
|
||||
if (!playlistID) {
|
||||
sendError(win, new Error("No playlist ID found"));
|
||||
return;
|
||||
}
|
||||
module.exports = (win, options, refreshMenu) => {
|
||||
if (!callbackIsRegistered) {
|
||||
const registerCallback = getSongInfo(win);
|
||||
registerCallback((info) => {
|
||||
metadataURL = info.url;
|
||||
});
|
||||
callbackIsRegistered = true;
|
||||
}
|
||||
|
||||
const playlist = await ytpl(playlistID);
|
||||
const playlistTitle = playlist.title;
|
||||
return [
|
||||
{
|
||||
label: downloadLabel,
|
||||
click: async () => {
|
||||
const currentURL = metadataURL || win.webContents.getURL();
|
||||
const playlistID = new URL(currentURL).searchParams.get("list");
|
||||
if (!playlistID) {
|
||||
sendError(win, new Error("No playlist ID found"));
|
||||
return;
|
||||
}
|
||||
|
||||
const folder = getFolder(options.downloadFolder);
|
||||
const playlistFolder = join(folder, playlistTitle);
|
||||
if (existsSync(playlistFolder)) {
|
||||
sendError(
|
||||
win,
|
||||
new Error(`The folder ${playlistFolder} already exists`)
|
||||
);
|
||||
return;
|
||||
}
|
||||
mkdirSync(playlistFolder, { recursive: true });
|
||||
const playlist = await ytpl(playlistID);
|
||||
const playlistTitle = playlist.title;
|
||||
|
||||
ipcMain.on("downloader-feedback", (_, feedback) => {
|
||||
downloadLabel = feedback;
|
||||
const folder = getFolder(options.downloadFolder);
|
||||
const playlistFolder = join(folder, playlistTitle);
|
||||
if (existsSync(playlistFolder)) {
|
||||
sendError(
|
||||
win,
|
||||
new Error(`The folder ${playlistFolder} already exists`)
|
||||
);
|
||||
return;
|
||||
}
|
||||
mkdirSync(playlistFolder, { recursive: true });
|
||||
|
||||
ipcMain.on("downloader-feedback", (_, feedback) => {
|
||||
downloadLabel = feedback;
|
||||
refreshMenu();
|
||||
});
|
||||
|
||||
downloadLabel = `Downloading "${playlistTitle}"`;
|
||||
refreshMenu();
|
||||
});
|
||||
|
||||
downloadLabel = `Downloading "${playlistTitle}"`;
|
||||
refreshMenu();
|
||||
if (is.dev()) {
|
||||
console.log(
|
||||
`Downloading playlist "${playlistTitle}" (${playlist.items.length} songs)`
|
||||
);
|
||||
}
|
||||
|
||||
if (is.dev()) {
|
||||
console.log(
|
||||
`Downloading playlist "${playlistTitle}" (${playlist.items.length} songs)`
|
||||
);
|
||||
}
|
||||
|
||||
playlist.items.slice(0, options.playlistMaxItems).forEach((song) => {
|
||||
win.webContents.send(
|
||||
"downloader-download-playlist",
|
||||
song,
|
||||
playlistTitle,
|
||||
options
|
||||
);
|
||||
});
|
||||
playlist.items.slice(0, options.playlistMaxItems).forEach((song) => {
|
||||
win.webContents.send(
|
||||
"downloader-download-playlist",
|
||||
song,
|
||||
playlistTitle,
|
||||
options
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
{
|
||||
label: "Choose download folder",
|
||||
click: () => {
|
||||
let result = dialog.showOpenDialogSync({
|
||||
properties: ["openDirectory", "createDirectory"],
|
||||
defaultPath: getFolder(options.downloadFolder),
|
||||
});
|
||||
if (result) {
|
||||
options.downloadFolder = result[0];
|
||||
setOptions("downloader", options);
|
||||
} // else = user pressed cancel
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
@ -19,11 +19,11 @@
|
||||
<g class="style-scope yt-icon">
|
||||
<path
|
||||
d="M25.462,19.105v6.848H4.515v-6.848H0.489v8.861c0,1.111,0.9,2.012,2.016,2.012h24.967c1.115,0,2.016-0.9,2.016-2.012v-8.861H25.462z"
|
||||
class="style-scope yt-icon"
|
||||
class="style-scope yt-icon" fill="#aaaaaa"
|
||||
/>
|
||||
<path
|
||||
d="M14.62,18.426l-5.764-6.965c0,0-0.877-0.828,0.074-0.828s3.248,0,3.248,0s0-0.557,0-1.416c0-2.449,0-6.906,0-8.723c0,0-0.129-0.494,0.615-0.494c0.75,0,4.035,0,4.572,0c0.536,0,0.524,0.416,0.524,0.416c0,1.762,0,6.373,0,8.742c0,0.768,0,1.266,0,1.266s1.842,0,2.998,0c1.154,0,0.285,0.867,0.285,0.867s-4.904,6.51-5.588,7.193C15.092,18.979,14.62,18.426,14.62,18.426z"
|
||||
class="style-scope yt-icon"
|
||||
class="style-scope yt-icon" fill="#aaaaaa"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
@ -3,6 +3,7 @@ const { writeFileSync } = require("fs");
|
||||
const { join } = require("path");
|
||||
|
||||
const Mutex = require("async-mutex").Mutex;
|
||||
const ID3Writer = require("browser-id3-writer");
|
||||
const { ipcRenderer } = require("electron");
|
||||
const is = require("electron-is");
|
||||
const filenamify = require("filenamify");
|
||||
@ -120,7 +121,7 @@ const toMP3 = async (
|
||||
);
|
||||
|
||||
const folder = getFolder(options.downloadFolder);
|
||||
const name = metadata
|
||||
const name = metadata.title
|
||||
? `${metadata.artist ? `${metadata.artist} - ` : ""}${metadata.title}`
|
||||
: videoName;
|
||||
const filename = filenamify(name + "." + extension, {
|
||||
@ -130,15 +131,29 @@ const toMP3 = async (
|
||||
const filePath = join(folder, subfolder, filename);
|
||||
const fileBuffer = ffmpeg.FS("readFile", safeVideoName + "." + extension);
|
||||
|
||||
if (existingMetadata) {
|
||||
writeFileSync(filePath, fileBuffer);
|
||||
// Add the metadata
|
||||
try {
|
||||
const writer = new ID3Writer(fileBuffer);
|
||||
if (metadata.image) {
|
||||
const coverBuffer = metadata.image.toPNG();
|
||||
|
||||
// Create the metadata tags
|
||||
writer
|
||||
.setFrame("TIT2", metadata.title)
|
||||
.setFrame("TPE1", [metadata.artist])
|
||||
.setFrame("APIC", {
|
||||
type: 3,
|
||||
data: coverBuffer,
|
||||
description: "",
|
||||
});
|
||||
writer.addTag();
|
||||
}
|
||||
|
||||
writeFileSync(filePath, Buffer.from(writer.arrayBuffer));
|
||||
} catch (error) {
|
||||
sendError(error);
|
||||
} finally {
|
||||
reinit();
|
||||
} else {
|
||||
// Add the metadata
|
||||
sendFeedback("Adding metadata…");
|
||||
ipcRenderer.send("add-metadata", filePath, fileBuffer);
|
||||
ipcRenderer.once("add-metadata-done", reinit);
|
||||
sendFeedback("Finished converting", metadata);
|
||||
}
|
||||
} catch (e) {
|
||||
sendError(e);
|
||||
|
||||
76
plugins/in-app-menu/back.js
Normal file
76
plugins/in-app-menu/back.js
Normal file
@ -0,0 +1,76 @@
|
||||
const path = require("path");
|
||||
|
||||
const { Menu } = require("electron");
|
||||
const electronLocalshortcut = require("electron-localshortcut");
|
||||
|
||||
const config = require("../../config");
|
||||
const { setApplicationMenu } = require("../../menu");
|
||||
const { injectCSS } = require("../utils");
|
||||
|
||||
//check that menu doesn't get created twice
|
||||
let done = false;
|
||||
// win hook for fixing menu
|
||||
let win;
|
||||
|
||||
const originalBuildMenu = Menu.buildFromTemplate;
|
||||
// This function natively gets called on all submenu so no more reason to use recursion
|
||||
Menu.buildFromTemplate = (template) => {
|
||||
// Fix checkboxes and radio buttons
|
||||
updateCheckboxesAndRadioButtons(win, template);
|
||||
|
||||
// return as normal
|
||||
return originalBuildMenu(template);
|
||||
};
|
||||
|
||||
module.exports = (winImport) => {
|
||||
win = winImport;
|
||||
|
||||
// css for custom scrollbar + disable drag area(was causing bugs)
|
||||
injectCSS(win.webContents, path.join(__dirname, "style.css"));
|
||||
|
||||
win.on("ready-to-show", () => {
|
||||
// (apparently ready-to-show is called twice)
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
done = true;
|
||||
|
||||
setApplicationMenu(win);
|
||||
|
||||
//register keyboard shortcut && hide menu if hideMenu is enabled
|
||||
if (config.get("options.hideMenu")) {
|
||||
switchMenuVisibility(win);
|
||||
electronLocalshortcut.register(win, "Esc", () => {
|
||||
switchMenuVisibility(win);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let visible = true;
|
||||
function switchMenuVisibility(win) {
|
||||
visible = !visible;
|
||||
win.webContents.send("updateMenu", visible);
|
||||
}
|
||||
|
||||
function checkCheckbox(win, item) {
|
||||
//check item
|
||||
item.checked = !item.checked;
|
||||
//update menu (closes it)
|
||||
win.webContents.send("updateMenu", true);
|
||||
}
|
||||
|
||||
// Update checkboxes/radio buttons
|
||||
function updateCheckboxesAndRadioButtons(win, template) {
|
||||
for (let item of template) {
|
||||
// Change onClick of checkbox+radio
|
||||
if ((item.type === "checkbox" || item.type === "radio") && !item.fixed) {
|
||||
let originalOnclick = item.click;
|
||||
item.click = (itemClicked) => {
|
||||
originalOnclick(itemClicked);
|
||||
checkCheckbox(win, itemClicked);
|
||||
};
|
||||
item.fixed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
24
plugins/in-app-menu/front.js
Normal file
24
plugins/in-app-menu/front.js
Normal file
@ -0,0 +1,24 @@
|
||||
const { remote, ipcRenderer } = require("electron");
|
||||
|
||||
const customTitlebar = require("custom-electron-titlebar");
|
||||
|
||||
module.exports = () => {
|
||||
const bar = new customTitlebar.Titlebar({
|
||||
backgroundColor: customTitlebar.Color.fromHex("#050505"),
|
||||
itemBackgroundColor: customTitlebar.Color.fromHex("#121212"),
|
||||
});
|
||||
bar.updateTitle(" ");
|
||||
document.title = "Youtube Music";
|
||||
|
||||
ipcRenderer.on("updateMenu", function (event, menu) {
|
||||
if (menu) {
|
||||
bar.updateMenu(remote.Menu.getApplicationMenu());
|
||||
} else {
|
||||
try {
|
||||
bar.updateMenu(null);
|
||||
} catch (e) {
|
||||
//will always throw type error - null isn't menu, but it works
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
69
plugins/in-app-menu/style.css
Normal file
69
plugins/in-app-menu/style.css
Normal file
@ -0,0 +1,69 @@
|
||||
/* increase font size for menu and menuItems */
|
||||
.titlebar,
|
||||
.menubar-menu-container .action-label {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
/* allow submenu's to show correctly */
|
||||
.menubar-menu-container {
|
||||
overflow-y: visible !important;
|
||||
}
|
||||
/* fixes scrollbar positioning relative to nav bar */
|
||||
#nav-bar-background.ytmusic-app-layout {
|
||||
right: 15px !important;
|
||||
}
|
||||
/* remove window dragging for nav bar (conflict with titlebar drag) */
|
||||
ytmusic-nav-bar,
|
||||
.tab-titleiron-icon,
|
||||
ytmusic-pivot-bar-item-renderer {
|
||||
-webkit-app-region: unset;
|
||||
}
|
||||
|
||||
/* Move navBar downwards and make it opaque */
|
||||
ytmusic-app-layout {
|
||||
--ytmusic-nav-bar-height: 120px;
|
||||
}
|
||||
|
||||
ytmusic-search-box.ytmusic-nav-bar {
|
||||
margin-top: 29px;
|
||||
}
|
||||
|
||||
.center-content.ytmusic-nav-bar {
|
||||
background: #030303;
|
||||
}
|
||||
yt-page-navigation-progress,
|
||||
#progress.yt-page-navigation-progress,
|
||||
ytmusic-item-section-renderer[has-item-section-tabbed-header-renderer_]
|
||||
#header.ytmusic-item-section-renderer,
|
||||
ytmusic-header-renderer.ytmusic-search-page {
|
||||
top: 90px !important;
|
||||
}
|
||||
/* Custom scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 12px;
|
||||
background-color: #030303;
|
||||
border-radius: 100px;
|
||||
-moz-border-radius: 100px;
|
||||
-webkit-border-radius: 100px;
|
||||
}
|
||||
/* hover effect for both scrollbar area, and scrollbar 'thumb' */
|
||||
::-webkit-scrollbar:hover {
|
||||
background-color: rgba(15, 15, 15, 0.699);
|
||||
}
|
||||
|
||||
/* The scrollbar 'thumb' ...that marque oval shape in a scrollbar */
|
||||
::-webkit-scrollbar-thumb:vertical {
|
||||
background-clip: padding-box;
|
||||
border: 2px solid rgba(0, 0, 0, 0);
|
||||
|
||||
background: rgb(49, 0, 0);
|
||||
border-radius: 100px;
|
||||
-moz-border-radius: 100px;
|
||||
-webkit-border-radius: 100px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:vertical:active {
|
||||
background: rgb(56, 0, 0); /* Some darker color when you click it */
|
||||
border-radius: 100px;
|
||||
-moz-border-radius: 100px;
|
||||
-webkit-border-radius: 100px;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
const { Notification } = require("electron");
|
||||
const getSongInfo = require("../../providers/song-info");
|
||||
|
||||
const notify = info => {
|
||||
const notify = (info, options) => {
|
||||
let notificationImage = "assets/youtube-music.png";
|
||||
|
||||
if (info.image) {
|
||||
@ -14,27 +14,38 @@ const notify = info => {
|
||||
body: info.artist,
|
||||
icon: notificationImage,
|
||||
silent: true,
|
||||
urgency: options.urgency,
|
||||
};
|
||||
|
||||
|
||||
// Send the notification
|
||||
currentNotification = new Notification(notification);
|
||||
const currentNotification = new Notification(notification);
|
||||
currentNotification.show()
|
||||
|
||||
|
||||
return currentNotification;
|
||||
};
|
||||
|
||||
module.exports = (win) => {
|
||||
module.exports = (win, options) => {
|
||||
const registerCallback = getSongInfo(win);
|
||||
let oldNotification;
|
||||
let oldURL = "";
|
||||
win.on("ready-to-show", () => {
|
||||
// Register the callback for new song information
|
||||
registerCallback(songInfo => {
|
||||
// If song is playing send notification
|
||||
if (!songInfo.isPaused) {
|
||||
// on pause - reset url? and skip notification
|
||||
if (songInfo.isPaused) {
|
||||
//reset oldURL if unpause notification option is on
|
||||
if (options.unpauseNotification) {
|
||||
oldURL = "";
|
||||
}
|
||||
return;
|
||||
}
|
||||
// If url isn't the same as last one - send notification
|
||||
if (songInfo.url !== oldURL) {
|
||||
oldURL = songInfo.url;
|
||||
// Close the old notification
|
||||
oldNotification?.close();
|
||||
// This fixes a weird bug that would cause the notification to be updated instead of showing
|
||||
setTimeout(()=>{ oldNotification = notify(songInfo) }, 10);
|
||||
setTimeout(()=>{ oldNotification = notify(songInfo, options) }, 10);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
19
plugins/notifications/menu.js
Normal file
19
plugins/notifications/menu.js
Normal file
@ -0,0 +1,19 @@
|
||||
const {urgencyLevels, setUrgency, setUnpause} = require("./utils");
|
||||
|
||||
module.exports = (win, options) => [
|
||||
{
|
||||
label: "Notification Priority",
|
||||
submenu: urgencyLevels.map(level => ({
|
||||
label: level.name,
|
||||
type: "radio",
|
||||
checked: options.urgency === level.value,
|
||||
click: () => setUrgency(options, level.value)
|
||||
})),
|
||||
},
|
||||
{
|
||||
label: "Show notification on unpause",
|
||||
type: "checkbox",
|
||||
checked: options.unpauseNotification,
|
||||
click: (item) => setUnpause(options, item.checked)
|
||||
}
|
||||
];
|
||||
19
plugins/notifications/utils.js
Normal file
19
plugins/notifications/utils.js
Normal file
@ -0,0 +1,19 @@
|
||||
const {setOptions} = require("../../config/plugins");
|
||||
|
||||
module.exports.urgencyLevels = [
|
||||
{name: "Low", value: "low"},
|
||||
{name: "Normal", value: "normal"},
|
||||
{name: "High", value: "critical"},
|
||||
];
|
||||
module.exports.setUrgency = (options, level) => {
|
||||
options.urgency = level
|
||||
setOption(options)
|
||||
};
|
||||
module.exports.setUnpause = (options, value) => {
|
||||
options.unpauseNotification = value
|
||||
setOption(options)
|
||||
};
|
||||
|
||||
let setOption = options => {
|
||||
setOptions("notifications", options)
|
||||
};
|
||||
BIN
plugins/taskbar-mediacontrol/assets/backward.png
Normal file
BIN
plugins/taskbar-mediacontrol/assets/backward.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 269 B |
BIN
plugins/taskbar-mediacontrol/assets/forward.png
Normal file
BIN
plugins/taskbar-mediacontrol/assets/forward.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 250 B |
BIN
plugins/taskbar-mediacontrol/assets/pause.png
Normal file
BIN
plugins/taskbar-mediacontrol/assets/pause.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 192 B |
BIN
plugins/taskbar-mediacontrol/assets/play.png
Normal file
BIN
plugins/taskbar-mediacontrol/assets/play.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 265 B |
58
plugins/taskbar-mediacontrol/back.js
Normal file
58
plugins/taskbar-mediacontrol/back.js
Normal file
@ -0,0 +1,58 @@
|
||||
const getSongControls = require('../../providers/song-controls');
|
||||
const getSongInfo = require('../../providers/song-info');
|
||||
const path = require('path');
|
||||
|
||||
module.exports = win => {
|
||||
win.hide = function () {
|
||||
win.minimize();
|
||||
win.setSkipTaskbar(true);
|
||||
};
|
||||
|
||||
const show = win.show;
|
||||
win.show = function () {
|
||||
win.restore();
|
||||
win.focus();
|
||||
win.setSkipTaskbar(false);
|
||||
show.apply(win);
|
||||
};
|
||||
|
||||
win.isVisible = function () {
|
||||
return !win.isMinimized();
|
||||
};
|
||||
|
||||
const registerCallback = getSongInfo(win);
|
||||
const {playPause, next, previous} = getSongControls(win);
|
||||
|
||||
// If the page is ready, register the callback
|
||||
win.on('ready-to-show', () => {
|
||||
registerCallback(songInfo => {
|
||||
// Wait for song to start before setting thumbar
|
||||
if (songInfo.title === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Win32 require full rewrite of components
|
||||
win.setThumbarButtons([
|
||||
{
|
||||
tooltip: 'Previous',
|
||||
icon: get('backward.png'),
|
||||
click() {previous(win.webContents);}
|
||||
}, {
|
||||
tooltip: 'Play/Pause',
|
||||
// Update icon based on play state
|
||||
icon: songInfo.isPaused ? get('play.png') : get('pause.png'),
|
||||
click() {playPause(win.webContents);}
|
||||
}, {
|
||||
tooltip: 'Next',
|
||||
icon: get('forward.png'),
|
||||
click() {next(win.webContents);}
|
||||
}
|
||||
]);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Util
|
||||
function get(file) {
|
||||
return path.join(__dirname,"assets", file);
|
||||
}
|
||||
Reference in New Issue
Block a user