Compare commits

..

19 Commits

Author SHA1 Message Date
53cecbcd18 added a hotkey on ctrl+0 for settings. fixes #91 2022-01-23 11:02:28 +01:00
5a65f60cc5 Fixed bug: Triggering fullscreen from the Tidal web app would cause the menubar to be visible even if it was disabled in the settings (#96)
Co-authored-by: Diogo Oliveira <dromarques@outlook.com>
2022-01-23 10:55:50 +01:00
d51d5cdc24 Use native electron notifications and album text (#90)
Co-authored-by: Diogo Oliveira <dromarques@outlook.com>
2021-12-28 17:31:10 +01:00
0dec967e71 Add album image to media module and discord (#86)
Co-authored-by: Diogo Oliveira <diogoomarques98@gmail.com>
Co-authored-by: Marie <marie@kaifa.ch>
2021-12-19 13:18:39 +01:00
Kevin Yuan
c940d0991d Generate pacman builds using Github workflows (#81)
* Show "Tidal Hifi" as application name for notify-send

Set the 'app-name' variable for notify-send under Linux

* Generate pacman builds using Github workflows
Previous builds failed due to missing build dependencies when building the package using the Github workflow Linux environment
2021-12-08 18:35:39 +01:00
662ef6ad7b new deps (#77) 2021-12-04 12:51:19 +01:00
5313ab13d3 Merge pull request #76 from Mastermindzh/develop 2021-12-04 11:23:32 +01:00
f43f227191 added changelog and bumped version 2021-12-04 11:23:03 +01:00
Kevin Yuan
ae25d88e94 Show "Tidal Hifi" as application name for notify-send notifications (#75) 2021-12-04 11:21:14 +01:00
5ef6074015 Release 2.4.0 (#74)
Update MPRIS functionality to provide length, artist, and current position.
Also added rescrobbler explanation to the README.

Co-authored-by: Vinay V <cool00geek@yahoo.com>
2021-11-29 22:43:51 +01:00
8fea5265e7 Merge branch 'master' of github.com:Mastermindzh/tidal-hifi 2021-06-17 20:51:15 +02:00
8d2e03ca6b Merge branch 'master' of github.com:Mastermindzh/tidal-hifi 2021-06-17 20:45:33 +02:00
1074de228b Merge branch 'master' of github.com:Mastermindzh/tidal-hifi 2021-06-17 20:44:30 +02:00
Ignacio Brasca
64d1aa4041 Implement minimized action to hide the application on close (#60)
* Implement minimzed action to hide the application on close instead of
closing it.

* Add close event on the tray icon

* Add all items in the menu (not only Show/Close app)

* Changes on mainWindow. Toggle instead of Open/Close pair button
2021-06-17 20:44:23 +02:00
Ignacio Brasca
6608330ed3 Implement minimized action to hide the application on close (#60)
* Implement minimzed action to hide the application on close instead of
closing it.

* Add close event on the tray icon

* Add all items in the menu (not only Show/Close app)

* Changes on mainWindow. Toggle instead of Open/Close pair button
2021-06-17 20:37:14 +02:00
aa562c4a30 Merge branch 'master' of github.com:Mastermindzh/tidal-hifi 2021-05-30 15:40:32 +02:00
d6f63ac560 fixed artists retrieval, removed arch build steps 2021-05-30 15:40:27 +02:00
cdc0f49789 corrected KWF link 2021-04-30 08:55:48 +02:00
2f290f83fd Dev -> master (#49)
Co-authored-by: Cristian <54779545+callapa1@users.noreply.github.com>
2021-04-30 08:55:04 +02:00
21 changed files with 3278 additions and 2411 deletions

View File

@@ -9,10 +9,12 @@ jobs:
build_on_linux: build_on_linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install libarchive-tools
run: sudo apt-get install -y libarchive-tools
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions/setup-node@master - uses: actions/setup-node@master
with: with:
node-version: 12 node-version: 16
- run: npm install - run: npm install
- run: npm run build - run: npm run build
@@ -22,7 +24,7 @@ jobs:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions/setup-node@master - uses: actions/setup-node@master
with: with:
node-version: 12 node-version: 16
- run: npm install - run: npm install
- run: npm run build - run: npm run build
@@ -32,6 +34,6 @@ jobs:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions/setup-node@master - uses: actions/setup-node@master
with: with:
node-version: 12 node-version: 16
- run: npm install - run: npm install
- run: npm run build - run: npm run build

View File

@@ -9,10 +9,12 @@ jobs:
build_on_linux: build_on_linux:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install libarchive-tools
run: sudo apt-get install -y libarchive-tools
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions/setup-node@master - uses: actions/setup-node@master
with: with:
node-version: 12 node-version: 16
- run: npm install - run: npm install
- run: npm run build - run: npm run build
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
@@ -26,7 +28,7 @@ jobs:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions/setup-node@master - uses: actions/setup-node@master
with: with:
node-version: 12 node-version: 16
- run: npm install - run: npm install
- run: npm run build - run: npm run build
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master
@@ -40,7 +42,7 @@ jobs:
- uses: actions/checkout@master - uses: actions/checkout@master
- uses: actions/setup-node@master - uses: actions/setup-node@master
with: with:
node-version: 12 node-version: 16
- run: npm install - run: npm install
- run: npm run build - run: npm run build
- uses: actions/upload-artifact@master - uses: actions/upload-artifact@master

View File

@@ -4,10 +4,55 @@ 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).
## 2.7.1
- Fixed bug: Triggering fullscreen from the Tidal web app would cause the menubar to be visible even if it was disabled in the settings
## 2.7.0
- Switched to the native Notifier (removed node-notifier)
- Album art now also has a name, based on [best effort](https://github.com/Mastermindzh/tidal-hifi/pull/88#pullrequestreview-840814847)
## 2.6.0
- Add album images to mediainfo and discord
## 2.5.0
- Notify-send now correctly shows "Tidal Hifi" as the program name
- Updated dependencies (including electron itself)
### known issues
- Requires older version of nodejs due to electron-builder (use lts/gallium)
### builds
updated to nodejs 16 in actions
## 2.4.0
- Added more mpris settings
- Added instruction for rescrobbler to get last.fm working without sandbox mode
## 2.3.0
- Added a setting to minimize to tray on app close (off by default)
- Added the main menu to the trayicon
## 2.2.1
- artists is now gotten specifically from the footer. This fixes the [unknown artists bug](https://github.com/Mastermindzh/tidal-hifi/issues/45).
- the discord module will check whether the artists is empty and if so substitute it with a default message. This is to prevent sending an empty state to Discord (which it doesn't support). fixes [#45](https://github.com/Mastermindzh/tidal-hifi/issues/54)
### removed arch build details from source control
moved to: [https://github.com/Mastermindzh/tidal-hifi-aur](https://github.com/Mastermindzh/tidal-hifi-aur)
## 2.2.0 ## 2.2.0
- The discord integration now adds a time remaining field based on the song duration - The discord integration now adds a time remaining field based on the song duration
- All fields (current, remaining, and url are also available in the API*) - All fields (current, remaining, and url are also available in the API\*)
- the artist field is now correctly identified - the artist field is now correctly identified
* current time only updates on play/pause. * current time only updates on play/pause.

View File

@@ -3,7 +3,7 @@ Tidal-hifi
<img src = "./build/icon.png" height="40" align="right" /> <img src = "./build/icon.png" height="40" align="right" />
</h1> </h1>
The web version of [listen.tidal.com](listen.tidal.com) running in electron with hifi support thanks to widevine. The web version of [listen.tidal.com](https://listen.tidal.com) running in electron with hifi support thanks to widevine.
![tidal-hifi preview](./docs/preview.png) ![tidal-hifi preview](./docs/preview.png)
@@ -20,6 +20,7 @@ The web version of [listen.tidal.com](listen.tidal.com) running in electron with
- [Integrations](#integrations) - [Integrations](#integrations)
- [not included](#not-included) - [not included](#not-included)
- [Known bugs](#known-bugs) - [Known bugs](#known-bugs)
- [last.fm doesn't work out of the box. Use rescrobbler as a workaround](#lastfm-doesnt-work-out-of-the-box-use-rescrobbler-as-a-workaround)
- [Why](#why) - [Why](#why)
- [Why not extend existing projects?](#why-not-extend-existing-projects) - [Why not extend existing projects?](#why-not-extend-existing-projects)
- [Special thanks to...](#special-thanks-to) - [Special thanks to...](#special-thanks-to)
@@ -76,7 +77,8 @@ To install and work with the code on this project follow these steps:
- Custom hotkeys ([source](https://defkey.com/tidal-desktop-shortcuts)) - Custom hotkeys ([source](https://defkey.com/tidal-desktop-shortcuts))
- API for status and playback - API for status and playback
- Custom [integrations](#integrations) - Custom [integrations](#integrations)
- [Settings feature](./docs/settings.png) to disable certain functionality. (`ctrl+=`) - [Settings feature](./docs/settings.png) to disable certain functionality. (`ctrl+=` or `ctrl+0`)
- AlbumArt in integrations ([best-effort](https://github.com/Mastermindzh/tidal-hifi/pull/88#pullrequestreview-840814847))
## Integrations ## Integrations
@@ -96,7 +98,11 @@ It currently includes:
### Known bugs ### Known bugs
- [Last.fm login doesn't work](https://github.com/Mastermindzh/tidal-hifi/issues/4). #### last.fm doesn't work out of the box. Use rescrobbler as a workaround
The last.fm login doesn't work, as is evident from the following issue: [Last.fm login doesn't work](https://github.com/Mastermindzh/tidal-hifi/issues/4).
However, in that same issue you can read about a workaround using [rescrobbler](https://github.com/InputUsername/rescrobbled).
For now that will be the default workaround.
## Why ## Why
@@ -122,7 +128,7 @@ Sometimes it's just easier to start over, cover my own needs and then making it
## Buy me a coffee? Please don't ## Buy me a coffee? Please don't
Instead spend some money on a charity I care for: [kwf.nl](secure.kwf.nl/donation). Instead spend some money on a charity I care for: [kwf.nl](https://secure.kwf.nl/donation).
Inspired by [haydenjames' issue](https://github.com/Mastermindzh/tidal-hifi/issues/27#issuecomment-704198429) Inspired by [haydenjames' issue](https://github.com/Mastermindzh/tidal-hifi/issues/27#issuecomment-704198429)
## Images ## Images

View File

@@ -10,7 +10,7 @@ snap:
linux: linux:
category: Audio category: Audio
target: target:
# - pacman - pacman
- tar.gz - tar.gz
- deb - deb
- rpm - rpm
@@ -34,3 +34,7 @@ mac:
category: public.app-category.entertainment category: public.app-category.entertainment
win: win:
target: msi target: msi
icon: build/icon.png
artifactName: "tidalhifi"
appId: com.rickvanlieshout.tidalhifi
executableName: tidalhifi

View File

@@ -1,20 +0,0 @@
pkgbase = tidal-hifi-git
pkgdesc = The web version of listen.tidal.com running in electron with hifi support thanks to widevine.
pkgver = 2.1.1
pkgrel = 1
url = https://github.com/Mastermindzh/tidal-hifi
arch = x86_64
license = custom:MIT
makedepends = npm
makedepends = git
depends = libxss
depends = nss
depends = gtk3
provides = tidal-hifi
source = https://github.com/Mastermindzh/tidal-hifi/archive/2.1.1.zip
source = tidal-hifi.desktop
sha512sums = 510c94d9db8573103ee900dcd75b0416ea06ea62af7ed21818d2a5a77ab009a2737c852e7e20b97f846e14b07754a9e5a36ac5b9d0cd0a2a8d0aff3bbc75e622
sha512sums = 35f38ac308b871c1822d7f6f760f2fb54c3748cf769822cb0f0dfb90f0f5754ba9316da5e903a0d2e9839de3a43ec76f238f3f2e44021956fa1da19142081349
pkgname = tidal-hifi-git

View File

@@ -1,56 +0,0 @@
# Maintainer: Rick van Lieshout <info@rickvanlieshout.com>
_pkgname=tidal-hifi
pkgname="$_pkgname-git"
pkgver=2.1.1
pkgrel=1
pkgdesc="The web version of listen.tidal.com running in electron with hifi support thanks to widevine."
arch=("x86_64")
url="https://github.com/Mastermindzh/tidal-hifi"
license=("custom:MIT")
depends=("libxss" "nss" "gtk3")
makedepends=("npm" "git")
provides=("$_pkgname")
source=("https://github.com/Mastermindzh/tidal-hifi/archive/$pkgver.zip"
"${_pkgname}.desktop")
sha512sums=('510c94d9db8573103ee900dcd75b0416ea06ea62af7ed21818d2a5a77ab009a2737c852e7e20b97f846e14b07754a9e5a36ac5b9d0cd0a2a8d0aff3bbc75e622'
'35f38ac308b871c1822d7f6f760f2fb54c3748cf769822cb0f0dfb90f0f5754ba9316da5e903a0d2e9839de3a43ec76f238f3f2e44021956fa1da19142081349')
cdToPkg(){
cd "tidal-hifi-$pkgver"
}
prepare() {
cdToPkg
# install build dependencies
npm install
}
build() {
cdToPkg
# We are not using the systems Electron as we need castlab's Electron.
npm run build-arch
}
package() {
cdToPkg
install -d "${pkgdir}/opt/${_pkgname}/" "${pkgdir}/usr/bin" "${pkgdir}/usr/share/doc" "${pkgdir}/usr/share/licenses"
cp -r dist/linux-unpacked/* "${pkgdir}/opt/${_pkgname}/"
chmod +x "${pkgdir}/opt/${_pkgname}/${_pkgname}"
ln -s "/opt/${_pkgname}/${_pkgname}" "${pkgdir}/usr/bin/${_pkgname}"
install -Dm 644 "build/icon.png" "${pkgdir}/usr/share/pixmaps/${_pkgname}.png"
install -Dm 644 "${srcdir}/${_pkgname}.desktop" "${pkgdir}/usr/share/applications/${_pkgname}.desktop"
install -Dm 644 "README.md" "${pkgdir}/usr/share/doc/${pkgname}/README.md"
install -Dm 644 "LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
ln -s "/opt/${_pkgname}/LICENSE.electron.txt" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE.electron.txt"
ln -s "/opt/${_pkgname}/LICENSES.chromium.html" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSES.chromium.html"
}

View File

@@ -1,18 +0,0 @@
#!/bin/bash
# Will generate a correctly formatted SRCINFO file
SCRIPT_DIST=".SRCINFO"
# generate SRCINFO
makepkg --printsrcinfo > $SCRIPT_DIST
# replace pkgbase with tidal-hifi-git
pkgName="tidal-hifi-git"
sed -i "1s/.*/pkgbase = $pkgName/" $SCRIPT_DIST
# replace pkgbase with tidal-hifi-git
sed -i '/^pkgname/ d' $SCRIPT_DIST
echo "pkgname = $pkgName" >> $SCRIPT_DIST
# remove double line breaks and replace with single line breaks
sed -i '/^$/N;/^\n$/D' $SCRIPT_DIST

View File

@@ -1,13 +0,0 @@
[Desktop Entry]
Encoding=UTF-8
Name=tidal-hifi
GenericName=tidal-hifi
Comment=The web version of listen.tidal.com running in electron with hifi support thanks to widevine.
Exec=tidal-hifi %u
Icon=tidal-hifi.png
StartupNotify=true
Terminal=false
Type=Application
Categories=Network;Application;Audio;Video
StartupWMClass=tidal-hifi
X-PulseAudio-Properties=media.role=music

5290
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "tidal-hifi", "name": "tidal-hifi",
"version": "2.2.0", "version": "2.7.1",
"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": {
@@ -23,21 +23,19 @@
"homepage": "https://github.com/Mastermindzh/tidal-hifi", "homepage": "https://github.com/Mastermindzh/tidal-hifi",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"discord-rpc": "^3.2.0", "discord-rpc": "^4.0.1",
"electron-store": "^5.1.1", "electron-store": "^8.0.1",
"express": "^4.17.1", "express": "^4.17.1",
"hotkeys-js": "^3.7.6", "hotkeys-js": "^3.8.7",
"mpris-service": "^2.1.0", "mpris-service": "^2.1.2",
"node-notifier": "^9.0.1",
"request": "^2.88.2" "request": "^2.88.2"
}, },
"devDependencies": { "devDependencies": {
"@mastermindzh/prettier-config": "^1.0.0", "@mastermindzh/prettier-config": "^1.0.0",
"dot-prop": ">=4.2.1", "electron": "git+https://github.com/castlabs/electron-releases.git#v16.0.4+wvcus",
"electron": "git+https://github.com/castlabs/electron-releases.git#v10.4.3-wvvmp", "electron-builder": "^22.14.5",
"electron-builder": "^21.2.0",
"electron-reload": "^1.5.0", "electron-reload": "^1.5.0",
"prettier": "^2.0.4" "prettier": "^2.5.0"
}, },
"prettier": "@mastermindzh/prettier-config" "prettier": "@mastermindzh/prettier-config"
} }

View File

@@ -6,6 +6,7 @@ const globalEvents = {
previous: "previous", previous: "previous",
updateInfo: "update-info", updateInfo: "update-info",
hideSettings: "hideSettings", hideSettings: "hideSettings",
refreshMenuBar: "refreshMenubar",
showSettings: "showSettings", showSettings: "showSettings",
storeChanged: "storeChanged", storeChanged: "storeChanged",
error: "error", error: "error",

View File

@@ -26,6 +26,7 @@ const settings = {
width: "windowBounds.width", width: "windowBounds.width",
height: "windowBounds.height", height: "windowBounds.height",
}, },
minimizeOnClose: "minimizeOnClose",
}; };
module.exports = settings; module.exports = settings;

View File

@@ -29,6 +29,14 @@ if (!app.isPackaged) {
}); });
} }
/**
* Update the menuBarVisbility according to the store value
*
*/
function syncMenuBarWithStore() {
mainWindow.setMenuBarVisibility(store.get(settings.menuBar));
}
function createWindow(options = {}) { function createWindow(options = {}) {
// Create the browser window. // Create the browser window.
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
@@ -48,7 +56,7 @@ function createWindow(options = {}) {
}, },
}); });
mainWindow.setMenuBarVisibility(store.get(settings.menuBar)); syncMenuBarWithStore();
// load the Tidal website // load the Tidal website
mainWindow.loadURL(tidalUrl); mainWindow.loadURL(tidalUrl);
@@ -56,6 +64,14 @@ function createWindow(options = {}) {
// run stuff after first load // run stuff after first load
mainWindow.webContents.once("did-finish-load", () => {}); mainWindow.webContents.once("did-finish-load", () => {});
mainWindow.on("close", function (event) {
if (!app.isQuiting && store.get(settings.minimizeOnClose)) {
event.preventDefault();
mainWindow.hide();
refreshTray(mainWindow);
}
return false;
});
// Emitted when the window is closed. // Emitted when the window is closed.
mainWindow.on("closed", function () { mainWindow.on("closed", function () {
closeSettingsWindow(); closeSettingsWindow();
@@ -87,6 +103,7 @@ app.on("ready", () => {
store.get(settings.trayIcon) && addTray({ icon }) && refreshTray(); store.get(settings.trayIcon) && addTray({ 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();
}); });
app.on("activate", function () { app.on("activate", function () {
@@ -109,8 +126,12 @@ ipcMain.on(globalEvents.showSettings, (event, arg) => {
showSettingsWindow(); showSettingsWindow();
}); });
ipcMain.on(globalEvents.refreshMenuBar, (event, arg) => {
syncMenuBarWithStore();
});
ipcMain.on(globalEvents.storeChanged, (event, arg) => { ipcMain.on(globalEvents.storeChanged, (event, arg) => {
mainWindow.setMenuBarVisibility(store.get(settings.menuBar)); syncMenuBarWithStore();
if (store.get(settings.enableDiscord) && !discordModule.rpc) { if (store.get(settings.enableDiscord) && !discordModule.rpc) {
discordModule.initRPC(); discordModule.initRPC();

View File

@@ -21,6 +21,7 @@ function refreshSettings() {
mpris.checked = store.get(settings.mpris); 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);
minimizeOnClose.checked = store.get(settings.minimizeOnClose);
} }
/** /**
@@ -80,6 +81,7 @@ window.addEventListener("DOMContentLoaded", () => {
port = get("port"); port = get("port");
menuBar = get("menuBar"); menuBar = get("menuBar");
trayIcon = get("trayIcon"); trayIcon = get("trayIcon");
minimizeOnClose = get("minimizeOnClose");
mpris = get("mprisCheckbox"); mpris = get("mprisCheckbox");
enableCustomHotkeys = get("enableCustomHotkeys"); enableCustomHotkeys = get("enableCustomHotkeys");
enableDiscord = get("enableDiscord"); enableDiscord = get("enableDiscord");
@@ -95,4 +97,5 @@ window.addEventListener("DOMContentLoaded", () => {
addInputListener(mpris, settings.mpris); addInputListener(mpris, settings.mpris);
addInputListener(enableCustomHotkeys, settings.enableCustomHotkeys); addInputListener(enableCustomHotkeys, settings.enableCustomHotkeys);
addInputListener(enableDiscord, settings.enableDiscord); addInputListener(enableDiscord, settings.enableDiscord);
addInputListener(minimizeOnClose, settings.minimizeOnClose);
}); });

View File

@@ -80,6 +80,16 @@
<span class="slider round"></span> <span class="slider round"></span>
</label> </label>
</div> </div>
<div class="option">
<h4>Minimize on Close</h4>
<p>
Minimize window on close instead <br />
</p>
<label class="switch">
<input id="minimizeOnClose" type="checkbox">
<span class="slider round"></span>
</label>
</div>
<div class="option"> <div class="option">
<h4>Hotkeys</h4> <h4>Hotkeys</h4>
<p> <p>

View File

@@ -1,5 +1,5 @@
const { setTitle } = require("./scripts/window-functions"); const { setTitle } = require("./scripts/window-functions");
const { dialog, process } = require("electron").remote; const { dialog, process, Notification } = require("electron").remote;
const { store, settings } = require("./scripts/settings"); const { store, settings } = require("./scripts/settings");
const { ipcRenderer } = require("electron"); const { ipcRenderer } = require("electron");
const { app } = require("electron").remote; const { app } = require("electron").remote;
@@ -7,7 +7,6 @@ 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 notifier = require("node-notifier");
const notificationPath = `${app.getPath("userData")}/notification.jpg`; const notificationPath = `${app.getPath("userData")}/notification.jpg`;
let currentSong = ""; let currentSong = "";
let player; let player;
@@ -23,7 +22,7 @@ const elements = {
next: '*[data-test="next"]', next: '*[data-test="next"]',
previous: 'button[data-test="previous"]', previous: 'button[data-test="previous"]',
title: '*[data-test^="footer-track-title"]', title: '*[data-test^="footer-track-title"]',
artists: '*[class^="elemental__text elemental__text css-oxcos"]', artists: '*[data-test^="grid-item-detail-text-title-artist"]',
home: '*[data-test="menu--home"]', home: '*[data-test="menu--home"]',
back: '[class^="backwardButton"]', back: '[class^="backwardButton"]',
forward: '[class^="forwardButton"]', forward: '[class^="forwardButton"]',
@@ -38,6 +37,11 @@ const elements = {
current: '*[data-test="current-time"]', current: '*[data-test="current-time"]',
duration: '*[data-test="duration-time"]', duration: '*[data-test="duration-time"]',
bar: '*[data-test="progress-bar"]', bar: '*[data-test="progress-bar"]',
footer: "#footerPlayer",
album_header_title: '.header-details [data-test="title"]',
playing_title: 'span[data-test="table-cell-title"].css-geqnfr',
album_name_cell: '[data-test="table-cell-album"]',
tracklist_row: '[data-test="tracklist-row"]',
/** /**
* Get an element from the dom * Get an element from the dom
@@ -56,7 +60,43 @@ const elements = {
if (figure) { if (figure) {
const mediaElement = figure.querySelector(this["image"]); const mediaElement = figure.querySelector(this["image"]);
if (mediaElement) { if (mediaElement) {
return mediaElement.src; return mediaElement.src.replace("80x80", "640x640");
}
}
return "";
},
getArtists: function () {
const footer = this.get("footer");
if (footer) {
const artists = footer.querySelector(this["artists"]);
if (artists) {
return artists.innerText;
}
}
return "unknown artist(s)";
},
getAlbumName: function () {
//If listening to an album, get its name from the header title
if (window.location.href.includes("/album/")) {
const albumName = window.document.querySelector(this.album_header_title);
if (albumName) {
return albumName.textContent;
}
//If listening to a playlist or a mix, get album name from the list
} else if (
window.location.href.includes("/playlist/") ||
window.location.href.includes("/mix/")
) {
if (currentPlayStatus === statuses.playing) {
const row = window.document.querySelector(this.playing_title).closest(this.tracklist_row);
if (row) {
return row.querySelector(this.album_name_cell).textContent;
}
} }
} }
@@ -143,6 +183,9 @@ function addHotKeys() {
hotkeys.add("control+=", function () { hotkeys.add("control+=", function () {
ipcRenderer.send(globalEvents.showSettings); ipcRenderer.send(globalEvents.showSettings);
}); });
hotkeys.add("control+0", function () {
ipcRenderer.send(globalEvents.showSettings);
});
} }
/** /**
@@ -176,6 +219,12 @@ function handleLogout() {
); );
} }
function addFullScreenListeners() {
window.document.addEventListener("fullscreenchange", (event) => {
ipcRenderer.send(globalEvents.refreshMenuBar);
});
}
/** /**
* Add ipc event listeners. * Add ipc event listeners.
* Some actions triggered outside of the site need info from the site. * Some actions triggered outside of the site need info from the site.
@@ -220,6 +269,15 @@ function getCurrentlyPlayingStatus() {
return status; return status;
} }
/**
* Convert the duration from MM:SS to seconds
* @param {*} duration
*/
function convertDuration(duration) {
const parts = duration.split(":");
return parseInt(parts[1]) + 60 * parseInt(parts[0]);
}
/** /**
* Update Tidal-hifi's media info * Update Tidal-hifi's media info
* *
@@ -228,15 +286,18 @@ function getCurrentlyPlayingStatus() {
function updateMediaInfo(options, notify) { function updateMediaInfo(options, notify) {
if (options) { if (options) {
ipcRenderer.send(globalEvents.updateInfo, options); ipcRenderer.send(globalEvents.updateInfo, options);
store.get(settings.notifications) && notify && notifier.notify(options); if (store.get(settings.notifications) && notify) {
new Notification({ title: options.title, body: options.message, 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.artists], "xesam:artist": [options.message],
"xesam:album": options.album,
"mpris:artUrl": options.image, "mpris:artUrl": options.image,
"mpris:length": convertDuration(options.duration) * 1000 * 1000,
}, },
}; };
player.playbackStatus = options.status == statuses.paused ? "Paused" : "Playing"; player.playbackStatus = options.status == statuses.paused ? "Paused" : "Playing";
@@ -266,19 +327,23 @@ function updateURL() {
*/ */
setInterval(function () { setInterval(function () {
const title = elements.getText("title"); const title = elements.getText("title");
const artists = elements.getText("artists"); const artists = elements.getArtists();
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 appName = "Tidal Hifi";
const progressBarcurrentTime = elements.get("bar").getAttribute("aria-valuenow"); const progressBarcurrentTime = elements.get("bar").getAttribute("aria-valuenow");
const songDashArtistTitle = `${title} - ${artists}`; const songDashArtistTitle = `${title} - ${artists}`;
const currentStatus = getCurrentlyPlayingStatus(); const currentStatus = getCurrentlyPlayingStatus();
const options = { const options = {
title, title,
message: artists, message: artists,
album: album,
status: currentStatus, status: currentStatus,
url: currentURL, url: currentURL,
current: current, current: current,
duration: duration, duration: duration,
"app-name": appName,
}; };
const playStatusChanged = currentStatus !== currentPlayStatus; const playStatusChanged = currentStatus !== currentPlayStatus;
@@ -293,21 +358,21 @@ setInterval(function () {
currentPlayStatus = currentStatus; currentPlayStatus = currentStatus;
// check progress bar value and make sure current stays up to date after switch // check progress bar value and make sure current stays up to date after switch
if(progressBarTime != progressBarcurrentTime && !titleOrArtistChanged) { if (progressBarTime != progressBarcurrentTime && !titleOrArtistChanged) {
progressBarTime = progressBarcurrentTime; progressBarTime = progressBarcurrentTime;
currentTime = options.current; currentTime = options.current;
options.duration = duration; options.duration = duration;
currentTimeChanged = true; currentTimeChanged = true;
} }
if(currentTimeChanged) { if (currentTimeChanged) {
if(options.current == currentTime && currentStatus != "paused") return; if (options.current == currentTime && currentStatus != "paused") return;
currentTime = options.current; currentTime = options.current;
currentTimeChanged = false; currentTimeChanged = false;
} }
// make sure current is set to 0 if title changes // make sure current is set to 0 if title changes
if(titleOrArtistChanged) { if (titleOrArtistChanged) {
options.current = "0:00"; options.current = "0:00";
currentTime = options.current; currentTime = options.current;
progressBarTime = progressBarcurrentTime; progressBarTime = progressBarcurrentTime;
@@ -317,6 +382,7 @@ setInterval(function () {
new Promise((resolve) => { new Promise((resolve) => {
if (image.startsWith("http")) { if (image.startsWith("http")) {
options.image = image;
downloadFile(image, notificationPath).then( downloadFile(image, notificationPath).then(
() => { () => {
options.icon = notificationPath; options.icon = notificationPath;
@@ -383,6 +449,10 @@ if (process.platform === "linux" && store.get(settings.mpris)) {
} }
}); });
}); });
// Override get position function
player.getPosition = function () {
return convertDuration(elements.getText("current")) * 1000 * 1000;
};
player.on("quit", function () { player.on("quit", function () {
app.quit(); app.quit();
@@ -394,3 +464,4 @@ if (process.platform === "linux" && store.get(settings.mpris)) {
addHotKeys(); addHotKeys();
addIPCEventListeners(); addIPCEventListeners();
addFullScreenListeners();

View File

@@ -6,8 +6,8 @@ const mediaInfoModule = require("./mediaInfo");
const discordModule = []; const discordModule = [];
function timeToSeconds(timeArray) { function timeToSeconds(timeArray) {
let minutes = (timeArray[0] * 1); let minutes = timeArray[0] * 1;
let seconds = (minutes * 60) + (timeArray[1] * 1); let seconds = minutes * 60 + timeArray[1] * 1;
return seconds; return seconds;
} }
@@ -19,16 +19,20 @@ const observer = (event, arg) => {
const currentSeconds = timeToSeconds(mediaInfoModule.mediaInfo.current.split(":")); const currentSeconds = timeToSeconds(mediaInfoModule.mediaInfo.current.split(":"));
const durationSeconds = timeToSeconds(mediaInfoModule.mediaInfo.duration.split(":")); const durationSeconds = timeToSeconds(mediaInfoModule.mediaInfo.duration.split(":"));
const date = new Date(); const date = new Date();
const now = date.getTime() / 1000 | 0; const now = (date.getTime() / 1000) | 0;
const remaining = date.setSeconds(date.getSeconds() + (durationSeconds - currentSeconds)); const remaining = date.setSeconds(date.getSeconds() + (durationSeconds - currentSeconds));
if (mediaInfoModule.mediaInfo.url) { if (mediaInfoModule.mediaInfo.url) {
rpc.setActivity({ rpc.setActivity({
...idleStatus, ...idleStatus,
...{ ...{
details: `Listening to ${mediaInfoModule.mediaInfo.title}`, details: `Listening to ${mediaInfoModule.mediaInfo.title}`,
state: mediaInfoModule.mediaInfo.artist, state: mediaInfoModule.mediaInfo.artist
? mediaInfoModule.mediaInfo.artist
: "unknown artist(s)",
startTimestamp: parseInt(now), startTimestamp: parseInt(now),
endTimestamp: parseInt(remaining), endTimestamp: parseInt(remaining),
largeImageKey: mediaInfoModule.mediaInfo.image,
largeImageText: (mediaInfoModule.mediaInfo.album) ? mediaInfoModule.mediaInfo.album : `${idleStatus.largeImageText}`,
buttons: [{ label: "Play on Tidal", url: mediaInfoModule.mediaInfo.url }], buttons: [{ label: "Play on Tidal", url: mediaInfoModule.mediaInfo.url }],
}, },
}); });

View File

@@ -3,11 +3,13 @@ const statuses = require("./../constants/statuses");
const mediaInfo = { const mediaInfo = {
title: "", title: "",
artist: "", artist: "",
album: "",
icon: "", icon: "",
status: statuses.paused, status: statuses.paused,
url: "", url: "",
current: "", current: "",
duration: "" duration: "",
image: "tidal-hifi-icon"
}; };
const mediaInfoModule = { const mediaInfoModule = {
mediaInfo, mediaInfo,
@@ -19,11 +21,13 @@ 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.artist = propOrDefault(arg.message);
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);
mediaInfo.status = propOrDefault(arg.status); mediaInfo.status = propOrDefault(arg.status);
mediaInfo.current = propOrDefault(arg.current); mediaInfo.current = propOrDefault(arg.current);
mediaInfo.duration = propOrDefault(arg.duration); mediaInfo.duration = propOrDefault(arg.duration);
mediaInfo.image = propOrDefault(arg.image);
}; };
/** /**

View File

@@ -15,6 +15,7 @@ const store = new Store({
port: 47836, port: 47836,
}, },
trayIcon: true, trayIcon: true,
minimizeOnClose : false,
mpris: false, mpris: false,
enableCustomHotkeys: false, enableCustomHotkeys: false,
enableDiscord: false, enableDiscord: false,

View File

@@ -1,5 +1,7 @@
const { Tray } = require("electron"); const { Tray, app } = require("electron");
const { getMenu } = require("./menu"); const { Menu } = require("electron");
const { getMenu, mainMenu } = require("./menu");
const { store, settings } = require("./settings");
const trayModule = {}; const trayModule = {};
let tray; let tray;
@@ -7,16 +9,41 @@ trayModule.addTray = function (options = { icon: "" }) {
tray = new Tray(options.icon); tray = new Tray(options.icon);
}; };
trayModule.refreshTray = function () { trayModule.refreshTray = function (mainWindow) {
if (!tray) { if (!tray) {
trayModule.addTray(); trayModule.addTray();
} }
tray.on("click", function (e) { tray.on("click", function (e) {
// do nothing on click if (mainWindow) {
mainWindow.show();
}
}); });
tray.setToolTip("Tidal-hifi"); tray.setToolTip("Tidal-hifi");
tray.setContextMenu(getMenu());
if (mainWindow && store.get(settings.minimizeOnClose)) {
tray.setContextMenu(
Menu.buildFromTemplate([
{
label: "Toggle Window",
click: function () {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show();
},
},
{
label: "Quit",
click: function () {
mainWindow.destroy();
app.quit();
},
},
...mainMenu, //we add menu items from the other context
])
);
} else {
tray.setContextMenu(getMenu());
}
}; };
module.exports = trayModule; module.exports = trayModule;