From 44b840eb0368c2e5b0754631c5b0b479e02c5a9f Mon Sep 17 00:00:00 2001 From: vapormusic Date: Wed, 19 Jan 2022 14:30:58 +0700 Subject: [PATCH 01/27] lastfm module (not working for now) --- src/main/index.ts | 4 +- src/main/plugins/lastfm.ts | 207 +++++++++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 src/main/plugins/lastfm.ts diff --git a/src/main/index.ts b/src/main/index.ts index 30ed265b..fcd03e28 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -31,9 +31,7 @@ electron.app.on('ready', () => { electron.components.whenReady().then(async () => { await Cider.createWindow() - plug.callPlugins('onReady', Cider); - - + plug.callPlugins('onReady', Cider); }) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts new file mode 100644 index 00000000..6469b4b9 --- /dev/null +++ b/src/main/plugins/lastfm.ts @@ -0,0 +1,207 @@ + +import * as electron from 'electron'; +import * as fs from 'fs'; +import {resolve} from 'path'; +const sessionPath = resolve(electron.app.getPath('userData'), 'session.json'), + apiCredentials = require('../../resources/lfmApiCredentials.json'), + LastfmAPI = require('lastfmapi'); + +export default class LastFMPlugin { + /** + * Private variables for interaction in plugins + */ + private _win: any; + private _app: any; + private _lastfm: any; + private authenticateFromFile() { + let sessionData = require(sessionPath) + console.log("[LastFM][authenticateFromFile] Logging in with Session Info.") + this._lastfm.setSessionCredentials(sessionData.name, sessionData.key) + console.log("[LastFM][authenticateFromFile] Logged in.") + } + + private authenticate() { + if (this._win.store.store.lastfm.auth_token) { + this._win.store.store.lastfm.enabled = true; + } + + if (!this._win.store.store.lastfm.enabled || !this._win.store.store.lastfm.auth_token) { + this._win.store.store.lastfm.enabled = false; + return + } + + const lfmAPI = new LastfmAPI({ + 'api_key': apiCredentials.key, + 'secret': apiCredentials.secret + }); + + this._lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false}); + + fs.stat(sessionPath, (err : any) => { + if (err) { + console.error("[LastFM][Session] Session file couldn't be opened or doesn't exist,", err) + console.log("[LastFM][Auth] Beginning authentication from configuration") + this._lastfm.authenticate(this._win.store.store.lastfm.auth_token, (err: any, session: any) => { + if (err) { + throw err; + } + console.log("[LastFM] Successfully obtained LastFM session info,", session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} + console.log("[LastFM] Saving session info to disk.") + let tempData = JSON.stringify(session) + fs.writeFile(sessionPath, tempData, (err: any) => { + if (err) + console.log("[LastFM][fs]", err) + else { + console.log("[LastFM][fs] File was written successfully.") + this.authenticateFromFile() + new electron.Notification({ + title: electron.app.getName(), + body: "Successfully logged into LastFM using Authentication Key." + }).show() + } + }) + }); + } else { + this.authenticateFromFile() + } + }) + } + + private async scrobbleSong(attributes : any) { + await new Promise(resolve => setTimeout(resolve, Math.round(attributes.durationInMillis * (this._win.store.store.lastfm.scrobble_after / 100)))); + const currentAttributes = attributes; + + if (!this._lastfm || this._lastfm.cachedAttributes === attributes ) { + return + } + + if (this._lastfm.cachedAttributes) { + if (this._lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return; + } + + if (currentAttributes.status && currentAttributes === attributes) { + if (fs.existsSync(sessionPath)) { + // Scrobble playing song. + if (attributes.status === true) { + this._lastfm.track.scrobble({ + 'artist': this.filterArtistName(attributes.artistName), + 'track': attributes.name, + 'album': attributes.albumName, + 'albumArtist': this.filterArtistName(attributes.artistName), + 'timestamp': new Date().getTime() / 1000 + }, function (err: any, scrobbled: any) { + if (err) { + return console.error('[LastFM] An error occurred while scrobbling', err); + } + + console.log('[LastFM] Successfully scrobbled: ', scrobbled); + }); + this._lastfm.cachedAttributes = attributes + } + } else { + this.authenticate(); + } + } else { + return console.log('[LastFM] Did not add ', attributes.name , '—' , this.filterArtistName(attributes.artistName), 'because now playing a other song.'); + } + } + + private filterArtistName(artist :any) { + if (!this._win.store.store.lastfm.enabledRemoveFeaturingArtists) return artist; + + artist = artist.split(' '); + if (artist.includes('&')) { + artist.length = artist.indexOf('&'); + } + if (artist.includes('and')) { + artist.length = artist.indexOf('and'); + } + artist = artist.join(' '); + if (artist.includes(',')) { + artist = artist.split(',') + artist = artist[0] + } + return artist.charAt(0).toUpperCase() + artist.slice(1); + } + + private updateNowPlayingSong(attributes : any) { + if (!this._lastfm ||this._lastfm.cachedNowPlayingAttributes === attributes || !this._win.store.store.lastfm.NowPlaying) { + return + } + + if (this._lastfm.cachedNowPlayingAttributes) { + if (this._lastfm.cachedNowPlayingAttributes.playParams.id === attributes.playParams.id) return; + } + + if (fs.existsSync(sessionPath)) { + // update Now Playing + if (attributes.status === true) { + this._lastfm.track.updateNowPlaying({ + 'artist': this.filterArtistName(attributes.artistName), + 'track': attributes.name, + 'album': attributes.albumName, + 'albumArtist': this.filterArtistName(attributes.artistName) + }, function (err : any, nowPlaying :any) { + if (err) { + return console.error('[LastFM] An error occurred while updating nowPlayingSong', err); + } + + console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying); + }); + this._lastfm.cachedNowPlayingAttributes = attributes + } + + } else { + this.authenticate() + } + } + + /** + * Base Plugin Details (Eventually implemented into a GUI in settings) + */ + public name: string = 'LastFMPlugin'; + public description: string = 'LastFM plugin for Cider'; + public version: string = '0.0.1'; + public author: string = 'vapormusic / Cider Collective'; + + /** + * Runs on plugin load (Currently run on application start) + */ + constructor(app: any) { + this._app = app; + } + + /** + * Runs on app ready + */ + onReady(win: any): void { + this._win = win; + this.authenticate() + } + + /** + * Runs on app stop + */ + onBeforeQuit(): void { + console.log('Example plugin stopped'); + } + + /** + * Runs on playback State Change + * @param attributes Music Attributes (attributes.state = current state) + */ + onPlaybackStateDidChange(attributes: object): void { + this.scrobbleSong(attributes) + this.updateNowPlayingSong(attributes) + } + + /** + * Runs on song change + * @param attributes Music Attributes + */ + onNowPlayingItemDidChange(attributes: object): void { + this.scrobbleSong(attributes) + this.updateNowPlayingSong(attributes) + } + +} From 5a661f3c01ad2e741101439351a837fb39ecccd9 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Wed, 19 Jan 2022 15:22:19 +0700 Subject: [PATCH 02/27] Revert "lastfm module (not working for now)" This reverts commit 44b840eb0368c2e5b0754631c5b0b479e02c5a9f. --- src/main/index.ts | 4 +- src/main/plugins/lastfm.ts | 207 ------------------------------------- 2 files changed, 3 insertions(+), 208 deletions(-) delete mode 100644 src/main/plugins/lastfm.ts diff --git a/src/main/index.ts b/src/main/index.ts index fcd03e28..30ed265b 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -31,7 +31,9 @@ electron.app.on('ready', () => { electron.components.whenReady().then(async () => { await Cider.createWindow() - plug.callPlugins('onReady', Cider); + plug.callPlugins('onReady', Cider); + + }) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts deleted file mode 100644 index 6469b4b9..00000000 --- a/src/main/plugins/lastfm.ts +++ /dev/null @@ -1,207 +0,0 @@ - -import * as electron from 'electron'; -import * as fs from 'fs'; -import {resolve} from 'path'; -const sessionPath = resolve(electron.app.getPath('userData'), 'session.json'), - apiCredentials = require('../../resources/lfmApiCredentials.json'), - LastfmAPI = require('lastfmapi'); - -export default class LastFMPlugin { - /** - * Private variables for interaction in plugins - */ - private _win: any; - private _app: any; - private _lastfm: any; - private authenticateFromFile() { - let sessionData = require(sessionPath) - console.log("[LastFM][authenticateFromFile] Logging in with Session Info.") - this._lastfm.setSessionCredentials(sessionData.name, sessionData.key) - console.log("[LastFM][authenticateFromFile] Logged in.") - } - - private authenticate() { - if (this._win.store.store.lastfm.auth_token) { - this._win.store.store.lastfm.enabled = true; - } - - if (!this._win.store.store.lastfm.enabled || !this._win.store.store.lastfm.auth_token) { - this._win.store.store.lastfm.enabled = false; - return - } - - const lfmAPI = new LastfmAPI({ - 'api_key': apiCredentials.key, - 'secret': apiCredentials.secret - }); - - this._lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false}); - - fs.stat(sessionPath, (err : any) => { - if (err) { - console.error("[LastFM][Session] Session file couldn't be opened or doesn't exist,", err) - console.log("[LastFM][Auth] Beginning authentication from configuration") - this._lastfm.authenticate(this._win.store.store.lastfm.auth_token, (err: any, session: any) => { - if (err) { - throw err; - } - console.log("[LastFM] Successfully obtained LastFM session info,", session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} - console.log("[LastFM] Saving session info to disk.") - let tempData = JSON.stringify(session) - fs.writeFile(sessionPath, tempData, (err: any) => { - if (err) - console.log("[LastFM][fs]", err) - else { - console.log("[LastFM][fs] File was written successfully.") - this.authenticateFromFile() - new electron.Notification({ - title: electron.app.getName(), - body: "Successfully logged into LastFM using Authentication Key." - }).show() - } - }) - }); - } else { - this.authenticateFromFile() - } - }) - } - - private async scrobbleSong(attributes : any) { - await new Promise(resolve => setTimeout(resolve, Math.round(attributes.durationInMillis * (this._win.store.store.lastfm.scrobble_after / 100)))); - const currentAttributes = attributes; - - if (!this._lastfm || this._lastfm.cachedAttributes === attributes ) { - return - } - - if (this._lastfm.cachedAttributes) { - if (this._lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return; - } - - if (currentAttributes.status && currentAttributes === attributes) { - if (fs.existsSync(sessionPath)) { - // Scrobble playing song. - if (attributes.status === true) { - this._lastfm.track.scrobble({ - 'artist': this.filterArtistName(attributes.artistName), - 'track': attributes.name, - 'album': attributes.albumName, - 'albumArtist': this.filterArtistName(attributes.artistName), - 'timestamp': new Date().getTime() / 1000 - }, function (err: any, scrobbled: any) { - if (err) { - return console.error('[LastFM] An error occurred while scrobbling', err); - } - - console.log('[LastFM] Successfully scrobbled: ', scrobbled); - }); - this._lastfm.cachedAttributes = attributes - } - } else { - this.authenticate(); - } - } else { - return console.log('[LastFM] Did not add ', attributes.name , '—' , this.filterArtistName(attributes.artistName), 'because now playing a other song.'); - } - } - - private filterArtistName(artist :any) { - if (!this._win.store.store.lastfm.enabledRemoveFeaturingArtists) return artist; - - artist = artist.split(' '); - if (artist.includes('&')) { - artist.length = artist.indexOf('&'); - } - if (artist.includes('and')) { - artist.length = artist.indexOf('and'); - } - artist = artist.join(' '); - if (artist.includes(',')) { - artist = artist.split(',') - artist = artist[0] - } - return artist.charAt(0).toUpperCase() + artist.slice(1); - } - - private updateNowPlayingSong(attributes : any) { - if (!this._lastfm ||this._lastfm.cachedNowPlayingAttributes === attributes || !this._win.store.store.lastfm.NowPlaying) { - return - } - - if (this._lastfm.cachedNowPlayingAttributes) { - if (this._lastfm.cachedNowPlayingAttributes.playParams.id === attributes.playParams.id) return; - } - - if (fs.existsSync(sessionPath)) { - // update Now Playing - if (attributes.status === true) { - this._lastfm.track.updateNowPlaying({ - 'artist': this.filterArtistName(attributes.artistName), - 'track': attributes.name, - 'album': attributes.albumName, - 'albumArtist': this.filterArtistName(attributes.artistName) - }, function (err : any, nowPlaying :any) { - if (err) { - return console.error('[LastFM] An error occurred while updating nowPlayingSong', err); - } - - console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying); - }); - this._lastfm.cachedNowPlayingAttributes = attributes - } - - } else { - this.authenticate() - } - } - - /** - * Base Plugin Details (Eventually implemented into a GUI in settings) - */ - public name: string = 'LastFMPlugin'; - public description: string = 'LastFM plugin for Cider'; - public version: string = '0.0.1'; - public author: string = 'vapormusic / Cider Collective'; - - /** - * Runs on plugin load (Currently run on application start) - */ - constructor(app: any) { - this._app = app; - } - - /** - * Runs on app ready - */ - onReady(win: any): void { - this._win = win; - this.authenticate() - } - - /** - * Runs on app stop - */ - onBeforeQuit(): void { - console.log('Example plugin stopped'); - } - - /** - * Runs on playback State Change - * @param attributes Music Attributes (attributes.state = current state) - */ - onPlaybackStateDidChange(attributes: object): void { - this.scrobbleSong(attributes) - this.updateNowPlayingSong(attributes) - } - - /** - * Runs on song change - * @param attributes Music Attributes - */ - onNowPlayingItemDidChange(attributes: object): void { - this.scrobbleSong(attributes) - this.updateNowPlayingSong(attributes) - } - -} From d2973353f6569d07b027ce1ec1c48773954e74ad Mon Sep 17 00:00:00 2001 From: Maikiwi Date: Wed, 19 Jan 2022 00:31:35 -0800 Subject: [PATCH 03/27] Song duration alignment --- src/renderer/style.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/style.less b/src/renderer/style.less index 1630e9d9..eb48e4ed 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -1025,7 +1025,7 @@ input[type=range].web-slider::-webkit-slider-runnable-track { height: 1.2em; line-height: 1.3em; overflow: hidden; - margin: 0 0 0.5em; + margin: 0 0 0 0.25em; } .app-chrome .app-chrome-item > .app-playback-controls .song-artist { @@ -4307,7 +4307,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { height: 1.2em; line-height: 1.3em; overflow: hidden; - margin: 0 0 0.5em; + margin: 0 0 0 0.25em; } &:hover { From d2f384eecba711b91111ff222c0a35ebfcf71347 Mon Sep 17 00:00:00 2001 From: booploops <49113086+booploops@users.noreply.github.com> Date: Wed, 19 Jan 2022 01:38:28 -0800 Subject: [PATCH 04/27] app will now reload on after logging in --- src/renderer/index.js | 9 ++++++++- src/renderer/views/main.ejs | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/renderer/index.js b/src/renderer/index.js index 611d27d8..870a3374 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -486,9 +486,12 @@ const app = new Vue({ let self = this clearTimeout(this.hangtimer) this.mk = MusicKit.getInstance() + let needsReload = (typeof localStorage["music.ampwebplay.media-user-token"] == "undefined") this.mk.authorize().then(() => { self.mkIsReady = true - //document.location.reload() + if(needsReload) { + document.location.reload() + } }) this.$forceUpdate() if (this.isDev) { @@ -708,6 +711,10 @@ const app = new Vue({ this.$forceUpdate() }, 500) }, + unauthorize() { + this.mk.unauthorize() + document.location.reload() + }, getAppClasses() { if (this.cfg.advanced.experiments.includes('compactui')) { return { compact: true } diff --git a/src/renderer/views/main.ejs b/src/renderer/views/main.ejs index fb0ea694..6c65a2d6 100644 --- a/src/renderer/views/main.ejs +++ b/src/renderer/views/main.ejs @@ -252,7 +252,7 @@ - From 4dc4999cca11452c606fff351380e71a67a36583 Mon Sep 17 00:00:00 2001 From: booploops <49113086+booploops@users.noreply.github.com> Date: Wed, 19 Jan 2022 03:31:39 -0800 Subject: [PATCH 05/27] testing podcasts --- src/renderer/views/main.ejs | 31 +++++++++++++++++++++------ src/renderer/views/pages/podcasts.ejs | 27 +++++++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 src/renderer/views/pages/podcasts.ejs diff --git a/src/renderer/views/main.ejs b/src/renderer/views/main.ejs index 6c65a2d6..61628029 100644 --- a/src/renderer/views/main.ejs +++ b/src/renderer/views/main.ejs @@ -83,9 +83,11 @@
+ :style="[mk.nowPlayingItem['attributes']['contentRating'] == 'explicit' ? {'margin-left' : '23px'} : {'margin-left' : '0px'} ]"> {{ mk.nowPlayingItem["attributes"]["name"] }} -
+
@@ -94,7 +96,8 @@ {{ mk.nowPlayingItem["attributes"]["artistName"] }}
+ @click="getNowPlayingItemDetailed('album')" + v-if="mk.nowPlayingItem['attributes']['albumName'] != ''">
{{"—"}}
{{(mk.nowPlayingItem["attributes"]["albumName"]) ? (mk.nowPlayingItem["attributes"]["albumName"]) : "" }} @@ -146,9 +149,9 @@
- + @click="invokeDrawer('lyrics')"> + +
@@ -196,6 +199,8 @@ page="browse"> +
Library
@@ -337,6 +342,14 @@
+ + + + + +
- - - -
- - - -
From 2440907eeb8fd3cc7ffd7fdd0dca07f9f0cebb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20G=C3=BCm=C3=BC=C5=9F?= <10urgumus@gmail.com> Date: Thu, 20 Jan 2022 04:51:10 +0300 Subject: [PATCH 20/27] little bit bigger.... to go well with the new icons --- src/renderer/style.less | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/style.less b/src/renderer/style.less index b92149e5..acf09dae 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -2026,9 +2026,9 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { .md-btn { background: rgba(100, 100, 100, 0.5); - padding: 4px 12px; + padding: 6px 12px; border-radius: 4px; - font-size: 13px; + font-size: 16px; border: 1px solid rgb(100 100 100 / 35%); color: #eee; box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.3), 0px 1px 1px rgba(0, 0, 0, 0.4); From 9f3dceaa215cee3a8dab384cbfc9e60278077269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20G=C3=BCm=C3=BC=C5=9F?= <10urgumus@gmail.com> Date: Thu, 20 Jan 2022 04:51:32 +0300 Subject: [PATCH 21/27] delete the "@" symbol from username I don't think this symbol needs to be there at all. it was bothering me so i removed it --- src/renderer/views/main.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/views/main.ejs b/src/renderer/views/main.ejs index e6709332..81fe3dd2 100644 --- a/src/renderer/views/main.ejs +++ b/src/renderer/views/main.ejs @@ -315,7 +315,7 @@ From 56bf8b478e5d6f6106ed18485cb94f565e9c146f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Onur=20G=C3=BCm=C3=BC=C5=9F?= <10urgumus@gmail.com> Date: Thu, 20 Jan 2022 04:51:52 +0300 Subject: [PATCH 22/27] png's for the list view icons --- src/renderer/assets/feather/x-circlePng.png | Bin 0 -> 4607 bytes src/renderer/assets/playPng.png | Bin 0 -> 3953 bytes src/renderer/assets/shufflePng.png | Bin 0 -> 3036 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/renderer/assets/feather/x-circlePng.png create mode 100644 src/renderer/assets/playPng.png create mode 100644 src/renderer/assets/shufflePng.png diff --git a/src/renderer/assets/feather/x-circlePng.png b/src/renderer/assets/feather/x-circlePng.png new file mode 100644 index 0000000000000000000000000000000000000000..9b0f9ca2685ace5b8c57d962351b744209bafc7e GIT binary patch literal 4607 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 literal 0 HcmV?d00001 diff --git a/src/renderer/assets/playPng.png b/src/renderer/assets/playPng.png new file mode 100644 index 0000000000000000000000000000000000000000..8ece27c0f3dc2004d8a55f08c7bdb2113647af9b GIT binary patch literal 3953 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 YncUvEnHm}JCqTr}*3G8+fbXUM0CPQe=l}o! literal 0 HcmV?d00001 diff --git a/src/renderer/assets/shufflePng.png b/src/renderer/assets/shufflePng.png new file mode 100644 index 0000000000000000000000000000000000000000..982547d6c3489200a61e1181fdd315849bcb4162 GIT binary patch literal 3036 zcmZ{mX*|@87RUdDga%P|(jt$o8B1X%lB_Y=l4Zz@&{#4Uld=7ld`6T%O061=DdfkStYwW7z zCDWaH4LQTnGN((?>el(^0IMrP0wf4v|ymFDj$sKA%Vb zVqJ5#lMm@unT4|Z`w3j_y<~H5ec#|(E-oido|P$c(d}p}ju#nRrX`1&7^cGI)?ciW z(DBf*l7j<6{<#OG;iWX@#(elMmoAh*8Z~OY#~=?sBhLF2stjf&lz8}7HInTqJ}Q`|eDRpmL;=E~HT$II_5oS>;u>FQU0 zBBekr@8j}u*!UwQfgV*d#mK1AHqEKDv5&pK5QWcty)4>-GTre#3!uJ2_OV;bRpi}S zydMP#Px?m=dXi77XaboypEd^WedSw^lRT13ba~q-_oFzAx#>Kwa1ddavIhNushk2DaJ)z!gkBRPi-;ck^JzykU(i2!P*uy0ke43f|WlFh8mvgyFosr(A6IUFo+6*n=di`P4Yr{}HxIx5TiBf>1(ew$G-0p)!=Y;3YD9U!o*ukJ^dj!q;h1$- zQcFGWFCHlx6rEB?b0Zzr2neJEs3~jp{`l4GH{<)6mUL1!1=h9NuIne|=`h2{M?{n| zn__|$Y1K(OY2SRLc9m|-)hbDOcsS=Ocq>qf*2EgB(0ck4nhh};F3rdiLKNOVK&(}r z-&>mewrHUgmH$3m7UY%MK=@@2T_yX>@9>XiZi>>p?93txhA1wLndDAkaa|=5U5BdO zPp#(fF*|l82+9r}j zc_NipM@Ls;#@T2C1YaUf6CGPi{F8GD_v(wQ9edNs0QS_1*-I-INZNCx={t_#$Ze(&N@3^ zm#`%Nni#}*+#&5gxad;gJR*Z$xlH_x;;8;^IBw72u6}OTw`jHT&)wAxH@Z}kHtSU` zl@ul)Lg<=9=`X1o^y_)1cEh7mx+An8T(o;`0yv#<@oTgZpU60_&lxzWyv1;z4uC7VUb_T@n^`IV#ix%nlr)CqL@4+%pz(0kd+HKY4{ z9xEde?|4|^`?*bf6z8(zwkBR+e!H67;N_bq--G?J4b?aaDk~>#w>a=qUV!jL8IjF$ zc#_9FB3uVThr{VAv1_+mwdgptbl=vd4AE;Ux4bVT#R>T(PU2J_Kg7n9LpJ67wmy<| zrTQB_+-k0U;3ae1r~6>JsOpWmDBlKtUr8Vi-@aHem2kt`b?Fw_8S(%t85I5&tri5O zX<@N}Pprjge!wx=rV=+H$+X~i-Zg~odU#G)Z~dqOTwJX%MbbRdarzuGQLTM|pS{1Jg) z@chgf;M#w3j@+7YzT0eUdwj52e7;9xavpwW7dc$0bsI)}H;n2eaRF&7v`LqnZ1xjb0{Y^H!ZabshF+v4;!__#)&)itVGYXz+x=#lY2|pE+ptDig*{3eXqxc zDS;LShAALfo3h3(`ILYV=q1xH7|SbbP${siVj z7ng6Q{Y2U>#3GyV@rf9CR7XkmjBxd-^E<~BNoU9I;+aDGjX(O7_TL#;QP6(*zUh2e5D5BjNPyPdx!T_K0>aIv1d%dKm_f8|wl+Q* zm(L^pcsDODIw^F%t;qN+{HY{eJL<}q(Vbb*I34j6lzfy4z z6DN1BqSq%`Hd@hh;1qkw*rrMGT0*}YNt4H?65^no+U;Pb91iwzc<`(lWol>i{ literal 0 HcmV?d00001 From 140d715498e28c3c336b2b97f02ec028f7d3decb Mon Sep 17 00:00:00 2001 From: vapormusic Date: Thu, 20 Jan 2022 09:12:26 +0700 Subject: [PATCH 23/27] Update style.less --- src/renderer/style.less | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/renderer/style.less b/src/renderer/style.less index acf09dae..735c1ee1 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -2087,6 +2087,15 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { align-self: center; } +.md-ico-add { + content:url("./assets/feather/plus.svg"); + width: 16px; + height: 16px; + margin-right: 1px; + margin-bottom: -1.5px; + align-self: center; +} + .md-select { width: 100%; padding: 6px; From 39a57621380dea138348701b12de61a092302b81 Mon Sep 17 00:00:00 2001 From: vapormusic Date: Thu, 20 Jan 2022 09:14:32 +0700 Subject: [PATCH 24/27] Update cider-playlist.ejs --- src/renderer/views/pages/cider-playlist.ejs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/views/pages/cider-playlist.ejs b/src/renderer/views/pages/cider-playlist.ejs index 0e8de09b..e9049d0a 100644 --- a/src/renderer/views/pages/cider-playlist.ejs +++ b/src/renderer/views/pages/cider-playlist.ejs @@ -71,7 +71,7 @@ Shuffle