Compare commits

...

46 Commits

Author SHA1 Message Date
Rowanda
16f98f4f1b Merge 256832dab6 into aaf7a1b662 2024-12-13 04:43:49 +00:00
Rowanda
256832dab6 fix formatting 2024-12-12 20:43:40 -08:00
Rowanda
977e50faa0 do axios requests through the main process 2024-12-12 20:42:24 -08:00
Rowanda
294701ec5f Merge branch 'Mastermindzh:master' into master 2024-12-12 20:37:31 -08:00
aaf7a1b662 Merge pull request #504 from darkiox/master
Fix Discord RPC Timestamp jitter
2024-12-09 11:21:27 +01:00
a44bf331e4 fixed indentation, removed request types 2024-12-09 11:16:34 +01:00
755be0ee30 Merge pull request #515 from Mastermindzh/snyk-fix-82857ea1745fc2cfbc5f06a87a8ff0b8
[Snyk] Security upgrade express from 4.21.1 to 4.21.2
2024-12-09 11:05:23 +01:00
Rowanda
73051716e7 Replace request with axios 2024-12-07 11:42:23 -08:00
snyk-bot
9d736b2bd9 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-PATHTOREGEXP-8482416
2024-12-06 20:33:54 +00:00
f4d4b1a1df Merge pull request #508 from Mastermindzh/snyk-fix-a6630fbdb3c8f0161d0b939cf0ec3ca3
[Snyk] Security upgrade axios from 1.7.7 to 1.7.8
2024-12-02 09:03:11 +01:00
snyk-bot
0c27c815f5 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-6671926
2024-11-30 06:57:38 +00:00
Darkiox
a3aa45a96b fix: discord rpc timestamp jitter 2024-11-25 19:15:26 -03:00
ae699887b2 Merge pull request #494 from Mastermindzh/develop
Develop
2024-10-27 21:51:50 +01:00
a8c635932f Merge branch 'develop' of github.com:Mastermindzh/tidal-hifi into develop 2024-10-27 21:27:38 +01:00
66d0d004bf discord listening to 2024-10-27 21:27:23 +01:00
d1e0321058 Merge pull request #488 from 3top1a/master
"Listening to" Discord RPC
2024-10-27 21:24:08 +01:00
2ab5a556ab Removed Songwhip (they shut down) and replaced it with TIDAL's universal link system 2024-10-27 21:01:37 +01:00
baf719fc60 Merge branch 'develop' of github.com:Mastermindzh/tidal-hifi into develop 2024-10-27 20:24:38 +01:00
15c8f6a418 prepping 5.17 2024-10-27 20:24:32 +01:00
f73521e2e5 Merge pull request #491 from darkiox/master
feat: Added ability to keep a static window title.
2024-10-27 20:20:23 +01:00
3top1a
0f5e00c4df Revert "Removed redundant RPC settings" 2024-10-23 19:14:36 +02:00
Darío Marmie
974877ea4f staticWindowTitle(fix): Order alphabetically on all appearances, change if to a ternary 2024-10-23 09:39:13 -03:00
3top1a
6be5774001 Added RPC connection retrying 2024-10-22 22:29:56 +02:00
3top1a
f96cf2e8da Removed redundant RPC settings 2024-10-22 22:27:29 +02:00
3top1a
f832bd2712 replaced discord rpc library 2024-10-22 17:20:06 +02:00
Darío Marmie
cb8667bd41 feat: Added ability to keep a static window title. 2024-10-21 18:28:03 -03:00
91156e5936 Merge pull request #490 from Mastermindzh/snyk-upgrade-aca3a223a3167341470045eeca25ec6e
[Snyk] Upgrade sass from 1.78.0 to 1.79.4
2024-10-21 09:12:32 +02:00
snyk-bot
57e9a2dcb8 fix: upgrade sass from 1.78.0 to 1.79.4
Snyk has created this PR to upgrade sass from 1.78.0 to 1.79.4.

See this package in npm:
https://www.npmjs.com/package/sass

See this project in Snyk:
https://app.snyk.io/org/mastermindzh/project/dade8f03-2064-49a3-8957-edbacec3887c?utm_source=github&utm_medium=referral&page=upgrade-pr
2024-10-19 06:05:50 +00:00
3top1a
21edcd6ad5 reverted more ugly/unnecessary changes 2024-10-17 20:51:23 +02:00
3top1a
3dc42eceb0 Reverted bad changes 2024-10-17 20:47:40 +02:00
3top1a
b1830f5684 Fixed impl 2024-10-17 20:16:22 +02:00
3top1a
1a0c15e17f Maybe? Can't build 2024-10-16 20:37:47 +02:00
6e59d59a1d Merge pull request #484 from Mastermindzh/snyk-fix-a313b5a6ce537f9549a8ae3a45f1033f
[Snyk] Security upgrade express from 4.21.0 to 4.21.1
2024-10-16 09:51:56 +02:00
snyk-bot
fab7497311 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-COOKIE-8163060
2024-10-12 06:26:33 +00:00
fccbcc77ea Merge pull request #478 from Mastermindzh/snyk-upgrade-28ef48ed574610f887d2ae8544baaf7d
[Snyk] Upgrade axios from 1.7.5 to 1.7.7
2024-09-26 11:09:22 +02:00
snyk-bot
041c19fb52 fix: upgrade axios from 1.7.5 to 1.7.7
Snyk has created this PR to upgrade axios from 1.7.5 to 1.7.7.

See this package in npm:
axios

See this project in Snyk:
https://app.snyk.io/org/mastermindzh/project/dade8f03-2064-49a3-8957-edbacec3887c?utm_source=github&utm_medium=referral&page=upgrade-pr
2024-09-26 08:54:14 +00:00
e36c562afa Merge pull request #472 from Mastermindzh/snyk-upgrade-6ce11eb8281ab57e87d8cb068d3cf64d
[Snyk] Upgrade axios from 1.7.4 to 1.7.5
2024-09-25 16:36:18 +02:00
1589aa5251 Merge pull request #473 from Mastermindzh/dependabot/npm_and_yarn/multi-cf87d80143
chore(deps): bump send and express
2024-09-25 16:35:39 +02:00
8c672dd1eb Merge pull request #476 from Mastermindzh/snyk-upgrade-3215721a01f05f1d0592d13bf3fb865f
[Snyk] Upgrade sass from 1.77.8 to 1.78.0
2024-09-25 16:34:49 +02:00
snyk-bot
3769550f24 fix: upgrade sass from 1.77.8 to 1.78.0
Snyk has created this PR to upgrade sass from 1.77.8 to 1.78.0.

See this package in npm:
sass

See this project in Snyk:
https://app.snyk.io/org/mastermindzh/project/dade8f03-2064-49a3-8957-edbacec3887c?utm_source=github&utm_medium=referral&page=upgrade-pr
2024-09-25 09:23:53 +00:00
dependabot[bot]
5a06b6c53f chore(deps): bump send and express
Bumps [send](https://github.com/pillarjs/send) to 0.19.0 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `send` from 0.18.0 to 0.19.0
- [Release notes](https://github.com/pillarjs/send/releases)
- [Changelog](https://github.com/pillarjs/send/blob/master/HISTORY.md)
- [Commits](https://github.com/pillarjs/send/compare/0.18.0...0.19.0)

Updates `express` from 4.20.0 to 4.21.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.0/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.0)

---
updated-dependencies:
- dependency-name: send
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-17 08:12:34 +00:00
snyk-bot
1d4ef66d27 fix: upgrade axios from 1.7.4 to 1.7.5
Snyk has created this PR to upgrade axios from 1.7.4 to 1.7.5.

See this package in npm:
axios

See this project in Snyk:
https://app.snyk.io/org/mastermindzh/project/dade8f03-2064-49a3-8957-edbacec3887c?utm_source=github&utm_medium=referral&page=upgrade-pr
2024-09-14 08:18:21 +00:00
e02f07401b Merge pull request #459 from Mastermindzh/snyk-fix-0bde81baefef700af2dc83cf83bf83d4
[Snyk] Security upgrade axios from 1.7.2 to 1.7.4
2024-09-10 15:27:26 +02:00
118f92e75a Merge pull request #469 from Mastermindzh/dependabot/npm_and_yarn/multi-ceff1a497b
chore(deps): bump path-to-regexp and express
2024-09-10 15:05:56 +02:00
dependabot[bot]
788d302ce8 chore(deps): bump path-to-regexp and express
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.10 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.7 to 0.1.10
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.10)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-10 10:21:44 +00:00
snyk-bot
cc09f35b49 fix: package.json & package-lock.json to reduce vulnerabilities
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-AXIOS-7361793
2024-08-14 22:44:20 +00:00
22 changed files with 449 additions and 645 deletions

View File

@@ -14,7 +14,6 @@
"rescrobbler",
"scrobble",
"scrobbling",
"Songwhip",
"trackid",
"tracklist",
"widevine",

View File

@@ -4,6 +4,13 @@ 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/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [5.17.0]
- Added an option to disable the dynamic title and set it to a static one, [#491](https://github.com/Mastermindzh/tidal-hifi/pull/491)
- Discord integration now says "Listening to" instead of "playing" [#488](https://github.com/Mastermindzh/tidal-hifi/pull/488) && [#454](https://github.com/Mastermindzh/tidal-hifi/pull/454)
- Fixed several element names in the dom scraper
- Removed the Songwhip (they shut down) integration and replaced it with TIDAL's universal link system
## [5.16.0]
- Fix issue #449 Discord RPC stuck on "Browsing Tidal".

View File

@@ -48,7 +48,6 @@ The web version of [listen.tidal.com](https://listen.tidal.com) running in elect
- AlbumArt in integrations ([best-effort](https://github.com/Mastermindzh/tidal-hifi/pull/88#pullrequestreview-840814847))
- Custom [integrations](#integrations)
- [ListenBrainz](https://listenbrainz.org/?redirect=false) integration
- Songwhip.com integration (hotkey `ctrl + w`)
- Discord RPC integration (showing "now listening", "Browsing", etc)
- Flatpak version only works if both Discord and Tidal-HiFi are flatpaks
- MPRIS integration

796
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "tidal-hifi",
"version": "5.16.0",
"version": "5.17.0",
"description": "Tidal on Electron with widevine(hifi) support",
"main": "ts-dist/main.js",
"scripts": {
@@ -42,24 +42,21 @@
"dependencies": {
"@electron/remote": "^2.1.2",
"@types/swagger-jsdoc": "^6.0.4",
"axios": "^1.7.2",
"@xhayper/discord-rpc": "^1.2.0",
"axios": "^1.7.9",
"cors": "^2.8.5",
"discord-rpc": "^4.0.1",
"electron-store": "^8.2.0",
"express": "^4.19.2",
"express": "^4.21.2",
"hotkeys-js": "^3.13.7",
"mpris-service": "^2.1.2",
"request": "^2.88.2",
"sass": "^1.77.8",
"sass": "^1.79.4",
"swagger-ui-express": "^5.0.1"
},
"devDependencies": {
"@mastermindzh/prettier-config": "^1.0.0",
"@types/cors": "^2.8.17",
"@types/discord-rpc": "^4.0.8",
"@types/express": "^4.17.21",
"@types/node": "^20.14.10",
"@types/request": "^2.48.12",
"@types/swagger-ui-express": "^4.1.6",
"@typescript-eslint/eslint-plugin": "^7.16.0",
"@typescript-eslint/parser": "^7.15.0",

View File

@@ -16,8 +16,9 @@
search: '[class^="searchField"]',
shuffle: '*[data-test="shuffle"]',
repeat: '*[data-test="repeat"]',
account: '*[class^="profileOptions"]',
settings: '*[data-test^="open-settings"]',
account: '*[data-test^="profile-image-button"]',
settings: '*[data-test^="sidebar-menu-button"]',
openSettings: '*[data-test^="open-settings"]',
media: '*[data-test="current-media-imagery"]',
image: "img",
current: '*[data-test="current-time"]',

View File

@@ -10,9 +10,11 @@ export const globalEvents = {
showSettings: "showSettings",
storeChanged: "storeChanged",
error: "error",
whip: "whip",
getUniversalLink: "getUniversalLink",
log: "log",
toggleFavorite: "toggleFavorite",
toggleShuffle: "toggleShuffle",
toggleRepeat: "toggleRepeat",
axios: "axios",
axiosReply: "axiosReply",
};

View File

@@ -55,6 +55,7 @@ export const settings = {
singleInstance: "singleInstance",
skipArtists: "skipArtists",
skippedArtists: "skippedArtists",
staticWindowTitle: "staticWindowTitle",
theme: "theme",
trayIcon: "trayIcon",
updateFrequency: "updateFrequency",

View File

@@ -2,7 +2,7 @@
"openapi": "3.1.0",
"info": {
"title": "TIDAL Hi-Fi API",
"version": "5.16.0",
"version": "5.17.0",
"description": "",
"license": {
"name": "MIT",

View File

@@ -0,0 +1,10 @@
export class SharingService {
/**
* Retrieve the universal link given a regular track link
* @param currentUrl
* @returns
*/
public static getUniversalLink(currentUrl: string): string {
return `${currentUrl}?u`;
}
}

View File

@@ -1,21 +0,0 @@
import { ServiceLinks } from "./ServiceLinks";
export interface Artist {
type: string;
id: number;
path: string;
name: string;
sourceUrl: string;
sourceCountry: string;
url: string;
image: string;
createdAt: string;
updatedAt: string;
refreshedAt: string;
serviceIds: { [key: string]: string };
orchardId: string;
spotifyId: string;
links: { [key: string]: ServiceLinks[] };
linksCountries: string[];
description: string;
}

View File

@@ -1,4 +0,0 @@
export interface ServiceLinks {
link: string;
countries: string[];
}

View File

@@ -1,27 +0,0 @@
import { Artist } from "./Artist";
import { ServiceLinks } from "./ServiceLinks";
export interface WhippedResult {
status: string;
data: {
item: {
type: string;
id: number;
path: string;
name: string;
url: string;
sourceUrl: string;
sourceCountry: string;
releaseDate: string;
createdAt: string;
updatedAt: string;
refreshedAt: string;
image: string;
isrc: string;
isExplicit: boolean;
links: { [key: string]: ServiceLinks[] };
linksCountries: string[];
artists: Artist[];
};
};
}

View File

@@ -1,32 +0,0 @@
import { WhippedResult } from "./models/whip";
import axios from "axios";
export class Songwhip {
/**
* Call the songwhip API and create a shareable songwhip page
* @param currentUrl
* @returns
*/
public static async whip(currentUrl: string): Promise<WhippedResult> {
try {
const response = await axios.post("https://songwhip.com/api/songwhip/create", {
url: currentUrl,
// doesn't actually matter.. returns everything the same way anyway
country: "NL",
});
return response.data;
} catch (error) {
console.log(JSON.stringify(error));
}
}
/**
* Transform a songwhip response into a shareable url
* @param response
* @returns
*/
public static getWhipUrl(response: WhippedResult) {
return `https://songwhip.com${response.data.item.url}`;
}
}

View File

@@ -10,7 +10,7 @@ import {
releaseInhibitorIfActive,
} from "./features/idleInhibitor/idleInhibitor";
import { Logger } from "./features/logger";
import { Songwhip } from "./features/songwhip/songwhip";
import { SharingService } from "./features/sharingService/sharingService";
import { MediaInfo } from "./models/mediaInfo";
import { MediaStatus } from "./models/mediaStatus";
import { initRPC, rpc, unRPC } from "./scripts/discord";
@@ -24,6 +24,7 @@ import {
showSettingsWindow,
} from "./scripts/settings";
import { addTray, refreshTray } from "./scripts/tray";
import { downloadFile } from "./scripts/download";
let mainInhibitorId = -1;
initialize();
@@ -250,8 +251,18 @@ ipcMain.on(globalEvents.error, (event) => {
console.log(event);
});
ipcMain.handle(globalEvents.whip, async (event, url) => {
return Songwhip.whip(url);
ipcMain.on(globalEvents.axios, (event, fileUrl: string, targetPath: string) => {
const download = downloadFile(fileUrl, targetPath);
download.then(() => {
event.reply(globalEvents.axiosReply, fileUrl, targetPath, false);
}).catch(() => {
// don't send error information, it isn't used anyways
event.reply(globalEvents.axiosReply, fileUrl, targetPath, true);
});
});
ipcMain.handle(globalEvents.getUniversalLink, async (event, url) => {
return SharingService.getUniversalLink(url);
});
Logger.watch(ipcMain);

View File

@@ -46,6 +46,7 @@ let adBlock: HTMLInputElement,
singleInstance: HTMLInputElement,
skipArtists: HTMLInputElement,
skippedArtists: HTMLInputElement,
staticWindowTitle: HTMLInputElement,
theme: HTMLSelectElement,
trayIcon: HTMLInputElement,
updateFrequency: HTMLInputElement,
@@ -140,8 +141,9 @@ function refreshSettings() {
port.value = settingsStore.get(settings.apiSettings.port);
singleInstance.checked = settingsStore.get(settings.singleInstance);
skipArtists.checked = settingsStore.get(settings.skipArtists);
theme.value = settingsStore.get(settings.theme);
skippedArtists.value = settingsStore.get<string, string[]>(settings.skippedArtists).join("\n");
staticWindowTitle.checked = settingsStore.get(settings.staticWindowTitle);
theme.value = settingsStore.get(settings.theme);
trayIcon.checked = settingsStore.get(settings.trayIcon);
updateFrequency.value = settingsStore.get(settings.updateFrequency);
enableListenBrainz.checked = settingsStore.get(settings.ListenBrainz.enabled);
@@ -261,6 +263,7 @@ window.addEventListener("DOMContentLoaded", () => {
trayIcon = get("trayIcon");
skipArtists = get("skipArtists");
skippedArtists = get("skippedArtists");
staticWindowTitle = get("staticWindowTitle");
singleInstance = get("singleInstance");
updateFrequency = get("updateFrequency");
enableListenBrainz = get("enableListenBrainz");
@@ -295,6 +298,7 @@ window.addEventListener("DOMContentLoaded", () => {
addInputListener(port, settings.apiSettings.port);
addInputListener(skipArtists, settings.skipArtists);
addTextAreaListener(skippedArtists, settings.skippedArtists);
addInputListener(staticWindowTitle, settings.staticWindowTitle);
addInputListener(singleInstance, settings.singleInstance);
addSelectListener(theme, settings.theme);
addInputListener(trayIcon, settings.trayIcon);

View File

@@ -106,6 +106,16 @@
<span class="switch__slider"></span>
</label>
</div>
<div class="group__option">
<div class="group__description">
<h4>Static Window Title</h4>
<p>Makes the window title "TIDAL Hi-Fi" instead of changing to the currently playing song.</p>
</div>
<label class="switch">
<input id="staticWindowTitle" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div>
<div class="group__option">
<div class="group__description">
<h4>Minimize on Close</h4>
@@ -468,7 +478,7 @@
<h4>TIDAL Hi-Fi</h4>
<div class="about-section__version">
<a target="_blank" rel="noopener"
href="https://github.com/Mastermindzh/tidal-hifi/releases/tag/5.16.0">5.16.0</a>
href="https://github.com/Mastermindzh/tidal-hifi/releases/tag/5.17.0">5.17.0</a>
</div>
<div class="about-section__links">
<a target="_blank" rel="noopener" href="https://github.com/mastermindzh/tidal-hifi/"
@@ -491,4 +501,4 @@
</div>
</body>
</html>
</html>

View File

@@ -10,13 +10,13 @@ import {
} from "./features/listenbrainz/listenbrainz";
import { StoreData } from "./features/listenbrainz/models/storeData";
import { Logger } from "./features/logger";
import { Songwhip } from "./features/songwhip/songwhip";
import { SharingService } from "./features/sharingService/sharingService";
import { addCustomCss } from "./features/theming/theming";
import { convertDurationToSeconds } from "./features/time/parse";
import { MediaInfo } from "./models/mediaInfo";
import { MediaStatus } from "./models/mediaStatus";
import { RepeatState } from "./models/repeatState";
import { downloadFile } from "./scripts/download";
import { downloadFile } from "./scripts/downloadPreload";
import { addHotkey } from "./scripts/hotkeys";
import { ObjectToDotNotation } from "./scripts/objectUtilities";
import { settingsStore } from "./scripts/settings";
@@ -48,8 +48,9 @@ const elements = {
search: '[class^="searchField"]',
shuffle: '*[data-test="shuffle"]',
repeat: '*[data-test="repeat"]',
account: '*[class^="profileOptions"]',
settings: '*[data-test^="open-settings"]',
account: '*[data-test^="profile-image-button"]',
settings: '*[data-test^="sidebar-menu-button"]',
openSettings: '*[data-test^="open-settings"]',
media: '*[data-test="current-media-imagery"]',
image: "img",
current: '*[data-test="current-time"]',
@@ -220,9 +221,9 @@ ListenBrainzStore.clear();
function addHotKeys() {
if (settingsStore.get(settings.enableCustomHotkeys)) {
addHotkey("Control+p", function () {
elements.click("account");
elements.click("settings");
setTimeout(() => {
elements.click("settings");
elements.click("openSettings");
}, 100);
});
addHotkey("Control+l", function () {
@@ -254,11 +255,10 @@ function addHotKeys() {
elements.click("repeat");
});
addHotkey("control+w", async function () {
const result = await ipcRenderer.invoke(globalEvents.whip, getTrackURL());
const url = Songwhip.getWhipUrl(result);
const url = SharingService.getUniversalLink(getTrackURL());
clipboard.writeText(url);
new Notification({
title: `Successfully whipped: `,
title: `Universal link generated: `,
body: `URL copied to clipboard: ${url}`,
}).show();
});
@@ -550,6 +550,7 @@ setInterval(function () {
const artistsArray = elements.getArtistsArray();
const artistsString = elements.getArtistsString(artistsArray);
const songDashArtistTitle = `${title} - ${artistsString}`;
const staticTitle = "TIDAL Hi-Fi";
const titleOrArtistsChanged = currentSong !== songDashArtistTitle;
const current = elements.getText("current");
const currentStatus = getCurrentlyPlayingStatus();
@@ -594,7 +595,9 @@ setInterval(function () {
};
// update title, url and play info with new info
setTitle(songDashArtistTitle);
settingsStore.get(settings.staticWindowTitle)
? setTitle(staticTitle)
: setTitle(songDashArtistTitle);
getTrackURL();
currentSong = songDashArtistTitle;
currentPlayStatus = currentStatus;

View File

@@ -1,4 +1,4 @@
import { Client, Presence } from "discord-rpc";
import { Client, SetActivity } from "@xhayper/discord-rpc";
import { app, ipcMain } from "electron";
import { globalEvents } from "../constants/globalEvents";
import { settings } from "../constants/settings";
@@ -12,6 +12,10 @@ const clientId = "833617820704440341";
export let rpc: Client;
const ACTIVITY_LISTENING = 2;
const MAX_RETRIES = 5;
const RETRY_DELAY = 10000;
const observer = () => {
if (rpc) {
updateActivity();
@@ -22,19 +26,20 @@ const defaultPresence = {
largeImageKey: "tidal-hifi-icon",
largeImageText: `TIDAL Hi-Fi ${app.getVersion()}`,
instance: false,
type: ACTIVITY_LISTENING
};
const updateActivity = () => {
const showIdle = settingsStore.get<string, boolean>(settings.discord.showIdle) ?? true;
if (mediaInfo.status === MediaStatus.paused && !showIdle) {
rpc.clearActivity();
rpc.user?.clearActivity();
} else {
rpc.setActivity(getActivity());
rpc.user?.setActivity(getActivity());
}
};
const getActivity = (): Presence => {
const presence: Presence = { ...defaultPresence };
const getActivity = (): SetActivity => {
const presence: SetActivity = { ...defaultPresence };
if (mediaInfo.status === MediaStatus.paused) {
presence.details =
@@ -50,6 +55,7 @@ const getActivity = (): Presence => {
settingsStore.get<string, string>(settings.discord.usingText) ?? "Playing media on TIDAL";
}
}
return presence;
function getFromStore() {
@@ -97,11 +103,29 @@ const getActivity = (): Presence => {
if (includeTimestamps) {
const currentSeconds = convertDurationToSeconds(mediaInfo.current);
const durationSeconds = convertDurationToSeconds(mediaInfo.duration);
const date = new Date();
const now = (date.getTime() / 1000) | 0;
const remaining = date.setSeconds(date.getSeconds() + (durationSeconds - currentSeconds));
presence.startTimestamp = now;
presence.endTimestamp = remaining;
const now = Math.trunc((Date.now() + 500) / 1000);
presence.startTimestamp = now - currentSeconds;
presence.endTimestamp = presence.startTimestamp + durationSeconds;
}
}
};
/**
* Try to login to RPC and retry if it errors
* @param retryCount Max retry count
*/
const connectWithRetry = async (retryCount = 0) => {
try {
await rpc.login();
Logger.log('Connected to Discord');
rpc.on("ready", updateActivity);
Object.values(globalEvents).forEach(event => ipcMain.on(event, observer));
} catch (error) {
if (retryCount < MAX_RETRIES) {
Logger.log(`Failed to connect to Discord, retrying in ${RETRY_DELAY/1000} seconds... (Attempt ${retryCount + 1}/${MAX_RETRIES})`);
setTimeout(() => connectWithRetry(retryCount + 1), RETRY_DELAY);
} else {
Logger.log('Failed to connect to Discord after maximum retry attempts');
}
}
};
@@ -110,22 +134,8 @@ const getActivity = (): Presence => {
* Set up the discord rpc and listen on globalEvents.updateInfo
*/
export const initRPC = () => {
rpc = new Client({ transport: "ipc" });
rpc.login({ clientId }).then(
() => {
rpc.on("ready", () => {
updateActivity();
});
const { updateInfo, play, pause, playPause } = globalEvents;
[updateInfo, play, pause, playPause].forEach((status) => {
ipcMain.on(status, observer);
});
},
() => {
Logger.log("Can't connect to Discord, is it running?");
}
);
rpc = new Client({ transport: {type: "ipc"}, clientId });
connectWithRetry();
};
/**
@@ -133,7 +143,7 @@ export const initRPC = () => {
*/
export const unRPC = () => {
if (rpc) {
rpc.clearActivity();
rpc.user?.clearActivity();
rpc.destroy();
rpc = null;
ipcMain.removeListener(globalEvents.updateInfo, observer);

View File

@@ -1,5 +1,5 @@
import fs from "fs";
import request from "request";
import axios from "axios";
/**
* download and save a file
@@ -8,16 +8,20 @@ import request from "request";
*/
export const downloadFile = function (fileUrl: string, targetPath: string) {
return new Promise((resolve, reject) => {
const req = request({
method: "GET",
uri: fileUrl,
});
axios
.get(fileUrl, {
responseType: "stream",
})
.then((res) => {
const out = fs.createWriteStream(targetPath);
const out = fs.createWriteStream(targetPath);
req.pipe(out);
res.data.pipe(out);
req.on("end", resolve);
out.on("finish", resolve);
req.on("error", reject);
out.on("error", reject);
res.data.on("error", reject);
}).catch(reject);
});
};

View File

@@ -0,0 +1,23 @@
import { ipcRenderer } from "electron";
import { globalEvents } from "../constants/globalEvents";
/**
* download and save a file (renderer version)
* @param {string} fileUrl url to download
* @param {string} targetPath path to save it at
*/
export const downloadFile = function (fileUrl: string, targetPath: string) {
return new Promise<void>((resolve, reject) => {
const handler = (event: Electron.IpcRendererEvent, newFileUrl: string, newTargetPath: string, error: boolean) => {
// it's possible for 2 requests to be running at the same time, so make sure it is the right one
// if there is 2 requests with the same fileUrl and targetPath, then it doesn't matter which one we intercept because the data is the same
if (fileUrl === newFileUrl && targetPath === newTargetPath) {
ipcRenderer.removeListener(globalEvents.axiosReply, handler);
if (error) reject();
else resolve();
}
}
ipcRenderer.on(globalEvents.axiosReply, handler);
ipcRenderer.send(globalEvents.axios, fileUrl, targetPath);
});
};

View File

@@ -69,6 +69,7 @@ export const settingsStore = new Store({
singleInstance: true,
skipArtists: false,
skippedArtists: [""],
staticWindowTitle: false,
theme: "none",
trayIcon: true,
updateFrequency: 500,