Compare commits
	
		
			10 Commits
		
	
	
		
			5.0.0
			...
			bccc979f43
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| bccc979f43 | |||
| 6849952c41 | |||
| 07be74af9f | |||
| fc6adc25ca | |||
| 4498e8a73e | |||
| 3d2a9c3992 | |||
| af6bfaf55e | |||
|  | 8bac90e0f1 | ||
|  | 887c75f61a | ||
|  | cde7408cc4 | 
							
								
								
									
										15
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						| @@ -4,9 +4,24 @@ 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.1.0 | ||||
|  | ||||
| ### New features | ||||
|  | ||||
| - Added proper updates through the MediaSession API | ||||
| - You can now add custom CSS in the "advanced" settings tab | ||||
| - You can now configure the updateFrequency in the settings window | ||||
|   - Default value is set to 500 and will overwrite the hardcoded value of 100 | ||||
|  | ||||
| ### Fixes | ||||
|  | ||||
| - Any songs **including** an artist listed in the `skipped artists` setting will now be skipped even if the song is a collaboration. | ||||
| - Linux desktop icons have been fixed. See [#222](https://github.com/Mastermindzh/tidal-hifi/pull/222) for details. | ||||
|  | ||||
| ## 5.0.0 | ||||
|  | ||||
| - Replaced "muting artists" with a full implementation of an Adblock mechanism | ||||
|  | ||||
|   > Disabled audio & visual ads, unlocked lyrics, suggested track, track info, unlimited skips thanks to uBlockOrigin custom filters ([source](https://github.com/uBlockOrigin/uAssets/issues/17495)) | ||||
|  | ||||
| - @thanasistrisp updated Electron to 24.1.2 and fixed the tray bug :) | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/128x128.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/16x16.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 5.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/22x22.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/24x24.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 9.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/256x256.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 29 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.7 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/384x384.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 46 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/48x48.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/64x64.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 11 KiB | 
| @@ -9,7 +9,7 @@ snap: | ||||
|     - screen-inhibit-control | ||||
| linux: | ||||
|   category: AudioVideo | ||||
|   icon: icon.png | ||||
|   icon: assets/icons | ||||
|   target: | ||||
|     - dir | ||||
|   executableName: tidal-hifi | ||||
| @@ -18,7 +18,7 @@ linux: | ||||
|     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: icon.png | ||||
|     Icon: tidal-hifi | ||||
|     StartupNotify: true | ||||
|     Terminal: false | ||||
|     Type: Application | ||||
|   | ||||
| @@ -1,5 +1,4 @@ | ||||
| extends: ./build/electron-builder.base.yml | ||||
| linux: | ||||
|   icon: icon.png | ||||
|   target: | ||||
|     - pacman | ||||
|   | ||||
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						| @@ -1,12 +1,12 @@ | ||||
| { | ||||
|   "name": "tidal-hifi", | ||||
|   "version": "5.0.0", | ||||
|   "version": "5.1.0", | ||||
|   "lockfileVersion": 3, | ||||
|   "requires": true, | ||||
|   "packages": { | ||||
|     "": { | ||||
|       "name": "tidal-hifi", | ||||
|       "version": "5.0.0", | ||||
|       "version": "5.1.0", | ||||
|       "license": "MIT", | ||||
|       "dependencies": { | ||||
|         "@electron/remote": "^2.0.9", | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "tidal-hifi", | ||||
|   "version": "5.0.0", | ||||
|   "version": "5.1.0", | ||||
|   "description": "Tidal on Electron with widevine(hifi) support", | ||||
|   "main": "src/main.js", | ||||
|   "scripts": { | ||||
|   | ||||
| @@ -9,34 +9,36 @@ | ||||
|  *    windowBounds: { width: 800, height: 600 }, | ||||
|  */ | ||||
| const settings = { | ||||
|   notifications: "notifications", | ||||
|   api: "api", | ||||
|   menuBar: "menuBar", | ||||
|   playBackControl: "playBackControl", | ||||
|   skipArtists: "skipArtists", | ||||
|   skippedArtists: "skippedArtists", | ||||
|   adBlock: "adBlock", | ||||
|   disableBackgroundThrottle: "disableBackgroundThrottle", | ||||
|   api: "api", | ||||
|   apiSettings: { | ||||
|     root: "apiSettings", | ||||
|     port: "apiSettings.port", | ||||
|   }, | ||||
|   singleInstance: "singleInstance", | ||||
|   customCSS: "customCSS", | ||||
|   disableBackgroundThrottle: "disableBackgroundThrottle", | ||||
|   disableHardwareMediaKeys: "disableHardwareMediaKeys", | ||||
|   enableCustomHotkeys: "enableCustomHotkeys", | ||||
|   enableDiscord: "enableDiscord", | ||||
|   flags: { | ||||
|     disableHardwareMediaKeys: "flags.disableHardwareMediaKeys", | ||||
|     gpuRasterization: "flags.gpuRasterization", | ||||
|   }, | ||||
|   menuBar: "menuBar", | ||||
|   minimizeOnClose: "minimizeOnClose", | ||||
|   mpris: "mpris", | ||||
|   enableCustomHotkeys: "enableCustomHotkeys", | ||||
|   notifications: "notifications", | ||||
|   playBackControl: "playBackControl", | ||||
|   singleInstance: "singleInstance", | ||||
|   skipArtists: "skipArtists", | ||||
|   skippedArtists: "skippedArtists", | ||||
|   trayIcon: "trayIcon", | ||||
|   enableDiscord: "enableDiscord", | ||||
|   updateFrequency: "updateFrequency", | ||||
|   windowBounds: { | ||||
|     root: "windowBounds", | ||||
|     width: "windowBounds.width", | ||||
|     height: "windowBounds.height", | ||||
|   }, | ||||
|   minimizeOnClose: "minimizeOnClose", | ||||
| }; | ||||
|  | ||||
| module.exports = settings; | ||||
|   | ||||
| @@ -172,7 +172,6 @@ app.on("ready", async () => { | ||||
|     store.get(settings.trayIcon) && addTray(mainWindow, { icon }) && refreshTray(); | ||||
|     store.get(settings.api) && expressModule.run(mainWindow); | ||||
|     store.get(settings.enableDiscord) && discordModule.initRPC(); | ||||
|     // mainWindow.webContents.openDevTools(); | ||||
|   } else { | ||||
|     app.quit(); | ||||
|   } | ||||
|   | ||||
| @@ -1,20 +1,22 @@ | ||||
| let trayIcon, | ||||
|   minimizeOnClose, | ||||
|   mpris, | ||||
| let adBlock, | ||||
|   api, | ||||
|   customCSS, | ||||
|   disableBackgroundThrottle, | ||||
|   disableHardwareMediaKeys, | ||||
|   enableCustomHotkeys, | ||||
|   enableDiscord, | ||||
|   skipArtists, | ||||
|   gpuRasterization, | ||||
|   menuBar, | ||||
|   minimizeOnClose, | ||||
|   mpris, | ||||
|   notifications, | ||||
|   playBackControl, | ||||
|   api, | ||||
|   port, | ||||
|   menuBar, | ||||
|   skippedArtists, | ||||
|   adBlock, | ||||
|   disableBackgroundThrottle, | ||||
|   singleInstance, | ||||
|   disableHardwareMediaKeys, | ||||
|   gpuRasterization; | ||||
|   skipArtists, | ||||
|   skippedArtists, | ||||
|   trayIcon, | ||||
|   updateFrequency; | ||||
|  | ||||
| const { store, settings } = require("./../../scripts/settings"); | ||||
| const { ipcRenderer } = require("electron"); | ||||
| @@ -25,23 +27,25 @@ const { app } = remote; | ||||
|  * Sync the UI forms with the current settings | ||||
|  */ | ||||
| function refreshSettings() { | ||||
|   notifications.checked = store.get(settings.notifications); | ||||
|   playBackControl.checked = store.get(settings.playBackControl); | ||||
|   adBlock.checked = store.get(settings.adBlock); | ||||
|   api.checked = store.get(settings.api); | ||||
|   port.value = store.get(settings.apiSettings.port); | ||||
|   menuBar.checked = store.get(settings.menuBar); | ||||
|   trayIcon.checked = store.get(settings.trayIcon); | ||||
|   mpris.checked = store.get(settings.mpris); | ||||
|   customCSS.value = store.get(settings.customCSS); | ||||
|   disableBackgroundThrottle.checked = store.get("disableBackgroundThrottle"); | ||||
|   disableHardwareMediaKeys.checked = store.get(settings.flags.disableHardwareMediaKeys); | ||||
|   enableCustomHotkeys.checked = store.get(settings.enableCustomHotkeys); | ||||
|   enableDiscord.checked = store.get(settings.enableDiscord); | ||||
|   gpuRasterization.checked = store.get(settings.flags.gpuRasterization); | ||||
|   menuBar.checked = store.get(settings.menuBar); | ||||
|   minimizeOnClose.checked = store.get(settings.minimizeOnClose); | ||||
|   mpris.checked = store.get(settings.mpris); | ||||
|   notifications.checked = store.get(settings.notifications); | ||||
|   playBackControl.checked = store.get(settings.playBackControl); | ||||
|   port.value = store.get(settings.apiSettings.port); | ||||
|   singleInstance.checked = store.get(settings.singleInstance); | ||||
|   skipArtists.checked = store.get(settings.skipArtists); | ||||
|   skippedArtists.value = store.get(settings.skippedArtists).join("\n"); | ||||
|   adBlock.checked = store.get(settings.adBlock); | ||||
|   singleInstance.checked = store.get(settings.singleInstance); | ||||
|   disableHardwareMediaKeys.checked = store.get(settings.flags.disableHardwareMediaKeys); | ||||
|   gpuRasterization.checked = store.get(settings.flags.gpuRasterization); | ||||
|   disableBackgroundThrottle.checked = store.get("disableBackgroundThrottle"); | ||||
|   trayIcon.checked = store.get(settings.trayIcon); | ||||
|   updateFrequency.value = store.get(settings.updateFrequency); | ||||
| } | ||||
|  | ||||
| /** | ||||
| @@ -109,41 +113,45 @@ window.addEventListener("DOMContentLoaded", () => { | ||||
|     document.getElementById(tab).click(); | ||||
|   }); | ||||
|  | ||||
|   notifications = get("notifications"); | ||||
|   playBackControl = get("playBackControl"); | ||||
|   adBlock = get("adBlock"); | ||||
|   api = get("apiCheckbox"); | ||||
|   port = get("port"); | ||||
|   menuBar = get("menuBar"); | ||||
|   trayIcon = get("trayIcon"); | ||||
|   minimizeOnClose = get("minimizeOnClose"); | ||||
|   mpris = get("mprisCheckbox"); | ||||
|   customCSS = get("customCSS"); | ||||
|   disableBackgroundThrottle = get("disableBackgroundThrottle"); | ||||
|   disableHardwareMediaKeys = get("disableHardwareMediaKeys"); | ||||
|   enableCustomHotkeys = get("enableCustomHotkeys"); | ||||
|   enableDiscord = get("enableDiscord"); | ||||
|   gpuRasterization = get("gpuRasterization"); | ||||
|   menuBar = get("menuBar"); | ||||
|   minimizeOnClose = get("minimizeOnClose"); | ||||
|   mpris = get("mprisCheckbox"); | ||||
|   notifications = get("notifications"); | ||||
|   playBackControl = get("playBackControl"); | ||||
|   port = get("port"); | ||||
|   trayIcon = get("trayIcon"); | ||||
|   skipArtists = get("skipArtists"); | ||||
|   skippedArtists = get("skippedArtists"); | ||||
|   adBlock = get("adBlock"); | ||||
|   disableBackgroundThrottle = get("disableBackgroundThrottle"); | ||||
|   singleInstance = get("singleInstance"); | ||||
|   disableHardwareMediaKeys = get("disableHardwareMediaKeys"); | ||||
|   gpuRasterization = get("gpuRasterization"); | ||||
|   updateFrequency = get("updateFrequency"); | ||||
|  | ||||
|   refreshSettings(); | ||||
|  | ||||
|   addInputListener(notifications, settings.notifications); | ||||
|   addInputListener(playBackControl, settings.playBackControl); | ||||
|   addInputListener(adBlock, settings.adBlock); | ||||
|   addInputListener(api, settings.api); | ||||
|   addInputListener(port, settings.apiSettings.port); | ||||
|   addInputListener(menuBar, settings.menuBar); | ||||
|   addInputListener(trayIcon, settings.trayIcon); | ||||
|   addInputListener(mpris, settings.mpris); | ||||
|   addTextAreaListener(customCSS, settings.customCSS); | ||||
|   addInputListener(disableBackgroundThrottle, settings.disableBackgroundThrottle); | ||||
|   addInputListener(disableHardwareMediaKeys, settings.flags.disableHardwareMediaKeys); | ||||
|   addInputListener(enableCustomHotkeys, settings.enableCustomHotkeys); | ||||
|   addInputListener(enableDiscord, settings.enableDiscord); | ||||
|   addInputListener(gpuRasterization, settings.flags.gpuRasterization); | ||||
|   addInputListener(menuBar, settings.menuBar); | ||||
|   addInputListener(minimizeOnClose, settings.minimizeOnClose); | ||||
|   addInputListener(mpris, settings.mpris); | ||||
|   addInputListener(notifications, settings.notifications); | ||||
|   addInputListener(playBackControl, settings.playBackControl); | ||||
|   addInputListener(port, settings.apiSettings.port); | ||||
|   addInputListener(skipArtists, settings.skipArtists); | ||||
|   addTextAreaListener(skippedArtists, settings.skippedArtists); | ||||
|   addInputListener(adBlock, settings.adBlock); | ||||
|   addInputListener(disableBackgroundThrottle, settings.disableBackgroundThrottle); | ||||
|   addInputListener(singleInstance, settings.singleInstance); | ||||
|   addInputListener(disableHardwareMediaKeys, settings.flags.disableHardwareMediaKeys); | ||||
|   addInputListener(gpuRasterization, settings.flags.gpuRasterization); | ||||
|   addInputListener(trayIcon, settings.trayIcon); | ||||
|   addInputListener(updateFrequency, settings.updateFrequency); | ||||
| }); | ||||
|   | ||||
| @@ -160,7 +160,7 @@ | ||||
|             <div class="group__option"> | ||||
|               <div class="group__description"> | ||||
|                 <label for="port">API port</label> | ||||
|                 <input id="port" type="text" class="text-input" name="port" /> | ||||
|                 <input id="port" type="number" class="text-input" name="port" /> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="group__option"> | ||||
| @@ -212,6 +212,31 @@ | ||||
|         </section> | ||||
|  | ||||
|         <section id="advanced-section" class="tabs__section"> | ||||
|           <div class="group"> | ||||
|             <p class="group__title">Settings</p> | ||||
|             <div class="group__option"> | ||||
|               <div class="group__description"> | ||||
|                 <h4>Update frequency</h4> | ||||
|                 <p> | ||||
|                   The amount of time, in milliseconds, that tidal-hifi will refresh its playback info by scraping the | ||||
|                   website. | ||||
|                   The default of 500 seems to work in more cases but if you are fine with a bit more resource usage you | ||||
|                   can decrease it as well. | ||||
|                 </p> | ||||
|                 <input id="updateFrequency" type="number" class="text-input" name="updateFrequency" /> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="group__option"> | ||||
|               <div class="group__description"> | ||||
|                 <h4>Custom CSS</h4> | ||||
|                 <p> | ||||
|                   The css that you put in here will be injected into a style tag in the head of the document. | ||||
|                 </p> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|           <textarea id="customCSS" class="textarea" cols="40" rows="8" spellcheck="false"></textarea> | ||||
|  | ||||
|           <div class="group"> | ||||
|             <p class="group__title">Flags</p> | ||||
|             <div class="group__option"> | ||||
|   | ||||
| @@ -7,7 +7,7 @@ const { downloadFile } = require("./scripts/download"); | ||||
| const statuses = require("./constants/statuses"); | ||||
| const hotkeys = require("./scripts/hotkeys"); | ||||
| const globalEvents = require("./constants/globalEvents"); | ||||
| const { skipArtists } = require("./constants/settings"); | ||||
| const { skipArtists, updateFrequency, customCSS } = require("./constants/settings"); | ||||
| const notificationPath = `${app.getPath("userData")}/notification.jpg`; | ||||
| const appName = "Tidal Hifi"; | ||||
| let currentSong = ""; | ||||
| @@ -65,16 +65,27 @@ const elements = { | ||||
|     return ""; | ||||
|   }, | ||||
|  | ||||
|   getArtists: function () { | ||||
|   /** | ||||
|    * returns an array of all artists in the current song | ||||
|    * @returns {Array} artists | ||||
|    */ | ||||
|   getArtistsArray: function () { | ||||
|     const footer = this.get("footer"); | ||||
|  | ||||
|     if (footer) { | ||||
|       const artists = footer.querySelector(this["artists"]); | ||||
|       if (artists) { | ||||
|         return artists.innerText; | ||||
|       } | ||||
|       const artists = footer.querySelectorAll(this.artists); | ||||
|       if (artists) return Array.from(artists).map((artist) => artist.textContent); | ||||
|     } | ||||
|     return []; | ||||
|   }, | ||||
|  | ||||
|   /** | ||||
|    * unify the artists array into a string separated by commas | ||||
|    * @param {Array} artistsArray | ||||
|    * @returns {String} artists | ||||
|    */ | ||||
|   getArtistsString: function (artistsArray) { | ||||
|     if (artistsArray.length > 0) return artistsArray.join(", "); | ||||
|     return "unknown artist(s)"; | ||||
|   }, | ||||
|  | ||||
| @@ -132,6 +143,29 @@ const elements = { | ||||
|   }, | ||||
| }; | ||||
|  | ||||
| function addCustomCss() { | ||||
|   window.addEventListener("DOMContentLoaded", () => { | ||||
|     const style = document.createElement("style"); | ||||
|     style.innerHTML = store.get(customCSS); | ||||
|     document.head.appendChild(style); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Get the update frequency from the store | ||||
|  * make sure it returns a number, if not use the default | ||||
|  */ | ||||
| function getUpdateFrequency() { | ||||
|   const storeValue = store.get(updateFrequency); | ||||
|   const defaultValue = 500; | ||||
|  | ||||
|   if (!isNaN(storeValue)) { | ||||
|     return storeValue; | ||||
|   } else { | ||||
|     return defaultValue; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Play or pause the current song | ||||
|  */ | ||||
| @@ -289,14 +323,14 @@ function updateMediaInfo(options, notify) { | ||||
|   if (options) { | ||||
|     ipcRenderer.send(globalEvents.updateInfo, options); | ||||
|     if (store.get(settings.notifications) && notify) { | ||||
|       new Notification({ title: options.title, body: options.message, icon: options.icon }).show(); | ||||
|       new Notification({ title: options.title, body: options.artists, icon: options.icon }).show(); | ||||
|     } | ||||
|     if (player) { | ||||
|       player.metadata = { | ||||
|         ...player.metadata, | ||||
|         ...{ | ||||
|           "xesam:title": options.title, | ||||
|           "xesam:artist": [options.message], | ||||
|           "xesam:artist": [options.artists], | ||||
|           "xesam:album": options.album, | ||||
|           "mpris:artUrl": options.image, | ||||
|           "mpris:length": convertDuration(options.duration) * 1000 * 1000, | ||||
| @@ -327,22 +361,40 @@ function getTrackID() { | ||||
|   return window.location; | ||||
| } | ||||
|  | ||||
| function updateMediaSession(options) { | ||||
|   if ("mediaSession" in navigator) { | ||||
|     navigator.mediaSession.metadata = new MediaMetadata({ | ||||
|       title: options.title, | ||||
|       artist: options.artists, | ||||
|       album: options.album, | ||||
|       artwork: [ | ||||
|         { | ||||
|           src: options.icon, | ||||
|           sizes: "640x640", | ||||
|           type: "image/png", | ||||
|         }, | ||||
|       ], | ||||
|     }); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Watch for song changes and update title + notify | ||||
|  */ | ||||
| setInterval(function () { | ||||
|   const title = elements.getText("title"); | ||||
|   const artists = elements.getArtists(); | ||||
|   skipArtistsIfFoundInSkippedArtistsList(artists); | ||||
|   const artistsArray = elements.getArtistsArray(); | ||||
|   const artistsString = elements.getArtistsString(artistsArray); | ||||
|   skipArtistsIfFoundInSkippedArtistsList(artistsArray); | ||||
|  | ||||
|   const album = elements.getAlbumName(); | ||||
|   const current = elements.getText("current"); | ||||
|   const duration = elements.getText("duration"); | ||||
|   const songDashArtistTitle = `${title} - ${artists}`; | ||||
|   const songDashArtistTitle = `${title} - ${artistsString}`; | ||||
|   const currentStatus = getCurrentlyPlayingStatus(); | ||||
|   const options = { | ||||
|     title, | ||||
|     message: artists, | ||||
|     artists: artistsString, | ||||
|     album: album, | ||||
|     status: currentStatus, | ||||
|     url: getTrackURL(), | ||||
| @@ -351,7 +403,7 @@ setInterval(function () { | ||||
|     "app-name": appName, | ||||
|   }; | ||||
|  | ||||
|   const titleOrArtistChanged = currentSong !== songDashArtistTitle; | ||||
|   const titleOrArtistsChanged = currentSong !== songDashArtistTitle; | ||||
|  | ||||
|   // update title, url and play info with new info | ||||
|   setTitle(songDashArtistTitle); | ||||
| @@ -380,24 +432,32 @@ setInterval(function () { | ||||
|     } | ||||
|   }).then( | ||||
|     () => { | ||||
|       updateMediaInfo(options, titleOrArtistChanged); | ||||
|       updateMediaInfo(options, titleOrArtistsChanged); | ||||
|       if (titleOrArtistsChanged) { | ||||
|         updateMediaSession(options); | ||||
|       } | ||||
|     }, | ||||
|     () => {} | ||||
|   ); | ||||
|  | ||||
|   /** | ||||
|    * automatically skip a song if the artists are found in the list of artists to skip | ||||
|    * @param {*} artists list of artists to skip | ||||
|    * @param {*} artists array of artists | ||||
|    */ | ||||
|   function skipArtistsIfFoundInSkippedArtistsList(artists) { | ||||
|     if (store.get(skipArtists)) { | ||||
|       const skippedArtists = store.get(settings.skippedArtists); | ||||
|       if (skippedArtists.find((artist) => artist === artists) !== undefined) { | ||||
|       if (skippedArtists.length > 0) { | ||||
|         const artistsToSkip = skippedArtists.map((artist) => artist); | ||||
|         const artistNames = Object.values(artists).map((artist) => artist); | ||||
|         const foundArtist = artistNames.some((artist) => artistsToSkip.includes(artist)); | ||||
|         if (foundArtist) { | ||||
|           elements.click("next"); | ||||
|         } | ||||
|       } | ||||
|     } | ||||
| }, 100); | ||||
|   } | ||||
| }, getUpdateFrequency()); | ||||
|  | ||||
| if (process.platform === "linux" && store.get(settings.mpris)) { | ||||
|   try { | ||||
| @@ -454,7 +514,7 @@ if (process.platform === "linux" && store.get(settings.mpris)) { | ||||
|     console.log("player api not working"); | ||||
|   } | ||||
| } | ||||
|  | ||||
| addCustomCss(); | ||||
| addHotKeys(); | ||||
| addIPCEventListeners(); | ||||
| addFullScreenListeners(); | ||||
|   | ||||
| @@ -26,8 +26,8 @@ const observer = (event, arg) => { | ||||
|         ...idleStatus, | ||||
|         ...{ | ||||
|           details: `Listening to ${mediaInfoModule.mediaInfo.title}`, | ||||
|           state: mediaInfoModule.mediaInfo.artist | ||||
|             ? mediaInfoModule.mediaInfo.artist | ||||
|           state: mediaInfoModule.mediaInfo.artists | ||||
|             ? mediaInfoModule.mediaInfo.artists | ||||
|             : "unknown artist(s)", | ||||
|           startTimestamp: parseInt(now), | ||||
|           endTimestamp: parseInt(remaining), | ||||
| @@ -43,7 +43,7 @@ const observer = (event, arg) => { | ||||
|         ...idleStatus, | ||||
|         ...{ | ||||
|           details: `Watching ${mediaInfoModule.mediaInfo.title}`, | ||||
|           state: mediaInfoModule.mediaInfo.artist, | ||||
|           state: mediaInfoModule.mediaInfo.artists, | ||||
|           startTimestamp: parseInt(now), | ||||
|           endTimestamp: parseInt(remaining), | ||||
|         }, | ||||
|   | ||||
| @@ -11,7 +11,7 @@ let expressInstance; | ||||
| /** | ||||
|  * Function to enable tidal-hifi's express api | ||||
|  */ | ||||
| expressModule.run = function(mainWindow) { | ||||
| expressModule.run = function (mainWindow) { | ||||
|   /** | ||||
|    * Shorthand to handle a fire and forget global event | ||||
|    * @param {*} res | ||||
| @@ -24,14 +24,14 @@ expressModule.run = function(mainWindow) { | ||||
|  | ||||
|   const expressApp = express(); | ||||
|   expressApp.get("/", (req, res) => res.send("Hello World!")); | ||||
|   expressApp.get("/current", (req, res) => res.json(mediaInfo)); | ||||
|   expressApp.get("/current", (req, res) => res.json({ ...mediaInfo, artist: mediaInfo.artists })); | ||||
|   expressApp.get("/image", (req, res) => { | ||||
|     var stream = fs.createReadStream(mediaInfo.icon); | ||||
|     stream.on("open", function() { | ||||
|     stream.on("open", function () { | ||||
|       res.set("Content-Type", "image/png"); | ||||
|       stream.pipe(res); | ||||
|     }); | ||||
|     stream.on("error", function() { | ||||
|     stream.on("error", function () { | ||||
|       res.set("Content-Type", "text/plain"); | ||||
|       res.status(404).end("Not found"); | ||||
|     }); | ||||
| @@ -54,7 +54,7 @@ expressModule.run = function(mainWindow) { | ||||
|     let port = store.get(settings.apiSettings.port); | ||||
|  | ||||
|     expressInstance = expressApp.listen(port, "127.0.0.1", () => {}); | ||||
|     expressInstance.on("error", function(e) { | ||||
|     expressInstance.on("error", function (e) { | ||||
|       let message = e.code; | ||||
|       if (e.code === "EADDRINUSE") { | ||||
|         message = `Port ${port} in use.`; | ||||
|   | ||||
| @@ -2,14 +2,14 @@ const statuses = require("./../constants/statuses"); | ||||
|  | ||||
| const mediaInfo = { | ||||
|   title: "", | ||||
|   artist: "", | ||||
|   artists: "", | ||||
|   album: "", | ||||
|   icon: "", | ||||
|   status: statuses.paused, | ||||
|   url: "", | ||||
|   current: "", | ||||
|   duration: "", | ||||
|   image: "tidal-hifi-icon" | ||||
|   image: "tidal-hifi-icon", | ||||
| }; | ||||
| const mediaInfoModule = { | ||||
|   mediaInfo, | ||||
| @@ -20,7 +20,7 @@ const mediaInfoModule = { | ||||
|  */ | ||||
| mediaInfoModule.update = function (arg) { | ||||
|   mediaInfo.title = propOrDefault(arg.title); | ||||
|   mediaInfo.artist = propOrDefault(arg.message); | ||||
|   mediaInfo.artists = propOrDefault(arg.artists); | ||||
|   mediaInfo.album = propOrDefault(arg.album); | ||||
|   mediaInfo.icon = propOrDefault(arg.icon); | ||||
|   mediaInfo.url = propOrDefault(arg.url); | ||||
|   | ||||
| @@ -7,29 +7,31 @@ let settingsWindow; | ||||
|  | ||||
| const store = new Store({ | ||||
|   defaults: { | ||||
|     notifications: true, | ||||
|     api: true, | ||||
|     playBackControl: true, | ||||
|     skipArtists: false, | ||||
|     skippedArtists: [""], | ||||
|     adBlock: false, | ||||
|     disableBackgroundThrottle: true, | ||||
|     menuBar: true, | ||||
|     api: true, | ||||
|     apiSettings: { | ||||
|       port: 47836, | ||||
|     }, | ||||
|     singleInstance: true, | ||||
|     customCSS: "", | ||||
|     disableBackgroundThrottle: true, | ||||
|     disableHardwareMediaKeys: false, | ||||
|     trayIcon: true, | ||||
|     minimizeOnClose: false, | ||||
|     mpris: false, | ||||
|     enableCustomHotkeys: false, | ||||
|     enableDiscord: false, | ||||
|     windowBounds: { width: 800, height: 600 }, | ||||
|     flags: { | ||||
|       gpuRasterization: true, | ||||
|       disableHardwareMediaKeys: false, | ||||
|     }, | ||||
|     menuBar: true, | ||||
|     minimizeOnClose: false, | ||||
|     mpris: false, | ||||
|     notifications: true, | ||||
|     playBackControl: true, | ||||
|     singleInstance: true, | ||||
|     skipArtists: false, | ||||
|     skippedArtists: [""], | ||||
|     trayIcon: true, | ||||
|     updateFrequency: 500, | ||||
|     windowBounds: { width: 800, height: 600 }, | ||||
|   }, | ||||
|   migrations: { | ||||
|     "3.1.0": (migrationStore) => { | ||||
|   | ||||