chore: more typescript

This commit is contained in:
Rick van Lieshout 2023-05-07 15:45:45 +02:00
parent e8509d42e7
commit 53e4711c39
15 changed files with 249 additions and 247 deletions

7
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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
View File

@ -0,0 +1 @@
declare module "mpris-service";

View File

@ -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
View 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;
}

View File

@ -0,0 +1,4 @@
export enum MediaStatus {
playing = "playing",
paused = "paused",
}

View File

@ -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);
}); });
} }

View File

@ -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",

View File

@ -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
View 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);
}
};

View File

@ -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);
}); });
}; };

View File

@ -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
View 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;
}

View File

@ -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;