diff --git a/package.json b/package.json index f4ba291..ac1bc96 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ }, "devDependencies": { "@mastermindzh/prettier-config": "^1.0.0", - "electron": "git+https://github.com/castlabs/electron-releases.git#v8.5.2-wvvmp", + "electron": "git+https://github.com/castlabs/electron-releases.git#v10.4.3-wvvmp", "electron-builder": "^21.2.0", "electron-reload": "^1.5.0", "prettier": "^2.0.4", diff --git a/src/main.js b/src/main.js index 45f61f0..39e9ba9 100644 --- a/src/main.js +++ b/src/main.js @@ -44,6 +44,7 @@ function createWindow(options = {}) { preload: path.join(__dirname, "preload.js"), plugins: true, devTools: true, // I like tinkering, others might too + enableRemoteModule: true, }, }); diff --git a/src/preload.js b/src/preload.js index 10ad1be..ed1f846 100644 --- a/src/preload.js +++ b/src/preload.js @@ -12,6 +12,10 @@ const notificationPath = `${app.getPath("userData")}/notification.jpg`; let currentSong = ""; let player; let currentPlayStatus = statuses.paused; +let progressBarTime; +let currentTimeChanged = false; +let currentTime; +let currentURL = undefined; const elements = { play: '*[data-test="play"]', @@ -19,7 +23,7 @@ const elements = { next: '*[data-test="next"]', previous: 'button[data-test="previous"]', title: '*[data-test^="footer-track-title"]', - artists: '*[data-test^="grid-item-detail-text-title-artist"]', + artists: '*[class^="elemental__text elemental__text css-oxcos"]', home: '*[data-test="menu--home"]', back: '[class^="backwardButton"]', forward: '[class^="forwardButton"]', @@ -31,7 +35,9 @@ const elements = { settings: '*[data-test^="open-settings"]', media: '*[data-test="current-media-imagery"]', image: "img", - url: 'a[href*="/track/"]', + current: '*[data-test="current-time"]', + duration: '*[data-test="duration-time"]', + bar: '*[data-test="progress-bar"]', /** * Get an element from the dom @@ -238,31 +244,75 @@ function updateMediaInfo(options, notify) { } } +/** + * Checks if Tidal is playing a video or song by grabbing the "a" element from the title. + * If it's a song it sets the track URL as currentURL, If it's a video it will set currentURL to undefined. + */ +function updateURL() { + const URLelement = elements.get("title").querySelector("a"); + switch (URLelement) { + case null: + currentURL = undefined; + break; + default: + const id = URLelement.href.replace(/[^0-9]/g, ""); + currentURL = `https://tidal.com/browse/track/${id}`; + break; + } +} + /** * Watch for song changes and update title + notify */ setInterval(function () { const title = elements.getText("title"); - const url = elements.get("url").href.replace(/[^0-9]/g, ""); const artists = elements.getText("artists"); + const current = elements.getText("current"); + const duration = elements.getText("duration"); + const progressBarcurrentTime = elements.get("bar").getAttribute("aria-valuenow"); const songDashArtistTitle = `${title} - ${artists}`; const currentStatus = getCurrentlyPlayingStatus(); const options = { title, message: artists, status: currentStatus, - url: `https://tidal.com/browse/track/${url}`, + url: currentURL, + current: current, + duration: duration, }; const playStatusChanged = currentStatus !== currentPlayStatus; + const progressBarTimeChanged = progressBarcurrentTime !== progressBarTime; const titleOrArtistChanged = currentSong !== songDashArtistTitle; - if (titleOrArtistChanged || playStatusChanged) { - // update title and play info with new info + if (titleOrArtistChanged || playStatusChanged || progressBarTimeChanged || currentTimeChanged) { + // update title, url and play info with new info setTitle(songDashArtistTitle); + updateURL(); currentSong = songDashArtistTitle; currentPlayStatus = currentStatus; + // check progress bar value and make sure current stays up to date after switch + if(progressBarTime != progressBarcurrentTime && !titleOrArtistChanged) { + progressBarTime = progressBarcurrentTime; + currentTime = options.current; + options.duration = duration; + currentTimeChanged = true; + } + + if(currentTimeChanged) { + if(options.current == currentTime && currentStatus != "paused") return; + currentTime = options.current; + currentTimeChanged = false; + } + + // make sure current is set to 0 if title changes + if(titleOrArtistChanged) { + options.current = "0:00"; + currentTime = options.current; + progressBarTime = progressBarcurrentTime; + } + const image = elements.getSongIcon(); new Promise((resolve) => { diff --git a/src/scripts/discord.js b/src/scripts/discord.js index 628d821..aae5ca6 100644 --- a/src/scripts/discord.js +++ b/src/scripts/discord.js @@ -1,31 +1,55 @@ const discordrpc = require("discord-rpc"); -const { ipcMain } = require("electron"); -const electron = require("electron"); +const { app, ipcMain } = require("electron"); const globalEvents = require("../constants/globalEvents"); const clientId = "833617820704440341"; const mediaInfoModule = require("./mediaInfo"); const discordModule = []; +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) { - rpc.setActivity({ - ...idleStatus, - ...{ - details: `Listening to ${mediaInfoModule.mediaInfo.title}`, - state: mediaInfoModule.mediaInfo.artist, - buttons: [{ label: "Play on Tidal", url: mediaInfoModule.mediaInfo.url }], - }, - }); + 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.artist, + startTimestamp: parseInt(now), + endTimestamp: parseInt(remaining), + buttons: [{ label: "Play on Tidal", url: mediaInfoModule.mediaInfo.url }], + }, + }); + } else { + rpc.setActivity({ + ...idleStatus, + ...{ + details: `Watching ${mediaInfoModule.mediaInfo.title}`, + state: mediaInfoModule.mediaInfo.artist, + startTimestamp: parseInt(now), + endTimestamp: parseInt(remaining), + }, + }); + } } }; const idleStatus = { details: `Browsing Tidal`, largeImageKey: "tidal-hifi-icon", - largeImageText: `Tidal HiFi ${electron.app.getVersion()}`, + largeImageText: `Tidal HiFi ${app.getVersion()}`, instance: false, }; diff --git a/src/scripts/mediaInfo.js b/src/scripts/mediaInfo.js index e7d7f62..0964aa5 100644 --- a/src/scripts/mediaInfo.js +++ b/src/scripts/mediaInfo.js @@ -6,6 +6,8 @@ const mediaInfo = { icon: "", status: statuses.paused, url: "", + current: "", + duration: "" }; const mediaInfoModule = { mediaInfo, @@ -20,6 +22,8 @@ mediaInfoModule.update = function (arg) { 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); }; /**