mirror of
https://github.com/Mastermindzh/tidal-hifi.git
synced 2025-09-13 15:19:17 +02:00
Compare commits
6 Commits
5.18.1
...
16f98f4f1b
Author | SHA1 | Date | |
---|---|---|---|
|
16f98f4f1b | ||
|
256832dab6 | ||
|
977e50faa0 | ||
|
294701ec5f | ||
a44bf331e4 | |||
|
73051716e7 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -24,10 +24,6 @@ jobs:
|
||||
node-version: 22.4
|
||||
- run: npm install
|
||||
- run: npm run build
|
||||
- uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: linux-builds
|
||||
path: dist/
|
||||
|
||||
build_on_mac:
|
||||
runs-on: macos-latest
|
||||
|
13
CHANGELOG.md
13
CHANGELOG.md
@@ -4,19 +4,6 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [5.18.1]
|
||||
|
||||
- Fixed the login bug
|
||||
- Upgraded electron to 35.1.1
|
||||
- Added Widevine/CDM info to startup
|
||||
- delayed remote electron initializer
|
||||
|
||||
## [5.18.0]
|
||||
|
||||
- [Dianoga](https://github.com/Dianoga) fixed the duration selector, restoring mpris & partial API data.
|
||||
- PR: #554
|
||||
- Added `xesam:url` property to mpris metadata fixes [#506](https://github.com/Mastermindzh/tidal-hifi/issues/506)
|
||||
|
||||
## [5.17.0]
|
||||
|
||||
- Added an option to disable the dynamic title and set it to a static one, [#491](https://github.com/Mastermindzh/tidal-hifi/pull/491)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
appId: com.rickvanlieshout.tidal-hifi
|
||||
electronVersion: 35.1.1
|
||||
electronVersion: 28.1.1
|
||||
electronDownload:
|
||||
version: 35.1.1+wvcus
|
||||
version: 28.1.1+wvcus
|
||||
mirror: https://github.com/castlabs/electron-releases/releases/download/v
|
||||
snap:
|
||||
plugs:
|
||||
@@ -22,20 +22,19 @@ linux:
|
||||
"--enable-features=WaylandWindowDecorations",
|
||||
]
|
||||
desktop:
|
||||
entry: |
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Name=TIDAL Hi-Fi
|
||||
GenericName=TIDAL Hi-Fi
|
||||
Comment=The web version of listen.tidal.com running in electron with hifi support thanks to widevine.
|
||||
Icon=tidal-hifi
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;Application;AudioVideo;Audio;Video
|
||||
StartupWMClass=tidal-hifi
|
||||
X-PulseAudio-Properties=media.role=music
|
||||
MimeType=x-scheme-handler/tidal;
|
||||
Encoding: UTF-8
|
||||
Name: TIDAL Hi-Fi
|
||||
GenericName: TIDAL Hi-Fi
|
||||
Comment: The web version of listen.tidal.com running in electron with hifi support thanks to widevine.
|
||||
Icon: tidal-hifi
|
||||
StartupNotify: true
|
||||
Terminal: false
|
||||
Type: Application
|
||||
Categories: Network;Application;AudioVideo;Audio;Video
|
||||
StartupWMClass: tidal-hifi
|
||||
X-PulseAudio-Properties: media.role=music
|
||||
MimeType: x-scheme-handler/tidal;
|
||||
|
||||
mac:
|
||||
category: public.app-category.entertainment
|
||||
win:
|
||||
|
4738
package-lock.json
generated
4738
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "tidal-hifi",
|
||||
"version": "5.18.1",
|
||||
"version": "5.17.0",
|
||||
"description": "Tidal on Electron with widevine(hifi) support",
|
||||
"main": "ts-dist/main.js",
|
||||
"scripts": {
|
||||
"start": "electron --inspect=0.0.0.0:5858 --remote-debugging-port=8315 --remote-allow-origins=* .",
|
||||
"start": "electron --inspect=0.0.0.0:5858 .",
|
||||
"watchStart": "nodemon dist -x \"npm run start\"",
|
||||
"compile": "tsc && npm run sass-and-copy",
|
||||
"deps": "npm run watch",
|
||||
@@ -42,29 +42,27 @@
|
||||
"dependencies": {
|
||||
"@electron/remote": "^2.1.2",
|
||||
"@types/swagger-jsdoc": "^6.0.4",
|
||||
"@xhayper/discord-rpc": "^1.2.1",
|
||||
"axios": "^1.8.4",
|
||||
"@xhayper/discord-rpc": "^1.2.0",
|
||||
"axios": "^1.7.9",
|
||||
"cors": "^2.8.5",
|
||||
"electron-store": "^8.2.0",
|
||||
"express": "^4.21.2",
|
||||
"hotkeys-js": "^3.13.9",
|
||||
"hotkeys-js": "^3.13.7",
|
||||
"mpris-service": "^2.1.2",
|
||||
"sass": "^1.79.4",
|
||||
"swagger-ui-express": "^5.0.1",
|
||||
"cors": "^2.8.5",
|
||||
"request": "^2.88.2"
|
||||
"swagger-ui-express": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mastermindzh/prettier-config": "^1.0.0",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/request": "^2.48.12",
|
||||
"@types/swagger-ui-express": "^4.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.16.0",
|
||||
"@typescript-eslint/parser": "^7.15.0",
|
||||
"copyfiles": "^2.4.1",
|
||||
"electron": "github:castlabs/electron-releases#v35.1.1+wvcus",
|
||||
"electron-builder": "~26.0.12",
|
||||
"electron": "git+https://github.com/castlabs/electron-releases#v31.1.0+wvcus",
|
||||
"electron-builder": "~24.9.4",
|
||||
"eslint": "^8.57.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"markdown-toc": "^1.2.0",
|
||||
|
@@ -22,13 +22,12 @@
|
||||
media: '*[data-test="current-media-imagery"]',
|
||||
image: "img",
|
||||
current: '*[data-test="current-time"]',
|
||||
duration: '*[class^=_playbackControlsContainer] *[data-test="duration"]',
|
||||
duration: '*[class^=playbackControlsContainer] *[data-test="duration"]',
|
||||
bar: '*[data-test="progress-bar"]',
|
||||
footer: "#footerPlayer",
|
||||
mediaItem: "[data-type='mediaItem']",
|
||||
album_header_title: '*[class^="_playingFrom"] span:nth-child(2)',
|
||||
playing_from: '*[class^="_playingFrom"] span:nth-child(2)',
|
||||
queue_album: "*[class^=playQueueItemsContainer] *[class^=groupTitle] span:nth-child(2)",
|
||||
album_header_title: '*[class^="playingFrom"] span:nth-child(2)',
|
||||
playingFrom: '*[class^="playingFrom"] span:nth-child(2)',
|
||||
currentlyPlaying: "[class^='isPlayingIcon'], [data-test-is-playing='true']",
|
||||
album_name_cell: '[class^="album"]',
|
||||
tracklist_row: '[data-test="tracklist-row"]',
|
||||
|
@@ -15,4 +15,6 @@ export const globalEvents = {
|
||||
toggleFavorite: "toggleFavorite",
|
||||
toggleShuffle: "toggleShuffle",
|
||||
toggleRepeat: "toggleRepeat",
|
||||
axios: "axios",
|
||||
axiosReply: "axiosReply",
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"openapi": "3.1.0",
|
||||
"info": {
|
||||
"title": "TIDAL Hi-Fi API",
|
||||
"version": "5.18.1",
|
||||
"version": "5.17.0",
|
||||
"description": "",
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
|
17
src/main.ts
17
src/main.ts
@@ -24,8 +24,10 @@ import {
|
||||
showSettingsWindow,
|
||||
} from "./scripts/settings";
|
||||
import { addTray, refreshTray } from "./scripts/tray";
|
||||
import { downloadFile } from "./scripts/download";
|
||||
let mainInhibitorId = -1;
|
||||
|
||||
initialize();
|
||||
let mainWindow: BrowserWindow;
|
||||
const icon = path.join(__dirname, "../assets/icon.png");
|
||||
const PROTOCOL_PREFIX = "tidal";
|
||||
@@ -97,7 +99,6 @@ function createWindow(options = { x: 0, y: 0, backgroundColor: "white" }) {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
enable(mainWindow.webContents);
|
||||
registerHttpProtocols();
|
||||
syncMenuBarWithStore();
|
||||
@@ -126,7 +127,6 @@ function createWindow(options = { x: 0, y: 0, backgroundColor: "white" }) {
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on("closed", function () {
|
||||
releaseInhibitorIfActive(mainInhibitorId);
|
||||
@@ -179,7 +179,6 @@ app.on("ready", async () => {
|
||||
|
||||
if (isMainInstance() || isMultipleInstancesAllowed()) {
|
||||
await components.whenReady();
|
||||
initialize();
|
||||
|
||||
// Adblock
|
||||
if (settingsStore.get(settings.adBlock)) {
|
||||
@@ -190,8 +189,6 @@ app.on("ready", async () => {
|
||||
});
|
||||
}
|
||||
|
||||
Logger.log("components ready:", components.status());
|
||||
|
||||
createWindow();
|
||||
addMenu(mainWindow);
|
||||
createSettingsWindow();
|
||||
@@ -254,6 +251,16 @@ ipcMain.on(globalEvents.error, (event) => {
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
ipcMain.on(globalEvents.axios, (event, fileUrl: string, targetPath: string) => {
|
||||
const download = downloadFile(fileUrl, targetPath);
|
||||
download.then(() => {
|
||||
event.reply(globalEvents.axiosReply, fileUrl, targetPath, false);
|
||||
}).catch(() => {
|
||||
// don't send error information, it isn't used anyways
|
||||
event.reply(globalEvents.axiosReply, fileUrl, targetPath, true);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle(globalEvents.getUniversalLink, async (event, url) => {
|
||||
return SharingService.getUniversalLink(url);
|
||||
});
|
||||
|
@@ -478,7 +478,7 @@
|
||||
<h4>TIDAL Hi-Fi</h4>
|
||||
<div class="about-section__version">
|
||||
<a target="_blank" rel="noopener"
|
||||
href="https://github.com/Mastermindzh/tidal-hifi/releases/tag/5.18.1">5.18.1</a>
|
||||
href="https://github.com/Mastermindzh/tidal-hifi/releases/tag/5.17.0">5.17.0</a>
|
||||
</div>
|
||||
<div class="about-section__links">
|
||||
<a target="_blank" rel="noopener" href="https://github.com/mastermindzh/tidal-hifi/"
|
||||
|
@@ -16,7 +16,7 @@ import { convertDurationToSeconds } from "./features/time/parse";
|
||||
import { MediaInfo } from "./models/mediaInfo";
|
||||
import { MediaStatus } from "./models/mediaStatus";
|
||||
import { RepeatState } from "./models/repeatState";
|
||||
import { downloadFile } from "./scripts/download";
|
||||
import { downloadFile } from "./scripts/downloadPreload";
|
||||
import { addHotkey } from "./scripts/hotkeys";
|
||||
import { ObjectToDotNotation } from "./scripts/objectUtilities";
|
||||
import { settingsStore } from "./scripts/settings";
|
||||
@@ -54,12 +54,12 @@ const elements = {
|
||||
media: '*[data-test="current-media-imagery"]',
|
||||
image: "img",
|
||||
current: '*[data-test="current-time"]',
|
||||
duration: '*[class^=_playbackControlsContainer] *[data-test="duration"]',
|
||||
duration: '*[class^=playbackControlsContainer] *[data-test="duration"]',
|
||||
bar: '*[data-test="progress-bar"]',
|
||||
footer: "#footerPlayer",
|
||||
mediaItem: "[data-type='mediaItem']",
|
||||
album_header_title: '*[class^="_playingFrom"] span:nth-child(2)',
|
||||
playing_from: '*[class^="_playingFrom"] span:nth-child(2)',
|
||||
album_header_title: '*[class^="playingFrom"] span:nth-child(2)',
|
||||
playing_from: '*[class^="playingFrom"] span:nth-child(2)',
|
||||
queue_album: "*[class^=playQueueItemsContainer] *[class^=groupTitle] span:nth-child(2)",
|
||||
currentlyPlaying: "[class^='isPlayingIcon'], [data-test-is-playing='true']",
|
||||
album_name_cell: '[class^="album"]',
|
||||
@@ -483,7 +483,6 @@ function updateMpris(mediaInfo: MediaInfo) {
|
||||
"xesam:title": mediaInfo.title,
|
||||
"xesam:artist": [mediaInfo.artists],
|
||||
"xesam:album": mediaInfo.album,
|
||||
"xesam:url": mediaInfo.url,
|
||||
"mpris:artUrl": mediaInfo.image,
|
||||
"mpris:length": convertDuration(mediaInfo.duration) * 1000 * 1000,
|
||||
"mpris:trackid": "/org/mpris/MediaPlayer2/track/" + getTrackID(),
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import fs from "fs";
|
||||
import request from "request";
|
||||
import axios from "axios";
|
||||
|
||||
/**
|
||||
* download and save a file
|
||||
@@ -8,16 +8,20 @@ import request from "request";
|
||||
*/
|
||||
export const downloadFile = function (fileUrl: string, targetPath: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const req = request({
|
||||
method: "GET",
|
||||
uri: fileUrl,
|
||||
});
|
||||
axios
|
||||
.get(fileUrl, {
|
||||
responseType: "stream",
|
||||
})
|
||||
.then((res) => {
|
||||
const out = fs.createWriteStream(targetPath);
|
||||
|
||||
const out = fs.createWriteStream(targetPath);
|
||||
req.pipe(out);
|
||||
res.data.pipe(out);
|
||||
|
||||
req.on("end", resolve);
|
||||
out.on("finish", resolve);
|
||||
|
||||
req.on("error", reject);
|
||||
out.on("error", reject);
|
||||
|
||||
res.data.on("error", reject);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
23
src/scripts/downloadPreload.ts
Normal file
23
src/scripts/downloadPreload.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ipcRenderer } from "electron";
|
||||
import { globalEvents } from "../constants/globalEvents";
|
||||
|
||||
/**
|
||||
* download and save a file (renderer version)
|
||||
* @param {string} fileUrl url to download
|
||||
* @param {string} targetPath path to save it at
|
||||
*/
|
||||
export const downloadFile = function (fileUrl: string, targetPath: string) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
const handler = (event: Electron.IpcRendererEvent, newFileUrl: string, newTargetPath: string, error: boolean) => {
|
||||
// it's possible for 2 requests to be running at the same time, so make sure it is the right one
|
||||
// if there is 2 requests with the same fileUrl and targetPath, then it doesn't matter which one we intercept because the data is the same
|
||||
if (fileUrl === newFileUrl && targetPath === newTargetPath) {
|
||||
ipcRenderer.removeListener(globalEvents.axiosReply, handler);
|
||||
if (error) reject();
|
||||
else resolve();
|
||||
}
|
||||
}
|
||||
ipcRenderer.on(globalEvents.axiosReply, handler);
|
||||
ipcRenderer.send(globalEvents.axios, fileUrl, targetPath);
|
||||
});
|
||||
};
|
Reference in New Issue
Block a user