mirror of
https://github.com/Mastermindzh/tidal-hifi.git
synced 2024-11-22 13:32:42 +01:00
commit
11cc209025
@ -13,4 +13,4 @@ steps:
|
|||||||
commands:
|
commands:
|
||||||
- apt-get update && apt-get upgrade -y
|
- apt-get update && apt-get upgrade -y
|
||||||
- apt-get install -y libarchive-tools rpm
|
- apt-get install -y libarchive-tools rpm
|
||||||
- npm run build
|
- npm run build-unpacked
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
|
"env": {
|
||||||
|
"node": true,
|
||||||
|
"browser": true
|
||||||
|
},
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"@typescript-eslint"
|
"@typescript-eslint"
|
||||||
|
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@ -5,6 +5,7 @@
|
|||||||
"hifi",
|
"hifi",
|
||||||
"playpause",
|
"playpause",
|
||||||
"rescrobbler",
|
"rescrobbler",
|
||||||
|
"Songwhip",
|
||||||
"trackid",
|
"trackid",
|
||||||
"tracklist",
|
"tracklist",
|
||||||
"widevine",
|
"widevine",
|
||||||
|
10
CHANGELOG.md
10
CHANGELOG.md
@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 5.4.0
|
||||||
|
|
||||||
|
- Removed Windows builds (from publishes) as they don't work anymore.
|
||||||
|
- Added [Songwhip](https://songwhip.com/) integration
|
||||||
|
- Fixed bug with several hotkeys not working due to Tidal's HTML/css changes
|
||||||
|
- [DEV]:
|
||||||
|
- added a logger to log into STDout
|
||||||
|
- added "watchStart" which will automatically restart electron when it detects a source code change
|
||||||
|
- added "listen.tidal.com-parsing-scripts" folder with a script to verify whether all elements (in the main preload.ts) are present on the page
|
||||||
|
|
||||||
## 5.3.0
|
## 5.3.0
|
||||||
|
|
||||||
- SPKChaosPhoenix updated the beautiful Tokyo Night theme:
|
- SPKChaosPhoenix updated the beautiful Tokyo Night theme:
|
||||||
|
13
README.md
13
README.md
@ -27,6 +27,7 @@ The web version of [listen.tidal.com](https://listen.tidal.com) running in elect
|
|||||||
- [Integrations](#integrations)
|
- [Integrations](#integrations)
|
||||||
- [Known bugs](#known-bugs)
|
- [Known bugs](#known-bugs)
|
||||||
- [last.fm doesn't work out of the box. Use rescrobbler as a workaround](#lastfm-doesnt-work-out-of-the-box-use-rescrobbler-as-a-workaround)
|
- [last.fm doesn't work out of the box. Use rescrobbler as a workaround](#lastfm-doesnt-work-out-of-the-box-use-rescrobbler-as-a-workaround)
|
||||||
|
- [DRM not working on Windows](#drm-not-working-on-windows)
|
||||||
- [Special thanks to](#special-thanks-to)
|
- [Special thanks to](#special-thanks-to)
|
||||||
- [Donations](#donations)
|
- [Donations](#donations)
|
||||||
- [Images](#images)
|
- [Images](#images)
|
||||||
@ -41,6 +42,7 @@ The web version of [listen.tidal.com](https://listen.tidal.com) running in elect
|
|||||||
- Notifications
|
- Notifications
|
||||||
- Custom [theming](./docs/theming.md)
|
- Custom [theming](./docs/theming.md)
|
||||||
- Custom hotkeys ([source](https://defkey.com/tidal-desktop-shortcuts))
|
- Custom hotkeys ([source](https://defkey.com/tidal-desktop-shortcuts))
|
||||||
|
- Songwhip.com integration (hotkey `ctrl + w`)
|
||||||
- API for status and playback
|
- API for status and playback
|
||||||
- Disabled audio & visual ads, unlocked lyrics, suggested track, track info, and unlimited skips thanks to uBlockOrigin custom filters ([source](https://github.com/uBlockOrigin/uAssets/issues/17495))
|
- Disabled audio & visual ads, unlocked lyrics, suggested track, track info, and unlimited skips thanks to uBlockOrigin custom filters ([source](https://github.com/uBlockOrigin/uAssets/issues/17495))
|
||||||
- Custom [integrations](#integrations)
|
- Custom [integrations](#integrations)
|
||||||
@ -65,10 +67,10 @@ Whilst there are a handful of projects attempting to run Tidal on Electron they
|
|||||||
|
|
||||||
- Lack of maintainers/developers. (no hotfixes, no issues being handled etc)
|
- Lack of maintainers/developers. (no hotfixes, no issues being handled etc)
|
||||||
- Most are simple web wrappers, not my cup of tea.
|
- Most are simple web wrappers, not my cup of tea.
|
||||||
- Some are DE oriented. I want this to work on WM's too.
|
- Some are DE-oriented. I want this to work on WM's too.
|
||||||
- None have widevine working at the moment
|
- None have Widevine working at the moment
|
||||||
|
|
||||||
Sometimes it's just easier to start over, cover my own needs and then making it available to the public :)
|
Sometimes it's just easier to start over, cover my own needs and after that making it available to the public :)
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@ -153,6 +155,11 @@ The last.fm login doesn't work, as is evident from the following issue: [Last.fm
|
|||||||
However, in that same issue you can read about a workaround using [rescrobbler](https://github.com/InputUsername/rescrobbled).
|
However, in that same issue you can read about a workaround using [rescrobbler](https://github.com/InputUsername/rescrobbled).
|
||||||
For now that will be the default workaround.
|
For now that will be the default workaround.
|
||||||
|
|
||||||
|
#### DRM not working on Windows
|
||||||
|
|
||||||
|
Most Windows users run into DRM issues when trying to use Tidal-hifi.
|
||||||
|
Nothing I can do about that I'm afraid... Tidal is working on removing/changing DRM so when they finish with that we can give it another shot.
|
||||||
|
|
||||||
## Special thanks to
|
## Special thanks to
|
||||||
|
|
||||||
- [Castlabs](https://castlabs.com/)
|
- [Castlabs](https://castlabs.com/)
|
||||||
|
43
listen.tidal.com-parsing-scripts/verifyElements.js
Normal file
43
listen.tidal.com-parsing-scripts/verifyElements.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// for some dumb reason `listen.tidal.com` has disabled console.log
|
||||||
|
// we can simply return an array with values though...
|
||||||
|
// run this on a playlist or mix page and observe the result
|
||||||
|
// NOTE: play & pause can't live together so one or the other will throw an error
|
||||||
|
(() => {
|
||||||
|
let elements = {
|
||||||
|
play: '*[data-test="play"]',
|
||||||
|
pause: '*[data-test="pause"]',
|
||||||
|
next: '*[data-test="next"]',
|
||||||
|
previous: 'button[data-test="previous"]',
|
||||||
|
title: '*[data-test^="footer-track-title"]',
|
||||||
|
artists: '*[data-test^="grid-item-detail-text-title-artist"]',
|
||||||
|
home: '*[data-test="menu--home"]',
|
||||||
|
back: '[title^="Back"]',
|
||||||
|
forward: '[title^="Next"]',
|
||||||
|
search: '[class^="searchField"]',
|
||||||
|
shuffle: '*[data-test="shuffle"]',
|
||||||
|
repeat: '*[data-test="repeat"]',
|
||||||
|
account: '*[data-test^="profile-image-button"]',
|
||||||
|
media: '*[data-test="current-media-imagery"]',
|
||||||
|
image: "img",
|
||||||
|
current: '*[data-test="current-time"]',
|
||||||
|
duration: '*[data-test="duration"]',
|
||||||
|
bar: '*[data-test="progress-bar"]',
|
||||||
|
footer: "#footerPlayer",
|
||||||
|
mediaItem: "[data-type='mediaItem']",
|
||||||
|
album_header_title: '.header-details [data-test="title"]',
|
||||||
|
currentlyPlaying: "[class^='isPlayingIcon'], [data-test-is-playing='true']",
|
||||||
|
album_name_cell: '[class^="album"]',
|
||||||
|
tracklist_row: '[data-test="tracklist-row"]',
|
||||||
|
volume: '*[data-test="volume"]',
|
||||||
|
};
|
||||||
|
|
||||||
|
let results = [];
|
||||||
|
|
||||||
|
Object.entries(elements).forEach(([key, value]) => {
|
||||||
|
const returnValue = document.querySelector(`${value}`);
|
||||||
|
if (!returnValue) {
|
||||||
|
results.push(`element ${key} not found`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
})();
|
1487
package-lock.json
generated
1487
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "tidal-hifi",
|
"name": "tidal-hifi",
|
||||||
"version": "5.3.0",
|
"version": "5.4.0",
|
||||||
"description": "Tidal on Electron with widevine(hifi) support",
|
"description": "Tidal on Electron with widevine(hifi) support",
|
||||||
"main": "ts-dist/main.js",
|
"main": "ts-dist/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "electron .",
|
"start": "electron --inspect=0.0.0.0:5858 .",
|
||||||
|
"watchStart": "nodemon dist -x \"npm run start\"",
|
||||||
"compile": "tsc && npm run sass-and-copy",
|
"compile": "tsc && npm run sass-and-copy",
|
||||||
"watch": "tsc-watch --onSuccess \"npm run sass-and-copy\"",
|
"watch": "tsc-watch --onSuccess \"npm run sass-and-copy\"",
|
||||||
"copy-files": "copyfiles -u 1 --exclude './src/**/*.ts' --exclude './src/**/*.scss' \"./src/**/*\" ts-dist",
|
"copy-files": "copyfiles -u 1 --exclude './src/**/*.ts' --exclude './src/**/*.scss' \"./src/**/*\" ts-dist",
|
||||||
@ -29,41 +30,46 @@
|
|||||||
"electron",
|
"electron",
|
||||||
"hifi",
|
"hifi",
|
||||||
"widevine",
|
"widevine",
|
||||||
"linux"
|
"linux",
|
||||||
|
"drm",
|
||||||
|
"castlabs"
|
||||||
],
|
],
|
||||||
"author": "Rick van Lieshout <info@rickvanlieshout.com> (http://rickvanlieshout.com)",
|
"author": "Rick van Lieshout <info@rickvanlieshout.com> (http://rickvanlieshout.com)",
|
||||||
"homepage": "https://github.com/Mastermindzh/tidal-hifi",
|
"homepage": "https://github.com/Mastermindzh/tidal-hifi",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.0.9",
|
"@electron/remote": "^2.0.10",
|
||||||
|
"axios": "^1.4.0",
|
||||||
"discord-rpc": "^4.0.1",
|
"discord-rpc": "^4.0.1",
|
||||||
"electron-store": "^8.1.0",
|
"electron-store": "^8.1.0",
|
||||||
"express": "^4.18.2",
|
"express": "^4.18.2",
|
||||||
"hotkeys-js": "^3.10.2",
|
"hotkeys-js": "^3.11.2",
|
||||||
"mpris-service": "^2.1.2",
|
"mpris-service": "^2.1.2",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"sass": "^1.62.0"
|
"sass": "^1.64.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@mastermindzh/prettier-config": "^1.0.0",
|
"@mastermindzh/prettier-config": "^1.0.0",
|
||||||
"@types/discord-rpc": "^4.0.4",
|
"@types/discord-rpc": "^4.0.5",
|
||||||
"@types/express": "^4.17.17",
|
"@types/express": "^4.17.17",
|
||||||
|
"@types/node": "^20.4.4",
|
||||||
"@types/request": "^2.48.8",
|
"@types/request": "^2.48.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
||||||
"@typescript-eslint/parser": "^5.59.1",
|
"@typescript-eslint/parser": "^6.1.0",
|
||||||
"copyfiles": "^2.4.1",
|
"copyfiles": "^2.4.1",
|
||||||
"electron": "git+https://github.com/castlabs/electron-releases.git#v24.1.2+wvcus",
|
"electron": "git+https://github.com/castlabs/electron-releases.git#v24.1.2+wvcus",
|
||||||
"electron-builder": "^24.2.1",
|
"electron-builder": "^24.4.0",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.45.0",
|
||||||
"js-yaml": "^4.1.0",
|
"js-yaml": "^4.1.0",
|
||||||
"markdown-toc": "^1.2.0",
|
"markdown-toc": "^1.2.0",
|
||||||
"prettier": "^2.8.8",
|
"nodemon": "^3.0.1",
|
||||||
"stylelint": "^15.10.1",
|
"prettier": "^3.0.0",
|
||||||
"stylelint-config-standard": "^33.0.0",
|
"stylelint": "^15.10.2",
|
||||||
"stylelint-config-standard-scss": "^9.0.0",
|
"stylelint-config-standard": "^34.0.0",
|
||||||
"stylelint-prettier": "^3.0.0",
|
"stylelint-config-standard-scss": "^10.0.0",
|
||||||
|
"stylelint-prettier": "^4.0.0",
|
||||||
"tsc-watch": "^6.0.4",
|
"tsc-watch": "^6.0.4",
|
||||||
"typescript": "^5.0.4"
|
"typescript": "^5.1.6"
|
||||||
},
|
},
|
||||||
"prettier": "@mastermindzh/prettier-config"
|
"prettier": "@mastermindzh/prettier-config"
|
||||||
}
|
}
|
||||||
|
@ -10,4 +10,6 @@ export const globalEvents = {
|
|||||||
showSettings: "showSettings",
|
showSettings: "showSettings",
|
||||||
storeChanged: "storeChanged",
|
storeChanged: "storeChanged",
|
||||||
error: "error",
|
error: "error",
|
||||||
|
whip: "whip",
|
||||||
|
log: "log",
|
||||||
};
|
};
|
||||||
|
33
src/features/logger.ts
Normal file
33
src/features/logger.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { IpcMain, IpcRenderer } from "electron";
|
||||||
|
import { globalEvents } from "../constants/globalEvents";
|
||||||
|
|
||||||
|
export class Logger {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param ipcRenderer renderer IPC client so we can send messages to the main thread
|
||||||
|
*/
|
||||||
|
constructor(private ipcRenderer: IpcRenderer) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribe to watch for logs from the IPC client
|
||||||
|
* @param ipcMain main thread IPC client so we can subscribe to events
|
||||||
|
*/
|
||||||
|
public static watch(ipcMain: IpcMain) {
|
||||||
|
ipcMain.on(globalEvents.log, (event, content, object) => {
|
||||||
|
console.log(content, JSON.stringify(object, null, 2));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log content to STDOut
|
||||||
|
* @param content
|
||||||
|
* @param object js(on) object that will be prettyPrinted
|
||||||
|
*/
|
||||||
|
public log(content: string, object: object = {}) {
|
||||||
|
if (this.ipcRenderer) {
|
||||||
|
this.ipcRenderer.send(globalEvents.log, { content, object });
|
||||||
|
} else {
|
||||||
|
console.log(`${content} \n ${JSON.stringify(object, null, 2)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
src/features/songwhip/models/Artist.ts
Normal file
21
src/features/songwhip/models/Artist.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
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;
|
||||||
|
}
|
4
src/features/songwhip/models/ServiceLinks.ts
Normal file
4
src/features/songwhip/models/ServiceLinks.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export interface ServiceLinks {
|
||||||
|
link: string;
|
||||||
|
countries: string[];
|
||||||
|
}
|
27
src/features/songwhip/models/whip.ts
Normal file
27
src/features/songwhip/models/whip.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
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[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
32
src/features/songwhip/songwhip.ts
Normal file
32
src/features/songwhip/songwhip.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
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}`;
|
||||||
|
}
|
||||||
|
}
|
@ -26,6 +26,8 @@ import {
|
|||||||
import { settings } from "./constants/settings";
|
import { settings } from "./constants/settings";
|
||||||
import { addTray, refreshTray } from "./scripts/tray";
|
import { addTray, refreshTray } from "./scripts/tray";
|
||||||
import { MediaInfo } from "./models/mediaInfo";
|
import { MediaInfo } from "./models/mediaInfo";
|
||||||
|
import { Songwhip } from "./features/songwhip/songwhip";
|
||||||
|
import { Logger } from "./features/logger";
|
||||||
const tidalUrl = "https://listen.tidal.com";
|
const tidalUrl = "https://listen.tidal.com";
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
@ -220,3 +222,9 @@ ipcMain.on(globalEvents.storeChanged, () => {
|
|||||||
ipcMain.on(globalEvents.error, (event) => {
|
ipcMain.on(globalEvents.error, (event) => {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle(globalEvents.whip, async (event, url) => {
|
||||||
|
return await Songwhip.whip(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
Logger.watch(ipcMain);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import remote, { app } from "@electron/remote";
|
import { app } from "@electron/remote";
|
||||||
import { ipcRenderer, shell } from "electron";
|
import { ipcRenderer, shell } from "electron";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { globalEvents } from "../../constants/globalEvents";
|
import { globalEvents } from "../../constants/globalEvents";
|
||||||
@ -107,8 +107,8 @@ function hide() {
|
|||||||
* Restart tidal-hifi after changes
|
* Restart tidal-hifi after changes
|
||||||
*/
|
*/
|
||||||
function restart() {
|
function restart() {
|
||||||
remote.app.relaunch();
|
app.relaunch();
|
||||||
remote.app.exit();
|
app.exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import { Notification, app, dialog } from "@electron/remote";
|
import { app, dialog, Notification } from "@electron/remote";
|
||||||
import { ipcRenderer } from "electron";
|
import { clipboard, ipcRenderer } from "electron";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import Player from "mpris-service";
|
import Player from "mpris-service";
|
||||||
import { globalEvents } from "./constants/globalEvents";
|
import { globalEvents } from "./constants/globalEvents";
|
||||||
import { settings } from "./constants/settings";
|
import { settings } from "./constants/settings";
|
||||||
import { statuses } from "./constants/statuses";
|
import { statuses } from "./constants/statuses";
|
||||||
|
import { Songwhip } from "./features/songwhip/songwhip";
|
||||||
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 { settingsStore } from "./scripts/settings";
|
import { settingsStore } from "./scripts/settings";
|
||||||
import { setTitle } from "./scripts/window-functions";
|
import { setTitle } from "./scripts/window-functions";
|
||||||
|
|
||||||
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 = "";
|
||||||
@ -25,13 +26,12 @@ const elements = {
|
|||||||
title: '*[data-test^="footer-track-title"]',
|
title: '*[data-test^="footer-track-title"]',
|
||||||
artists: '*[data-test^="grid-item-detail-text-title-artist"]',
|
artists: '*[data-test^="grid-item-detail-text-title-artist"]',
|
||||||
home: '*[data-test="menu--home"]',
|
home: '*[data-test="menu--home"]',
|
||||||
back: '[class^="backwardButton"]',
|
back: '[title^="Back"]',
|
||||||
forward: '[class^="forwardButton"]',
|
forward: '[title^="Next"]',
|
||||||
search: '[class^="searchField"]',
|
search: '[class^="searchField"]',
|
||||||
shuffle: '*[data-test="shuffle"]',
|
shuffle: '*[data-test="shuffle"]',
|
||||||
repeat: '*[data-test="repeat"]',
|
repeat: '*[data-test="repeat"]',
|
||||||
block: '[class="blockButton"]',
|
account: '*[class^="profileOptions"]',
|
||||||
account: '*[data-test^="profile-image-button"]',
|
|
||||||
settings: '*[data-test^="open-settings"]',
|
settings: '*[data-test^="open-settings"]',
|
||||||
media: '*[data-test="current-media-imagery"]',
|
media: '*[data-test="current-media-imagery"]',
|
||||||
image: "img",
|
image: "img",
|
||||||
@ -39,9 +39,10 @@ const elements = {
|
|||||||
duration: '*[data-test="duration"]',
|
duration: '*[data-test="duration"]',
|
||||||
bar: '*[data-test="progress-bar"]',
|
bar: '*[data-test="progress-bar"]',
|
||||||
footer: "#footerPlayer",
|
footer: "#footerPlayer",
|
||||||
|
mediaItem: "[data-type='mediaItem']",
|
||||||
album_header_title: '.header-details [data-test="title"]',
|
album_header_title: '.header-details [data-test="title"]',
|
||||||
playing_title: 'span[data-test="table-cell-title"].css-1vjc1xk',
|
currentlyPlaying: "[class^='isPlayingIcon'], [data-test-is-playing='true']",
|
||||||
album_name_cell: '[data-test="table-cell-album"]',
|
album_name_cell: '[class^="album"]',
|
||||||
tracklist_row: '[data-test="tracklist-row"]',
|
tracklist_row: '[data-test="tracklist-row"]',
|
||||||
volume: '*[data-test="volume"]',
|
volume: '*[data-test="volume"]',
|
||||||
/**
|
/**
|
||||||
@ -105,7 +106,9 @@ const elements = {
|
|||||||
window.location.href.includes("/mix/")
|
window.location.href.includes("/mix/")
|
||||||
) {
|
) {
|
||||||
if (currentPlayStatus === statuses.playing) {
|
if (currentPlayStatus === statuses.playing) {
|
||||||
const row = window.document.querySelector(this.playing_title).closest(this.tracklist_row);
|
// find the currently playing element from the list (which might be in an album icon), traverse back up to the mediaItem (row) and select the album cell.
|
||||||
|
// document.querySelector("[class^='isPlayingIcon'], [data-test-is-playing='true']").closest('[data-type="mediaItem"]').querySelector('[class^="album"]').textContent
|
||||||
|
const row = window.document.querySelector(this.currentlyPlaying).closest(this.mediaItem);
|
||||||
if (row) {
|
if (row) {
|
||||||
return row.querySelector(this.album_name_cell).textContent;
|
return row.querySelector(this.album_name_cell).textContent;
|
||||||
}
|
}
|
||||||
@ -206,7 +209,10 @@ function playPause() {
|
|||||||
function addHotKeys() {
|
function addHotKeys() {
|
||||||
if (settingsStore.get(settings.enableCustomHotkeys)) {
|
if (settingsStore.get(settings.enableCustomHotkeys)) {
|
||||||
addHotkey("Control+p", function () {
|
addHotkey("Control+p", function () {
|
||||||
elements.click("account").click("settings");
|
elements.click("account");
|
||||||
|
setTimeout(() => {
|
||||||
|
elements.click("settings");
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
addHotkey("Control+l", function () {
|
addHotkey("Control+l", function () {
|
||||||
handleLogout();
|
handleLogout();
|
||||||
@ -232,6 +238,15 @@ function addHotKeys() {
|
|||||||
addHotkey("control+r", function () {
|
addHotkey("control+r", function () {
|
||||||
elements.click("repeat");
|
elements.click("repeat");
|
||||||
});
|
});
|
||||||
|
addHotkey("control+w", async function () {
|
||||||
|
const result = await ipcRenderer.invoke(globalEvents.whip, getTrackURL());
|
||||||
|
const url = Songwhip.getWhipUrl(result);
|
||||||
|
clipboard.writeText(url);
|
||||||
|
new Notification({
|
||||||
|
title: `Successfully whipped: `,
|
||||||
|
body: `URL copied to clipboard: ${url}`,
|
||||||
|
}).show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// always add the hotkey for the settings window
|
// always add the hotkey for the settings window
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"typeRoots": ["src/types"],
|
"typeRoots": ["src/types", "node_modules/@types"],
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "ES6",
|
"target": "ES6",
|
||||||
|
"lib": ["ES2020", "DOM"],
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user