tidal-hifi/src/preload.js

392 lines
10 KiB
JavaScript
Raw Normal View History

const { setTitle } = require("./scripts/window-functions");
2020-10-04 11:52:08 +02:00
const { dialog, process } = require("electron").remote;
const { store, settings } = require("./scripts/settings");
2019-10-22 21:25:57 +02:00
const { ipcRenderer } = require("electron");
const { app } = require("electron").remote;
const { downloadFile } = require("./scripts/download");
const statuses = require("./constants/statuses");
const hotkeys = require("./scripts/hotkeys");
const globalEvents = require("./constants/globalEvents");
const notifier = require("node-notifier");
2019-10-22 21:25:57 +02:00
const notificationPath = `${app.getPath("userData")}/notification.jpg`;
2019-11-03 18:52:15 +01:00
let currentSong = "";
let player;
let currentPlayStatus = statuses.paused;
2021-04-20 21:56:02 +02:00
let barvalue;
let updatecurrent = false;
let oldcurrent;
2021-04-21 03:31:28 +02:00
let currentURL = undefined;
const elements = {
play: '*[data-test="play"]',
pause: '*[data-test="pause"]',
next: '*[data-test="next"]',
previous: 'button[data-test="previous"]',
title: '*[data-test^="footer-track-title"]',
2021-04-21 03:31:28 +02:00
artists: '*[class^="elemental__text elemental__text css-oxcos"]',
home: '*[data-test="menu--home"]',
back: '[class^="backwardButton"]',
forward: '[class^="forwardButton"]',
search: '[class^="searchField"]',
shuffle: '*[data-test="shuffle"]',
repeat: '*[data-test="repeat"]',
block: '[class="blockButton"]',
account: '*[data-test^="profile-image-button"]',
settings: '*[data-test^="open-settings"]',
2019-10-22 21:25:57 +02:00
media: '*[data-test="current-media-imagery"]',
image: "img",
url: 'a[href*="/track/"]',
2021-04-20 21:56:02 +02:00
current: '*[data-test="current-time"]',
duration: '*[data-test="duration-time"]',
bar: '*[data-test="progress-bar"]',
2019-10-22 21:25:57 +02:00
/**
* Get an element from the dom
* @param {*} key key in elements object to fetch
*/
2020-10-04 11:52:08 +02:00
get: function (key) {
return window.document.querySelector(this[key.toLowerCase()]);
},
2019-10-22 21:25:57 +02:00
/**
* Get the icon of the current song
*/
2020-10-04 11:52:08 +02:00
getSongIcon: function () {
2019-10-22 21:25:57 +02:00
const figure = this.get("media");
if (figure) {
const mediaElement = figure.querySelector(this["image"]);
if (mediaElement) {
return mediaElement.src;
}
}
return "";
},
/**
* Shorthand function to get the text of a dom element
* @param {*} key key in elements object to fetch
*/
2020-10-04 11:52:08 +02:00
getText: function (key) {
2019-10-22 21:25:57 +02:00
const element = this.get(key);
return element ? element.textContent : "";
},
2019-10-22 21:25:57 +02:00
/**
* Shorthand function to click a dom element
* @param {*} key key in elements object to fetch
*/
2020-10-04 11:52:08 +02:00
click: function (key) {
this.get(key).click();
return this;
},
2019-10-22 21:25:57 +02:00
/**
* Shorthand function to focus a dom element
* @param {*} key key in elements object to fetch
*/
2020-10-04 11:52:08 +02:00
focus: function (key) {
return this.get(key).focus();
},
};
/**
* Play or pause the current song
*/
function playPause() {
const play = elements.get("play");
if (play) {
elements.click("play");
} else {
elements.click("pause");
}
}
/**
* Add hotkeys for when tidal is focused
* Reflects the desktop hotkeys found on:
* https://defkey.com/tidal-desktop-shortcuts
*/
function addHotKeys() {
if (store.get(settings.enableCustomHotkeys)) {
hotkeys.add("Control+p", function () {
elements.click("account").click("settings");
});
hotkeys.add("Control+l", function () {
handleLogout();
});
hotkeys.add("Control+h", function () {
elements.click("home");
});
hotkeys.add("backspace", function () {
elements.click("back");
});
hotkeys.add("shift+backspace", function () {
elements.click("forward");
});
hotkeys.add("control+u", function () {
// reloading window without cache should show the update bar if applicable
window.location.reload(true);
});
hotkeys.add("control+r", function () {
elements.click("repeat");
});
}
2019-11-03 18:52:15 +01:00
// always add the hotkey for the settings window
hotkeys.add("control+=", function () {
2019-11-03 18:52:15 +01:00
ipcRenderer.send(globalEvents.showSettings);
});
}
/**
* This function will ask the user whether he/she wants to log out.
* It will log the user out if he/she selects "yes"
*/
function handleLogout() {
const logoutOptions = ["Cancel", "Yes, please", "No, thanks"];
dialog.showMessageBox(
null,
{
type: "question",
title: "Logging out",
message: "Are you sure you want to log out?",
buttons: logoutOptions,
defaultId: 2,
},
2020-10-04 11:52:08 +02:00
function (response) {
if (logoutOptions.indexOf("Yes, please") == response) {
for (let i = 0; i < window.localStorage.length; i++) {
const key = window.localStorage.key(i);
if (key.startsWith("_TIDAL_activeSession")) {
window.localStorage.removeItem(key);
i = window.localStorage.length + 1;
}
}
window.location.reload();
}
}
);
}
/**
* Add ipc event listeners.
* Some actions triggered outside of the site need info from the site.
*/
function addIPCEventListeners() {
window.addEventListener("DOMContentLoaded", () => {
2019-10-22 21:25:57 +02:00
ipcRenderer.on("globalEvent", (event, args) => {
switch (args) {
case globalEvents.playPause:
2019-10-22 21:25:57 +02:00
playPause();
break;
case globalEvents.next:
2019-10-22 21:25:57 +02:00
elements.click("next");
break;
case globalEvents.previous:
2019-10-22 21:25:57 +02:00
elements.click("previous");
break;
case globalEvents.play:
elements.click("play");
break;
case globalEvents.pause:
elements.click("pause");
break;
2019-10-22 21:25:57 +02:00
}
});
});
}
/**
* Update the current status of tidal (e.g playing or paused)
*/
function getCurrentlyPlayingStatus() {
2020-10-04 11:52:08 +02:00
let pause = elements.get("pause");
let status = undefined;
2020-10-04 11:52:08 +02:00
// if pause button is visible tidal is playing
if (pause) {
status = statuses.playing;
2020-10-04 11:52:08 +02:00
} else {
status = statuses.paused;
}
return status;
}
/**
* Update Tidal-hifi's media info
*
* @param {*} options
*/
function updateMediaInfo(options, notify) {
if (options) {
ipcRenderer.send(globalEvents.updateInfo, options);
store.get(settings.notifications) && notify && notifier.notify(options);
2020-10-04 11:52:08 +02:00
if (player) {
player.metadata = {
...player.metadata,
...{
"xesam:title": options.title,
"xesam:artist": [options.artists],
"mpris:artUrl": options.image,
},
};
player.playbackStatus = options.status == statuses.paused ? "Paused" : "Playing";
}
}
}
/**
2019-10-22 21:25:57 +02:00
* Watch for song changes and update title + notify
*/
2020-10-04 11:52:08 +02:00
setInterval(function () {
const title = elements.getText("title");
2021-04-21 03:31:28 +02:00
//const id = elements.get("url").href.replace(/[^0-9]/g, "");
const artists = elements.getText("artists");
2021-04-20 21:56:02 +02:00
const current = elements.getText("current");
const duration = elements.getText("duration");
const barval = elements.get("bar").getAttribute("aria-valuenow");
const songDashArtistTitle = `${title} - ${artists}`;
const currentStatus = getCurrentlyPlayingStatus();
const options = {
title,
message: artists,
status: currentStatus,
2021-04-21 03:31:28 +02:00
url: currentURL,
2021-04-20 21:56:02 +02:00
current: current,
duration: duration,
};
2019-10-22 21:25:57 +02:00
const playStatusChanged = currentStatus !== currentPlayStatus;
2021-04-20 21:56:02 +02:00
const barvalChanged = barval !== barvalue;
const titleOrArtistChanged = currentSong !== songDashArtistTitle;
if (titleOrArtistChanged || playStatusChanged || barvalChanged || updatecurrent) {
// update title and play info with new info
setTitle(songDashArtistTitle);
currentSong = songDashArtistTitle;
currentPlayStatus = currentStatus;
2019-10-22 21:25:57 +02:00
2021-04-20 22:15:34 +02:00
// check progress bar value and make sure current stays up to date after switch
if(barvalue != barval && !titleOrArtistChanged) {
2021-04-20 22:15:34 +02:00
barvalue = barval;
oldcurrent = options.current;
options.duration = duration;
2021-04-20 22:15:34 +02:00
updatecurrent = true;
}
2021-04-21 03:31:28 +02:00
// Video/Song check if it's a video return URL as undefined due to it not having an id.
switch(elements.get("url")) {
case null:
currentURL = undefined;
break;
default:
const id = elements.get("url").href.replace(/[^0-9]/g, "");
currentURL = `https://tidal.com/browse/track/${id}`;
break;
}
2021-04-20 22:15:34 +02:00
if(updatecurrent) {
if(options.current == oldcurrent && currentStatus != "paused") return;
oldcurrent = options.current;
updatecurrent = false;
}
2021-04-20 21:56:02 +02:00
// make sure current is set to 0 if title changes
2021-04-20 22:15:34 +02:00
if(titleOrArtistChanged) {
2021-04-20 21:56:02 +02:00
options.current = "0:00";
oldcurrent = options.current;
2021-04-20 21:56:02 +02:00
barvalue = barval;
2021-04-20 22:15:34 +02:00
}
const image = elements.getSongIcon();
2019-11-03 18:52:15 +01:00
new Promise((resolve) => {
if (image.startsWith("http")) {
downloadFile(image, notificationPath).then(
() => {
options.icon = notificationPath;
resolve();
},
() => {
// if the image can't be downloaded then continue without it
resolve();
}
);
} else {
// if the image can't be found on the page continue without it
resolve();
}
}).then(
() => {
updateMediaInfo(options, titleOrArtistChanged);
},
() => {}
);
}
2019-10-22 21:25:57 +02:00
}, 200);
if (process.platform === "linux" && store.get(settings.mpris)) {
try {
const Player = require("mpris-service");
player = Player({
name: "tidal-hifi",
identity: "tidal-hifi",
supportedUriSchemes: ["file"],
supportedMimeTypes: [
"audio/mpeg",
"audio/flac",
"audio/x-flac",
"application/ogg",
"audio/wav",
],
supportedInterfaces: ["player"],
desktopEntry: "tidal-hifi",
});
// Events
var events = {
next: "next",
previous: "previous",
pause: "pause",
playpause: "playpause",
stop: "stop",
play: "play",
loopStatus: "repeat",
shuffle: "shuffle",
seek: "seek",
};
Object.keys(events).forEach(function (eventName) {
player.on(eventName, function () {
const eventValue = events[eventName];
switch (events[eventValue]) {
case events.playpause:
playPause();
break;
default:
elements.click(eventValue);
}
});
});
player.on("quit", function () {
app.quit();
});
} catch (exception) {
console.log("player api not working");
}
}
2020-10-04 11:52:08 +02:00
addHotKeys();
addIPCEventListeners();