mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-16 12:42:06 +00:00
Globalized the songinfo and song controls, and changed the pause/play button.
Globalized the songinfo and song controls, and changed the pause/play button. The songInfo file should eventually get another location, because it isn't really a plugin.
This commit is contained in:
120
plugins/songInfo/back.js
Normal file
120
plugins/songInfo/back.js
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
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 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 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 = async win => {
|
||||||
|
// Fill songInfo with empty values
|
||||||
|
global.songInfo = {
|
||||||
|
title: '',
|
||||||
|
artist: '',
|
||||||
|
views: '',
|
||||||
|
likes: '',
|
||||||
|
imageSrc: '',
|
||||||
|
image: null,
|
||||||
|
isPaused: true
|
||||||
|
};
|
||||||
|
// The song control funcions
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
@ -1,6 +1,4 @@
|
|||||||
const {
|
const {TouchBar} = require('electron');
|
||||||
TouchBar, nativeImage
|
|
||||||
} = require('electron');
|
|
||||||
const {
|
const {
|
||||||
TouchBarButton,
|
TouchBarButton,
|
||||||
TouchBarLabel,
|
TouchBarLabel,
|
||||||
@ -8,103 +6,80 @@ const {
|
|||||||
TouchBarSegmentedControl,
|
TouchBarSegmentedControl,
|
||||||
TouchBarScrubber
|
TouchBarScrubber
|
||||||
} = TouchBar;
|
} = TouchBar;
|
||||||
const fetch = require('node-fetch');
|
|
||||||
|
|
||||||
// This selects the song title
|
// Songtitle label
|
||||||
const titleSelector = '.title.style-scope.ytmusic-player-bar';
|
const songTitle = new TouchBarLabel({
|
||||||
|
label: ''
|
||||||
|
});
|
||||||
|
// This will store the song controls once available
|
||||||
|
let controls = [];
|
||||||
|
|
||||||
// This selects the song image
|
// This will store the song image once available
|
||||||
const imageSelector = '#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > img';
|
const songImage = {};
|
||||||
|
|
||||||
// These keys will be used to go backwards, pause, skip songs, like songs, dislike songs
|
// Pause/play button
|
||||||
const keys = ['k', 'space', 'j', '_', '+'];
|
const pausePlayButton = new TouchBarButton();
|
||||||
|
|
||||||
const presskey = (window, key) => {
|
// The song control buttons (control functions are in the same order)
|
||||||
window.webContents.sendInputEvent({
|
const buttons = new TouchBarSegmentedControl({
|
||||||
type: 'keydown',
|
mode: 'buttons',
|
||||||
keyCode: key
|
segments: [
|
||||||
});
|
new TouchBarButton({
|
||||||
};
|
label: '⏮'
|
||||||
|
}),
|
||||||
|
pausePlayButton,
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '⏭'
|
||||||
|
}),
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '👎'
|
||||||
|
}),
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '👍'
|
||||||
|
})
|
||||||
|
],
|
||||||
|
change: i => controls[i]()
|
||||||
|
});
|
||||||
|
|
||||||
// Grab the title using the selector
|
// This is the touchbar object, this combines everything with proper layout
|
||||||
const getTitle = win => {
|
const touchBar = new TouchBar({
|
||||||
return win.webContents.executeJavaScript(
|
items: [
|
||||||
'document.querySelector(\'' + titleSelector + '\').innerText'
|
new TouchBarScrubber({
|
||||||
).catch(error => {
|
items: [songImage, songTitle],
|
||||||
console.log(error);
|
continuous: false
|
||||||
});
|
}),
|
||||||
};
|
new TouchBarSpacer({
|
||||||
|
size: 'flexible'
|
||||||
// Grab the image src using the selector
|
}),
|
||||||
const getImage = win => {
|
buttons
|
||||||
return win.webContents.executeJavaScript(
|
]
|
||||||
'document.querySelector(\'' + imageSelector + '\').src'
|
});
|
||||||
).catch(error => {
|
|
||||||
console.log(error);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = win => {
|
module.exports = win => {
|
||||||
// Songtitle label
|
// If the page is ready, register the callback
|
||||||
const songTitle = new TouchBarLabel({
|
win.on('ready-to-show', () => {
|
||||||
label: ''
|
controls = [
|
||||||
});
|
global.songControls.previous,
|
||||||
|
global.songControls.pause,
|
||||||
|
global.songControls.next,
|
||||||
|
global.songControls.like,
|
||||||
|
global.songControls.dislike
|
||||||
|
];
|
||||||
|
|
||||||
// This will store the song image once available
|
// Register the callback
|
||||||
const songImage = {};
|
global.songInfo.onNewData(songInfo => {
|
||||||
|
// Song information changed, so lets update the touchBar
|
||||||
|
|
||||||
// The song control buttons (keys to press are in the same order)
|
// Set the song title
|
||||||
const buttons = new TouchBarSegmentedControl({
|
songTitle.label = songInfo.title;
|
||||||
mode: 'buttons',
|
|
||||||
segments: [
|
|
||||||
new TouchBarButton({
|
|
||||||
label: '⏮'
|
|
||||||
}),
|
|
||||||
new TouchBarButton({
|
|
||||||
label: '⏯️'
|
|
||||||
}),
|
|
||||||
new TouchBarButton({
|
|
||||||
label: '⏭'
|
|
||||||
}),
|
|
||||||
new TouchBarButton({
|
|
||||||
label: '👎'
|
|
||||||
}),
|
|
||||||
new TouchBarButton({
|
|
||||||
label: '👍'
|
|
||||||
})
|
|
||||||
],
|
|
||||||
change: i => presskey(win, keys[i])
|
|
||||||
});
|
|
||||||
|
|
||||||
// This is the touchbar object, this combines everything with proper layout
|
// Changes the pause button if paused
|
||||||
const touchBar = new TouchBar({
|
pausePlayButton.label = songInfo.isPaused ? '▶️' : '⏸';
|
||||||
items: [
|
|
||||||
new TouchBarScrubber({
|
|
||||||
items: [songImage, songTitle],
|
|
||||||
continuous: false
|
|
||||||
}),
|
|
||||||
new TouchBarSpacer({
|
|
||||||
size: 'flexible'
|
|
||||||
}),
|
|
||||||
buttons
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the page title changes, update touchbar and song title
|
// Get image source
|
||||||
win.on('page-title-updated', async () => {
|
songImage.icon = songInfo.image ? songInfo.image.resize({height: 23}) : null;
|
||||||
// Set the song title
|
|
||||||
songTitle.label = await getTitle(win);
|
|
||||||
|
|
||||||
// Get image source
|
win.setTouchBar(touchBar);
|
||||||
const imageSrc = await getImage(win);
|
});
|
||||||
|
|
||||||
// Fetch and set song image
|
|
||||||
await fetch(imageSrc)
|
|
||||||
.then(response => response.buffer())
|
|
||||||
.then(data => {
|
|
||||||
songImage.icon = nativeImage.createFromBuffer(data).resize({height: 23});
|
|
||||||
});
|
|
||||||
|
|
||||||
win.setTouchBar(touchBar);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user