15
CHANGELOG.md
@ -4,9 +4,24 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 5.1.0
|
||||||
|
|
||||||
|
### New features
|
||||||
|
|
||||||
|
- Added proper updates through the MediaSession API
|
||||||
|
- You can now add custom CSS in the "advanced" settings tab
|
||||||
|
- You can now configure the updateFrequency in the settings window
|
||||||
|
- Default value is set to 500 and will overwrite the hardcoded value of 100
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
|
||||||
|
- Any songs **including** an artist listed in the `skipped artists` setting will now be skipped even if the song is a collaboration.
|
||||||
|
- Linux desktop icons have been fixed. See [#222](https://github.com/Mastermindzh/tidal-hifi/pull/222) for details.
|
||||||
|
|
||||||
## 5.0.0
|
## 5.0.0
|
||||||
|
|
||||||
- Replaced "muting artists" with a full implementation of an Adblock mechanism
|
- Replaced "muting artists" with a full implementation of an Adblock mechanism
|
||||||
|
|
||||||
> Disabled audio & visual ads, unlocked lyrics, suggested track, track info, unlimited skips thanks to uBlockOrigin custom filters ([source](https://github.com/uBlockOrigin/uAssets/issues/17495))
|
> Disabled audio & visual ads, unlocked lyrics, suggested track, track info, unlimited skips thanks to uBlockOrigin custom filters ([source](https://github.com/uBlockOrigin/uAssets/issues/17495))
|
||||||
|
|
||||||
- @thanasistrisp updated Electron to 24.1.2 and fixed the tray bug :)
|
- @thanasistrisp updated Electron to 24.1.2 and fixed the tray bug :)
|
||||||
|
BIN
assets/icons/128x128.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
assets/icons/16x16.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
assets/icons/22x22.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
assets/icons/24x24.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
assets/icons/256x256.png
Normal file
After Width: | Height: | Size: 29 KiB |
BIN
assets/icons/32x32.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
assets/icons/384x384.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
assets/icons/48x48.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
assets/icons/64x64.png
Normal file
After Width: | Height: | Size: 11 KiB |
@ -9,7 +9,7 @@ snap:
|
|||||||
- screen-inhibit-control
|
- screen-inhibit-control
|
||||||
linux:
|
linux:
|
||||||
category: AudioVideo
|
category: AudioVideo
|
||||||
icon: icon.png
|
icon: assets/icons
|
||||||
target:
|
target:
|
||||||
- dir
|
- dir
|
||||||
executableName: tidal-hifi
|
executableName: tidal-hifi
|
||||||
@ -18,7 +18,7 @@ linux:
|
|||||||
Name: TIDAL Hi-Fi
|
Name: TIDAL Hi-Fi
|
||||||
GenericName: TIDAL Hi-Fi
|
GenericName: TIDAL Hi-Fi
|
||||||
Comment: The web version of listen.tidal.com running in electron with hifi support thanks to widevine.
|
Comment: The web version of listen.tidal.com running in electron with hifi support thanks to widevine.
|
||||||
Icon: icon.png
|
Icon: tidal-hifi
|
||||||
StartupNotify: true
|
StartupNotify: true
|
||||||
Terminal: false
|
Terminal: false
|
||||||
Type: Application
|
Type: Application
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
extends: ./build/electron-builder.base.yml
|
extends: ./build/electron-builder.base.yml
|
||||||
linux:
|
linux:
|
||||||
icon: icon.png
|
|
||||||
target:
|
target:
|
||||||
- pacman
|
- pacman
|
||||||
|
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "tidal-hifi",
|
"name": "tidal-hifi",
|
||||||
"version": "5.0.0",
|
"version": "5.1.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "tidal-hifi",
|
"name": "tidal-hifi",
|
||||||
"version": "5.0.0",
|
"version": "5.1.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.0.9",
|
"@electron/remote": "^2.0.9",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "tidal-hifi",
|
"name": "tidal-hifi",
|
||||||
"version": "5.0.0",
|
"version": "5.1.0",
|
||||||
"description": "Tidal on Electron with widevine(hifi) support",
|
"description": "Tidal on Electron with widevine(hifi) support",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -51,4 +51,4 @@
|
|||||||
"sass-lint-auto-fix": "^0.21.2"
|
"sass-lint-auto-fix": "^0.21.2"
|
||||||
},
|
},
|
||||||
"prettier": "@mastermindzh/prettier-config"
|
"prettier": "@mastermindzh/prettier-config"
|
||||||
}
|
}
|
@ -9,34 +9,36 @@
|
|||||||
* windowBounds: { width: 800, height: 600 },
|
* windowBounds: { width: 800, height: 600 },
|
||||||
*/
|
*/
|
||||||
const settings = {
|
const settings = {
|
||||||
notifications: "notifications",
|
|
||||||
api: "api",
|
|
||||||
menuBar: "menuBar",
|
|
||||||
playBackControl: "playBackControl",
|
|
||||||
skipArtists: "skipArtists",
|
|
||||||
skippedArtists: "skippedArtists",
|
|
||||||
adBlock: "adBlock",
|
adBlock: "adBlock",
|
||||||
disableBackgroundThrottle: "disableBackgroundThrottle",
|
api: "api",
|
||||||
apiSettings: {
|
apiSettings: {
|
||||||
root: "apiSettings",
|
root: "apiSettings",
|
||||||
port: "apiSettings.port",
|
port: "apiSettings.port",
|
||||||
},
|
},
|
||||||
singleInstance: "singleInstance",
|
customCSS: "customCSS",
|
||||||
|
disableBackgroundThrottle: "disableBackgroundThrottle",
|
||||||
disableHardwareMediaKeys: "disableHardwareMediaKeys",
|
disableHardwareMediaKeys: "disableHardwareMediaKeys",
|
||||||
|
enableCustomHotkeys: "enableCustomHotkeys",
|
||||||
|
enableDiscord: "enableDiscord",
|
||||||
flags: {
|
flags: {
|
||||||
disableHardwareMediaKeys: "flags.disableHardwareMediaKeys",
|
disableHardwareMediaKeys: "flags.disableHardwareMediaKeys",
|
||||||
gpuRasterization: "flags.gpuRasterization",
|
gpuRasterization: "flags.gpuRasterization",
|
||||||
},
|
},
|
||||||
|
menuBar: "menuBar",
|
||||||
|
minimizeOnClose: "minimizeOnClose",
|
||||||
mpris: "mpris",
|
mpris: "mpris",
|
||||||
enableCustomHotkeys: "enableCustomHotkeys",
|
notifications: "notifications",
|
||||||
|
playBackControl: "playBackControl",
|
||||||
|
singleInstance: "singleInstance",
|
||||||
|
skipArtists: "skipArtists",
|
||||||
|
skippedArtists: "skippedArtists",
|
||||||
trayIcon: "trayIcon",
|
trayIcon: "trayIcon",
|
||||||
enableDiscord: "enableDiscord",
|
updateFrequency: "updateFrequency",
|
||||||
windowBounds: {
|
windowBounds: {
|
||||||
root: "windowBounds",
|
root: "windowBounds",
|
||||||
width: "windowBounds.width",
|
width: "windowBounds.width",
|
||||||
height: "windowBounds.height",
|
height: "windowBounds.height",
|
||||||
},
|
},
|
||||||
minimizeOnClose: "minimizeOnClose",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = settings;
|
module.exports = settings;
|
||||||
|
@ -172,7 +172,6 @@ app.on("ready", async () => {
|
|||||||
store.get(settings.trayIcon) && addTray(mainWindow, { icon }) && refreshTray();
|
store.get(settings.trayIcon) && addTray(mainWindow, { icon }) && refreshTray();
|
||||||
store.get(settings.api) && expressModule.run(mainWindow);
|
store.get(settings.api) && expressModule.run(mainWindow);
|
||||||
store.get(settings.enableDiscord) && discordModule.initRPC();
|
store.get(settings.enableDiscord) && discordModule.initRPC();
|
||||||
// mainWindow.webContents.openDevTools();
|
|
||||||
} else {
|
} else {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,22 @@
|
|||||||
let trayIcon,
|
let adBlock,
|
||||||
minimizeOnClose,
|
api,
|
||||||
mpris,
|
customCSS,
|
||||||
|
disableBackgroundThrottle,
|
||||||
|
disableHardwareMediaKeys,
|
||||||
enableCustomHotkeys,
|
enableCustomHotkeys,
|
||||||
enableDiscord,
|
enableDiscord,
|
||||||
skipArtists,
|
gpuRasterization,
|
||||||
|
menuBar,
|
||||||
|
minimizeOnClose,
|
||||||
|
mpris,
|
||||||
notifications,
|
notifications,
|
||||||
playBackControl,
|
playBackControl,
|
||||||
api,
|
|
||||||
port,
|
port,
|
||||||
menuBar,
|
|
||||||
skippedArtists,
|
|
||||||
adBlock,
|
|
||||||
disableBackgroundThrottle,
|
|
||||||
singleInstance,
|
singleInstance,
|
||||||
disableHardwareMediaKeys,
|
skipArtists,
|
||||||
gpuRasterization;
|
skippedArtists,
|
||||||
|
trayIcon,
|
||||||
|
updateFrequency;
|
||||||
|
|
||||||
const { store, settings } = require("./../../scripts/settings");
|
const { store, settings } = require("./../../scripts/settings");
|
||||||
const { ipcRenderer } = require("electron");
|
const { ipcRenderer } = require("electron");
|
||||||
@ -25,23 +27,25 @@ const { app } = remote;
|
|||||||
* Sync the UI forms with the current settings
|
* Sync the UI forms with the current settings
|
||||||
*/
|
*/
|
||||||
function refreshSettings() {
|
function refreshSettings() {
|
||||||
notifications.checked = store.get(settings.notifications);
|
adBlock.checked = store.get(settings.adBlock);
|
||||||
playBackControl.checked = store.get(settings.playBackControl);
|
|
||||||
api.checked = store.get(settings.api);
|
api.checked = store.get(settings.api);
|
||||||
port.value = store.get(settings.apiSettings.port);
|
customCSS.value = store.get(settings.customCSS);
|
||||||
menuBar.checked = store.get(settings.menuBar);
|
disableBackgroundThrottle.checked = store.get("disableBackgroundThrottle");
|
||||||
trayIcon.checked = store.get(settings.trayIcon);
|
disableHardwareMediaKeys.checked = store.get(settings.flags.disableHardwareMediaKeys);
|
||||||
mpris.checked = store.get(settings.mpris);
|
|
||||||
enableCustomHotkeys.checked = store.get(settings.enableCustomHotkeys);
|
enableCustomHotkeys.checked = store.get(settings.enableCustomHotkeys);
|
||||||
enableDiscord.checked = store.get(settings.enableDiscord);
|
enableDiscord.checked = store.get(settings.enableDiscord);
|
||||||
|
gpuRasterization.checked = store.get(settings.flags.gpuRasterization);
|
||||||
|
menuBar.checked = store.get(settings.menuBar);
|
||||||
minimizeOnClose.checked = store.get(settings.minimizeOnClose);
|
minimizeOnClose.checked = store.get(settings.minimizeOnClose);
|
||||||
|
mpris.checked = store.get(settings.mpris);
|
||||||
|
notifications.checked = store.get(settings.notifications);
|
||||||
|
playBackControl.checked = store.get(settings.playBackControl);
|
||||||
|
port.value = store.get(settings.apiSettings.port);
|
||||||
|
singleInstance.checked = store.get(settings.singleInstance);
|
||||||
skipArtists.checked = store.get(settings.skipArtists);
|
skipArtists.checked = store.get(settings.skipArtists);
|
||||||
skippedArtists.value = store.get(settings.skippedArtists).join("\n");
|
skippedArtists.value = store.get(settings.skippedArtists).join("\n");
|
||||||
adBlock.checked = store.get(settings.adBlock);
|
trayIcon.checked = store.get(settings.trayIcon);
|
||||||
singleInstance.checked = store.get(settings.singleInstance);
|
updateFrequency.value = store.get(settings.updateFrequency);
|
||||||
disableHardwareMediaKeys.checked = store.get(settings.flags.disableHardwareMediaKeys);
|
|
||||||
gpuRasterization.checked = store.get(settings.flags.gpuRasterization);
|
|
||||||
disableBackgroundThrottle.checked = store.get("disableBackgroundThrottle");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -109,41 +113,45 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||||||
document.getElementById(tab).click();
|
document.getElementById(tab).click();
|
||||||
});
|
});
|
||||||
|
|
||||||
notifications = get("notifications");
|
adBlock = get("adBlock");
|
||||||
playBackControl = get("playBackControl");
|
|
||||||
api = get("apiCheckbox");
|
api = get("apiCheckbox");
|
||||||
port = get("port");
|
customCSS = get("customCSS");
|
||||||
menuBar = get("menuBar");
|
disableBackgroundThrottle = get("disableBackgroundThrottle");
|
||||||
trayIcon = get("trayIcon");
|
disableHardwareMediaKeys = get("disableHardwareMediaKeys");
|
||||||
minimizeOnClose = get("minimizeOnClose");
|
|
||||||
mpris = get("mprisCheckbox");
|
|
||||||
enableCustomHotkeys = get("enableCustomHotkeys");
|
enableCustomHotkeys = get("enableCustomHotkeys");
|
||||||
enableDiscord = get("enableDiscord");
|
enableDiscord = get("enableDiscord");
|
||||||
|
gpuRasterization = get("gpuRasterization");
|
||||||
|
menuBar = get("menuBar");
|
||||||
|
minimizeOnClose = get("minimizeOnClose");
|
||||||
|
mpris = get("mprisCheckbox");
|
||||||
|
notifications = get("notifications");
|
||||||
|
playBackControl = get("playBackControl");
|
||||||
|
port = get("port");
|
||||||
|
trayIcon = get("trayIcon");
|
||||||
skipArtists = get("skipArtists");
|
skipArtists = get("skipArtists");
|
||||||
skippedArtists = get("skippedArtists");
|
skippedArtists = get("skippedArtists");
|
||||||
adBlock = get("adBlock");
|
|
||||||
disableBackgroundThrottle = get("disableBackgroundThrottle");
|
|
||||||
singleInstance = get("singleInstance");
|
singleInstance = get("singleInstance");
|
||||||
disableHardwareMediaKeys = get("disableHardwareMediaKeys");
|
updateFrequency = get("updateFrequency");
|
||||||
gpuRasterization = get("gpuRasterization");
|
|
||||||
|
|
||||||
refreshSettings();
|
refreshSettings();
|
||||||
|
|
||||||
addInputListener(notifications, settings.notifications);
|
addInputListener(adBlock, settings.adBlock);
|
||||||
addInputListener(playBackControl, settings.playBackControl);
|
|
||||||
addInputListener(api, settings.api);
|
addInputListener(api, settings.api);
|
||||||
addInputListener(port, settings.apiSettings.port);
|
addTextAreaListener(customCSS, settings.customCSS);
|
||||||
addInputListener(menuBar, settings.menuBar);
|
addInputListener(disableBackgroundThrottle, settings.disableBackgroundThrottle);
|
||||||
addInputListener(trayIcon, settings.trayIcon);
|
addInputListener(disableHardwareMediaKeys, settings.flags.disableHardwareMediaKeys);
|
||||||
addInputListener(mpris, settings.mpris);
|
|
||||||
addInputListener(enableCustomHotkeys, settings.enableCustomHotkeys);
|
addInputListener(enableCustomHotkeys, settings.enableCustomHotkeys);
|
||||||
addInputListener(enableDiscord, settings.enableDiscord);
|
addInputListener(enableDiscord, settings.enableDiscord);
|
||||||
|
addInputListener(gpuRasterization, settings.flags.gpuRasterization);
|
||||||
|
addInputListener(menuBar, settings.menuBar);
|
||||||
addInputListener(minimizeOnClose, settings.minimizeOnClose);
|
addInputListener(minimizeOnClose, settings.minimizeOnClose);
|
||||||
|
addInputListener(mpris, settings.mpris);
|
||||||
|
addInputListener(notifications, settings.notifications);
|
||||||
|
addInputListener(playBackControl, settings.playBackControl);
|
||||||
|
addInputListener(port, settings.apiSettings.port);
|
||||||
addInputListener(skipArtists, settings.skipArtists);
|
addInputListener(skipArtists, settings.skipArtists);
|
||||||
addTextAreaListener(skippedArtists, settings.skippedArtists);
|
addTextAreaListener(skippedArtists, settings.skippedArtists);
|
||||||
addInputListener(adBlock, settings.adBlock);
|
|
||||||
addInputListener(disableBackgroundThrottle, settings.disableBackgroundThrottle);
|
|
||||||
addInputListener(singleInstance, settings.singleInstance);
|
addInputListener(singleInstance, settings.singleInstance);
|
||||||
addInputListener(disableHardwareMediaKeys, settings.flags.disableHardwareMediaKeys);
|
addInputListener(trayIcon, settings.trayIcon);
|
||||||
addInputListener(gpuRasterization, settings.flags.gpuRasterization);
|
addInputListener(updateFrequency, settings.updateFrequency);
|
||||||
});
|
});
|
||||||
|
@ -160,7 +160,7 @@
|
|||||||
<div class="group__option">
|
<div class="group__option">
|
||||||
<div class="group__description">
|
<div class="group__description">
|
||||||
<label for="port">API port</label>
|
<label for="port">API port</label>
|
||||||
<input id="port" type="text" class="text-input" name="port" />
|
<input id="port" type="number" class="text-input" name="port" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="group__option">
|
<div class="group__option">
|
||||||
@ -212,6 +212,31 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section id="advanced-section" class="tabs__section">
|
<section id="advanced-section" class="tabs__section">
|
||||||
|
<div class="group">
|
||||||
|
<p class="group__title">Settings</p>
|
||||||
|
<div class="group__option">
|
||||||
|
<div class="group__description">
|
||||||
|
<h4>Update frequency</h4>
|
||||||
|
<p>
|
||||||
|
The amount of time, in milliseconds, that tidal-hifi will refresh its playback info by scraping the
|
||||||
|
website.
|
||||||
|
The default of 500 seems to work in more cases but if you are fine with a bit more resource usage you
|
||||||
|
can decrease it as well.
|
||||||
|
</p>
|
||||||
|
<input id="updateFrequency" type="number" class="text-input" name="updateFrequency" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="group__option">
|
||||||
|
<div class="group__description">
|
||||||
|
<h4>Custom CSS</h4>
|
||||||
|
<p>
|
||||||
|
The css that you put in here will be injected into a style tag in the head of the document.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea id="customCSS" class="textarea" cols="40" rows="8" spellcheck="false"></textarea>
|
||||||
|
|
||||||
<div class="group">
|
<div class="group">
|
||||||
<p class="group__title">Flags</p>
|
<p class="group__title">Flags</p>
|
||||||
<div class="group__option">
|
<div class="group__option">
|
||||||
|
@ -7,7 +7,7 @@ const { downloadFile } = require("./scripts/download");
|
|||||||
const statuses = require("./constants/statuses");
|
const statuses = require("./constants/statuses");
|
||||||
const hotkeys = require("./scripts/hotkeys");
|
const hotkeys = require("./scripts/hotkeys");
|
||||||
const globalEvents = require("./constants/globalEvents");
|
const globalEvents = require("./constants/globalEvents");
|
||||||
const { skipArtists } = require("./constants/settings");
|
const { skipArtists, updateFrequency, customCSS } = require("./constants/settings");
|
||||||
const notificationPath = `${app.getPath("userData")}/notification.jpg`;
|
const notificationPath = `${app.getPath("userData")}/notification.jpg`;
|
||||||
const appName = "Tidal Hifi";
|
const appName = "Tidal Hifi";
|
||||||
let currentSong = "";
|
let currentSong = "";
|
||||||
@ -65,16 +65,27 @@ const elements = {
|
|||||||
return "";
|
return "";
|
||||||
},
|
},
|
||||||
|
|
||||||
getArtists: function () {
|
/**
|
||||||
|
* returns an array of all artists in the current song
|
||||||
|
* @returns {Array} artists
|
||||||
|
*/
|
||||||
|
getArtistsArray: function () {
|
||||||
const footer = this.get("footer");
|
const footer = this.get("footer");
|
||||||
|
|
||||||
if (footer) {
|
if (footer) {
|
||||||
const artists = footer.querySelector(this["artists"]);
|
const artists = footer.querySelectorAll(this.artists);
|
||||||
if (artists) {
|
if (artists) return Array.from(artists).map((artist) => artist.textContent);
|
||||||
return artists.innerText;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unify the artists array into a string separated by commas
|
||||||
|
* @param {Array} artistsArray
|
||||||
|
* @returns {String} artists
|
||||||
|
*/
|
||||||
|
getArtistsString: function (artistsArray) {
|
||||||
|
if (artistsArray.length > 0) return artistsArray.join(", ");
|
||||||
return "unknown artist(s)";
|
return "unknown artist(s)";
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -132,6 +143,29 @@ const elements = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function addCustomCss() {
|
||||||
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.innerHTML = store.get(customCSS);
|
||||||
|
document.head.appendChild(style);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the update frequency from the store
|
||||||
|
* make sure it returns a number, if not use the default
|
||||||
|
*/
|
||||||
|
function getUpdateFrequency() {
|
||||||
|
const storeValue = store.get(updateFrequency);
|
||||||
|
const defaultValue = 500;
|
||||||
|
|
||||||
|
if (!isNaN(storeValue)) {
|
||||||
|
return storeValue;
|
||||||
|
} else {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Play or pause the current song
|
* Play or pause the current song
|
||||||
*/
|
*/
|
||||||
@ -289,14 +323,14 @@ function updateMediaInfo(options, notify) {
|
|||||||
if (options) {
|
if (options) {
|
||||||
ipcRenderer.send(globalEvents.updateInfo, options);
|
ipcRenderer.send(globalEvents.updateInfo, options);
|
||||||
if (store.get(settings.notifications) && notify) {
|
if (store.get(settings.notifications) && notify) {
|
||||||
new Notification({ title: options.title, body: options.message, icon: options.icon }).show();
|
new Notification({ title: options.title, body: options.artists, icon: options.icon }).show();
|
||||||
}
|
}
|
||||||
if (player) {
|
if (player) {
|
||||||
player.metadata = {
|
player.metadata = {
|
||||||
...player.metadata,
|
...player.metadata,
|
||||||
...{
|
...{
|
||||||
"xesam:title": options.title,
|
"xesam:title": options.title,
|
||||||
"xesam:artist": [options.message],
|
"xesam:artist": [options.artists],
|
||||||
"xesam:album": options.album,
|
"xesam:album": options.album,
|
||||||
"mpris:artUrl": options.image,
|
"mpris:artUrl": options.image,
|
||||||
"mpris:length": convertDuration(options.duration) * 1000 * 1000,
|
"mpris:length": convertDuration(options.duration) * 1000 * 1000,
|
||||||
@ -327,22 +361,40 @@ function getTrackID() {
|
|||||||
return window.location;
|
return window.location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateMediaSession(options) {
|
||||||
|
if ("mediaSession" in navigator) {
|
||||||
|
navigator.mediaSession.metadata = new MediaMetadata({
|
||||||
|
title: options.title,
|
||||||
|
artist: options.artists,
|
||||||
|
album: options.album,
|
||||||
|
artwork: [
|
||||||
|
{
|
||||||
|
src: options.icon,
|
||||||
|
sizes: "640x640",
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Watch for song changes and update title + notify
|
* Watch for song changes and update title + notify
|
||||||
*/
|
*/
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
const title = elements.getText("title");
|
const title = elements.getText("title");
|
||||||
const artists = elements.getArtists();
|
const artistsArray = elements.getArtistsArray();
|
||||||
skipArtistsIfFoundInSkippedArtistsList(artists);
|
const artistsString = elements.getArtistsString(artistsArray);
|
||||||
|
skipArtistsIfFoundInSkippedArtistsList(artistsArray);
|
||||||
|
|
||||||
const album = elements.getAlbumName();
|
const album = elements.getAlbumName();
|
||||||
const current = elements.getText("current");
|
const current = elements.getText("current");
|
||||||
const duration = elements.getText("duration");
|
const duration = elements.getText("duration");
|
||||||
const songDashArtistTitle = `${title} - ${artists}`;
|
const songDashArtistTitle = `${title} - ${artistsString}`;
|
||||||
const currentStatus = getCurrentlyPlayingStatus();
|
const currentStatus = getCurrentlyPlayingStatus();
|
||||||
const options = {
|
const options = {
|
||||||
title,
|
title,
|
||||||
message: artists,
|
artists: artistsString,
|
||||||
album: album,
|
album: album,
|
||||||
status: currentStatus,
|
status: currentStatus,
|
||||||
url: getTrackURL(),
|
url: getTrackURL(),
|
||||||
@ -351,7 +403,7 @@ setInterval(function () {
|
|||||||
"app-name": appName,
|
"app-name": appName,
|
||||||
};
|
};
|
||||||
|
|
||||||
const titleOrArtistChanged = currentSong !== songDashArtistTitle;
|
const titleOrArtistsChanged = currentSong !== songDashArtistTitle;
|
||||||
|
|
||||||
// update title, url and play info with new info
|
// update title, url and play info with new info
|
||||||
setTitle(songDashArtistTitle);
|
setTitle(songDashArtistTitle);
|
||||||
@ -380,24 +432,32 @@ setInterval(function () {
|
|||||||
}
|
}
|
||||||
}).then(
|
}).then(
|
||||||
() => {
|
() => {
|
||||||
updateMediaInfo(options, titleOrArtistChanged);
|
updateMediaInfo(options, titleOrArtistsChanged);
|
||||||
|
if (titleOrArtistsChanged) {
|
||||||
|
updateMediaSession(options);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
() => {}
|
() => {}
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* automatically skip a song if the artists are found in the list of artists to skip
|
* automatically skip a song if the artists are found in the list of artists to skip
|
||||||
* @param {*} artists list of artists to skip
|
* @param {*} artists array of artists
|
||||||
*/
|
*/
|
||||||
function skipArtistsIfFoundInSkippedArtistsList(artists) {
|
function skipArtistsIfFoundInSkippedArtistsList(artists) {
|
||||||
if (store.get(skipArtists)) {
|
if (store.get(skipArtists)) {
|
||||||
const skippedArtists = store.get(settings.skippedArtists);
|
const skippedArtists = store.get(settings.skippedArtists);
|
||||||
if (skippedArtists.find((artist) => artist === artists) !== undefined) {
|
if (skippedArtists.length > 0) {
|
||||||
elements.click("next");
|
const artistsToSkip = skippedArtists.map((artist) => artist);
|
||||||
|
const artistNames = Object.values(artists).map((artist) => artist);
|
||||||
|
const foundArtist = artistNames.some((artist) => artistsToSkip.includes(artist));
|
||||||
|
if (foundArtist) {
|
||||||
|
elements.click("next");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, 100);
|
}, getUpdateFrequency());
|
||||||
|
|
||||||
if (process.platform === "linux" && store.get(settings.mpris)) {
|
if (process.platform === "linux" && store.get(settings.mpris)) {
|
||||||
try {
|
try {
|
||||||
@ -454,7 +514,7 @@ if (process.platform === "linux" && store.get(settings.mpris)) {
|
|||||||
console.log("player api not working");
|
console.log("player api not working");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
addCustomCss();
|
||||||
addHotKeys();
|
addHotKeys();
|
||||||
addIPCEventListeners();
|
addIPCEventListeners();
|
||||||
addFullScreenListeners();
|
addFullScreenListeners();
|
||||||
|
@ -26,8 +26,8 @@ const observer = (event, arg) => {
|
|||||||
...idleStatus,
|
...idleStatus,
|
||||||
...{
|
...{
|
||||||
details: `Listening to ${mediaInfoModule.mediaInfo.title}`,
|
details: `Listening to ${mediaInfoModule.mediaInfo.title}`,
|
||||||
state: mediaInfoModule.mediaInfo.artist
|
state: mediaInfoModule.mediaInfo.artists
|
||||||
? mediaInfoModule.mediaInfo.artist
|
? mediaInfoModule.mediaInfo.artists
|
||||||
: "unknown artist(s)",
|
: "unknown artist(s)",
|
||||||
startTimestamp: parseInt(now),
|
startTimestamp: parseInt(now),
|
||||||
endTimestamp: parseInt(remaining),
|
endTimestamp: parseInt(remaining),
|
||||||
@ -43,7 +43,7 @@ const observer = (event, arg) => {
|
|||||||
...idleStatus,
|
...idleStatus,
|
||||||
...{
|
...{
|
||||||
details: `Watching ${mediaInfoModule.mediaInfo.title}`,
|
details: `Watching ${mediaInfoModule.mediaInfo.title}`,
|
||||||
state: mediaInfoModule.mediaInfo.artist,
|
state: mediaInfoModule.mediaInfo.artists,
|
||||||
startTimestamp: parseInt(now),
|
startTimestamp: parseInt(now),
|
||||||
endTimestamp: parseInt(remaining),
|
endTimestamp: parseInt(remaining),
|
||||||
},
|
},
|
||||||
|
@ -11,7 +11,7 @@ let expressInstance;
|
|||||||
/**
|
/**
|
||||||
* Function to enable tidal-hifi's express api
|
* Function to enable tidal-hifi's express api
|
||||||
*/
|
*/
|
||||||
expressModule.run = function(mainWindow) {
|
expressModule.run = function (mainWindow) {
|
||||||
/**
|
/**
|
||||||
* Shorthand to handle a fire and forget global event
|
* Shorthand to handle a fire and forget global event
|
||||||
* @param {*} res
|
* @param {*} res
|
||||||
@ -24,14 +24,14 @@ expressModule.run = function(mainWindow) {
|
|||||||
|
|
||||||
const expressApp = express();
|
const expressApp = express();
|
||||||
expressApp.get("/", (req, res) => res.send("Hello World!"));
|
expressApp.get("/", (req, res) => res.send("Hello World!"));
|
||||||
expressApp.get("/current", (req, res) => res.json(mediaInfo));
|
expressApp.get("/current", (req, res) => res.json({ ...mediaInfo, artist: mediaInfo.artists }));
|
||||||
expressApp.get("/image", (req, res) => {
|
expressApp.get("/image", (req, res) => {
|
||||||
var stream = fs.createReadStream(mediaInfo.icon);
|
var stream = fs.createReadStream(mediaInfo.icon);
|
||||||
stream.on("open", function() {
|
stream.on("open", function () {
|
||||||
res.set("Content-Type", "image/png");
|
res.set("Content-Type", "image/png");
|
||||||
stream.pipe(res);
|
stream.pipe(res);
|
||||||
});
|
});
|
||||||
stream.on("error", function() {
|
stream.on("error", function () {
|
||||||
res.set("Content-Type", "text/plain");
|
res.set("Content-Type", "text/plain");
|
||||||
res.status(404).end("Not found");
|
res.status(404).end("Not found");
|
||||||
});
|
});
|
||||||
@ -54,7 +54,7 @@ expressModule.run = function(mainWindow) {
|
|||||||
let port = store.get(settings.apiSettings.port);
|
let port = store.get(settings.apiSettings.port);
|
||||||
|
|
||||||
expressInstance = expressApp.listen(port, "127.0.0.1", () => {});
|
expressInstance = expressApp.listen(port, "127.0.0.1", () => {});
|
||||||
expressInstance.on("error", function(e) {
|
expressInstance.on("error", function (e) {
|
||||||
let message = e.code;
|
let message = e.code;
|
||||||
if (e.code === "EADDRINUSE") {
|
if (e.code === "EADDRINUSE") {
|
||||||
message = `Port ${port} in use.`;
|
message = `Port ${port} in use.`;
|
||||||
|
@ -2,14 +2,14 @@ const statuses = require("./../constants/statuses");
|
|||||||
|
|
||||||
const mediaInfo = {
|
const mediaInfo = {
|
||||||
title: "",
|
title: "",
|
||||||
artist: "",
|
artists: "",
|
||||||
album: "",
|
album: "",
|
||||||
icon: "",
|
icon: "",
|
||||||
status: statuses.paused,
|
status: statuses.paused,
|
||||||
url: "",
|
url: "",
|
||||||
current: "",
|
current: "",
|
||||||
duration: "",
|
duration: "",
|
||||||
image: "tidal-hifi-icon"
|
image: "tidal-hifi-icon",
|
||||||
};
|
};
|
||||||
const mediaInfoModule = {
|
const mediaInfoModule = {
|
||||||
mediaInfo,
|
mediaInfo,
|
||||||
@ -20,7 +20,7 @@ const mediaInfoModule = {
|
|||||||
*/
|
*/
|
||||||
mediaInfoModule.update = function (arg) {
|
mediaInfoModule.update = function (arg) {
|
||||||
mediaInfo.title = propOrDefault(arg.title);
|
mediaInfo.title = propOrDefault(arg.title);
|
||||||
mediaInfo.artist = propOrDefault(arg.message);
|
mediaInfo.artists = propOrDefault(arg.artists);
|
||||||
mediaInfo.album = propOrDefault(arg.album);
|
mediaInfo.album = propOrDefault(arg.album);
|
||||||
mediaInfo.icon = propOrDefault(arg.icon);
|
mediaInfo.icon = propOrDefault(arg.icon);
|
||||||
mediaInfo.url = propOrDefault(arg.url);
|
mediaInfo.url = propOrDefault(arg.url);
|
||||||
|
@ -7,29 +7,31 @@ let settingsWindow;
|
|||||||
|
|
||||||
const store = new Store({
|
const store = new Store({
|
||||||
defaults: {
|
defaults: {
|
||||||
notifications: true,
|
|
||||||
api: true,
|
|
||||||
playBackControl: true,
|
|
||||||
skipArtists: false,
|
|
||||||
skippedArtists: [""],
|
|
||||||
adBlock: false,
|
adBlock: false,
|
||||||
disableBackgroundThrottle: true,
|
api: true,
|
||||||
menuBar: true,
|
|
||||||
apiSettings: {
|
apiSettings: {
|
||||||
port: 47836,
|
port: 47836,
|
||||||
},
|
},
|
||||||
singleInstance: true,
|
customCSS: "",
|
||||||
|
disableBackgroundThrottle: true,
|
||||||
disableHardwareMediaKeys: false,
|
disableHardwareMediaKeys: false,
|
||||||
trayIcon: true,
|
|
||||||
minimizeOnClose: false,
|
|
||||||
mpris: false,
|
|
||||||
enableCustomHotkeys: false,
|
enableCustomHotkeys: false,
|
||||||
enableDiscord: false,
|
enableDiscord: false,
|
||||||
windowBounds: { width: 800, height: 600 },
|
|
||||||
flags: {
|
flags: {
|
||||||
gpuRasterization: true,
|
gpuRasterization: true,
|
||||||
disableHardwareMediaKeys: false,
|
disableHardwareMediaKeys: false,
|
||||||
},
|
},
|
||||||
|
menuBar: true,
|
||||||
|
minimizeOnClose: false,
|
||||||
|
mpris: false,
|
||||||
|
notifications: true,
|
||||||
|
playBackControl: true,
|
||||||
|
singleInstance: true,
|
||||||
|
skipArtists: false,
|
||||||
|
skippedArtists: [""],
|
||||||
|
trayIcon: true,
|
||||||
|
updateFrequency: 500,
|
||||||
|
windowBounds: { width: 800, height: 600 },
|
||||||
},
|
},
|
||||||
migrations: {
|
migrations: {
|
||||||
"3.1.0": (migrationStore) => {
|
"3.1.0": (migrationStore) => {
|
||||||
|