From d19f5d3c041aebd10d93044dd6ba9a944033d0de Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Mon, 13 Jun 2022 15:20:32 +0100 Subject: [PATCH 001/289] Initial lastfm overhaul commit --- package.json | 1 + src/main/plugins/lfm_new.ts | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/main/plugins/lfm_new.ts diff --git a/package.json b/package.json index 5ca5c12b..fdceb0f6 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "get-port": "^5.1.1", "jimp": "^0.16.1", "jsonc": "^2.0.0", + "lastfm-autocorrect": "^1.0.0", "lastfmapi": "^0.1.1", "mdns-js": "git+https://github.com/ciderapp/node-mdns-js.git", "mpris-service": "^2.1.2", diff --git a/src/main/plugins/lfm_new.ts b/src/main/plugins/lfm_new.ts new file mode 100644 index 00000000..72d8d422 --- /dev/null +++ b/src/main/plugins/lfm_new.ts @@ -0,0 +1,53 @@ +import * as utils from '../base/utils'; +import {app} from 'electron'; +// @ts-ignore +import LastfmAPI from 'lastfmapi'; + +// https://github.com/maxkueng/node-lastfmapi +// https://github.com/maxkueng/lastfm-autocorrect + +export default class lfm_new { + + /** + * Base Plugin Information + */ + public name: string = 'LastFM Plugin for Cider'; + public version: string = '2.0.0'; + public author: string = 'Core (Cider Collective)'; + + /** + * Private variables for interaction in plugins + */ + private _attributes: any; + private _apiCredentials = { + key: "f9986d12aab5a0fe66193c559435ede3", + secret: "acba3c29bd5973efa38cc2f0b63cc625" + } + + /** + * Plugin Initialization + */ + private _client: any = null; + private _lastfm: any = null; + private _activityCache: any = { + details: '', + state: '', + largeImageKey: '', + largeImageText: '', + smallImageKey: '', + smallImageText: '', + instance: false + }; + + constructor() { + } + + /** + * Private Methods + */ + private initializeLastFM(clientSession: string): void { + + } + + +} \ No newline at end of file From f9becc61aea9d3e23d347f3131a5a872d2752587 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Mon, 13 Jun 2022 15:26:47 +0100 Subject: [PATCH 002/289] just adding todo for later --- src/main/plugins/lfm_new.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/plugins/lfm_new.ts b/src/main/plugins/lfm_new.ts index 72d8d422..2165d937 100644 --- a/src/main/plugins/lfm_new.ts +++ b/src/main/plugins/lfm_new.ts @@ -5,6 +5,9 @@ import LastfmAPI from 'lastfmapi'; // https://github.com/maxkueng/node-lastfmapi // https://github.com/maxkueng/lastfm-autocorrect +// @todo: add autocorrect +// @todo: add scrobble and filter to prevent no-title-found being scrobbled +// @todo: handle session keys through config to stop aids session.json export default class lfm_new { From c8c437449e7583d5a477c86c855bcbd48a703431 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Tue, 14 Jun 2022 12:40:49 +0100 Subject: [PATCH 003/289] yh --- {src/main/plugins => resources}/lastfm.ts | 0 src/main/base/app.ts | 12 ++-- src/main/base/store.ts | 8 ++- src/main/base/utils.ts | 7 +++ src/main/plugins/lfm_new.ts | 68 ++++++++++++++++++++--- 5 files changed, 78 insertions(+), 17 deletions(-) rename {src/main/plugins => resources}/lastfm.ts (100%) diff --git a/src/main/plugins/lastfm.ts b/resources/lastfm.ts similarity index 100% rename from src/main/plugins/lastfm.ts rename to resources/lastfm.ts diff --git a/src/main/base/app.ts b/src/main/base/app.ts index 58ccda47..2799eb9f 100644 --- a/src/main/base/app.ts +++ b/src/main/base/app.ts @@ -162,13 +162,13 @@ export class AppEvents { // LastFM Auth URL if (arg.includes('auth')) { - let authURI = arg.split('/auth/')[1] + const authURI = arg.split('/auth/')[1] if (authURI.startsWith('lastfm')) { // If we wanted more auth options - const authKey = authURI.split('lastfm?token=')[1]; - utils.setStoreValue('lastfm.enabled', true); - utils.setStoreValue('lastfm.auth_token', authKey); - utils.getWindow().webContents.send('LastfmAuthenticated', authKey); - this.plugin.callPlugin('lastfm', 'authenticate', authKey); + // const authKey = authURI.split('lastfm?token=')[1]; + // utils.setStoreValue('lastfm.enabled', true); + // utils.setStoreValue('lastfm.auth_token', authKey); + // utils.getWindow().webContents.send('LastfmAuthenticated', authKey); + this.plugin.callPlugin('lastfm', 'authenticateUser', authURI.split('lastfm?token=')[1]); } } // Play diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 8cbcd2c4..53f3a42a 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -222,10 +222,14 @@ export class Store { "lastfm": { "enabled": false, "scrobble_after": 30, - "auth_token": "", "enabledRemoveFeaturingArtists": true, "filterLoop": true, - "NowPlaying": "true" + "NowPlaying": "true", + "secrets": { + "auth_token": "", + "session": {}, + } + }, "advanced": { "AudioContext": false, diff --git a/src/main/base/utils.ts b/src/main/base/utils.ts index 41e0ae12..035553d7 100644 --- a/src/main/base/utils.ts +++ b/src/main/base/utils.ts @@ -43,6 +43,13 @@ export class utils { return app; } + /** + * Get the IPCMain + */ + static getIPCMain(): Electron.IpcMain { + return ipcMain + } + /** * Fetches the i18n locale for the given language. * @param language {string} The language to fetch the locale for. diff --git a/src/main/plugins/lfm_new.ts b/src/main/plugins/lfm_new.ts index 2165d937..8bcbba88 100644 --- a/src/main/plugins/lfm_new.ts +++ b/src/main/plugins/lfm_new.ts @@ -1,7 +1,4 @@ -import * as utils from '../base/utils'; import {app} from 'electron'; -// @ts-ignore -import LastfmAPI from 'lastfmapi'; // https://github.com/maxkueng/node-lastfmapi // https://github.com/maxkueng/lastfm-autocorrect @@ -30,8 +27,9 @@ export default class lfm_new { /** * Plugin Initialization */ - private _client: any = null; - private _lastfm: any = null; + private _lfm: any = null; + private _authenticated: boolean = false; + private _utils: any = null; private _activityCache: any = { details: '', state: '', @@ -42,15 +40,67 @@ export default class lfm_new { instance: false }; - constructor() { + /** + * Initialize LastFM + * @param token + * @param api + * @private + */ + private initializeLastFM(token: string, api: {key: string, secret: string}): void { + const LastfmAPI = require("lastfmapi") + this._lfm = new LastfmAPI({ + 'api_key' : api.key, + 'secret' : api.secret, + }); + + if (this._utils.getStoreValue("lastfm.secrets.session")) { + this._lfm.setSessionCredentials(this._utils.getStoreValue("lastfm.secrets.session")); + this._authenticated = true; + } else { + this.authenticateLastFM(token) + } } /** - * Private Methods + * Authenticate the user with the given token + * @param token + * @private */ - private initializeLastFM(clientSession: string): void { - + private authenticateLastFM(token: string): void { + if (!token) return; + this._lfm.authenticate(token, (err: any, session: any) => { + if (err) { console.error(err); return; } + console.log(session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} + this._utils.setStoreValue('lastfm.secrets.session', session); + this._authenticated = true; + }); + } + + /** + * Public Methods + */ + public authenticateUser(token: string): void { + this.initializeLastFM(token, this._apiCredentials) + } + + constructor(utils: any) { + this._utils = utils; + this.authenticateUser("") + } + + public onReady(win: Electron.BrowserWindow): void { + + this._utils.getIPCMain().handle('lfm_new:url', (event: any) => { + console.debug('lfm_new:url', event) + return this._lfm.getAuthenticationUrl({"cb": "cider://auth/lastfm"}) + }) + + this._utils.getIPCMain().on('lfm_new:auth', (event: any, token: string) => { + console.debug('lfm_new:auth', event, token) + this.authenticateUser(token) + }) } + } \ No newline at end of file From d4c8d9001aa527385a091edf9992c90e18b6b422 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:23:13 +0100 Subject: [PATCH 004/289] no more mk lookup :) --- package.json | 1 - src/main/base/app.ts | 7 +- src/main/base/plugins.ts | 3 +- src/main/base/store.ts | 8 +- src/main/plugins/lastfm.ts | 216 ++++++++++++++++++++++++++ src/main/plugins/lfm_new.ts | 106 ------------- src/renderer/main/vueapp.js | 31 ---- src/renderer/views/pages/settings.ejs | 60 ++++--- 8 files changed, 250 insertions(+), 182 deletions(-) create mode 100644 src/main/plugins/lastfm.ts delete mode 100644 src/main/plugins/lfm_new.ts diff --git a/package.json b/package.json index fdceb0f6..5ca5c12b 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "get-port": "^5.1.1", "jimp": "^0.16.1", "jsonc": "^2.0.0", - "lastfm-autocorrect": "^1.0.0", "lastfmapi": "^0.1.1", "mdns-js": "git+https://github.com/ciderapp/node-mdns-js.git", "mpris-service": "^2.1.2", diff --git a/src/main/base/app.ts b/src/main/base/app.ts index 2799eb9f..24dd1e4f 100644 --- a/src/main/base/app.ts +++ b/src/main/base/app.ts @@ -164,11 +164,8 @@ export class AppEvents { if (arg.includes('auth')) { const authURI = arg.split('/auth/')[1] if (authURI.startsWith('lastfm')) { // If we wanted more auth options - // const authKey = authURI.split('lastfm?token=')[1]; - // utils.setStoreValue('lastfm.enabled', true); - // utils.setStoreValue('lastfm.auth_token', authKey); - // utils.getWindow().webContents.send('LastfmAuthenticated', authKey); - this.plugin.callPlugin('lastfm', 'authenticateUser', authURI.split('lastfm?token=')[1]); + console.log('token: ', authURI.split('lastfm?token=')[1]) + utils.getWindow().webContents.executeJavaScript(`ipcRenderer.send('lastfm:auth', "${authURI.split('lastfm?token=')[1]}")`).catch(console.error) } } // Play diff --git a/src/main/base/plugins.ts b/src/main/base/plugins.ts index d51e8a85..24402278 100644 --- a/src/main/base/plugins.ts +++ b/src/main/base/plugins.ts @@ -107,7 +107,8 @@ export class Plugins { try{ this.pluginsList[plugin][event](...args); }catch(e) { - console.log(`[${plugin}] Plugin error: ${e}`); + console.error(`[${plugin}] An error was encountered: ${e}`); + console.error(e) } } } diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 53f3a42a..76b96a43 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -222,12 +222,10 @@ export class Store { "lastfm": { "enabled": false, "scrobble_after": 30, - "enabledRemoveFeaturingArtists": true, - "filterLoop": true, - "NowPlaying": "true", "secrets": { - "auth_token": "", - "session": {}, + "username": "", + "key": "", + "token": "" } }, diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts new file mode 100644 index 00000000..5c3c9767 --- /dev/null +++ b/src/main/plugins/lastfm.ts @@ -0,0 +1,216 @@ +// https://github.com/maxkueng/node-lastfmapi +// https://github.com/maxkueng/lastfm-autocorrect +// @todo: add autocorrect +// @todo: add scrobble and filter to prevent no-title-found being scrobbled +// @todo: handle session keys through config to stop aids session.json + +export default class lastfm { + + /** + * Base Plugin Information + */ + public name: string = 'LastFM Plugin for Cider'; + public version: string = '2.0.0'; + public author: string = 'Core (Cider Collective)'; + + /** + * Private variables for interaction in plugins + */ + private _attributes: any; + private _apiCredentials = { + key: "f9986d12aab5a0fe66193c559435ede3", + secret: "acba3c29bd5973efa38cc2f0b63cc625" + } + /** + * Plugin Initialization + */ + private _lfm: any = null; + private _authenticated: boolean = false; + private _utils: any = null; + private _activityCache: any = { + details: '', + state: '', + largeImageKey: '', + largeImageText: '', + smallImageKey: '', + smallImageText: '', + instance: false + }; + + + /** + * Public Methods + */ + + constructor(utils: any) { + this._utils = utils; + this.initializeLastFM("", this._apiCredentials) + } + + onReady(win: Electron.BrowserWindow): void { + + // Register the ipcMain handlers + this._utils.getIPCMain().handle('lastfm:url', (event: any) => { + // console.debug('lastfm:url', event) + return this._lfm.getAuthenticationUrl({"cb": "cider://auth/lastfm"}) + }) + + this._utils.getIPCMain().on('lastfm:auth', (event: any, token: string) => { + // console.debug('lastfm:auth', event, token) + this.authenticateLastFM(token) + }) + } + + /** + * Runs on playback State Change + * @param attributes Music Attributes (attributes.status = current state) + */ + onPlaybackStateDidChange(attributes: object): void { + this._attributes = attributes + // this.scrobbleTrack(attributes) + } + + /** + * Runs on song change + * @param attributes Music Attributes + */ + onNowPlayingItemDidChange(attributes: object): void { + this._attributes = attributes + this.scrobbleTrack(attributes) + } + + /** + * Initialize LastFM + * @param token + * @param api + * @private + */ + private initializeLastFM(token: string, api: { key: string, secret: string }): void { + const LastfmAPI = require("lastfmapi") + this._lfm = new LastfmAPI({ + 'api_key': api.key, + 'secret': api.secret, + }); + + if (this._utils.getStoreValue("lastfm.secrets.username") && this._utils.getStoreValue("lastfm.secrets.key")) { + this._lfm.setSessionCredentials(this._utils.getStoreValue("lastfm.secrets.session.username"), this._utils.getStoreValue("lastfm.secrets.session.key")); + this._authenticated = true; + } else { + this.authenticateLastFM(token) + } + } + + /** + * Authenticate the user with the given token + * @param token + * @private + */ + private authenticateLastFM(token: string): void { + if (!token) return; + this._lfm.authenticate(token, (err: any, session: any) => { + if (err) { + console.error(err); + return; + } + console.log(session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} + this._utils.setStoreValue("lastfm.secrets.token", token) + this._utils.setStoreValue('lastfm.secrets.username', session.username); + this._utils.setStoreValue('lastfm.secrets.key', session.key); + this._authenticated = true; + }); + } + + /** + * Verifies the track information with lastfm + * @param attributes + * @private + */ + private verifyTrack(attributes: any): object { + if (!attributes) return {}; + + if (!attributes.lfmAlbum) { + return this._lfm.album.getInfo({ + "artist": attributes.artistName, + "album": attributes.albumName + }, (err: any, data: any) => { + if (err) { + console.error(`[${lastfm.name}] [album.getInfo] Error: ${err}`) + return {}; + } + if (data) { + attributes.lfmAlbum = data + } + this.scrobbleTrack(attributes) + }) + } else { + return this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => { + if (err) { + console.error(`[${lastfm.name}] [track.getCorrection] Error: ${err}`) + console.error(err) + return {}; + } + if (data) { + attributes.lfmTrack = data.correction.track + } + this.scrobbleTrack(attributes) + }) + } + + + } + + /** + * Scrobbles the track to lastfm + * @param attributes + * @private + */ + private scrobbleTrack(attributes: any): void { + if (!attributes?.lfmTrack || !attributes?.lfmAlbum) { + this.verifyTrack(attributes) + return + } + + if (!this._authenticated || !attributes) return; + // Scrobble + + const scrobble = { + 'artist': attributes.lfmTrack.artist.name, + 'track': attributes.lfmTrack.name, + 'album': attributes.lfmAlbum.name, + 'albumArtist': attributes.lfmAlbum.artist, + 'timestamp': new Date().getTime() / 1000, + 'trackNumber': attributes.trackNumber, + 'duration': attributes.durationInMillis / 1000, + } + if (!this._utils.getApp().isPackaged) { + console.debug(scrobble) + } + this._lfm.track.scrobble(scrobble, (err: any, res: any) => { + if (err) { + console.error(`[${lastfm.name}] [lastfm:scrobble] Scrobble failed: ${err.message}`); + } else { + console.debug(`[${lastfm.name}] [lastfm:scrobble] Track scrobbled: ${res}`); + } + }); + this._activityCache = attributes + } + + private updateNowPlaying(attributes: any): void { + if (!this._authenticated) return; + this._lfm.track.updateNowPlaying({ + 'artist': attributes.artistName, + 'track': attributes.name, + 'album': attributes.albumName, + 'albumArtist': attributes.albumName, + 'trackNumber': attributes.trackNumber, + 'duration': attributes.duration / 1000, + }, function (err: any, scrobbled: any) { + if (err) { + return console.error('[LastFM] An error occurred while updating now playing', err); + } + + console.log('[LastFM] Successfully updated now playing: ', scrobbled); + }); + } + +} \ No newline at end of file diff --git a/src/main/plugins/lfm_new.ts b/src/main/plugins/lfm_new.ts deleted file mode 100644 index 8bcbba88..00000000 --- a/src/main/plugins/lfm_new.ts +++ /dev/null @@ -1,106 +0,0 @@ -import {app} from 'electron'; - -// https://github.com/maxkueng/node-lastfmapi -// https://github.com/maxkueng/lastfm-autocorrect -// @todo: add autocorrect -// @todo: add scrobble and filter to prevent no-title-found being scrobbled -// @todo: handle session keys through config to stop aids session.json - -export default class lfm_new { - - /** - * Base Plugin Information - */ - public name: string = 'LastFM Plugin for Cider'; - public version: string = '2.0.0'; - public author: string = 'Core (Cider Collective)'; - - /** - * Private variables for interaction in plugins - */ - private _attributes: any; - private _apiCredentials = { - key: "f9986d12aab5a0fe66193c559435ede3", - secret: "acba3c29bd5973efa38cc2f0b63cc625" - } - - /** - * Plugin Initialization - */ - private _lfm: any = null; - private _authenticated: boolean = false; - private _utils: any = null; - private _activityCache: any = { - details: '', - state: '', - largeImageKey: '', - largeImageText: '', - smallImageKey: '', - smallImageText: '', - instance: false - }; - - /** - * Initialize LastFM - * @param token - * @param api - * @private - */ - private initializeLastFM(token: string, api: {key: string, secret: string}): void { - const LastfmAPI = require("lastfmapi") - this._lfm = new LastfmAPI({ - 'api_key' : api.key, - 'secret' : api.secret, - }); - - if (this._utils.getStoreValue("lastfm.secrets.session")) { - this._lfm.setSessionCredentials(this._utils.getStoreValue("lastfm.secrets.session")); - this._authenticated = true; - } else { - this.authenticateLastFM(token) - } - } - - /** - * Authenticate the user with the given token - * @param token - * @private - */ - private authenticateLastFM(token: string): void { - if (!token) return; - this._lfm.authenticate(token, (err: any, session: any) => { - if (err) { console.error(err); return; } - console.log(session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} - this._utils.setStoreValue('lastfm.secrets.session', session); - this._authenticated = true; - }); - } - - /** - * Public Methods - */ - public authenticateUser(token: string): void { - this.initializeLastFM(token, this._apiCredentials) - } - - constructor(utils: any) { - this._utils = utils; - this.authenticateUser("") - } - - public onReady(win: Electron.BrowserWindow): void { - - this._utils.getIPCMain().handle('lfm_new:url', (event: any) => { - console.debug('lfm_new:url', event) - return this._lfm.getAuthenticationUrl({"cb": "cider://auth/lastfm"}) - }) - - this._utils.getIPCMain().on('lfm_new:auth', (event: any, token: string) => { - console.debug('lfm_new:auth', event, token) - this.authenticateUser(token) - }) - } - - - -} \ No newline at end of file diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 94a39304..58f54f25 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -4339,37 +4339,6 @@ const app = new Vue({ } }, - LastFMDeauthorize() { - ipcRenderer.invoke('setStoreValue', 'lastfm.enabled', false).catch((e) => console.error(e)); - ipcRenderer.invoke('setStoreValue', 'lastfm.auth_token', '').catch((e) => console.error(e)); - app.cfg.lastfm.auth_token = ""; - app.cfg.lastfm.enabled = false; - const element = document.getElementById('lfmConnect'); - element.innerHTML = app.getLz('term.connect'); - element.onclick = app.LastFMAuthenticate; - }, - LastFMAuthenticate() { - console.log("[LastFM] Received LastFM authentication callback") - const element = document.getElementById('lfmConnect'); - // new key : f9986d12aab5a0fe66193c559435ede3 - window.open('https://www.last.fm/api/auth?api_key=f9986d12aab5a0fe66193c559435ede3&cb=cider://auth/lastfm'); - element.innerText = app.getLz('term.connecting') + '...'; - - /* Just a timeout for the button */ - setTimeout(() => { - if (element.innerText === app.getLz('term.connecting') + '...') { - element.innerText = app.getLz('term.connect'); - console.warn('[LastFM] Attempted connection timed out.'); - } - }, 20000); - - ipcRenderer.on('LastfmAuthenticated', function (_event, lfmAuthKey) { - app.cfg.lastfm.auth_token = lfmAuthKey; - app.cfg.lastfm.enabled = true; - element.innerHTML = `${app.getLz('term.disconnect')}\n

(${app.getLz('term.authed')}: ${lfmAuthKey})

`; - element.onclick = app.LastFMDeauthorize; - }); - }, fullscreen(flag) { this.fullscreenState = flag; if (flag) { diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 30774200..1cca7314 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1064,7 +1064,7 @@
@@ -1079,37 +1079,6 @@ -
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.nowPlaying')}} -
-
- -
-
-
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.removeFeatured')}} -
-
- -
-
-
-
- {{$root.getLz('settings.option.connectivity.lastfmScrobble.filterLoop')}} -
-
- -
-
@@ -1504,7 +1473,32 @@ }, reloadDiscordRPC() { ipcRenderer.send('reloadRPC') - } + }, + lfmDisconnect(event) { + ipcRenderer.invoke('setStoreValue', 'lastfm.enabled', false).catch((e) => console.error(e)); + ipcRenderer.invoke('setStoreValue', 'lastfm.secrets.session', {}).catch((e) => console.error(e)); + event.target.innerHTML = app.getLz('term.connect'); + event.target.onclick = this.lfmAuthorize; + }, + async lfmAuthorize(event) { + console.debug("[lastfm:authorize] Token received.") + window.open(await ipcRenderer.invoke('lastfm:url')); + event.target.innerText = app.getLz('term.connecting') + '...'; + + /* Just a timeout for the button */ + setTimeout(() => { + if (event.target.innerText === app.getLz('term.connecting') + '...') { + event.target.innerText = app.getLz('term.connect'); + console.warn('[lastfm:authorize] Last.fm authorization timed out.'); + } + }, 20000); + + ipcRenderer.on('lastfm:renderer-auth', function (event, session) { + element.innerHTML = `${app.getLz('term.disconnect')}\n

(${app.getLz('term.authed')}: ${session.username})

`; + element.onclick = this.lfmDisconnect; + }); + + }, } }) \ No newline at end of file From 5c955820dd007b74d04c831b33169241e50c4190 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:28:18 +0100 Subject: [PATCH 005/289] also no more session.json --- src/main/plugins/lastfm.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index 5c3c9767..902671e7 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -93,7 +93,7 @@ export default class lastfm { }); if (this._utils.getStoreValue("lastfm.secrets.username") && this._utils.getStoreValue("lastfm.secrets.key")) { - this._lfm.setSessionCredentials(this._utils.getStoreValue("lastfm.secrets.session.username"), this._utils.getStoreValue("lastfm.secrets.session.key")); + this._lfm.setSessionCredentials(this._utils.getStoreValue("lastfm.secrets.username"), this._utils.getStoreValue("lastfm.secrets.key")); this._authenticated = true; } else { this.authenticateLastFM(token) @@ -112,7 +112,6 @@ export default class lastfm { console.error(err); return; } - console.log(session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} this._utils.setStoreValue("lastfm.secrets.token", token) this._utils.setStoreValue('lastfm.secrets.username', session.username); this._utils.setStoreValue('lastfm.secrets.key', session.key); From f98a82240b23228639fc588fd4c60af084e6240f Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 21:22:04 +0100 Subject: [PATCH 006/289] Now Playing Working Commented some annoying mpris debugs --- src/main/base/store.ts | 2 +- src/main/plugins/lastfm.ts | 102 ++++++++++++++++++++----------------- src/main/plugins/mpris.ts | 6 +-- 3 files changed, 60 insertions(+), 50 deletions(-) diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 76b96a43..56b0743f 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -221,7 +221,7 @@ export class Store { }, "lastfm": { "enabled": false, - "scrobble_after": 30, + "scrobble_after": 50, "secrets": { "username": "", "key": "", diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index 902671e7..c49b0b2d 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -26,17 +26,10 @@ export default class lastfm { */ private _lfm: any = null; private _authenticated: boolean = false; + private _scrobbleDelay: any = null; private _utils: any = null; - private _activityCache: any = { - details: '', - state: '', - largeImageKey: '', - largeImageText: '', - smallImageKey: '', - smallImageText: '', - instance: false - }; - + private _scrobbleCache: any = {}; + private _nowPlayingCache: any = {}; /** * Public Methods @@ -74,9 +67,14 @@ export default class lastfm { * Runs on song change * @param attributes Music Attributes */ - onNowPlayingItemDidChange(attributes: object): void { + onNowPlayingItemDidChange(attributes: any): void { this._attributes = attributes + if (!attributes?.lfmTrack || !attributes?.lfmAlbum) { + this.verifyTrack(attributes) + return + } this.scrobbleTrack(attributes) + this.updateNowPlayingTrack(attributes) } /** @@ -139,7 +137,7 @@ export default class lastfm { if (data) { attributes.lfmAlbum = data } - this.scrobbleTrack(attributes) + this.onNowPlayingItemDidChange(attributes) }) } else { return this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => { @@ -151,7 +149,7 @@ export default class lastfm { if (data) { attributes.lfmTrack = data.correction.track } - this.scrobbleTrack(attributes) + this.onNowPlayingItemDidChange(attributes) }) } @@ -164,52 +162,64 @@ export default class lastfm { * @private */ private scrobbleTrack(attributes: any): void { - if (!attributes?.lfmTrack || !attributes?.lfmAlbum) { - this.verifyTrack(attributes) - return + if (!this._authenticated || !attributes || (this._scrobbleCache.track === attributes.lfmTrack.name)) return; + + if (this._scrobbleDelay) { + clearTimeout(this._scrobbleDelay); } - if (!this._authenticated || !attributes) return; - // Scrobble + // Scrobble delay + this._scrobbleDelay = setTimeout(() => { - const scrobble = { + // Scrobble + const scrobble = { + 'artist': attributes.lfmTrack.artist.name, + 'track': attributes.lfmTrack.name, + 'album': attributes.lfmAlbum.name, + 'albumArtist': attributes.lfmAlbum.artist, + 'timestamp': new Date().getTime() / 1000, + 'trackNumber': attributes.trackNumber, + 'duration': attributes.durationInMillis / 1000, + } + + // Easy Debugging + if (!this._utils.getApp().isPackaged) { + console.debug(scrobble) + } + + // Scrobble the track + this._lfm.track.scrobble(scrobble, (err: any, _res: any) => { + if (err) { + console.error(`[${lastfm.name}] [lastfm:scrobble] Scrobble failed: ${err.message}`); + } else { + console.debug(`[${lastfm.name}] [lastfm:scrobble] Track scrobbled: ${scrobble.artist} - ${scrobble.track}`); + this._scrobbleCache = scrobble + } + }); + }, Math.round(attributes.durationInMillis * Math.min((this._utils.getStoreValue("lastfm.scrobble_after") / 100), 0.8))) + } + + private updateNowPlayingTrack(attributes: any): void { + if (!this._authenticated || !attributes || (this._nowPlayingCache.track === attributes.lfmTrack.name)) return; + + const nowPlaying = { 'artist': attributes.lfmTrack.artist.name, 'track': attributes.lfmTrack.name, 'album': attributes.lfmAlbum.name, - 'albumArtist': attributes.lfmAlbum.artist, - 'timestamp': new Date().getTime() / 1000, 'trackNumber': attributes.trackNumber, 'duration': attributes.durationInMillis / 1000, + 'albumArtist': attributes.lfmAlbum.artist, } - if (!this._utils.getApp().isPackaged) { - console.debug(scrobble) - } - this._lfm.track.scrobble(scrobble, (err: any, res: any) => { + + this._lfm.track.updateNowPlaying(nowPlaying, (err: any, res: any) => { if (err) { - console.error(`[${lastfm.name}] [lastfm:scrobble] Scrobble failed: ${err.message}`); + console.error(`[${lastfm.name}] [lastfm:updateNowPlaying] Now Playing Update failed: ${err.message}`); } else { - console.debug(`[${lastfm.name}] [lastfm:scrobble] Track scrobbled: ${res}`); + console.log(res) + console.debug(`[${lastfm.name}] [lastfm:updateNowPlaying] Now Playing Updated: ${nowPlaying.artist} - ${nowPlaying.track}`); + this._nowPlayingCache = nowPlaying } }); - this._activityCache = attributes - } - - private updateNowPlaying(attributes: any): void { - if (!this._authenticated) return; - this._lfm.track.updateNowPlaying({ - 'artist': attributes.artistName, - 'track': attributes.name, - 'album': attributes.albumName, - 'albumArtist': attributes.albumName, - 'trackNumber': attributes.trackNumber, - 'duration': attributes.duration / 1000, - }, function (err: any, scrobbled: any) { - if (err) { - return console.error('[LastFM] An error occurred while updating now playing', err); - } - - console.log('[LastFM] Successfully updated now playing: ', scrobbled); - }); } } \ No newline at end of file diff --git a/src/main/plugins/mpris.ts b/src/main/plugins/mpris.ts index 25730ee9..6b70c5c8 100644 --- a/src/main/plugins/mpris.ts +++ b/src/main/plugins/mpris.ts @@ -37,7 +37,7 @@ export default class mpris { * @private */ private static runMediaEvent(type: string) { - console.debug(`[Plugin][${this.name}] ${type}.`); + // console.debug(`[Plugin][${this.name}] ${type}.`); mpris.utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.${type}()`).catch(console.error) } @@ -188,7 +188,7 @@ export default class mpris { */ @mpris.linuxOnly onPlaybackStateDidChange(attributes: object): void { - console.debug(`[Plugin][${mpris.name}] onPlaybackStateDidChange.`); + // console.debug(`[Plugin][${mpris.name}] onPlaybackStateDidChange.`); mpris.updatePlayerState(attributes) } @@ -198,7 +198,7 @@ export default class mpris { */ @mpris.linuxOnly onNowPlayingItemDidChange(attributes: object): void { - console.debug(`[Plugin][${mpris.name}] onMetadataDidChange.`); + // console.debug(`[Plugin][${mpris.name}] onMetadataDidChange.`); mpris.updatePlayer(attributes); } From 47e3ad5b446a8af3f0d04b574581cecd358c79d6 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 21:33:32 +0100 Subject: [PATCH 007/289] removed redundant code --- src/preload/cider-preload.js | 49 +++++++----------------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index 44ba7589..3923fbd3 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -11,9 +11,6 @@ const MusicKitInterop = { if (MusicKitInterop.filterTrack(attributes, true, false)) { global.ipcRenderer.send('playbackStateDidChange', attributes) global.ipcRenderer.send('wsapi-updatePlaybackState', attributes); - // if (typeof _plugins != "undefined") { - // _plugins.execute("OnPlaybackStateChanged", {Attributes: MusicKitInterop.getAttributes()}) - // } } }); @@ -24,7 +21,7 @@ const MusicKitInterop = { /** wsapi */ MusicKit.getInstance().addEventListener(MusicKit.Events.nowPlayingItemDidChange, async () => { - console.debug('nowPlayingItemDidChange') + console.debug('[cider:preload] nowPlayingItemDidChange') const attributes = MusicKitInterop.getAttributes() const trackFilter = MusicKitInterop.filterTrack(attributes, false, true) @@ -32,12 +29,6 @@ const MusicKitInterop = { global.ipcRenderer.send('nowPlayingItemDidChange', attributes); } - // LastFM's Custom Call - await MusicKitInterop.modifyNamesOnLocale(); - if (trackFilter || !app.cfg.lastfm.filterLoop) { - global.ipcRenderer.send('nowPlayingItemDidChangeLastFM', attributes); - } - if (MusicKit.getInstance().nowPlayingItem) { await this.sleep(750); MusicKit.getInstance().playbackRate = app.cfg.audio.playbackRate; @@ -49,38 +40,16 @@ const MusicKitInterop = { }) MusicKit.getInstance().addEventListener(MusicKit.Events.mediaPlaybackError, (e) => { - console.warn(`[mediaPlaybackError] ${e}`); + console.warn(`[cider:preload] mediaPlaybackError] ${e}`); }) }, sleep(ms) { return new Promise((resolve) => { - setTimeout(resolve, ms); + setTimeout(resolve, ms); }); }, - async modifyNamesOnLocale() { - if (app.mklang === '' || app.mklang == null) { - return; - } - const mk = MusicKit.getInstance() - const nowPlayingItem = mk.nowPlayingItem; - if ((nowPlayingItem?._songId ?? nowPlayingItem?.songId) == null){ - return; - } - const id = nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? nowPlayingItem?.id) - if (id != null && id !== -1) { - try{ - const query = await mk.api.v3.music(`/v1${(((nowPlayingItem?._songId ?? nowPlayingItem?.songId) != null) && ((nowPlayingItem?._songId ?? nowPlayingItem?.songId) !== -1)) ? `/catalog/${mk.storefrontId}/` : `/me/library/`}songs/${id}?l=${app.mklang}`); - if (query?.data?.data[0]){ - let attrs = query?.data?.data[0]?.attributes; - if (attrs?.name) { nowPlayingItem.attributes.name = attrs?.name ?? ''} - if (attrs?.albumName) { nowPlayingItem.attributes.albumName = attrs?.albumName ?? ''} - if (attrs?.artistName) { nowPlayingItem.attributes.artistName = attrs?.artistName ?? ''} - - }} catch (e) { } - } else {} - }, getAttributes: function () { const mk = MusicKit.getInstance() const nowPlayingItem = mk.nowPlayingItem; @@ -96,8 +65,8 @@ const MusicKitInterop = { attributes.playParams = attributes?.playParams ?? {id: 'no-id-found'}; attributes.playParams.id = attributes?.playParams?.id ?? 'no-id-found'; attributes.url = { - cider: `https://cider.sh/link?play/s/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ??'no-id-found')}`, - appleMusic: attributes.websiteUrl ? attributes.websiteUrl : `https://music.apple.com/${mk.storefrontId}/song/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ??'no-id-found')}` + cider: `https://cider.sh/link?play/s/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? 'no-id-found')}`, + appleMusic: attributes.websiteUrl ? attributes.websiteUrl : `https://music.apple.com/${mk.storefrontId}/song/${nowPlayingItem?._songId ?? (nowPlayingItem?.songId ?? 'no-id-found')}` } if (attributes.playParams.id === 'no-id-found') { attributes.playParams.id = nowPlayingItem?.id ?? 'no-id-found'; @@ -115,7 +84,7 @@ const MusicKitInterop = { attributes?.playParams?.id === cache.playParams.id ? Date.now() + attributes?.remainingTime : attributes?.startTime + attributes?.durationInMillis - ); + ); return attributes; }, @@ -156,19 +125,19 @@ const MusicKitInterop = { // } catch (e) { } // if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) // MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex); - MusicKit.getInstance().skipToNextItem().then(r => console.debug(`[MusicKitInterop.next] Skipping to Next ${r}`)); + MusicKit.getInstance().skipToNextItem().then(r => console.debug(`[cider:preload] [next] Skipping to Next ${r}`)); }, previous: () => { // if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) // MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex); - MusicKit.getInstance().skipToPreviousItem().then(r => console.debug(`[MusicKitInterop.previous] Skipping to Previous ${r}`)); + MusicKit.getInstance().skipToPreviousItem().then(r => console.debug(`[cider:preload] [previous] Skipping to Previous ${r}`)); } } process.once('loaded', () => { - console.debug("Setting ipcRenderer") + console.debug("[cider:preload] IPC Listeners Created!") global.MusicKitInterop = MusicKitInterop; }); From 2827dfb36dc95dafe980ca75db8b677f30b92c34 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:11:54 +0100 Subject: [PATCH 008/289] renderer side of lastfm updated --- src/i18n/README.md | 3 +++ src/i18n/en_US.json | 1 + src/i18n/source/en_US.json | 1 + src/main/plugins/lastfm.ts | 12 ++++++++++- src/renderer/views/pages/settings.ejs | 29 ++++++++------------------- 5 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/i18n/README.md b/src/i18n/README.md index a21bf49e..575da984 100644 --- a/src/i18n/README.md +++ b/src/i18n/README.md @@ -448,3 +448,6 @@ Update 10/06/2022 20:00 UTC * `settings.option.visual.purplePodcastPlaybackBar`: Added to `en_US` +Update 15/06/2022 20:00 UTC + +* `settings.notyf.connectivity.lastfmScrobble.connectError`: Added to `en_US` \ No newline at end of file diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json index 692e86c2..06a09bdf 100644 --- a/src/i18n/en_US.json +++ b/src/i18n/en_US.json @@ -539,6 +539,7 @@ "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enable Last.fm Now Playing", "settings.option.connectivity.lastfmScrobble.removeFeatured": "Remove featuring artists from song title (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", + "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", "settings.header.debug": "Debug", "settings.option.debug.copy_log": "Copy logs to clipboard", "settings.option.debug.openAppData": "Open Cider Folder", diff --git a/src/i18n/source/en_US.json b/src/i18n/source/en_US.json index e202b0bf..3a05d741 100644 --- a/src/i18n/source/en_US.json +++ b/src/i18n/source/en_US.json @@ -527,6 +527,7 @@ "settings.option.connectivity.lastfmScrobble.nowPlaying": "Enable Last.fm Now Playing", "settings.option.connectivity.lastfmScrobble.removeFeatured": "Remove featuring artists from song title (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", + "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", "settings.header.debug": "Debug", "settings.option.debug.copy_log": "Copy logs to clipboard", "settings.option.debug.openAppData": "Open Cider Folder", diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index c49b0b2d..4960781d 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -52,6 +52,15 @@ export default class lastfm { // console.debug('lastfm:auth', event, token) this.authenticateLastFM(token) }) + + this._utils.getIPCMain().on('lastfm:disconnect', (event: any) => { + this._lfm.setSessionCredentials(null, null); + this._authenticated = false; + this._utils.setStoreValue('lastfm.enabled', false) + this._utils.setStoreValue('lastfm.secrets.username', "") + this._utils.setStoreValue('lastfm.secrets.key', "") + console.debug('[lastfm] [disconnect] Disconnected') + }) } /** @@ -110,10 +119,11 @@ export default class lastfm { console.error(err); return; } - this._utils.setStoreValue("lastfm.secrets.token", token) this._utils.setStoreValue('lastfm.secrets.username', session.username); this._utils.setStoreValue('lastfm.secrets.key', session.key); + this._utils.setStoreValue('lastfm.enabled', true) this._authenticated = true; + console.debug(`[${lastfm.name}] [authenticate] Authenticated as ${session.username}`) }); } diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 1cca7314..8e0d45aa 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1063,8 +1063,11 @@ {{$root.getLz('settings.option.connectivity.lastfmScrobble')}}
- +
@@ -1346,14 +1349,6 @@ this.canChangeHash = true } }) - - if (app.cfg.lastfm.enabled) { - const element = document.getElementById('lfmConnect'); - if (element) { - element.innerHTML = `Disconnect\n

(Authed: ${app.cfg.lastfm.auth_token})

`; - element.onclick = app.LastFMDeauthorize; - } - } }, methods: { windowBgStyleChange() { @@ -1474,14 +1469,10 @@ reloadDiscordRPC() { ipcRenderer.send('reloadRPC') }, - lfmDisconnect(event) { - ipcRenderer.invoke('setStoreValue', 'lastfm.enabled', false).catch((e) => console.error(e)); - ipcRenderer.invoke('setStoreValue', 'lastfm.secrets.session', {}).catch((e) => console.error(e)); - event.target.innerHTML = app.getLz('term.connect'); - event.target.onclick = this.lfmAuthorize; + lfmDisconnect() { + ipcRenderer.send('lastfm:disconnect'); }, async lfmAuthorize(event) { - console.debug("[lastfm:authorize] Token received.") window.open(await ipcRenderer.invoke('lastfm:url')); event.target.innerText = app.getLz('term.connecting') + '...'; @@ -1489,15 +1480,11 @@ setTimeout(() => { if (event.target.innerText === app.getLz('term.connecting') + '...') { event.target.innerText = app.getLz('term.connect'); + app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError')); console.warn('[lastfm:authorize] Last.fm authorization timed out.'); } }, 20000); - ipcRenderer.on('lastfm:renderer-auth', function (event, session) { - element.innerHTML = `${app.getLz('term.disconnect')}\n

(${app.getLz('term.authed')}: ${session.username})

`; - element.onclick = this.lfmDisconnect; - }); - }, } }) From 3e3c38a25f04ab40a1fca0c6195bdb217e6c5c04 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:13:42 +0100 Subject: [PATCH 009/289] that was bad --- src/main/plugins/lastfm.ts | 7 +------ src/renderer/main/vueapp.js | 6 ++++++ src/renderer/views/pages/settings.ejs | 3 +++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index 4960781d..db808902 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -56,9 +56,6 @@ export default class lastfm { this._utils.getIPCMain().on('lastfm:disconnect', (event: any) => { this._lfm.setSessionCredentials(null, null); this._authenticated = false; - this._utils.setStoreValue('lastfm.enabled', false) - this._utils.setStoreValue('lastfm.secrets.username', "") - this._utils.setStoreValue('lastfm.secrets.key', "") console.debug('[lastfm] [disconnect] Disconnected') }) } @@ -119,9 +116,7 @@ export default class lastfm { console.error(err); return; } - this._utils.setStoreValue('lastfm.secrets.username', session.username); - this._utils.setStoreValue('lastfm.secrets.key', session.key); - this._utils.setStoreValue('lastfm.enabled', true) + this._utils.getWindow().webContents.send('lastfm:authenticated', session) this._authenticated = true; console.debug(`[${lastfm.name}] [authenticate] Authenticated as ${session.username}`) }); diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 58f54f25..7e051b58 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -829,6 +829,12 @@ const app = new Vue({ MusicKit.getInstance().videoContainerElement = document.getElementById("apple-music-video-player") + ipcRenderer.on('lastfm:authenticated', (_e, session) => { + app.cfg.lastfm.username = session.username + app.cfg.lastfm.key = session.key + app.cfg.lastfm.enabled = true + }) + ipcRenderer.on('theme-update', async (event, arg) => { await less.refresh(true, true, true) self.setTheme(self.cfg.visual.theme, true) diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 8e0d45aa..3aef03bb 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1470,6 +1470,9 @@ ipcRenderer.send('reloadRPC') }, lfmDisconnect() { + app.cfg.lastfm.enabled = false; + app.cfg.lastfm.username = ""; + app.cfg.lastfm.key = ""; ipcRenderer.send('lastfm:disconnect'); }, async lfmAuthorize(event) { From 69c460ad03a352afad6b66fdd60a82b7082c3929 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 22:27:27 +0100 Subject: [PATCH 010/289] patch cider connect renderer issues --- src/main/base/browserwindow.ts | 3 +-- src/renderer/main/vueapp.js | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index 89c54e55..ac84bef7 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -614,8 +614,7 @@ export class BrowserWindow { //region Connect Integration app.get("/connect/set-cc-user/:data", (req, res) => { //utils.getStoreValue('connectUser', JSON.parse()) // [Connect] Save user in store - utils.setStoreValue('connectUser', JSON.parse(req.params.data)) - utils.getWindow().reload() + utils.getWindow().webContents.send('setStoreValue', 'connectUser', JSON.parse(req.params.data)) res.redirect(`https://connect.cidercollective.dev/linked.html`) }); // [Connect] Set auth URL in store for `shell.openExternal` diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 7e051b58..4e6af4e7 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -835,6 +835,10 @@ const app = new Vue({ app.cfg.lastfm.enabled = true }) + ipcRenderer.on('setStoreValue', (e, key, value) => { + app.cfg[key] = value + }) + ipcRenderer.on('theme-update', async (event, arg) => { await less.refresh(true, true, true) self.setTheme(self.cfg.visual.theme, true) From bd330c1ec0c31299b697c15af6cf08090210dd78 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Wed, 15 Jun 2022 23:26:51 +0100 Subject: [PATCH 011/289] various optimisations --- src/i18n/README.md | 4 +++- src/i18n/en_US.json | 2 ++ src/i18n/source/en_US.json | 2 ++ src/main/base/store.ts | 3 +-- src/renderer/main/vueapp.js | 6 ------ src/renderer/views/pages/settings.ejs | 27 +++++++++++++++------------ 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/i18n/README.md b/src/i18n/README.md index 575da984..265a6214 100644 --- a/src/i18n/README.md +++ b/src/i18n/README.md @@ -450,4 +450,6 @@ Update 10/06/2022 20:00 UTC Update 15/06/2022 20:00 UTC -* `settings.notyf.connectivity.lastfmScrobble.connectError`: Added to `en_US` \ No newline at end of file +* `settings.notyf.connectivity.lastfmScrobble.connectError`: Added to `en_US` +* `settings.notyf.connectivity.lastfmScrobble.connectSuccess`: Added to `en_US` +* `settings.notyf.connectivity.lastfmScrobble.connecting`: Added to `en_US` \ No newline at end of file diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json index 06a09bdf..e094d697 100644 --- a/src/i18n/en_US.json +++ b/src/i18n/en_US.json @@ -540,6 +540,8 @@ "settings.option.connectivity.lastfmScrobble.removeFeatured": "Remove featuring artists from song title (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", + "settings.notyf.connectivity.lastfmScrobble.connectSuccess": "Last.fm Connection Successful", + "settings.notyf.connectivity.lastfmScrobble.connecting": "Connecting to Last.fm...", "settings.header.debug": "Debug", "settings.option.debug.copy_log": "Copy logs to clipboard", "settings.option.debug.openAppData": "Open Cider Folder", diff --git a/src/i18n/source/en_US.json b/src/i18n/source/en_US.json index 3a05d741..8316123c 100644 --- a/src/i18n/source/en_US.json +++ b/src/i18n/source/en_US.json @@ -528,6 +528,8 @@ "settings.option.connectivity.lastfmScrobble.removeFeatured": "Remove featuring artists from song title (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", + "settings.notyf.connectivity.lastfmScrobble.connectSuccess": "Last.fm Connection Successful", + "settings.notyf.connectivity.lastfmScrobble.connecting": "Connecting to Last.fm...", "settings.header.debug": "Debug", "settings.option.debug.copy_log": "Copy logs to clipboard", "settings.option.debug.openAppData": "Open Cider Folder", diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 56b0743f..fd706f8e 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -224,8 +224,7 @@ export class Store { "scrobble_after": 50, "secrets": { "username": "", - "key": "", - "token": "" + "key": "" } }, diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 4e6af4e7..526bb3b5 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -829,12 +829,6 @@ const app = new Vue({ MusicKit.getInstance().videoContainerElement = document.getElementById("apple-music-video-player") - ipcRenderer.on('lastfm:authenticated', (_e, session) => { - app.cfg.lastfm.username = session.username - app.cfg.lastfm.key = session.key - app.cfg.lastfm.enabled = true - }) - ipcRenderer.on('setStoreValue', (e, key, value) => { app.cfg[key] = value }) diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 3aef03bb..5833c872 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1063,12 +1063,9 @@ {{$root.getLz('settings.option.connectivity.lastfmScrobble')}}
- -
@@ -1471,23 +1468,29 @@ }, lfmDisconnect() { app.cfg.lastfm.enabled = false; - app.cfg.lastfm.username = ""; - app.cfg.lastfm.key = ""; + app.cfg.lastfm.secrets.username = ""; + app.cfg.lastfm.secrets.key = ""; ipcRenderer.send('lastfm:disconnect'); }, - async lfmAuthorize(event) { + async lfmAuthorize() { window.open(await ipcRenderer.invoke('lastfm:url')); - event.target.innerText = app.getLz('term.connecting') + '...'; + app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connecting')); /* Just a timeout for the button */ setTimeout(() => { - if (event.target.innerText === app.getLz('term.connecting') + '...') { - event.target.innerText = app.getLz('term.connect'); + if (document.getElementById('lfmConnect').innerText === app.getLz('term.connecting') + '...') { app.notyf.error(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectError')); console.warn('[lastfm:authorize] Last.fm authorization timed out.'); } }, 20000); + ipcRenderer.once('lastfm:authenticated', (_e, session) => { + app.cfg.lastfm.secrets.username = session.username + app.cfg.lastfm.secrets.key = session.key + app.cfg.lastfm.enabled = true + app.notyf.success(app.getLz('settings.notyf.connectivity.lastfmScrobble.connectSuccess')); + }) + }, } }) From bbcae012b818b111acfa660007ee16e63a53c412 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Thu, 16 Jun 2022 14:01:04 +0100 Subject: [PATCH 012/289] Restructure --- src/main/base/utils.ts | 54 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 31 deletions(-) diff --git a/src/main/base/utils.ts b/src/main/base/utils.ts index 0c75015b..46b865be 100644 --- a/src/main/base/utils.ts +++ b/src/main/base/utils.ts @@ -2,18 +2,36 @@ import * as fs from "fs"; import * as path from "path"; import {Store} from "./store"; import {BrowserWindow as bw} from "./browserwindow"; -import {app, dialog, ipcMain, Notification, shell, BrowserWindow} from "electron"; +import {app, BrowserWindow, ipcMain} from "electron"; import fetch from "electron-fetch"; -import {AppImageUpdater, NsisUpdater} from "electron-updater"; -import * as log from "electron-log"; import ElectronStore from "electron-store"; export class utils { + /** + * Playback Functions + */ + static playback = { + pause: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.pause()") + }, + play: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.play()") + }, + playPause: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.playPause()") + }, + next: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.next()") + }, + previous: () => { + bw.win.webContents.executeJavaScript("MusicKitInterop.previous()") + } + } /** * Paths for the application to use */ - private static paths: any = { + static paths: any = { srcPath: path.join(__dirname, "../../src"), rendererPath: path.join(__dirname, "../../src/renderer"), mainPath: path.join(__dirname, "../../src/main"), @@ -71,7 +89,7 @@ export class utils { } else { i18n = Object.assign(i18n, JSON.parse(fs.readFileSync(path.join(this.paths.i18nPath, `en_US.json`), "utf8"))); } - }) + }) } if (key) { return i18n[key] @@ -97,7 +115,6 @@ export class utils { return Store.cfg.store } - /** * Get the store instance * @returns {Store} @@ -123,10 +140,6 @@ export class utils { return Store.pushToCloud } - - - - /** * Gets the browser window */ @@ -145,25 +158,4 @@ export class utils { static loadJSFrontend(path: string): void { bw.win.webContents.executeJavaScript(fs.readFileSync(path, "utf8")); } - - /** - * Playback Functions - */ - static playback = { - pause: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.pause()") - }, - play: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.play()") - }, - playPause: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.playPause()") - }, - next: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.next()") - }, - previous: () => { - bw.win.webContents.executeJavaScript("MusicKitInterop.previous()") - } - } } From 23ad2640dc146f6cfb9c72f316eedd6f032a5d4a Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Thu, 16 Jun 2022 14:33:24 +0100 Subject: [PATCH 013/289] Private implemented --- src/main/index.ts | 57 +++++++++++++++++++------------------- src/main/plugins/lastfm.ts | 7 +---- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index ce2d043d..4a74f0e9 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,18 +1,19 @@ -require('v8-compile-cache'); - -const {app, components, ipcMain} = require('electron'); -import {join} from 'path'; +require("v8-compile-cache"); +import {join} from "path"; +import {app} from "electron" if (!app.isPackaged) { - app.setPath('userData', join(app.getPath('appData'), 'Cider')); + app.setPath("userData", join(app.getPath("appData"), "Cider")); } import {Store} from "./base/store"; import {AppEvents} from "./base/app"; import {Plugins} from "./base/plugins"; import {BrowserWindow} from "./base/browserwindow"; -import {init as Sentry} from '@sentry/electron'; +import {init as Sentry} from "@sentry/electron"; import {RewriteFrames} from "@sentry/integrations"; +import {components, ipcMain} from "electron" + // Analytics for debugging fun yeah. Sentry({ @@ -32,13 +33,13 @@ const CiderPlug = new Plugins(); * App Event Handlers * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -app.on('ready', () => { +app.on("ready", () => { Cider.ready(CiderPlug); - console.log('[Cider] Application is Ready. Creating Window.') + console.log("[Cider] Application is Ready. Creating Window.") if (!app.isPackaged) { - console.info('[Cider] Running in development mode.') - require('vue-devtools').install() + console.info("[Cider] Running in development mode.") + require("vue-devtools").install() } components.whenReady().then(async () => { @@ -49,11 +50,11 @@ app.on('ready', () => { console.log(gpuInfo) }) - console.log('[Cider][Widevine] Status:', components.status()); + console.log("[Cider][Widevine] Status:", components.status()); Cider.bwCreated(); win.on("ready-to-show", () => { - console.debug('[Cider] Window is Ready.') - CiderPlug.callPlugins('onReady', win); + console.debug("[Cider] Window is Ready.") + CiderPlug.callPlugins("onReady", win); win.show(); }); }); @@ -68,20 +69,20 @@ ipcMain.handle("renderer-ready", (event) => { CiderPlug.callPlugins("onRendererReady", event); }) -ipcMain.on('playbackStateDidChange', (_event, attributes) => { - CiderPlug.callPlugins('onPlaybackStateDidChange', attributes); +ipcMain.on("playbackStateDidChange", (_event, attributes) => { + CiderPlug.callPlugins("onPlaybackStateDidChange", attributes); }); -ipcMain.on('nowPlayingItemDidChange', (_event, attributes) => { - CiderPlug.callPlugins('onNowPlayingItemDidChange', attributes); +ipcMain.on("nowPlayingItemDidChange", (_event, attributes) => { + CiderPlug.callPlugins("onNowPlayingItemDidChange", attributes); }); -ipcMain.on('nowPlayingItemDidChangeLastFM', (_event, attributes) => { - CiderPlug.callPlugin('lastfm.js', 'nowPlayingItemDidChangeLastFM', attributes); +ipcMain.on("nowPlayingItemDidChangeLastFM", (_event, attributes) => { + CiderPlug.callPlugin("lastfm.js", "nowPlayingItemDidChangeLastFM", attributes); }) -app.on('before-quit', () => { - CiderPlug.callPlugins('onBeforeQuit'); +app.on("before-quit", () => { + CiderPlug.callPlugins("onBeforeQuit"); console.warn(`${app.getName()} exited.`); }); @@ -90,21 +91,21 @@ app.on('before-quit', () => { * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ // @ts-ignore -app.on('widevine-ready', (version, lastVersion) => { +app.on("widevine-ready", (version, lastVersion) => { if (null !== lastVersion) { - console.log('[Cider][Widevine] Widevine ' + version + ', upgraded from ' + lastVersion + ', is ready to be used!') + console.log("[Cider][Widevine] Widevine " + version + ", upgraded from " + lastVersion + ", is ready to be used!") } else { - console.log('[Cider][Widevine] Widevine ' + version + ' is ready to be used!') + console.log("[Cider][Widevine] Widevine " + version + " is ready to be used!") } }) // @ts-ignore -app.on('widevine-update-pending', (currentVersion, pendingVersion) => { - console.log('[Cider][Widevine] Widevine ' + currentVersion + ' is ready to be upgraded to ' + pendingVersion + '!') +app.on("widevine-update-pending", (currentVersion, pendingVersion) => { + console.log("[Cider][Widevine] Widevine " + currentVersion + " is ready to be upgraded to " + pendingVersion + "!") }) // @ts-ignore -app.on('widevine-error', (error) => { - console.log('[Cider][Widevine] Widevine installation encountered an error: ' + error) +app.on("widevine-error", (error) => { + console.log("[Cider][Widevine] Widevine installation encountered an error: " + error) app.exit() }) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index db808902..b85383f6 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -1,9 +1,3 @@ -// https://github.com/maxkueng/node-lastfmapi -// https://github.com/maxkueng/lastfm-autocorrect -// @todo: add autocorrect -// @todo: add scrobble and filter to prevent no-title-found being scrobbled -// @todo: handle session keys through config to stop aids session.json - export default class lastfm { /** @@ -74,6 +68,7 @@ export default class lastfm { * @param attributes Music Attributes */ onNowPlayingItemDidChange(attributes: any): void { + if (this._utils.getStoreValue("general.privateEnabled")) return; this._attributes = attributes if (!attributes?.lfmTrack || !attributes?.lfmAlbum) { this.verifyTrack(attributes) From 7850493c9e5eb101340203a369e639baa50acb31 Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Thu, 16 Jun 2022 14:47:52 +0100 Subject: [PATCH 014/289] Filter loop added --- src/main/base/store.ts | 1 + src/main/plugins/lastfm.ts | 4 ++-- src/renderer/views/pages/settings.ejs | 10 ++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/base/store.ts b/src/main/base/store.ts index fd706f8e..9bfb548f 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -222,6 +222,7 @@ export class Store { "lastfm": { "enabled": false, "scrobble_after": 50, + "filter_loop": false, "secrets": { "username": "", "key": "" diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index b85383f6..af63f4a1 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -162,7 +162,7 @@ export default class lastfm { * @private */ private scrobbleTrack(attributes: any): void { - if (!this._authenticated || !attributes || (this._scrobbleCache.track === attributes.lfmTrack.name)) return; + if (!this._authenticated || !attributes || (this._utils.getStoreValue("lastfm.filter_loop") && this._scrobbleCache.track === attributes.lfmTrack.name)) return; if (this._scrobbleDelay) { clearTimeout(this._scrobbleDelay); @@ -200,7 +200,7 @@ export default class lastfm { } private updateNowPlayingTrack(attributes: any): void { - if (!this._authenticated || !attributes || (this._nowPlayingCache.track === attributes.lfmTrack.name)) return; + if (!this._authenticated || !attributes || (this._utils.getStoreValue("lastfm.filter_loop") && this._nowPlayingCache.track === attributes.lfmTrack.name)) return; const nowPlaying = { 'artist': attributes.lfmTrack.artist.name, diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index ff1bdbc9..c64432f1 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1079,6 +1079,16 @@ +
+
+ {{$root.getLz('settings.option.connectivity.filterLoop')}} +
+
+ +
+
From 742e606c09a876b0b3eeddc53be2447b5d2a09ff Mon Sep 17 00:00:00 2001 From: Core <64542347+coredev-uk@users.noreply.github.com> Date: Thu, 16 Jun 2022 16:14:53 +0100 Subject: [PATCH 015/289] filter loop fixes --- src/main/plugins/lastfm.ts | 14 +++++++++++--- src/preload/cider-preload.js | 2 ++ src/renderer/views/pages/settings.ejs | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index af63f4a1..bf0b88e5 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -52,6 +52,11 @@ export default class lastfm { this._authenticated = false; console.debug('[lastfm] [disconnect] Disconnected') }) + + this._utils.getIPCMain().on('lastfm:nowPlayingChange', (event: any, attributes: any) => { + if (this._utils.getStoreValue("lastfm.filter_loop")) return; + this.onNowPlayingItemDidChange(attributes) + }) } /** @@ -123,15 +128,18 @@ export default class lastfm { * @private */ private verifyTrack(attributes: any): object { - if (!attributes) return {}; + if (!attributes) return attributes; if (!attributes.lfmAlbum) { + console.log(attributes.artistName) + console.log(attributes.albumName) return this._lfm.album.getInfo({ "artist": attributes.artistName, "album": attributes.albumName }, (err: any, data: any) => { if (err) { - console.error(`[${lastfm.name}] [album.getInfo] Error: ${err}`) + console.error(`[${lastfm.name}] [album.getInfo] Error: ${typeof err === "string" ? err : err.message}`) + console.error(err) return {}; } if (data) { @@ -142,7 +150,7 @@ export default class lastfm { } else { return this._lfm.track.getCorrection(attributes.artistName, attributes.name, (err: any, data: any) => { if (err) { - console.error(`[${lastfm.name}] [track.getCorrection] Error: ${err}`) + console.error(`[${lastfm.name}] [track.getCorrection] Error: ${typeof err === "string" ? err : err.message}`) console.error(err) return {}; } diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index 3923fbd3..57ae5df3 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -29,6 +29,8 @@ const MusicKitInterop = { global.ipcRenderer.send('nowPlayingItemDidChange', attributes); } + global.ipcRenderer.send('lastfm:nowPlayingChange', attributes); + if (MusicKit.getInstance().nowPlayingItem) { await this.sleep(750); MusicKit.getInstance().playbackRate = app.cfg.audio.playbackRate; diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index c64432f1..170dcfd8 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1081,7 +1081,7 @@
- {{$root.getLz('settings.option.connectivity.filterLoop')}} + {{$root.getLz('settings.option.connectivity.lastfmScrobble.filterLoop')}}
@@ -305,17 +305,24 @@ }, mounted: function () { this.$nextTick(function () { - this.isInLibrary() - }) + if (this.data.id != "ciderlocal") { + this.isInLibrary() + } else { + if (this.data.relationships != null && this.data.id == "ciderlocal") { + this.displayListing = this.data.relationships.tracks.data + } + + this.inPlaylist = this.data.type == "library-playlists"; + }}) }, beforeMount() { - if( window.location.hash.includes("playlist") ) { + if (window.location.hash.includes("playlist")) { window.addEventListener('keydown', this.getCopiedPlayListSongs); window.addEventListener('keydown', this.pasteSongs); } }, beforeDestroy() { - if( window.location.hash.includes("playlist") ) { + if (window.location.hash.includes("playlist")) { window.removeEventListener('keydown', this.getCopiedPlayListSongs); window.removeEventListener('keydown', this.pasteSongs); } @@ -326,10 +333,14 @@ this.isInLibrary() this.getBadges() - if (this.data.relationships) { - this.generateNestedPlaylist(this.data.relationships.tracks.data) - if (!this.hasNestedPlaylist) { + if (this.data.relationships != null) { + if (this.data.id == "ciderlocal") { this.displayListing = this.data.relationships.tracks.data + } else { + this.generateNestedPlaylist(this.data.relationships.tracks.data) + if (!this.hasNestedPlaylist) { + this.displayListing = this.data.relationships.tracks.data + } } } @@ -382,21 +393,21 @@ this.headerVisible = visible }, hasHero() { - if(this.data.attributes?.editorialArtwork?.bannerUber){ + if (this.data.attributes?.editorialArtwork?.bannerUber) { return this.data.attributes?.editorialArtwork?.bannerUber.url - } else if(this.data.attributes?.editorialArtwork?.subscriptionHero) { + } else if (this.data.attributes?.editorialArtwork?.subscriptionHero) { return this.data.attributes?.editorialArtwork?.subscriptionHero.url - } else if(this.data.attributes?.editorialArtwork?.storeFlowcase){ + } else if (this.data.attributes?.editorialArtwork?.storeFlowcase) { return this.data.attributes?.editorialArtwork?.storeFlowcase.url } return false; }, hasHeroObject() { - if(this.data.attributes?.editorialArtwork?.bannerUber){ + if (this.data.attributes?.editorialArtwork?.bannerUber) { return this.data.attributes?.editorialArtwork?.bannerUber - } else if(this.data.attributes?.editorialArtwork?.subscriptionHero) { + } else if (this.data.attributes?.editorialArtwork?.subscriptionHero) { return this.data.attributes?.editorialArtwork?.subscriptionHero - } else if(this.data.attributes?.editorialArtwork?.storeFlowcase){ + } else if (this.data.attributes?.editorialArtwork?.storeFlowcase) { return this.data.attributes?.editorialArtwork?.storeFlowcase } return []; @@ -774,14 +785,17 @@ } } - const id = this.data.attributes.playParams.id ?? this.data.id; + const id = this.data.attributes.playParams?.id ?? this.data.id; //console.log("1") - const kind = this.data.attributes.playParams.kind ?? this.data.type ?? ''; + const kind = this.data.attributes.playParams?.kind ?? this.data.type ?? ''; //console.log("1") + if (kind == "podcast-episodes") {kind = "episode"} const truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; let query = (this.data ?? app.showingPlaylist).relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); - app.mk.stop().then(function () { + + app.mk.stop().then(() => { + if (id != 'ciderlocal'){ app.mk.setQueue({ [truekind]: [id], parameters: { l: app.mklang } }).then(function () { app.mk.play().then(function () { if (query.length > 100) { @@ -792,7 +806,12 @@ app.mk.queue.append(u) } }) - }) + })} else { + let u = app.library.localsongs.map(i => {return i.id}) + app.mk.setQueue({"episodes" : u}).then(()=>{ + app.mk.play() + }) + } }) @@ -802,7 +821,7 @@ return "d-none"; }, async getCopiedPlayListSongs(event) { - if( event.ctrlKey && event.keyCode === 67 ) { + if (event.ctrlKey && event.keyCode === 67) { let urls = []; app.selectedMediaItems.forEach(item => { this.app.mk.api.v3.music(`/v1/me/library/songs/${item.id}`).then((response) => { @@ -816,14 +835,14 @@ } }, async pasteSongs(event) { - if( event.ctrlKey && event.keyCode === 86 && this.data.attributes.canEdit ) { + if (event.ctrlKey && event.keyCode === 86 && this.data.attributes.canEdit) { let clipboard = await navigator.clipboard.readText() let songs = [] clipboard = clipboard.split(",") clipboard.forEach(item => { songs.push({ - id: item.substring(item.indexOf("i=")+2, item.length), + id: item.substring(item.indexOf("i=") + 2, item.length), type: "songs", }) }) @@ -901,4 +920,4 @@ } } }) - + \ No newline at end of file From 0014999586ba14b10017e1a52d04414ee42ad43f Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 26 Jun 2022 07:49:46 +0700 Subject: [PATCH 091/289] some fixes --- src/main/base/browserwindow.ts | 2 +- src/renderer/views/components/mediaitem-list-item.ejs | 9 ++++++--- src/renderer/views/components/sidebar-playlist.ejs | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index e5c896e7..fd698ad4 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -1257,7 +1257,7 @@ export class BrowserWindow { "assetUrl": "file:///" +audio, "contentAdvisory": "", "releaseDateTime": "2022-05-13T00:23:00Z", - "durationInMilliseconds": Math.floor((metadata.format.duration?? 0) * 1000), + "durationInMillis": Math.floor((metadata.format.duration?? 0) * 1000), "offers": [ { diff --git a/src/renderer/views/components/mediaitem-list-item.ejs b/src/renderer/views/components/mediaitem-list-item.ejs index 894ef000..1073ab44 100644 --- a/src/renderer/views/components/mediaitem-list-item.ejs +++ b/src/renderer/views/components/mediaitem-list-item.ejs @@ -185,15 +185,18 @@ return minutes + ":" + (seconds < 10 ? '0' : '') + seconds; }, getDataType() { + let type = '' if (typeof this.item.attributes.playParams != "undefined") { if (this.item.attributes.playParams?.isLibrary) { - return this.item.type + type = this.item.type } else { - return this.item.attributes.playParams?.kind + type = this.item.attributes.playParams?.kind } } else { - return this.item.type + type = this.item.type } + if (type == 'podcast-episodes') type = 'episode'; + return type; }, select(e) { let data_type = this.getDataType() diff --git a/src/renderer/views/components/sidebar-playlist.ejs b/src/renderer/views/components/sidebar-playlist.ejs index 17048fa9..1a24eb7b 100644 --- a/src/renderer/views/components/sidebar-playlist.ejs +++ b/src/renderer/views/components/sidebar-playlist.ejs @@ -231,7 +231,7 @@ }, "isPublic": true, "description": { - "standard": "LocalSongs" + "standard": "" } }, "relationships": { From ae0fbbc1d3f8d2d2d6edd3217c7e373f842f8c39 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 26 Jun 2022 08:02:19 +0700 Subject: [PATCH 092/289] worki v1 --- src/main/base/browserwindow.ts | 32 ++++------- src/main/base/store.ts | 1 + src/main/base/vcomponents.json | 1 + src/renderer/main/vueapp.js | 5 +- src/renderer/views/app/panels.ejs | 3 + src/renderer/views/components/pathmenu.ejs | 65 ++++++++++++++++++++++ src/renderer/views/pages/settings.ejs | 14 ++++- 7 files changed, 98 insertions(+), 23 deletions(-) create mode 100644 src/renderer/views/components/pathmenu.ejs diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index fd698ad4..caf2d4e5 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -1,5 +1,5 @@ -import { join } from "path"; -import { app, BrowserWindow as bw, ipcMain, ShareMenu, shell, screen } from "electron"; +import {join} from "path"; +import {app, BrowserWindow as bw, ipcMain, ShareMenu, shell, screen, dialog} from "electron"; import * as windowStateKeeper from "electron-window-state"; import * as express from "express"; import * as getPort from "get-port"; @@ -122,6 +122,7 @@ export class BrowserWindow { "components/fullscreen", "components/miniplayer", "components/castmenu", + "components/pathmenu", "components/airplay-modal", "components/artist-chip", "components/hello-world", @@ -1256,7 +1257,7 @@ export class BrowserWindow { "copyright": metadata.common.copyright ?? "", "assetUrl": "file:///" +audio, "contentAdvisory": "", - "releaseDateTime": "2022-05-13T00:23:00Z", + "releaseDateTime": `${metadata?.common?.year ?? '2022'}-05-13T00:23:00Z`, "durationInMillis": Math.floor((metadata.format.duration?? 0) * 1000), "offers": [ @@ -1268,24 +1269,6 @@ export class BrowserWindow { "contentRating": "clean" } }; - - - // let form = {"id": "/ciderlocal?" + audio, - // "type": "library-songs", - // "href": "/ciderlocal?" + audio, - // "artwork": { - // "url": metadata.common.picture != undefined ? "data:image/png;base64,"+metadata.common.picture[0].data.toString('base64')+"" : "", - // }, - // "attributes": - // { "durationInMillis": Math.floor((metadata.format.duration?? 0) * 1000), - // "hasLyrics": false, - // "playParams": { "id": "/ciderlocal?" + audio, "kind": "song", "isLibrary": true, "reporting": false }, - // "trackNumber": 0, - // "discNumber": 0, - // "genreNames": [""], - // "name": metadata.common.title, - // "albumName": metadata.common.album, - // "artistName": metadata.common.artist}} metadatalistart.push({ id : "ciderlocal" + numid, url: metadata.common.picture != undefined ? metadata.common.picture[0].data.toString('base64') : "", @@ -1497,10 +1480,17 @@ export class BrowserWindow { } }); + ipcMain.on('open-appdata', (_event) => { shell.openPath(app.getPath('userData')); }); + ipcMain.handle('folderSelector', async (_event) => { + let u = await dialog.showOpenDialog({ + properties: ['openDirectory','multiSelections'] + }); + return u.filePaths + }); //#region Cider Connect ipcMain.on('cc-auth', (_event) => { diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 6bf6071c..a4fda8a7 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -155,6 +155,7 @@ export class Store { "sortOrder": "asc", "viewAs": "covers" }, + "localPaths": [] }, "audio": { "volume": 1, diff --git a/src/main/base/vcomponents.json b/src/main/base/vcomponents.json index 42f86c68..53232dc8 100644 --- a/src/main/base/vcomponents.json +++ b/src/main/base/vcomponents.json @@ -60,6 +60,7 @@ "components/fullscreen", "components/miniplayer", "components/castmenu", + "components/pathmenu", "components/airplay-modal", "components/artist-chip", "components/hello-world", diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 37ade84b..52d9b817 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -216,6 +216,7 @@ const app = new Vue({ audioPlaybackRate: false, showPlaylist: false, castMenu: false, + pathMenu: false, moreInfo: false, airplayPW: false, settings: false @@ -858,7 +859,7 @@ const app = new Vue({ }) ipcRenderer.on('getUpdatedLocalList', (event, data) => { - console.log("cider-local", data); + // console.log("cider-local", data); this.library.localsongs = data; }) @@ -1072,6 +1073,8 @@ const app = new Vue({ if (this.cfg.general.themeUpdateNotification && !this.isDev) { this.checkForThemeUpdates() } + + ipcRenderer.send("scanLibrary",app.cfg.libraryPrefs.localPaths) }, showFoo(querySelector, time) { clearTimeout(this.idleTimer); diff --git a/src/renderer/views/app/panels.ejs b/src/renderer/views/app/panels.ejs index 2489a2a5..cd5783a1 100644 --- a/src/renderer/views/app/panels.ejs +++ b/src/renderer/views/app/panels.ejs @@ -25,6 +25,9 @@ + + + diff --git a/src/renderer/views/components/pathmenu.ejs b/src/renderer/views/components/pathmenu.ejs new file mode 100644 index 00000000..560bc1e4 --- /dev/null +++ b/src/renderer/views/components/pathmenu.ejs @@ -0,0 +1,65 @@ + + \ No newline at end of file diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index f67799af..a287d74d 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -1147,7 +1147,16 @@
- +
+
+ {{'Local Songs'}} +
+
+ +
+
{{$root.getLz('settings.option.experimental.reinstallwidevine')}} @@ -1523,6 +1532,9 @@ }, filterChange(e) { this.$root.cfg.connectivity.lastfm.filter_types[e.target.value] = e.target.checked; + }, + openLocalSongsPathMenu() { + app.modals.pathMenu = true } } }) From 4ede7c3e734bee6414ef1b7f90cbd44e42dfb44e Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 26 Jun 2022 08:06:29 +0700 Subject: [PATCH 093/289] move to general for visibility --- src/renderer/views/pages/settings.ejs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index a287d74d..0b9fcbe8 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -220,6 +220,16 @@
+
+
+ {{'Local files path'}} +
+
+ +
+
@@ -1147,16 +1157,6 @@ -
-
- {{'Local Songs'}} -
-
- -
-
{{$root.getLz('settings.option.experimental.reinstallwidevine')}} From af1e074d9a2e2292476c77522947714d28becc7e Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 26 Jun 2022 07:15:13 +0700 Subject: [PATCH 094/289] test --- src/renderer/views/components/mediaitem-list-item.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/views/components/mediaitem-list-item.ejs b/src/renderer/views/components/mediaitem-list-item.ejs index 1073ab44..56b0c409 100644 --- a/src/renderer/views/components/mediaitem-list-item.ejs +++ b/src/renderer/views/components/mediaitem-list-item.ejs @@ -16,7 +16,7 @@ @controller-click="route()" tabindex="0" :class="[{'mediaitem-selected': app.select_hasMediaItem(guid)}, addClasses]"> -
+
From a14437b869d8e4311bd203c084d6fb8d32473b36 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 26 Jun 2022 07:16:01 +0700 Subject: [PATCH 095/289] fix multiroom --- src/renderer/main/vueapp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 52d9b817..a7ccc81c 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -1915,7 +1915,7 @@ const app = new Vue({ this.routeView(item.relationships.contents.data[0]) } else if (item.attributes?.link?.url != null) { if (item.attributes.link.url.includes("viewMultiRoom")) { - const params = new Proxy(new URLSearchParams(item.attributes.link.url), { + const params = new Proxy(new URLSearchParams(new URL(item.attributes.link.url).search), { get: (searchParams, prop) => searchParams.get(prop), }); id = params.fcId From e69e394e2acfe71bb894a25b83f880caec932abc Mon Sep 17 00:00:00 2001 From: vapormusic Date: Sun, 26 Jun 2022 07:32:15 +0700 Subject: [PATCH 096/289] attempt for fix rare cast bug --- src/renderer/audio/audio.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/audio/audio.js b/src/renderer/audio/audio.js index d4c2da18..6809acb1 100644 --- a/src/renderer/audio/audio.js +++ b/src/renderer/audio/audio.js @@ -386,7 +386,7 @@ const CiderAudio = { if (this._isBufferFull()) { this._flush(); } - let dataLength = audioRawData[0].length; + let dataLength = audioRawData[0]?.length ?? 0; for (let idx=0; idx Date: Mon, 27 Jun 2022 12:14:42 -0700 Subject: [PATCH 097/289] changes for local files: read below * added pouchdb-node * moved all logic for local files to src/main/providers/local * added new local library section on sidebar --- package.json | 5 + src/main/base/browserwindow.ts | 128 +++------------------ src/main/base/store.ts | 3 +- src/main/base/utils.ts | 8 ++ src/main/index.ts | 2 + src/main/providers/local/db/index.ts | 8 ++ src/main/providers/local/index.ts | 122 ++++++++++++++++++++ src/renderer/main/vueapp.js | 2 +- src/renderer/views/components/pathmenu.ejs | 4 +- tsconfig.json | 1 + 10 files changed, 165 insertions(+), 118 deletions(-) create mode 100644 src/main/providers/local/db/index.ts create mode 100644 src/main/providers/local/index.ts diff --git a/package.json b/package.json index af970515..e3c81145 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,8 @@ "dependencies": { "@sentry/electron": "^3.0.7", "@sentry/integrations": "^6.19.6", + "@types/pouchdb": "^6.4.0", + "@types/pouchdb-node": "^6.1.4", "adm-zip": "0.4.10", "airtunes2": "git+https://github.com/ciderapp/node_airtunes2", "castv2-client": "^1.2.0", @@ -58,11 +60,14 @@ "jimp": "^0.16.1", "jsonc": "^2.0.0", "lastfmapi": "^0.1.1", + "level": "^8.0.0", "mdns-js": "git+https://github.com/ciderapp/node-mdns-js.git", "mpris-service": "^2.1.2", "music-metadata": "^7.12.3", "node-gyp": "^9.0.0", "node-ssdp": "^4.0.1", + "pouchdb-adapter-leveldb": "^7.3.0", + "pouchdb-node": "^7.3.0", "qrcode": "^1.5.0", "react": "^18.0.0", "react-dom": "^18.0.0", diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index caf2d4e5..46023194 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -1,5 +1,5 @@ -import {join} from "path"; -import {app, BrowserWindow as bw, ipcMain, ShareMenu, shell, screen, dialog} from "electron"; +import { join } from "path"; +import { app, BrowserWindow as bw, ipcMain, ShareMenu, shell, screen, dialog } from "electron"; import * as windowStateKeeper from "electron-window-state"; import * as express from "express"; import * as getPort from "get-port"; @@ -27,8 +27,7 @@ import { watch } from "chokidar"; import * as os from "os"; import wallpaper from "wallpaper"; import * as AdmZip from "adm-zip"; -import * as path from 'path'; -const { readdir } = require('fs').promises; +import { LocalFiles } from "../providers/local/"; /** @@ -40,12 +39,11 @@ const { readdir } = require('fs').promises; export class BrowserWindow { public static win: any | undefined = null; private devMode: boolean = !app.isPackaged; + public static express: any | undefined = null; private audioStream: any = new Stream.PassThrough(); private headerSent: any = false; private chromecastIP: any = []; - private localSongs: any = []; - private localSongsArts: any = []; private clientPort: number = 0; private remotePort: number = 6942; private EnvironmentVariables: object = { @@ -410,9 +408,10 @@ export class BrowserWindow { } // Start the webserver for the browser window to load - + // LocalFiles.DB.init() this.startWebServer(); + BrowserWindow.win = new bw(this.options); // cant be built in CI // if (process.platform === "win32" && (utils.getStoreValue('visual.transparent') ?? false)) { @@ -468,7 +467,7 @@ export class BrowserWindow { */ private startWebServer(): void { const app = express(); - + BrowserWindow.express = app; app.use(express.static(join(utils.getPath('srcPath'), "./renderer/"))); app.set("views", join(utils.getPath('srcPath'), "./renderer/views")); app.set("view engine", "ejs"); @@ -553,23 +552,6 @@ export class BrowserWindow { } }); - app.get("/ciderlocal/:songs", (req, res) => { - const audio = atob(req.params.songs.replace(/_/g, '/').replace(/-/g, '+')); - //console.log('auss', audio) - let data = {data: - this.localSongs.filter((f: any) => audio.split(',').includes(f.id))}; - res.send(data); - }); - - app.get("/ciderlocalart/:songs", (req, res) => { - const audio = req.params.songs; - // metadata.common.picture[0].data.toString('base64') - let data = - this.localSongsArts.filter((f: any) => f.id == audio); - res.status(200).send(Buffer.from(data[0]?.url, 'base64')); - }); - - app.get("/themes/:theme/*", (req: { params: { theme: string, 0: string } }, res) => { const theme = req.params.theme; const file = req.params[0]; @@ -632,6 +614,9 @@ export class BrowserWindow { utils.getWindow().webContents.send('setStoreValue', 'connectUser', JSON.parse(req.params.data)) res.redirect(`https://connect.cidercollective.dev/linked.html`) }); + + LocalFiles.setupHandlers() + // [Connect] Set auth URL in store for `shell.openExternal` utils.setStoreValue('cc_authURL', `https://connect.cidercollective.dev/callback/discord?app=cider&appPort=${this.clientPort}`) console.log(`[Connect] Auth URL: ${utils.getStoreValue('cc_authURL')}`) @@ -1199,95 +1184,10 @@ export class BrowserWindow { }); - ipcMain.on("scanLibrary", async (event, folders) => { - async function getFiles(dir: any) { - const dirents = await readdir(dir, { withFileTypes: true }); - const files = await Promise.all(dirents.map((dirent: any) => { - const res = path.resolve(dir, dirent.name); - return dirent.isDirectory() ? getFiles(res) : res; - })); - return Array.prototype.concat(...files); - } - if (folders == null || folders.length == null || folders.length == 0) folders = ["D:\\Music"] - console.log('folders', folders) - let files: any[] = [] - for (var folder of folders){ - // get files from the Music folder - files = files.concat(await getFiles(folder)) - } - - //console.log("cider.files", files2); - let supporttedformats = ["mp3", "aac", "webm", "flac", "m4a", "ogg", "wav", "opus"] - let audiofiles = files.filter(f => supporttedformats.includes(f.substring(f.lastIndexOf('.') + 1))); - // console.log("cider.files2", audiofiles, audiofiles.length); - let metadatalist = [] - let metadatalistart = [] - let numid = 0; - for (var audio of audiofiles) { - try{ - const metadata = await mm.parseFile(audio); - if (metadata != null){ - let form = { - "id": "ciderlocal" + numid, - "type": "podcast-episodes", - "href": audio, - "attributes": { - "artwork": { - "width": 3000, - "height": 3000, - "url": "/ciderlocalart/" + "ciderlocal" + numid, - }, - "topics": [], - "url": "", - "subscribable": true, - "mediaKind": "audio", - "genreNames": [ - "" - ], - // "playParams": { - // "id": "ciderlocal" + numid, - // "kind": "podcast", - // "isLibrary": true, - // "reporting": false }, - "trackNumber": metadata.common.track?.no ?? 0, - "discNumber": metadata.common.disk?.no ?? 0, - "name": metadata.common.title ?? audio.substring(audio.lastIndexOf('\\') + 1), - "albumName": metadata.common.album, - "artistName": metadata.common.artist, - "copyright": metadata.common.copyright ?? "", - "assetUrl": "file:///" +audio, - "contentAdvisory": "", - "releaseDateTime": `${metadata?.common?.year ?? '2022'}-05-13T00:23:00Z`, - "durationInMillis": Math.floor((metadata.format.duration?? 0) * 1000), - - "offers": [ - { - "kind": "get", - "type": "STDQ" - } - ], - "contentRating": "clean" - } - }; - metadatalistart.push({ - id : "ciderlocal" + numid, - url: metadata.common.picture != undefined ? metadata.common.picture[0].data.toString('base64') : "", - }) - numid += 1; - metadatalist.push(form)} - } catch (e){} - } - // console.log('metadatalist', metadatalist); - this.localSongs = metadatalist; - this.localSongsArts = metadatalistart; - BrowserWindow.win.webContents.send('getUpdatedLocalList', metadatalist); - } - // console.log('metadatalist', metadatalist); - this.localSongs = metadatalist; + ipcMain.handle("scanLibrary", async (event, folders) => { + const metadatalist = await LocalFiles.scanLibrary() BrowserWindow.win.webContents.send('getUpdatedLocalList', metadatalist); - } - - ) + }) ipcMain.on('writeWAV', (event, leftpcm, rightpcm, bufferlength) => { @@ -1487,7 +1387,7 @@ export class BrowserWindow { ipcMain.handle('folderSelector', async (_event) => { let u = await dialog.showOpenDialog({ - properties: ['openDirectory','multiSelections'] + properties: ['openDirectory', 'multiSelections'] }); return u.filePaths }); diff --git a/src/main/base/store.ts b/src/main/base/store.ts index a4fda8a7..a014ae45 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -31,7 +31,8 @@ export class Store { "applemusic": false, "library": false, "amplaylists": false, - "playlists": false + "playlists": false, + "localLibrary": false }, "onStartup": { "enabled": false, diff --git a/src/main/base/utils.ts b/src/main/base/utils.ts index 46b865be..f2108528 100644 --- a/src/main/base/utils.ts +++ b/src/main/base/utils.ts @@ -67,6 +67,14 @@ export class utils { static getIPCMain(): Electron.IpcMain { return ipcMain } + + /* + * Get the Express instance + * @returns {any} + */ + static getExpress(): any { + return bw.express + } /** * Fetches the i18n locale for the given language. diff --git a/src/main/index.ts b/src/main/index.ts index 4a74f0e9..a5a2de99 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -13,7 +13,9 @@ import {BrowserWindow} from "./base/browserwindow"; import {init as Sentry} from "@sentry/electron"; import {RewriteFrames} from "@sentry/integrations"; import {components, ipcMain} from "electron" +import {ProviderDB} from "./providers/local/db"; +ProviderDB.init() // Analytics for debugging fun yeah. Sentry({ diff --git a/src/main/providers/local/db/index.ts b/src/main/providers/local/db/index.ts new file mode 100644 index 00000000..0add4b93 --- /dev/null +++ b/src/main/providers/local/db/index.ts @@ -0,0 +1,8 @@ +import * as PouchDB from 'pouchdb-node'; + +export class ProviderDB { + public static db: any = null + static async init() { + // ProviderDB.db = new PouchDB('tracks') + } +} \ No newline at end of file diff --git a/src/main/providers/local/index.ts b/src/main/providers/local/index.ts new file mode 100644 index 00000000..1c95e0f3 --- /dev/null +++ b/src/main/providers/local/index.ts @@ -0,0 +1,122 @@ +// import { ProviderDB } from "./db"; +import * as path from 'path'; +const { readdir } = require('fs').promises; +import { utils } from '../../base/utils'; +import * as mm from 'music-metadata'; + +export class LocalFiles { + static localSongs: any = []; + static localSongsArts: any = []; + // public static DB = ProviderDB.db; + + + static async scanLibrary() { + let folders = utils.getStoreValue("libraryPrefs.localPaths") + if (folders == null || folders.length == null || folders.length == 0) folders = ["D:\\Music"] + console.log('folders', folders) + let files: any[] = [] + for (var folder of folders) { + // get files from the Music folder + files = files.concat(await LocalFiles.getFiles(folder)) + } + + //console.log("cider.files", files2); + let supporttedformats = ["mp3", "aac", "webm", "flac", "m4a", "ogg", "wav", "opus"] + let audiofiles = files.filter(f => supporttedformats.includes(f.substring(f.lastIndexOf('.') + 1))); + // console.log("cider.files2", audiofiles, audiofiles.length); + let metadatalist = [] + let metadatalistart = [] + let numid = 0; + for (var audio of audiofiles) { + try { + const metadata = await mm.parseFile(audio); + if (metadata != null) { + let form = { + "id": "ciderlocal" + numid, + "type": "podcast-episodes", + "href": audio, + "attributes": { + "artwork": { + "width": 3000, + "height": 3000, + "url": "/ciderlocalart/" + "ciderlocal" + numid, + }, + "topics": [], + "url": "", + "subscribable": true, + "mediaKind": "audio", + "genreNames": [ + "" + ], + // "playParams": { + // "id": "ciderlocal" + numid, + // "kind": "podcast", + // "isLibrary": true, + // "reporting": false }, + "trackNumber": metadata.common.track?.no ?? 0, + "discNumber": metadata.common.disk?.no ?? 0, + "name": metadata.common.title ?? audio.substring(audio.lastIndexOf('\\') + 1), + "albumName": metadata.common.album, + "artistName": metadata.common.artist, + "copyright": metadata.common.copyright ?? "", + "assetUrl": "file:///" + audio, + "contentAdvisory": "", + "releaseDateTime": `${metadata?.common?.year ?? '2022'}-05-13T00:23:00Z`, + "durationInMillis": Math.floor((metadata.format.duration ?? 0) * 1000), + + "offers": [ + { + "kind": "get", + "type": "STDQ" + } + ], + "contentRating": "clean" + } + }; + metadatalistart.push({ + id: "ciderlocal" + numid, + url: metadata.common.picture != undefined ? metadata.common.picture[0].data.toString('base64') : "", + }) + numid += 1; + metadatalist.push(form) + } + } catch (e) { } + } + // console.log('metadatalist', metadatalist); + this.localSongs = metadatalist; + this.localSongsArts = metadatalistart; + return metadatalist; + } + static async getFiles(dir: any) { + const dirents = await readdir(dir, { withFileTypes: true }); + const files = await Promise.all(dirents.map((dirent: any) => { + const res = path.resolve(dir, dirent.name); + return dirent.isDirectory() ? this.getFiles(res) : res; + })); + return Array.prototype.concat(...files); + } + + static setupHandlers () { + const app = utils.getExpress() + console.log("Setting up handlers for local files") + app.get("/ciderlocal/:songs", (req: any, res: any) => { + const audio = atob(req.params.songs.replace(/_/g, '/').replace(/-/g, '+')); + //console.log('auss', audio) + let data = { + data: + LocalFiles.localSongs.filter((f: any) => audio.split(',').includes(f.id)) + }; + res.send(data); + }); + + app.get("/ciderlocalart/:songs", (req: any, res: any) => { + const audio = req.params.songs; + // metadata.common.picture[0].data.toString('base64') + let data = + LocalFiles.localSongsArts.filter((f: any) => f.id == audio); + res.status(200).send(Buffer.from(data[0]?.url, 'base64')); + }); + + return app + } +} \ No newline at end of file diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index a7ccc81c..86638d0e 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -1074,7 +1074,7 @@ const app = new Vue({ this.checkForThemeUpdates() } - ipcRenderer.send("scanLibrary",app.cfg.libraryPrefs.localPaths) + ipcRenderer.invoke("scanLibrary") }, showFoo(querySelector, time) { clearTimeout(this.idleTimer); diff --git a/src/renderer/views/components/pathmenu.ejs b/src/renderer/views/components/pathmenu.ejs index 560bc1e4..05e6db0a 100644 --- a/src/renderer/views/components/pathmenu.ejs +++ b/src/renderer/views/components/pathmenu.ejs @@ -53,12 +53,12 @@ } } this.$root.cfg.libraryPrefs.localPaths = this.folders; - ipcRenderer.send("scanLibrary",app.cfg.libraryPrefs.localPaths) + ipcRenderer.invoke("scanLibrary") }, remove(dir){ this.folders = this.folders.filter(item => item !== dir) this.$root.cfg.libraryPrefs.localPaths = this.folders; - ipcRenderer.send("scanLibrary",app.cfg.libraryPrefs.localPaths) + ipcRenderer.invoke("scanLibrary") } } }); diff --git a/tsconfig.json b/tsconfig.json index f9e5503c..c1b41500 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,6 +13,7 @@ "paths": { "*": ["node_modules/*"] }, + "skipLibCheck": true, "allowSyntheticDefaultImports": true, "typeRoots": [ "node_modules/musickit-typescript", From 1cb957c1abf468d4a8601b2df46bdb2da5240058 Mon Sep 17 00:00:00 2001 From: booploops <49113086+booploops@users.noreply.github.com> Date: Mon, 27 Jun 2022 15:31:35 -0700 Subject: [PATCH 098/289] removed dupe --- src/main/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/index.ts b/src/main/index.ts index a5a2de99..4c13a1a8 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -13,9 +13,6 @@ import {BrowserWindow} from "./base/browserwindow"; import {init as Sentry} from "@sentry/electron"; import {RewriteFrames} from "@sentry/integrations"; import {components, ipcMain} from "electron" -import {ProviderDB} from "./providers/local/db"; - -ProviderDB.init() // Analytics for debugging fun yeah. Sentry({ From 2da91c6623dd5fab73e3ba4ad5ad923019ae1fe8 Mon Sep 17 00:00:00 2001 From: booploops <49113086+booploops@users.noreply.github.com> Date: Mon, 27 Jun 2022 15:35:11 -0700 Subject: [PATCH 099/289] added caching headers --- src/main/providers/local/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/providers/local/index.ts b/src/main/providers/local/index.ts index 1c95e0f3..fe12f368 100644 --- a/src/main/providers/local/index.ts +++ b/src/main/providers/local/index.ts @@ -112,6 +112,11 @@ export class LocalFiles { app.get("/ciderlocalart/:songs", (req: any, res: any) => { const audio = req.params.songs; // metadata.common.picture[0].data.toString('base64') + + res.setHeader('Cache-Control', 'public, max-age=31536000'); + res.setHeader('Expires', new Date(Date.now() + 31536000).toUTCString()); + res.setHeader('Content-Type', 'image/jpeg'); + let data = LocalFiles.localSongsArts.filter((f: any) => f.id == audio); res.status(200).send(Buffer.from(data[0]?.url, 'base64')); From d103462920e3496dcab296fb0371e4172df5d5bb Mon Sep 17 00:00:00 2001 From: vapormusic Date: Tue, 28 Jun 2022 09:01:04 +0700 Subject: [PATCH 100/289] fix --- src/renderer/views/components/fullscreen.ejs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/views/components/fullscreen.ejs b/src/renderer/views/components/fullscreen.ejs index 66babdd8..812e7ded 100644 --- a/src/renderer/views/components/fullscreen.ejs +++ b/src/renderer/views/components/fullscreen.ejs @@ -137,8 +137,8 @@ v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
- - +
+
From 8c46111a3bb41da60e2cb7051e982bcfbb7d4a36 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Tue, 28 Jun 2022 09:17:07 +0700 Subject: [PATCH 101/289] add path menu to settings-window --- src/renderer/views/components/settings-window.ejs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/renderer/views/components/settings-window.ejs b/src/renderer/views/components/settings-window.ejs index baac65f4..d46c0720 100644 --- a/src/renderer/views/components/settings-window.ejs +++ b/src/renderer/views/components/settings-window.ejs @@ -228,6 +228,16 @@
+
+
+ {{'Local files path'}} +
+
+ +
+
@@ -1893,8 +1903,11 @@ app.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => { if (ok) ipcRenderer.invoke("relaunchApp") }) - } + }, /* keybindings */ + openLocalSongsPathMenu() { + app.modals.pathMenu = true + } } }) \ No newline at end of file From f0ceaae958cf19af86e9ac308ec4637082008147 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Wed, 29 Jun 2022 21:09:57 +0700 Subject: [PATCH 102/289] fix mxm for local --- src/main/base/browserwindow.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index 46023194..b3822530 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -667,7 +667,7 @@ export class BrowserWindow { callback({ redirectURL: `http://localhost:${this.clientPort}/apple-hls.js`, }); - } else if (details.url.includes("ciderlocal")) { + } else if (details.url.includes("ciderlocal") && !details.url.includes("https://apic-desktop.musixmatch.com") ) { let text = details.url.toString().includes('ids=') ? decodeURIComponent(details.url.toString()).split("?ids=")[1] : decodeURIComponent(details.url.toString().substring(details.url.toString().lastIndexOf('/') + 1)); //console.log('localurl',text) callback({ From d8720876857c61e030c8c07d3835d4a1e3f9aab9 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Thu, 30 Jun 2022 22:34:00 +0700 Subject: [PATCH 103/289] some test --- package.json | 2 ++ src/main/base/browserwindow.ts | 2 ++ src/main/providers/local/db/index.ts | 10 +++++++--- src/main/providers/local/index.ts | 25 +++++++++++++++++++------ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index e3c81145..64b8ec00 100644 --- a/package.json +++ b/package.json @@ -68,11 +68,13 @@ "node-ssdp": "^4.0.1", "pouchdb-adapter-leveldb": "^7.3.0", "pouchdb-node": "^7.3.0", + "pouchdb-upsert": "^2.2.0", "qrcode": "^1.5.0", "react": "^18.0.0", "react-dom": "^18.0.0", "run-script-os": "^1.1.6", "source-map-support": "^0.5.21", + "ts-md5": "^1.2.11", "v8-compile-cache": "^2.3.0", "wallpaper": "5.0.1", "ws": "^8.5.0", diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index b3822530..e4a53270 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -1185,6 +1185,8 @@ export class BrowserWindow { ipcMain.handle("scanLibrary", async (event, folders) => { + const oldmetadatalist = await LocalFiles.sendOldLibrary() + BrowserWindow.win.webContents.send('getUpdatedLocalList', oldmetadatalist); const metadatalist = await LocalFiles.scanLibrary() BrowserWindow.win.webContents.send('getUpdatedLocalList', metadatalist); }) diff --git a/src/main/providers/local/db/index.ts b/src/main/providers/local/db/index.ts index 0add4b93..89063d20 100644 --- a/src/main/providers/local/db/index.ts +++ b/src/main/providers/local/db/index.ts @@ -1,8 +1,12 @@ import * as PouchDB from 'pouchdb-node'; - +import {join} from 'path'; +import {app} from "electron"; +PouchDB.plugin(require('pouchdb-upsert')); export class ProviderDB { public static db: any = null - static async init() { - // ProviderDB.db = new PouchDB('tracks') + static init() { + if (ProviderDB.db == null){ + ProviderDB.db = new PouchDB(join(app.getPath('userData'), 'tracksdb')) + } } } \ No newline at end of file diff --git a/src/main/providers/local/index.ts b/src/main/providers/local/index.ts index fe12f368..6d0db3b5 100644 --- a/src/main/providers/local/index.ts +++ b/src/main/providers/local/index.ts @@ -1,16 +1,26 @@ -// import { ProviderDB } from "./db"; +import { ProviderDB } from "./db"; import * as path from 'path'; const { readdir } = require('fs').promises; import { utils } from '../../base/utils'; import * as mm from 'music-metadata'; +import {Md5} from 'ts-md5/dist/md5'; export class LocalFiles { static localSongs: any = []; static localSongsArts: any = []; - // public static DB = ProviderDB.db; - + public static DB = ProviderDB.db; + static async sendOldLibrary() { + ProviderDB.init() + let u = (await ProviderDB.db.allDocs({include_docs: true, + attachments: true})).rows.map((item: any)=>{return item.doc}) + this.localSongs = u; + console.log('sdadad', u.length) + return u; + } + static async scanLibrary() { + ProviderDB.init() let folders = utils.getStoreValue("libraryPrefs.localPaths") if (folders == null || folders.length == null || folders.length == 0) folders = ["D:\\Music"] console.log('folders', folders) @@ -30,16 +40,18 @@ export class LocalFiles { for (var audio of audiofiles) { try { const metadata = await mm.parseFile(audio); + let lochash = Md5.hashStr(audio) ?? numid; if (metadata != null) { let form = { - "id": "ciderlocal" + numid, + "id": "ciderlocal" + lochash, + "_id": "ciderlocal" + lochash, "type": "podcast-episodes", "href": audio, "attributes": { "artwork": { "width": 3000, "height": 3000, - "url": "/ciderlocalart/" + "ciderlocal" + numid, + "url": "/ciderlocalart/" + "ciderlocal" + lochash, }, "topics": [], "url": "", @@ -74,10 +86,11 @@ export class LocalFiles { } }; metadatalistart.push({ - id: "ciderlocal" + numid, + id: "ciderlocal" + lochash, url: metadata.common.picture != undefined ? metadata.common.picture[0].data.toString('base64') : "", }) numid += 1; + ProviderDB.db.putIfNotExists(form) metadatalist.push(form) } } catch (e) { } From 80d75fc0fc27df69d0d37854337a8fd5dc6298e8 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Thu, 30 Jun 2022 23:16:22 +0700 Subject: [PATCH 104/289] some fix --- src/renderer/style.css | 38 ++++++++++++++++++++--- src/renderer/views/components/sidebar.ejs | 11 ++++++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/renderer/style.css b/src/renderer/style.css index e1d1ddff..cbeee3c8 100644 --- a/src/renderer/style.css +++ b/src/renderer/style.css @@ -16458,7 +16458,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { display: flex; justify-content: center; align-items: center; - --chromeHeight1: 60px; + --chromeHeight1: 70px; } .fullscreen-view .app-content-container { width: 100%; @@ -16484,8 +16484,6 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { left: 0; right: 0; height: var(--chromeHeight1); - background: var(--color1); - backdrop-filter: var(--glassFilter); display: flex; justify-content: center; align-items: center; @@ -16496,8 +16494,9 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { border: 1px solid #323232; border-radius: 12px; display: flex; - height: 42px; + height: 55px; width: 90%; + backdrop-filter: var(--glassFilter); } .fullscreen-view .fs-header .top-nav-group .app-sidebar-item { background-color: #1e1e1e00; @@ -16510,6 +16509,8 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { margin: 0px; height: 100%; position: relative; + font-size: 1.1em; + font-weight: 500; } .fullscreen-view .fs-header .top-nav-group .app-sidebar-item:before { --dist: 1px; @@ -16850,10 +16851,25 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { font-size: 1.1em; font-weight: 380; } +.fullscreen-view .cd-mediaitem-list-item .duration { + font-size: 1.2em; +} .fullscreen-view .cd-mediaitem-list-item .artwork { width: 50px; height: 50px; } +.fullscreen-view .cd-btn-seeall { + font-size: 1.2em; +} +.fullscreen-view h1 { + font-size: 3em; +} +.fullscreen-view h3 { + font-size: 1.5rem; +} +.fullscreen-view .home-page .well.artistfeed-well { + height: 512px; +} .fullscreen-view .header-text { font-size: 3em; height: 3em; @@ -16891,6 +16907,20 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { gap: 16px; margin-top: 40px; } +.fullscreen-view .playlist-page .playlist-display .playlistInfo .playlist-hero { + transform: unset; +} +.fullscreen-view .artist-page .artist-header { + min-height: 60vh; +} +.fullscreen-view .artist-page .artist-image { + width: 20vh; + height: 20vh; + aspect-ratio: 1; +} +.fullscreen-view .artist-page.animated .artist-header { + min-height: 80vh; +} .fullscreen-view .playlist-page .playlist-body { flex: 1; } diff --git a/src/renderer/views/components/sidebar.ejs b/src/renderer/views/components/sidebar.ejs index d642b7c0..f91c9b06 100644 --- a/src/renderer/views/components/sidebar.ejs +++ b/src/renderer/views/components/sidebar.ejs @@ -138,7 +138,16 @@ > - + -