2019-10-20 22:47:01 +02:00
|
|
|
const { setTitle, getTitle } = require("./scripts/window-functions");
|
2020-10-04 11:52:08 +02:00
|
|
|
const { dialog, process } = require("electron").remote;
|
2019-11-03 11:18:01 +01:00
|
|
|
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");
|
2019-10-30 23:42:08 +01:00
|
|
|
const statuses = require("./constants/statuses");
|
2019-10-30 22:49:04 +01:00
|
|
|
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 = "";
|
2020-11-29 10:55:01 +01:00
|
|
|
let player;
|
2019-10-20 22:47:01 +02:00
|
|
|
|
|
|
|
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"]',
|
|
|
|
artists: '*[class^="mediaArtists"]',
|
|
|
|
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: '*[class^="image--"]',
|
2019-10-20 22:47:01 +02:00
|
|
|
|
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) {
|
2019-10-20 22:47:01 +02:00
|
|
|
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-20 22:47:01 +02:00
|
|
|
},
|
|
|
|
|
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) {
|
2019-10-20 22:47:01 +02:00
|
|
|
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) {
|
2019-10-20 22:47:01 +02:00
|
|
|
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() {
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("Control+p", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("account").click("settings");
|
|
|
|
});
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("Control+l", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
handleLogout();
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("Control+h", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("home");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("backspace", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("back");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("shift+backspace", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("forward");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+f", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.focus("search");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+u", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
// reloading window without cache should show the update bar if applicable
|
|
|
|
window.location.reload(true);
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+left", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("previous");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+right", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("next");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+right", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("next");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+s", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("shuffle");
|
|
|
|
});
|
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+r", function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
elements.click("repeat");
|
|
|
|
});
|
2019-11-03 18:52:15 +01:00
|
|
|
|
2020-10-04 11:52:08 +02:00
|
|
|
hotkeys.add("control+/", function () {
|
2019-11-03 18:52:15 +01:00
|
|
|
ipcRenderer.send(globalEvents.showSettings);
|
|
|
|
});
|
2019-10-20 22:47:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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) {
|
2019-10-20 22:47:01 +02:00
|
|
|
if (logoutOptions.indexOf("Yes, please") == response) {
|
|
|
|
for (i = 0; i < window.localStorage.length; i++) {
|
|
|
|
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) {
|
2019-10-30 22:49:04 +01:00
|
|
|
case globalEvents.playPause:
|
2019-10-22 21:25:57 +02:00
|
|
|
playPause();
|
|
|
|
break;
|
2019-10-30 22:49:04 +01:00
|
|
|
case globalEvents.next:
|
2019-10-22 21:25:57 +02:00
|
|
|
elements.click("next");
|
|
|
|
break;
|
2019-10-30 22:49:04 +01:00
|
|
|
case globalEvents.previous:
|
2019-10-22 21:25:57 +02:00
|
|
|
elements.click("previous");
|
|
|
|
break;
|
2019-10-30 22:49:04 +01:00
|
|
|
case globalEvents.play:
|
|
|
|
elements.click("play");
|
|
|
|
break;
|
|
|
|
case globalEvents.pause:
|
|
|
|
elements.click("pause");
|
|
|
|
break;
|
2019-10-22 21:25:57 +02:00
|
|
|
}
|
|
|
|
});
|
2019-10-20 22:47:01 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-10-30 23:42:08 +01:00
|
|
|
/**
|
|
|
|
* Update the current status of tidal (e.g playing or paused)
|
|
|
|
*/
|
|
|
|
function updateStatus() {
|
2020-10-04 11:52:08 +02:00
|
|
|
let pause = elements.get("pause");
|
|
|
|
let status;
|
|
|
|
|
|
|
|
// if pause button is visible tidal is playing
|
|
|
|
if (pause) {
|
2019-10-30 23:42:08 +01:00
|
|
|
status = statuses.playing;
|
2020-10-04 11:52:08 +02:00
|
|
|
} else {
|
|
|
|
status = statuses.paused;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
ipcRenderer.send(globalEvents.updateStatus, status);
|
2020-11-29 10:55:01 +01:00
|
|
|
if (player) {
|
|
|
|
player.playbackStatus = status == statuses.paused ? "Paused" : "Playing";
|
|
|
|
}
|
2019-10-30 23:42:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-20 22:47:01 +02:00
|
|
|
/**
|
2019-10-22 21:25:57 +02:00
|
|
|
* Watch for song changes and update title + notify
|
2019-10-20 22:47:01 +02:00
|
|
|
*/
|
2020-10-04 11:52:08 +02:00
|
|
|
setInterval(function () {
|
2019-10-20 22:47:01 +02:00
|
|
|
const title = elements.getText("title");
|
|
|
|
const artists = elements.getText("artists");
|
|
|
|
const songDashArtistTitle = `${title} - ${artists}`;
|
2019-10-22 21:25:57 +02:00
|
|
|
|
2019-10-30 23:42:08 +01:00
|
|
|
updateStatus();
|
|
|
|
|
2019-10-20 22:47:01 +02:00
|
|
|
if (getTitle() !== songDashArtistTitle) {
|
|
|
|
setTitle(songDashArtistTitle);
|
2019-10-22 21:25:57 +02:00
|
|
|
|
2019-11-03 18:52:15 +01:00
|
|
|
if (currentSong !== songDashArtistTitle) {
|
|
|
|
currentSong = songDashArtistTitle;
|
|
|
|
const image = elements.getSongIcon();
|
|
|
|
|
|
|
|
const options = {
|
|
|
|
title,
|
|
|
|
message: artists,
|
|
|
|
};
|
|
|
|
new Promise((resolve, reject) => {
|
|
|
|
if (image.startsWith("http")) {
|
|
|
|
downloadFile(image, notificationPath).then(
|
|
|
|
() => {
|
|
|
|
options.icon = notificationPath;
|
|
|
|
resolve();
|
|
|
|
},
|
|
|
|
() => {
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
reject();
|
|
|
|
}
|
|
|
|
}).then(
|
|
|
|
() => {
|
|
|
|
ipcRenderer.send(globalEvents.updateInfo, options);
|
|
|
|
store.get(settings.notifications) && notifier.notify(options);
|
2020-10-04 11:52:08 +02:00
|
|
|
|
2020-11-29 10:55:01 +01:00
|
|
|
if (player) {
|
|
|
|
player.metadata = {
|
|
|
|
...player.metadata,
|
|
|
|
...{
|
|
|
|
"xesam:title": title,
|
|
|
|
"xesam:artist": [artists],
|
|
|
|
"mpris:artUrl": image,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2019-11-03 18:52:15 +01:00
|
|
|
},
|
|
|
|
() => {}
|
|
|
|
);
|
|
|
|
}
|
2019-10-20 22:47:01 +02:00
|
|
|
}
|
2019-10-22 21:25:57 +02:00
|
|
|
}, 200);
|
2019-10-20 22:47:01 +02:00
|
|
|
|
2020-11-29 10:55:01 +01:00
|
|
|
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
|
|
|
|
2019-10-20 22:47:01 +02:00
|
|
|
addHotKeys();
|
|
|
|
addIPCEventListeners();
|