mirror of
https://github.com/Mastermindzh/tidal-hifi.git
synced 2024-11-22 13:32:42 +01:00
chore: more typescript
This commit is contained in:
parent
e8509d42e7
commit
53e4711c39
7
package-lock.json
generated
7
package-lock.json
generated
@ -20,6 +20,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mastermindzh/prettier-config": "^1.0.0",
|
"@mastermindzh/prettier-config": "^1.0.0",
|
||||||
|
"@types/discord-rpc": "^4.0.4",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/request": "^2.48.8",
|
"@types/request": "^2.48.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
||||||
@ -953,6 +954,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/discord-rpc": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/discord-rpc/-/discord-rpc-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-Afr+3GqUqZnQ6bA/WzNp388heVAmfKuNxy6giAde2ZZP7sNr6mnl+ELpcecD/z2sndfKSauLB89ABNqjWWCZlg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/express": {
|
"node_modules/@types/express": {
|
||||||
"version": "4.17.17",
|
"version": "4.17.17",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mastermindzh/prettier-config": "^1.0.0",
|
"@mastermindzh/prettier-config": "^1.0.0",
|
||||||
|
"@types/discord-rpc": "^4.0.4",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
"@types/request": "^2.48.8",
|
"@types/request": "^2.48.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* },
|
* },
|
||||||
* windowBounds: { width: 800, height: 600 },
|
* windowBounds: { width: 800, height: 600 },
|
||||||
*/
|
*/
|
||||||
const settings = {
|
export const settings = {
|
||||||
adBlock: "adBlock",
|
adBlock: "adBlock",
|
||||||
api: "api",
|
api: "api",
|
||||||
apiSettings: {
|
apiSettings: {
|
||||||
@ -41,5 +41,3 @@ const settings = {
|
|||||||
height: "windowBounds.height",
|
height: "windowBounds.height",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = settings;
|
|
1
src/declarations.d.ts
vendored
Normal file
1
src/declarations.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare module "mpris-service";
|
57
src/main.ts
57
src/main.ts
@ -12,19 +12,20 @@ import path from "path";
|
|||||||
import flagValues from "./constants/flags";
|
import flagValues from "./constants/flags";
|
||||||
import globalEvents from "./constants/globalEvents";
|
import globalEvents from "./constants/globalEvents";
|
||||||
import mediaKeys from "./constants/mediaKeys";
|
import mediaKeys from "./constants/mediaKeys";
|
||||||
import discordModule from "./scripts/discord";
|
import { initRPC, rpc, unRPC } from "./scripts/discord";
|
||||||
import { startExpress } from "./scripts/express";
|
import { startExpress } from "./scripts/express";
|
||||||
import mediaInfoModule from "./scripts/mediaInfo";
|
import { updateMediaInfo } from "./scripts/mediaInfo";
|
||||||
import { addMenu } from "./scripts/menu";
|
import { addMenu } from "./scripts/menu";
|
||||||
import {
|
import {
|
||||||
closeSettingsWindow,
|
closeSettingsWindow,
|
||||||
createSettingsWindow,
|
createSettingsWindow,
|
||||||
hideSettingsWindow,
|
hideSettingsWindow,
|
||||||
settings,
|
|
||||||
showSettingsWindow,
|
showSettingsWindow,
|
||||||
store,
|
settingsStore,
|
||||||
} from "./scripts/settings";
|
} from "./scripts/settings";
|
||||||
|
import { settings } from "./constants/settings";
|
||||||
import { addTray, refreshTray } from "./scripts/tray";
|
import { addTray, refreshTray } from "./scripts/tray";
|
||||||
|
import { MediaInfo } from "./models/mediaInfo";
|
||||||
const tidalUrl = "https://listen.tidal.com";
|
const tidalUrl = "https://listen.tidal.com";
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
@ -36,7 +37,7 @@ const PROTOCOL_PREFIX = "tidal";
|
|||||||
setFlags();
|
setFlags();
|
||||||
|
|
||||||
function setFlags() {
|
function setFlags() {
|
||||||
const flags = store.get(settings.flags.root);
|
const flags = settingsStore.get(settings.flags.root);
|
||||||
if (flags) {
|
if (flags) {
|
||||||
for (const [key, value] of Object.entries(flags)) {
|
for (const [key, value] of Object.entries(flags)) {
|
||||||
if (value) {
|
if (value) {
|
||||||
@ -59,7 +60,7 @@ function setFlags() {
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function syncMenuBarWithStore() {
|
function syncMenuBarWithStore() {
|
||||||
const fixedMenuBar = !!store.get(settings.menuBar);
|
const fixedMenuBar = !!settingsStore.get(settings.menuBar);
|
||||||
|
|
||||||
mainWindow.autoHideMenuBar = !fixedMenuBar;
|
mainWindow.autoHideMenuBar = !fixedMenuBar;
|
||||||
mainWindow.setMenuBarVisibility(fixedMenuBar);
|
mainWindow.setMenuBarVisibility(fixedMenuBar);
|
||||||
@ -72,7 +73,7 @@ function syncMenuBarWithStore() {
|
|||||||
* @returns true if singInstance is not requested, otherwise true/false based on whether the current window is the main window
|
* @returns true if singInstance is not requested, otherwise true/false based on whether the current window is the main window
|
||||||
*/
|
*/
|
||||||
function isMainInstanceOrMultipleInstancesAllowed() {
|
function isMainInstanceOrMultipleInstancesAllowed() {
|
||||||
if (store.get(settings.singleInstance)) {
|
if (settingsStore.get(settings.singleInstance)) {
|
||||||
const gotTheLock = app.requestSingleInstanceLock();
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
|
|
||||||
if (!gotTheLock) {
|
if (!gotTheLock) {
|
||||||
@ -87,8 +88,8 @@ function createWindow(options = { x: 0, y: 0, backgroundColor: "white" }) {
|
|||||||
mainWindow = new BrowserWindow({
|
mainWindow = new BrowserWindow({
|
||||||
x: options.x,
|
x: options.x,
|
||||||
y: options.y,
|
y: options.y,
|
||||||
width: store && store.get(settings.windowBounds.width),
|
width: settingsStore && settingsStore.get(settings.windowBounds.width),
|
||||||
height: store && store.get(settings.windowBounds.height),
|
height: settingsStore && settingsStore.get(settings.windowBounds.height),
|
||||||
icon,
|
icon,
|
||||||
backgroundColor: options.backgroundColor,
|
backgroundColor: options.backgroundColor,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
@ -106,13 +107,13 @@ function createWindow(options = { x: 0, y: 0, backgroundColor: "white" }) {
|
|||||||
// load the Tidal website
|
// load the Tidal website
|
||||||
mainWindow.loadURL(tidalUrl);
|
mainWindow.loadURL(tidalUrl);
|
||||||
|
|
||||||
if (store.get(settings.disableBackgroundThrottle)) {
|
if (settingsStore.get(settings.disableBackgroundThrottle)) {
|
||||||
// prevent setInterval lag
|
// prevent setInterval lag
|
||||||
mainWindow.webContents.setBackgroundThrottling(false);
|
mainWindow.webContents.setBackgroundThrottling(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow.on("close", function (event: CloseEvent) {
|
mainWindow.on("close", function (event: CloseEvent) {
|
||||||
if (store.get(settings.minimizeOnClose)) {
|
if (settingsStore.get(settings.minimizeOnClose)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
mainWindow.hide();
|
mainWindow.hide();
|
||||||
refreshTray(mainWindow);
|
refreshTray(mainWindow);
|
||||||
@ -126,12 +127,12 @@ function createWindow(options = { x: 0, y: 0, backgroundColor: "white" }) {
|
|||||||
});
|
});
|
||||||
mainWindow.on("resize", () => {
|
mainWindow.on("resize", () => {
|
||||||
const { width, height } = mainWindow.getBounds();
|
const { width, height } = mainWindow.getBounds();
|
||||||
store.set(settings.windowBounds.root, { width, height });
|
settingsStore.set(settings.windowBounds.root, { width, height });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerHttpProtocols() {
|
function registerHttpProtocols() {
|
||||||
protocol.registerHttpProtocol(PROTOCOL_PREFIX, (request, _callback) => {
|
protocol.registerHttpProtocol(PROTOCOL_PREFIX, (request) => {
|
||||||
mainWindow.loadURL(`${tidalUrl}/${request.url.substring(PROTOCOL_PREFIX.length + 3)}`);
|
mainWindow.loadURL(`${tidalUrl}/${request.url.substring(PROTOCOL_PREFIX.length + 3)}`);
|
||||||
});
|
});
|
||||||
if (!app.isDefaultProtocolClient(PROTOCOL_PREFIX)) {
|
if (!app.isDefaultProtocolClient(PROTOCOL_PREFIX)) {
|
||||||
@ -155,7 +156,7 @@ app.on("ready", async () => {
|
|||||||
await components.whenReady();
|
await components.whenReady();
|
||||||
|
|
||||||
// Adblock
|
// Adblock
|
||||||
if (store.get(settings.adBlock)) {
|
if (settingsStore.get(settings.adBlock)) {
|
||||||
const filter = { urls: ["https://listen.tidal.com/*"] };
|
const filter = { urls: ["https://listen.tidal.com/*"] };
|
||||||
session.defaultSession.webRequest.onBeforeRequest(filter, (details, callback) => {
|
session.defaultSession.webRequest.onBeforeRequest(filter, (details, callback) => {
|
||||||
if (details.url.match(/\/users\/.*\d\?country/)) callback({ cancel: true });
|
if (details.url.match(/\/users\/.*\d\?country/)) callback({ cancel: true });
|
||||||
@ -167,12 +168,12 @@ app.on("ready", async () => {
|
|||||||
addMenu(mainWindow);
|
addMenu(mainWindow);
|
||||||
createSettingsWindow();
|
createSettingsWindow();
|
||||||
addGlobalShortcuts();
|
addGlobalShortcuts();
|
||||||
if (store.get(settings.trayIcon)) {
|
if (settingsStore.get(settings.trayIcon)) {
|
||||||
addTray(mainWindow, { icon });
|
addTray(mainWindow, { icon });
|
||||||
refreshTray(mainWindow);
|
refreshTray(mainWindow);
|
||||||
}
|
}
|
||||||
store.get(settings.api) && startExpress(mainWindow);
|
settingsStore.get(settings.api) && startExpress(mainWindow);
|
||||||
store.get(settings.enableDiscord) && discordModule.initRPC();
|
settingsStore.get(settings.enableDiscord) && initRPC();
|
||||||
} else {
|
} else {
|
||||||
app.quit();
|
app.quit();
|
||||||
}
|
}
|
||||||
@ -191,31 +192,31 @@ app.on("browser-window-created", (_, window) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// IPC
|
// IPC
|
||||||
ipcMain.on(globalEvents.updateInfo, (_event, arg) => {
|
ipcMain.on(globalEvents.updateInfo, (_event, arg: MediaInfo) => {
|
||||||
mediaInfoModule.update(arg);
|
updateMediaInfo(arg);
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on(globalEvents.hideSettings, (_event, _arg) => {
|
ipcMain.on(globalEvents.hideSettings, () => {
|
||||||
hideSettingsWindow();
|
hideSettingsWindow();
|
||||||
});
|
});
|
||||||
ipcMain.on(globalEvents.showSettings, (_event, _arg) => {
|
ipcMain.on(globalEvents.showSettings, () => {
|
||||||
showSettingsWindow();
|
showSettingsWindow();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on(globalEvents.refreshMenuBar, (_event, _arg) => {
|
ipcMain.on(globalEvents.refreshMenuBar, () => {
|
||||||
syncMenuBarWithStore();
|
syncMenuBarWithStore();
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on(globalEvents.storeChanged, (_event, _arg) => {
|
ipcMain.on(globalEvents.storeChanged, () => {
|
||||||
syncMenuBarWithStore();
|
syncMenuBarWithStore();
|
||||||
|
|
||||||
if (store.get(settings.enableDiscord) && !discordModule.rpc) {
|
if (settingsStore.get(settings.enableDiscord) && !rpc) {
|
||||||
discordModule.initRPC();
|
initRPC();
|
||||||
} else if (!store.get(settings.enableDiscord) && discordModule.rpc) {
|
} else if (!settingsStore.get(settings.enableDiscord) && rpc) {
|
||||||
discordModule.unRPC();
|
unRPC();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.on(globalEvents.error, (event, _arg) => {
|
ipcMain.on(globalEvents.error, (event) => {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
});
|
});
|
||||||
|
13
src/models/mediaInfo.ts
Normal file
13
src/models/mediaInfo.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { MediaStatus } from "./mediaStatus";
|
||||||
|
|
||||||
|
export interface MediaInfo {
|
||||||
|
title: string;
|
||||||
|
artists: string;
|
||||||
|
album: string;
|
||||||
|
icon: string;
|
||||||
|
status: MediaStatus;
|
||||||
|
url: string;
|
||||||
|
current: string;
|
||||||
|
duration: string;
|
||||||
|
image: string;
|
||||||
|
}
|
4
src/models/mediaStatus.ts
Normal file
4
src/models/mediaStatus.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export enum MediaStatus {
|
||||||
|
playing = "playing",
|
||||||
|
paused = "paused",
|
||||||
|
}
|
@ -1,3 +1,9 @@
|
|||||||
|
import remote from "@electron/remote";
|
||||||
|
import { ipcRenderer, shell } from "electron";
|
||||||
|
import globalEvents from "../../constants/globalEvents";
|
||||||
|
import { settings } from "../../constants/settings";
|
||||||
|
import { settingsStore } from "./../../scripts/settings";
|
||||||
|
|
||||||
let adBlock: HTMLInputElement,
|
let adBlock: HTMLInputElement,
|
||||||
api: HTMLInputElement,
|
api: HTMLInputElement,
|
||||||
customCSS: HTMLInputElement,
|
customCSS: HTMLInputElement,
|
||||||
@ -18,42 +24,35 @@ let adBlock: HTMLInputElement,
|
|||||||
trayIcon: HTMLInputElement,
|
trayIcon: HTMLInputElement,
|
||||||
updateFrequency: HTMLInputElement;
|
updateFrequency: HTMLInputElement;
|
||||||
|
|
||||||
const { store, settings } = require("../../scripts/settings");
|
|
||||||
const { ipcRenderer } = require("electron");
|
|
||||||
const globalEvents = require("../../constants/globalEvents");
|
|
||||||
const remote = require("@electron/remote");
|
|
||||||
const { app } = remote;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sync the UI forms with the current settings
|
* Sync the UI forms with the current settings
|
||||||
*/
|
*/
|
||||||
function refreshSettings() {
|
function refreshSettings() {
|
||||||
adBlock.checked = store.get(settings.adBlock);
|
adBlock.checked = settingsStore.get(settings.adBlock);
|
||||||
api.checked = store.get(settings.api);
|
api.checked = settingsStore.get(settings.api);
|
||||||
customCSS.value = store.get(settings.customCSS);
|
customCSS.value = settingsStore.get(settings.customCSS);
|
||||||
disableBackgroundThrottle.checked = store.get(settings.disableBackgroundThrottle);
|
disableBackgroundThrottle.checked = settingsStore.get(settings.disableBackgroundThrottle);
|
||||||
disableHardwareMediaKeys.checked = store.get(settings.flags.disableHardwareMediaKeys);
|
disableHardwareMediaKeys.checked = settingsStore.get(settings.flags.disableHardwareMediaKeys);
|
||||||
enableCustomHotkeys.checked = store.get(settings.enableCustomHotkeys);
|
enableCustomHotkeys.checked = settingsStore.get(settings.enableCustomHotkeys);
|
||||||
enableDiscord.checked = store.get(settings.enableDiscord);
|
enableDiscord.checked = settingsStore.get(settings.enableDiscord);
|
||||||
gpuRasterization.checked = store.get(settings.flags.gpuRasterization);
|
gpuRasterization.checked = settingsStore.get(settings.flags.gpuRasterization);
|
||||||
menuBar.checked = store.get(settings.menuBar);
|
menuBar.checked = settingsStore.get(settings.menuBar);
|
||||||
minimizeOnClose.checked = store.get(settings.minimizeOnClose);
|
minimizeOnClose.checked = settingsStore.get(settings.minimizeOnClose);
|
||||||
mpris.checked = store.get(settings.mpris);
|
mpris.checked = settingsStore.get(settings.mpris);
|
||||||
notifications.checked = store.get(settings.notifications);
|
notifications.checked = settingsStore.get(settings.notifications);
|
||||||
playBackControl.checked = store.get(settings.playBackControl);
|
playBackControl.checked = settingsStore.get(settings.playBackControl);
|
||||||
port.value = store.get(settings.apiSettings.port);
|
port.value = settingsStore.get(settings.apiSettings.port);
|
||||||
singleInstance.checked = store.get(settings.singleInstance);
|
singleInstance.checked = settingsStore.get(settings.singleInstance);
|
||||||
skipArtists.checked = store.get(settings.skipArtists);
|
skipArtists.checked = settingsStore.get(settings.skipArtists);
|
||||||
skippedArtists.value = (store.get(settings.skippedArtists) as string[]).join("\n");
|
skippedArtists.value = settingsStore.get<string, string[]>(settings.skippedArtists).join("\n");
|
||||||
trayIcon.checked = store.get(settings.trayIcon);
|
trayIcon.checked = settingsStore.get(settings.trayIcon);
|
||||||
updateFrequency.value = store.get(settings.updateFrequency);
|
updateFrequency.value = settingsStore.get(settings.updateFrequency);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open an url in the default browsers
|
* Open an url in the default browsers
|
||||||
*/
|
*/
|
||||||
function openExternal(url: string) {
|
function openExternal(url: string) {
|
||||||
const { shell } = require("electron");
|
|
||||||
shell.openExternal(url);
|
shell.openExternal(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,8 +67,8 @@ function hide() {
|
|||||||
* Restart tidal-hifi after changes
|
* Restart tidal-hifi after changes
|
||||||
*/
|
*/
|
||||||
function restart() {
|
function restart() {
|
||||||
app.relaunch();
|
remote.app.relaunch();
|
||||||
app.exit();
|
remote.app.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,9 +90,9 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||||||
function addInputListener(source: HTMLInputElement, key: string) {
|
function addInputListener(source: HTMLInputElement, key: string) {
|
||||||
source.addEventListener("input", () => {
|
source.addEventListener("input", () => {
|
||||||
if (source.value === "on") {
|
if (source.value === "on") {
|
||||||
store.set(key, source.checked);
|
settingsStore.set(key, source.checked);
|
||||||
} else {
|
} else {
|
||||||
store.set(key, source.value);
|
settingsStore.set(key, source.value);
|
||||||
}
|
}
|
||||||
ipcRenderer.send(globalEvents.storeChanged);
|
ipcRenderer.send(globalEvents.storeChanged);
|
||||||
});
|
});
|
||||||
@ -101,7 +100,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||||||
|
|
||||||
function addTextAreaListener(source: HTMLInputElement, key: string) {
|
function addTextAreaListener(source: HTMLInputElement, key: string) {
|
||||||
source.addEventListener("input", () => {
|
source.addEventListener("input", () => {
|
||||||
store.set(key, source.value.split("\n"));
|
settingsStore.set(key, source.value.split("\n"));
|
||||||
ipcRenderer.send(globalEvents.storeChanged);
|
ipcRenderer.send(globalEvents.storeChanged);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { Notification, app, dialog } from "@electron/remote";
|
import { Notification, app, dialog } from "@electron/remote";
|
||||||
import { ipcRenderer } from "electron";
|
import { ipcRenderer } from "electron";
|
||||||
|
import Player from "mpris-service";
|
||||||
import globalEvents from "./constants/globalEvents";
|
import globalEvents from "./constants/globalEvents";
|
||||||
import { customCSS, skipArtists, updateFrequency } from "./constants/settings";
|
import { settings } from "./constants/settings";
|
||||||
import statuses from "./constants/statuses";
|
import statuses from "./constants/statuses";
|
||||||
import { Options } from "./models/options";
|
import { Options } from "./models/options";
|
||||||
import { downloadFile } from "./scripts/download";
|
import { downloadFile } from "./scripts/download";
|
||||||
import { addHotkey } from "./scripts/hotkeys";
|
import { addHotkey } from "./scripts/hotkeys";
|
||||||
import { settings, store } from "./scripts/settings";
|
|
||||||
import { setTitle } from "./scripts/window-functions";
|
import { setTitle } from "./scripts/window-functions";
|
||||||
|
import { settingsStore } from "./scripts/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 = "";
|
||||||
@ -146,7 +148,7 @@ const elements = {
|
|||||||
function addCustomCss() {
|
function addCustomCss() {
|
||||||
window.addEventListener("DOMContentLoaded", () => {
|
window.addEventListener("DOMContentLoaded", () => {
|
||||||
const style = document.createElement("style");
|
const style = document.createElement("style");
|
||||||
style.innerHTML = store.get(customCSS);
|
style.innerHTML = settingsStore.get(settings.customCSS);
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -156,7 +158,7 @@ function addCustomCss() {
|
|||||||
* make sure it returns a number, if not use the default
|
* make sure it returns a number, if not use the default
|
||||||
*/
|
*/
|
||||||
function getUpdateFrequency() {
|
function getUpdateFrequency() {
|
||||||
const storeValue = store.get(updateFrequency) as number;
|
const storeValue = settingsStore.get(settings.updateFrequency) as number;
|
||||||
const defaultValue = 500;
|
const defaultValue = 500;
|
||||||
|
|
||||||
if (!isNaN(storeValue)) {
|
if (!isNaN(storeValue)) {
|
||||||
@ -185,7 +187,7 @@ function playPause() {
|
|||||||
* https://defkey.com/tidal-desktop-shortcuts
|
* https://defkey.com/tidal-desktop-shortcuts
|
||||||
*/
|
*/
|
||||||
function addHotKeys() {
|
function addHotKeys() {
|
||||||
if (store.get(settings.enableCustomHotkeys)) {
|
if (settingsStore.get(settings.enableCustomHotkeys)) {
|
||||||
addHotkey("Control+p", function () {
|
addHotkey("Control+p", function () {
|
||||||
elements.click("account").click("settings");
|
elements.click("account").click("settings");
|
||||||
});
|
});
|
||||||
@ -291,7 +293,7 @@ function addIPCEventListeners() {
|
|||||||
* Update the current status of tidal (e.g playing or paused)
|
* Update the current status of tidal (e.g playing or paused)
|
||||||
*/
|
*/
|
||||||
function getCurrentlyPlayingStatus() {
|
function getCurrentlyPlayingStatus() {
|
||||||
let pause = elements.get("pause");
|
const pause = elements.get("pause");
|
||||||
let status = undefined;
|
let status = undefined;
|
||||||
|
|
||||||
// if pause button is visible tidal is playing
|
// if pause button is visible tidal is playing
|
||||||
@ -320,7 +322,7 @@ function convertDuration(duration: string) {
|
|||||||
function updateMediaInfo(options: Options, notify: boolean) {
|
function updateMediaInfo(options: Options, notify: boolean) {
|
||||||
if (options) {
|
if (options) {
|
||||||
ipcRenderer.send(globalEvents.updateInfo, options);
|
ipcRenderer.send(globalEvents.updateInfo, options);
|
||||||
if (store.get(settings.notifications) && notify) {
|
if (settingsStore.get(settings.notifications) && notify) {
|
||||||
new Notification({ title: options.title, body: options.artists, icon: options.icon }).show();
|
new Notification({ title: options.title, body: options.artists, icon: options.icon }).show();
|
||||||
}
|
}
|
||||||
if (player) {
|
if (player) {
|
||||||
@ -430,23 +432,20 @@ setInterval(function () {
|
|||||||
// if the image can't be found on the page continue without it
|
// if the image can't be found on the page continue without it
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
}).then(
|
}).then(() => {
|
||||||
() => {
|
updateMediaInfo(options, titleOrArtistsChanged);
|
||||||
updateMediaInfo(options, titleOrArtistsChanged);
|
if (titleOrArtistsChanged) {
|
||||||
if (titleOrArtistsChanged) {
|
updateMediaSession(options);
|
||||||
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 array of artists
|
* @param {*} artists array of artists
|
||||||
*/
|
*/
|
||||||
function skipArtistsIfFoundInSkippedArtistsList(artists: string[]) {
|
function skipArtistsIfFoundInSkippedArtistsList(artists: string[]) {
|
||||||
if (store.get(skipArtists)) {
|
if (settingsStore.get(settings.skipArtists)) {
|
||||||
const skippedArtists = store.get(settings.skippedArtists) as string[];
|
const skippedArtists = settingsStore.get<string, string[]>(settings.skippedArtists);
|
||||||
if (skippedArtists.length > 0) {
|
if (skippedArtists.length > 0) {
|
||||||
const artistsToSkip = skippedArtists.map((artist) => artist);
|
const artistsToSkip = skippedArtists.map((artist) => artist);
|
||||||
const artistNames = Object.values(artists).map((artist) => artist);
|
const artistNames = Object.values(artists).map((artist) => artist);
|
||||||
@ -459,9 +458,8 @@ setInterval(function () {
|
|||||||
}
|
}
|
||||||
}, getUpdateFrequency());
|
}, getUpdateFrequency());
|
||||||
|
|
||||||
if (process.platform === "linux" && store.get(settings.mpris)) {
|
if (process.platform === "linux" && settingsStore.get(settings.mpris)) {
|
||||||
try {
|
try {
|
||||||
const Player = require("mpris-service");
|
|
||||||
player = Player({
|
player = Player({
|
||||||
name: "tidal-hifi",
|
name: "tidal-hifi",
|
||||||
identity: "tidal-hifi",
|
identity: "tidal-hifi",
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
const discordrpc = require("discord-rpc");
|
|
||||||
const { app, ipcMain } = require("electron");
|
|
||||||
const globalEvents = require("../constants/globalEvents");
|
|
||||||
const clientId = "833617820704440341";
|
|
||||||
const mediaInfoModule = require("./mediaInfo");
|
|
||||||
const discordModule = {
|
|
||||||
rpc: {},
|
|
||||||
unRPC: function () {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
initRPC: function () {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function timeToSeconds(timeArray) {
|
|
||||||
let minutes = timeArray[0] * 1;
|
|
||||||
let seconds = minutes * 60 + timeArray[1] * 1;
|
|
||||||
return seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
let rpc;
|
|
||||||
const observer = (event, arg) => {
|
|
||||||
if (mediaInfoModule.mediaInfo.status == "paused" && rpc) {
|
|
||||||
rpc.setActivity(idleStatus);
|
|
||||||
} else if (rpc) {
|
|
||||||
const currentSeconds = timeToSeconds(mediaInfoModule.mediaInfo.current.split(":"));
|
|
||||||
const durationSeconds = timeToSeconds(mediaInfoModule.mediaInfo.duration.split(":"));
|
|
||||||
const date = new Date();
|
|
||||||
const now = (date.getTime() / 1000) | 0;
|
|
||||||
const remaining = date.setSeconds(date.getSeconds() + (durationSeconds - currentSeconds));
|
|
||||||
if (mediaInfoModule.mediaInfo.url) {
|
|
||||||
rpc.setActivity({
|
|
||||||
...idleStatus,
|
|
||||||
...{
|
|
||||||
details: `Listening to ${mediaInfoModule.mediaInfo.title}`,
|
|
||||||
state: mediaInfoModule.mediaInfo.artists
|
|
||||||
? mediaInfoModule.mediaInfo.artists
|
|
||||||
: "unknown artist(s)",
|
|
||||||
startTimestamp: parseInt(now),
|
|
||||||
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 }],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
rpc.setActivity({
|
|
||||||
...idleStatus,
|
|
||||||
...{
|
|
||||||
details: `Watching ${mediaInfoModule.mediaInfo.title}`,
|
|
||||||
state: mediaInfoModule.mediaInfo.artists,
|
|
||||||
startTimestamp: parseInt(now),
|
|
||||||
endTimestamp: parseInt(remaining),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const idleStatus = {
|
|
||||||
details: `Browsing Tidal`,
|
|
||||||
largeImageKey: "tidal-hifi-icon",
|
|
||||||
largeImageText: `Tidal HiFi ${app.getVersion()}`,
|
|
||||||
instance: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set up the discord rpc and listen on globalEvents.updateInfo
|
|
||||||
*/
|
|
||||||
discordModule.initRPC = function () {
|
|
||||||
rpc = new discordrpc.Client({ transport: "ipc" });
|
|
||||||
rpc.login({ clientId }).then(
|
|
||||||
() => {
|
|
||||||
discordModule.rpc = rpc;
|
|
||||||
|
|
||||||
rpc.on("ready", () => {
|
|
||||||
rpc.setActivity(idleStatus);
|
|
||||||
});
|
|
||||||
ipcMain.on(globalEvents.updateInfo, observer);
|
|
||||||
},
|
|
||||||
() => {
|
|
||||||
console.error("Can't connect to Discord, is it running?");
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove any RPC connection with discord and remove the event listener on globalEvents.updateInfo
|
|
||||||
*/
|
|
||||||
discordModule.unRPC = function () {
|
|
||||||
if (rpc) {
|
|
||||||
rpc.clearActivity();
|
|
||||||
rpc.destroy();
|
|
||||||
rpc = false;
|
|
||||||
discordModule.rpc = undefined;
|
|
||||||
ipcMain.removeListener(globalEvents.updateInfo, observer);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = discordModule;
|
|
88
src/scripts/discord.ts
Normal file
88
src/scripts/discord.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { Client } from "discord-rpc";
|
||||||
|
import { app, ipcMain } from "electron";
|
||||||
|
import globalEvents from "../constants/globalEvents";
|
||||||
|
import { MediaStatus } from "../models/mediaStatus";
|
||||||
|
import { mediaInfo } from "./mediaInfo";
|
||||||
|
|
||||||
|
const clientId = "833617820704440341";
|
||||||
|
|
||||||
|
function timeToSeconds(timeArray: string[]) {
|
||||||
|
const minutes = parseInt(timeArray[0]) * 1;
|
||||||
|
const seconds = minutes * 60 + parseInt(timeArray[1]) * 1;
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let rpc: Client;
|
||||||
|
|
||||||
|
const observer = () => {
|
||||||
|
if (mediaInfo.status == MediaStatus.paused && rpc) {
|
||||||
|
rpc.setActivity(idleStatus);
|
||||||
|
} else if (rpc) {
|
||||||
|
const currentSeconds = timeToSeconds(mediaInfo.current.split(":"));
|
||||||
|
const durationSeconds = timeToSeconds(mediaInfo.duration.split(":"));
|
||||||
|
const date = new Date();
|
||||||
|
const now = (date.getTime() / 1000) | 0;
|
||||||
|
const remaining = date.setSeconds(date.getSeconds() + (durationSeconds - currentSeconds));
|
||||||
|
if (mediaInfo.url) {
|
||||||
|
rpc.setActivity({
|
||||||
|
...idleStatus,
|
||||||
|
...{
|
||||||
|
details: `Listening to ${mediaInfo.title}`,
|
||||||
|
state: mediaInfo.artists ? mediaInfo.artists : "unknown artist(s)",
|
||||||
|
startTimestamp: now,
|
||||||
|
endTimestamp: remaining,
|
||||||
|
largeImageKey: mediaInfo.image,
|
||||||
|
largeImageText: mediaInfo.album ? mediaInfo.album : `${idleStatus.largeImageText}`,
|
||||||
|
buttons: [{ label: "Play on Tidal", url: mediaInfo.url }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rpc.setActivity({
|
||||||
|
...idleStatus,
|
||||||
|
...{
|
||||||
|
details: `Watching ${mediaInfo.title}`,
|
||||||
|
state: mediaInfo.artists,
|
||||||
|
startTimestamp: now,
|
||||||
|
endTimestamp: remaining,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const idleStatus = {
|
||||||
|
details: `Browsing Tidal`,
|
||||||
|
largeImageKey: "tidal-hifi-icon",
|
||||||
|
largeImageText: `Tidal HiFi ${app.getVersion()}`,
|
||||||
|
instance: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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", () => {
|
||||||
|
rpc.setActivity(idleStatus);
|
||||||
|
});
|
||||||
|
ipcMain.on(globalEvents.updateInfo, observer);
|
||||||
|
},
|
||||||
|
() => {
|
||||||
|
console.error("Can't connect to Discord, is it running?");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any RPC connection with discord and remove the event listener on globalEvents.updateInfo
|
||||||
|
*/
|
||||||
|
export const unRPC = () => {
|
||||||
|
if (rpc) {
|
||||||
|
rpc.clearActivity();
|
||||||
|
rpc.destroy();
|
||||||
|
rpc = null;
|
||||||
|
ipcMain.removeListener(globalEvents.updateInfo, observer);
|
||||||
|
}
|
||||||
|
};
|
@ -1,10 +1,11 @@
|
|||||||
import { BrowserWindow } from "electron";
|
import { BrowserWindow, dialog } from "electron";
|
||||||
import express, { Response } from "express";
|
import express, { Response } from "express";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
const { mediaInfo } = require("./mediaInfo");
|
import globalEvents from "./../constants/globalEvents";
|
||||||
const { store, settings } = require("./settings");
|
import statuses from "./../constants/statuses";
|
||||||
const globalEvents = require("./../constants/globalEvents");
|
import { mediaInfo } from "./mediaInfo";
|
||||||
const statuses = require("./../constants/statuses");
|
import { settingsStore } from "./settings";
|
||||||
|
import { settings } from "../constants/settings";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function to enable tidal-hifi's express api
|
* Function to enable tidal-hifi's express api
|
||||||
@ -37,7 +38,7 @@ export const startExpress = (mainWindow: BrowserWindow) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (store.get(settings.playBackControl)) {
|
if (settingsStore.get(settings.playBackControl)) {
|
||||||
expressApp.get("/play", (req, res) => handleGlobalEvent(res, globalEvents.play));
|
expressApp.get("/play", (req, res) => handleGlobalEvent(res, globalEvents.play));
|
||||||
expressApp.get("/pause", (req, res) => handleGlobalEvent(res, globalEvents.pause));
|
expressApp.get("/pause", (req, res) => handleGlobalEvent(res, globalEvents.pause));
|
||||||
expressApp.get("/next", (req, res) => handleGlobalEvent(res, globalEvents.next));
|
expressApp.get("/next", (req, res) => handleGlobalEvent(res, globalEvents.next));
|
||||||
@ -51,15 +52,15 @@ export const startExpress = (mainWindow: BrowserWindow) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let port = store.get(settings.apiSettings.port);
|
const port = settingsStore.get<string, number>(settings.apiSettings.port);
|
||||||
|
|
||||||
const expressInstance = expressApp.listen(port, "127.0.0.1", () => {});
|
const expressInstance = expressApp.listen(port, "127.0.0.1");
|
||||||
expressInstance.on("error", function (e: { code: string }) {
|
expressInstance.on("error", function (e: { code: string }) {
|
||||||
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.`;
|
||||||
}
|
}
|
||||||
const { dialog } = require("electron");
|
|
||||||
dialog.showErrorBox("Api failed to start.", message);
|
dialog.showErrorBox("Api failed to start.", message);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
const statuses = require("./../constants/statuses");
|
|
||||||
|
|
||||||
const mediaInfo = {
|
|
||||||
title: "",
|
|
||||||
artists: "",
|
|
||||||
album: "",
|
|
||||||
icon: "",
|
|
||||||
status: statuses.paused,
|
|
||||||
url: "",
|
|
||||||
current: "",
|
|
||||||
duration: "",
|
|
||||||
image: "tidal-hifi-icon",
|
|
||||||
};
|
|
||||||
const mediaInfoModule = {
|
|
||||||
mediaInfo,
|
|
||||||
update: function (arg) {
|
|
||||||
mediaInfo.title = propOrDefault(arg.title);
|
|
||||||
mediaInfo.artists = propOrDefault(arg.artists);
|
|
||||||
mediaInfo.album = propOrDefault(arg.album);
|
|
||||||
mediaInfo.icon = propOrDefault(arg.icon);
|
|
||||||
mediaInfo.url = propOrDefault(arg.url);
|
|
||||||
mediaInfo.status = propOrDefault(arg.status);
|
|
||||||
mediaInfo.current = propOrDefault(arg.current);
|
|
||||||
mediaInfo.duration = propOrDefault(arg.duration);
|
|
||||||
mediaInfo.image = propOrDefault(arg.image);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the property or a default value
|
|
||||||
* @param {*} prop property to check
|
|
||||||
* @param {*} defaultValue defaults to ""
|
|
||||||
*/
|
|
||||||
function propOrDefault(prop, defaultValue = "") {
|
|
||||||
return prop ? prop : defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = mediaInfoModule;
|
|
35
src/scripts/mediaInfo.ts
Normal file
35
src/scripts/mediaInfo.ts
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import { MediaInfo } from "../models/mediaInfo";
|
||||||
|
import statuses from "./../constants/statuses";
|
||||||
|
|
||||||
|
export const mediaInfo = {
|
||||||
|
title: "",
|
||||||
|
artists: "",
|
||||||
|
album: "",
|
||||||
|
icon: "",
|
||||||
|
status: statuses.paused,
|
||||||
|
url: "",
|
||||||
|
current: "",
|
||||||
|
duration: "",
|
||||||
|
image: "tidal-hifi-icon",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateMediaInfo = (arg: MediaInfo) => {
|
||||||
|
mediaInfo.title = propOrDefault(arg.title);
|
||||||
|
mediaInfo.artists = propOrDefault(arg.artists);
|
||||||
|
mediaInfo.album = propOrDefault(arg.album);
|
||||||
|
mediaInfo.icon = propOrDefault(arg.icon);
|
||||||
|
mediaInfo.url = propOrDefault(arg.url);
|
||||||
|
mediaInfo.status = propOrDefault(arg.status);
|
||||||
|
mediaInfo.current = propOrDefault(arg.current);
|
||||||
|
mediaInfo.duration = propOrDefault(arg.duration);
|
||||||
|
mediaInfo.image = propOrDefault(arg.image);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the property or a default value
|
||||||
|
* @param {*} prop property to check
|
||||||
|
* @param {*} defaultValue defaults to ""
|
||||||
|
*/
|
||||||
|
function propOrDefault(prop: string, defaultValue = "") {
|
||||||
|
return prop ? prop : defaultValue;
|
||||||
|
}
|
@ -1,12 +1,12 @@
|
|||||||
const Store = require("electron-store");
|
import Store from "electron-store";
|
||||||
|
|
||||||
const settings = require("../constants/settings");
|
import { settings } from "../constants/settings";
|
||||||
const path = require("path");
|
import path from "path";
|
||||||
const { BrowserWindow } = require("electron");
|
import { BrowserWindow } from "electron";
|
||||||
|
|
||||||
let settingsWindow;
|
let settingsWindow: BrowserWindow;
|
||||||
|
|
||||||
const store = new Store({
|
export const settingsStore = new Store({
|
||||||
defaults: {
|
defaults: {
|
||||||
adBlock: false,
|
adBlock: false,
|
||||||
api: true,
|
api: true,
|
||||||
@ -46,12 +46,11 @@ const store = new Store({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const settingsModule = {
|
const settingsModule = {
|
||||||
store,
|
// settings,
|
||||||
settings,
|
|
||||||
settingsWindow,
|
settingsWindow,
|
||||||
};
|
};
|
||||||
|
|
||||||
settingsModule.createSettingsWindow = function () {
|
export const createSettingsWindow = function () {
|
||||||
settingsWindow = new BrowserWindow({
|
settingsWindow = new BrowserWindow({
|
||||||
width: 700,
|
width: 700,
|
||||||
height: 600,
|
height: 600,
|
||||||
@ -67,7 +66,7 @@ settingsModule.createSettingsWindow = function () {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
settingsWindow.on("close", (event) => {
|
settingsWindow.on("close", (event: any) => {
|
||||||
if (settingsWindow != null) {
|
if (settingsWindow != null) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
settingsWindow.hide();
|
settingsWindow.hide();
|
||||||
@ -79,19 +78,17 @@ settingsModule.createSettingsWindow = function () {
|
|||||||
settingsModule.settingsWindow = settingsWindow;
|
settingsModule.settingsWindow = settingsWindow;
|
||||||
};
|
};
|
||||||
|
|
||||||
settingsModule.showSettingsWindow = function (tab = "general") {
|
export const showSettingsWindow = function (tab = "general") {
|
||||||
settingsWindow.webContents.send("goToTab", tab);
|
settingsWindow.webContents.send("goToTab", tab);
|
||||||
|
|
||||||
// refresh data just before showing the window
|
// refresh data just before showing the window
|
||||||
settingsWindow.webContents.send("refreshData");
|
settingsWindow.webContents.send("refreshData");
|
||||||
settingsWindow.show();
|
settingsWindow.show();
|
||||||
};
|
};
|
||||||
settingsModule.hideSettingsWindow = function () {
|
export const hideSettingsWindow = function () {
|
||||||
settingsWindow.hide();
|
settingsWindow.hide();
|
||||||
};
|
};
|
||||||
|
|
||||||
settingsModule.closeSettingsWindow = function () {
|
export const closeSettingsWindow = function () {
|
||||||
settingsWindow = null;
|
settingsWindow = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = settingsModule;
|
|
Loading…
Reference in New Issue
Block a user