From 02ba9a7c4249bdfe14ab8d276ef791472be4469d Mon Sep 17 00:00:00 2001 From: booploops <49113086+booploops@users.noreply.github.com> Date: Sat, 19 Feb 2022 01:13:22 -0800 Subject: [PATCH] Added resume from history --- src/main/base/store.ts | 3 +- src/renderer/index.js | 638 ++++++++++++++------------ src/renderer/views/pages/settings.ejs | 17 + 3 files changed, 354 insertions(+), 304 deletions(-) diff --git a/src/main/base/store.ts b/src/main/base/store.ts index 7a15af84..4436b3fc 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -12,7 +12,8 @@ export class Store { "discord_rpc_clear_on_pause": true, "language": "en_US", // electron.app.getLocale().replace('-', '_') this can be used in future "playbackNotifications": true, - "update_branch": "innolab" + "update_branch": "main", + "resumeOnStartupBehavior": "local" }, "home": { "followedArtists": [], diff --git a/src/renderer/index.js b/src/renderer/index.js index 39b9226d..61a2dc3a 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -20,7 +20,7 @@ const CiderFrontAPI = { MenuEntry: function () { this.id = "" this.name = "" - this.onClick = ()=>{} + this.onClick = () => { } } }, AddMenuEntry(entry) { @@ -103,7 +103,7 @@ const app = new Vue({ radio: { personal: [] }, - mklang : 'en', + mklang: 'en', webview: { url: "", title: "", @@ -134,7 +134,7 @@ const app = new Vue({ sorting: "name", sortOrder: "asc", listing: [], - meta: {total: 0, progress: 0}, + meta: { total: 0, progress: 0 }, search: "", displayListing: [], downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library @@ -150,7 +150,7 @@ const app = new Vue({ sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page listing: [], - meta: {total: 0, progress: 0}, + meta: { total: 0, progress: 0 }, search: "", displayListing: [], downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library @@ -166,7 +166,7 @@ const app = new Vue({ sorting: ["dateAdded", "name"], // [0] = recentlyadded page, [1] = albums page sortOrder: ["desc", "asc"], // [0] = recentlyadded page, [1] = albums page listing: [], - meta: {total: 0, progress: 0}, + meta: { total: 0, progress: 0 }, search: "", displayListing: [], downloadState: 0 // 0 = not started, 1 = in progress, 2 = complete, 3 = empty library @@ -215,7 +215,7 @@ const app = new Vue({ "attributes": { "name": "Cider User", "handle": "CiderUser", - "artwork": {"url": "./assets/logocut.png"} + "artwork": { "url": "./assets/logocut.png" } } }, menuOpened: false, @@ -265,7 +265,7 @@ const app = new Vue({ headerItems: {} } }, - pauseButtonTimer : null + pauseButtonTimer: null }, watch: { cfg: { @@ -292,7 +292,7 @@ const app = new Vue({ }, methods: { songLinkShare(amUrl) { - notyf.open({type: "info", message: app.getLz('term.song.link.generate')}) + notyf.open({ type: "info", message: app.getLz('term.song.link.generate') }) let self = this httpRequest = new XMLHttpRequest(); httpRequest.open('GET', `https://api.song.link/v1-alpha.1/links?url=${amUrl}&userCountry=US`, true); @@ -313,7 +313,7 @@ const app = new Vue({ mainMenuVisibility(val) { if (val) { (this.mk.isAuthorized) ? this.chrome.menuOpened = !this.chrome.menuOpened : false; - if (!this.mk.isAuthorized){ + if (!this.mk.isAuthorized) { this.mk.authorize() } } else { @@ -340,16 +340,17 @@ const app = new Vue({ }, getLz(message, options = {}) { if (this.lz[message]) { - if(options["count"] ) { - if (typeof this.lz[message] === "object"){ - let type = window.fastPluralRules.getPluralFormNameForCardinalByLocale(this.cfg.general.language.replace("_","-"),options["count"]); + if (options["count"]) { + if (typeof this.lz[message] === "object") { + let type = window.fastPluralRules.getPluralFormNameForCardinalByLocale(this.cfg.general.language.replace("_", "-"), options["count"]); return this.lz[message][type] ?? ((this.lz[message])[Object.keys(this.lz[message])[0]] ?? this.lz[message]) } else { // fallback English plural forms ( old i18n ) if (options["count"] > 1) { - return this.lz[message+ "s"] ?? this.lz[message]} else { return this.lz[message] ?? this.lz[message+ "s"]} + return this.lz[message + "s"] ?? this.lz[message] + } else { return this.lz[message] ?? this.lz[message + "s"] } } - } else if(typeof this.lz[message] === "object") { + } else if (typeof this.lz[message] === "object") { return (this.lz[message])[Object.keys(this.lz[message])[0]] } return this.lz[message] @@ -384,7 +385,7 @@ const app = new Vue({ }, async showSocialListeningTo() { let contentIds = Object.keys(app.socialBadges.badgeMap) - app.showCollection({data: this.socialBadges.mediaItems}, "Friends Listening To", "albums") + app.showCollection({ data: this.socialBadges.mediaItems }, "Friends Listening To", "albums") if (this.socialBadges.mediaItemDLState == 1 || this.socialBadges.mediaItemDLState == 2) { return } @@ -495,7 +496,7 @@ const app = new Vue({ self.selectedMediaItems[i].kind = "albums" let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`); let ids = res.data.data.map(function (i) { - return {id: i.id, type: i.type} + return { id: i.id, type: i.type } }) pl_items = pl_items.concat(ids) } else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") { @@ -508,7 +509,7 @@ const app = new Vue({ self.selectedMediaItems[i].kind = "library-albums" let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`); let ids = res.data.data.map(function (i) { - return {id: i.id, type: i.type} + return { id: i.id, type: i.type } }) pl_items = pl_items.concat(ids) } else { @@ -535,7 +536,7 @@ const app = new Vue({ self.selectedMediaItems[i].kind = "albums" let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`); let ids = res.data.data.map(function (i) { - return {id: i.id, type: i.type} + return { id: i.id, type: i.type } }) pl_items = pl_items.concat(ids) } else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") { @@ -548,7 +549,7 @@ const app = new Vue({ self.selectedMediaItems[i].kind = "library-albums" let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`); let ids = res.data.data.map(function (i) { - return {id: i.id, type: i.type} + return { id: i.id, type: i.type } }) pl_items = pl_items.concat(ids) } else { @@ -562,13 +563,13 @@ const app = new Vue({ this.modals.addToPlaylist = false await app.mk.api.v3.music( `/v1/me/library/playlists/${playlist_id}/tracks`, {}, { - fetchOptions: { - method: "POST", - body: JSON.stringify({ - data: pl_items - }) - } + fetchOptions: { + method: "POST", + body: JSON.stringify({ + data: pl_items + }) } + } ).then(() => { if (this.page == 'playlist_' + this.showingPlaylist.id) { this.getPlaylistFromID(this.showingPlaylist.id, true) @@ -622,7 +623,7 @@ const app = new Vue({ "attributes": { "name": "Cider User", "handle": "CiderUser", - "artwork": {"url": "./assets/logocut.png"} + "artwork": { "url": "./assets/logocut.png" } } } } @@ -664,55 +665,84 @@ const app = new Vue({ app.cfg.audio.quality = "HIGH" } - // load last played track - try { - let lastItem = window.localStorage.getItem("currentTrack") - let time = window.localStorage.getItem("currentTime") - let queue = window.localStorage.getItem("currentQueue") - if (lastItem != null) { - lastItem = JSON.parse(lastItem) - let kind = lastItem.attributes.playParams.kind; - let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; - app.mk.setQueue({ - [truekind]: [lastItem.attributes.playParams.id], - parameters : {l : app.mklang} - }) - app.mk.mute() - setTimeout(() => { - app.mk.play().then(() => { - app.mk.pause().then(() => { - if (time != null) { - app.mk.seekToTime(time) - } - app.mk.unmute() - if (queue != null) { - queue = JSON.parse(queue) - if (queue && queue.length > 0) { - let ids = queue.map(e => (e.playParams ? e.playParams.id : (e.attributes.playParams ? e.attributes.playParams.id : ''))) - let i = 0; - if (ids.length > 0) { - for (id of ids) { - if (!(i == 0 && ids[0] == lastItem.attributes.playParams.id)) { - try { - app.mk.playLater({songs: [id]}) - } catch (err) { + switch (this.cfg.general.resumeOnStartupBehavior) { + default: + case "local": + // load last played track + try { + let lastItem = window.localStorage.getItem("currentTrack") + let time = window.localStorage.getItem("currentTime") + let queue = window.localStorage.getItem("currentQueue") + if (lastItem != null) { + lastItem = JSON.parse(lastItem) + let kind = lastItem.attributes.playParams.kind; + let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; + app.mk.setQueue({ + [truekind]: [lastItem.attributes.playParams.id], + parameters: { l: app.mklang } + }) + app.mk.mute() + setTimeout(() => { + app.mk.play().then(() => { + app.mk.pause().then(() => { + if (time != null) { + app.mk.seekToTime(time) + } + app.mk.unmute() + if (queue != null) { + queue = JSON.parse(queue) + if (queue && queue.length > 0) { + let ids = queue.map(e => (e.playParams ? e.playParams.id : (e.attributes.playParams ? e.attributes.playParams.id : ''))) + let i = 0; + if (ids.length > 0) { + for (id of ids) { + if (!(i == 0 && ids[0] == lastItem.attributes.playParams.id)) { + try { + app.mk.playLater({ songs: [id] }) + } catch (err) { + } + } + i++; } } - i++; } } - } - } - }) + }) + }) + }, 1500) + + } + + } catch (e) { + console.log(e) + } + break; + case "history": + let history = await app.mk.api.v3.music(`/v1/me/recent/played/tracks`, { l : app.mklang}) + if (history.data.data.length > 0) { + let lastItem = history.data.data[0] + let kind = lastItem.attributes.playParams.kind; + let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; + app.mk.setQueue({ + [truekind]: [lastItem.attributes.playParams.id], + parameters: { l: app.mklang } }) - }, 1500) + app.mk.mute() + setTimeout(() => { + app.mk.play().then(() => { + app.mk.pause().then(() => { + app.mk.unmute() + }) + }) + }, 1500) + } + + break; + case "disabled": - } - - } catch (e) { - console.log(e) + break; } MusicKit.getInstance().videoContainerElement = document.getElementById("apple-music-video-player") @@ -721,16 +751,16 @@ const app = new Vue({ let replaygain = self.parseSCTagToRG(tag) try { CiderAudio.audioNodes.gainNode.gain.value = (Math.min(Math.pow(10, (replaygain.gain / 20)), (1 / replaygain.peak))) - } catch (e) {} + } catch (e) { } }) - ipcRenderer.on('play', function(_event, mode, id) { - if (mode !== 'url'){ - self.mk.setQueue({[mode]: id , parameters : {l : self.mklang}}).then(() => { - app.mk.play() - }) - - } else { + ipcRenderer.on('play', function (_event, mode, id) { + if (mode !== 'url') { + self.mk.setQueue({ [mode]: id, parameters: { l: self.mklang } }).then(() => { + app.mk.play() + }) + + } else { app.openAppleMusicURL(id) } }); @@ -752,7 +782,7 @@ const app = new Vue({ self.$refs.queue.updateQueue(); } this.currentSongInfo = a - + if (app.cfg.audio.normalization) { // get unencrypted audio previews to get SoundCheck's normalization tag @@ -762,8 +792,8 @@ const app = new Vue({ previewURL = app.mk.nowPlayingItem.previewURL } catch (e) { } - if (previewURL == null && ((app.mk.nowPlayingItem?._songId ?? (app.mk.nowPlayingItem["songId"] ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id)) != -1)) { - app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/songs/${app.mk.nowPlayingItem?._songId ?? (app.mk.nowPlayingItem["songId"] ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id)}`).then((response) => { + if (previewURL == null && ((app.mk.nowPlayingItem?._songId ?? (app.mk.nowPlayingItem["songId"] ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id)) != -1)) { + app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/songs/${app.mk.nowPlayingItem?._songId ?? (app.mk.nowPlayingItem["songId"] ?? app.mk.nowPlayingItem.relationships.catalog.data[0].id)}`).then((response) => { previewURL = response.data.data[0].attributes.previews[0].url if (previewURL) ipcRenderer.send('getPreviewURL', previewURL) @@ -776,7 +806,7 @@ const app = new Vue({ } catch (e) { } } - + try { a = a.item.attributes; @@ -942,12 +972,12 @@ const app = new Vue({ this.newPlaylist() } }, - { - name: app.getLz('term.createNewPlaylistFolder'), - action: () => { - this.newPlaylistFolder() - } + { + name: app.getLz('term.createNewPlaylistFolder'), + action: () => { + this.newPlaylistFolder() } + } ] } this.showMenuPanel(menu, event) @@ -956,13 +986,13 @@ const app = new Vue({ let self = this this.mk.api.v3.music( `/v1/me/library/playlist-folders/${id}`, {}, { - fetchOptions: { - method: "PATCH", - body: JSON.stringify({ - attributes: {name: name} - }) - } + fetchOptions: { + method: "PATCH", + body: JSON.stringify({ + attributes: { name: name } + }) } + } ).then(res => { self.refreshPlaylists() }) @@ -971,19 +1001,19 @@ const app = new Vue({ let self = this this.mk.api.v3.music( `/v1/me/library/playlists/${id}`, {}, { - fetchOptions: { - method: "PATCH", - body: JSON.stringify({ - attributes: {name: name} - }) - } + fetchOptions: { + method: "PATCH", + body: JSON.stringify({ + attributes: { name: name } + }) } + } ).then(res => { self.refreshPlaylists() }) }, copyToClipboard(str) { - if (navigator.userAgent.includes('Darwin') || navigator.appVersion.indexOf("Mac")!=-1) { + if (navigator.userAgent.includes('Darwin') || navigator.appVersion.indexOf("Mac") != -1) { this.darwinShare(str) } else { notyf.success(app.getLz('term.share.success')) @@ -1002,9 +1032,9 @@ const app = new Vue({ fetchOptions: { method: "POST", body: JSON.stringify({ - "attributes": {"name": name}, + "attributes": { "name": name }, "relationships": { - "tracks": {"data": tracks}, + "tracks": { "data": tracks }, } }) } @@ -1054,7 +1084,7 @@ const app = new Vue({ app.appRoute("collection-list") }, async showArtistView(artist, title, view) { - let response = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artist}/view/${view}?l=${this.mklang}`, {}, {includeResponseMeta: !0})).data + let response = (await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artist}/view/${view}?l=${this.mklang}`, {}, { includeResponseMeta: !0 })).data console.log(response) await this.showCollection(response, title, "artists") }, @@ -1090,7 +1120,7 @@ const app = new Vue({ resource: ["autos"] }, groups: group, - l : this.mklang + l: this.mklang } let response = await app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/search?term=${term}`, requestBody, { includeResponseMeta: !0 @@ -1142,7 +1172,7 @@ const app = new Vue({ "include[library-songs]": "catalog,artists,albums,playParams,name,artwork,url", "fields[catalog]": "artistUrl,albumUrl,url", "fields[songs]": "artistUrl,albumUrl,playParams,name,artwork,url,artistName,albumName,durationInMillis", - l : this.mklang + l: this.mklang } if (!transient) { this.playlists.loadingState = 0; @@ -1171,8 +1201,8 @@ const app = new Vue({ "fields[albums]": "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialVideo,name,playParams,releaseDate,url,trackCount", "limit[artists:top-songs]": 20, "art[url]": "f", - l : this.mklang - }, {includeResponseMeta: !0}) + l: this.mklang + }, { includeResponseMeta: !0 }) console.log(artistData.data.data[0]) this.artistPage.data = artistData.data.data[0] this.page = "artist-page" @@ -1287,7 +1317,7 @@ const app = new Vue({ kind: page, id: id, attributes: { - playParams: {kind: page, id: id, isLibrary: isLibrary} + playParams: { kind: page, id: id, isLibrary: isLibrary } } }) }, @@ -1334,10 +1364,10 @@ const app = new Vue({ extend: "offers,editorialVideo", "views": "appears-on,more-by-artist,related-videos,other-versions,you-might-also-like,video-extras,audio-extras", } - if (kind.includes("playlist")){ + if (kind.includes("playlist")) { params["include"] = "tracks"; } - if (kind.includes("album")){ + if (kind.includes("album")) { params["include[albums]"] = "artists" params["fields[artists]"] = "name,url" params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url" @@ -1370,11 +1400,11 @@ const app = new Vue({ prevButton() { if (!app.prevButtonBackIndicator && app.mk.nowPlayingItem && app.mk.currentPlaybackTime > 2) { app.prevButtonBackIndicator = true; - try{clearTimeout(app.pauseButtonTimer)} catch (e){ } + try { clearTimeout(app.pauseButtonTimer) } catch (e) { } app.mk.seekToTime(0); - app.pauseButtonTimer = setTimeout(() => {app.prevButtonBackIndicator = false},3000); + app.pauseButtonTimer = setTimeout(() => { app.prevButtonBackIndicator = false }, 3000); } else { - try{clearTimeout(app.pauseButtonTimer)} catch (e){ } + try { clearTimeout(app.pauseButtonTimer) } catch (e) { } app.prevButtonBackIndicator = false; app.skipToPreviousItem() } @@ -1488,7 +1518,7 @@ const app = new Vue({ } if (labelId != "") { app.showingPlaylist = [] - await app.getTypeFromID("recordLabel", labelId, false, {views: 'top-releases,latest-releases,top-artists'}); + await app.getTypeFromID("recordLabel", labelId, false, { views: 'top-releases,latest-releases,top-artists' }); app.page = "recordLabel_" + labelId; } @@ -1512,75 +1542,75 @@ const app = new Vue({ console.log(kind, id, isLibrary) app.mk.stop().then(() => { if (kind.includes("artist")) { - app.mk.setStationQueue({artist: 'a-' + id}).then(() => { + app.mk.setStationQueue({ artist: 'a-' + id }).then(() => { app.mk.play() }) } - // else if (kind.includes("playlist") && (id.startsWith("p.") || id.startsWith("pl."))){ - // /* Randomize array in-place using Durstenfeld shuffle algorithm */ - // function shuffleArray(array) { - // for (var i = array.length - 1; i > 0; i--) { - // var j = Math.floor(Math.random() * (i + 1)); - // var temp = array[i]; - // array[i] = array[j]; - // array[j] = temp; - // } - // } - // app.mk.clearQueue().then(function () { { - // app.mk.setQueue({[truekind]: [item.attributes.playParams.id ?? item.id]}).then(function () { - // app.mk.play().then(function (){ - // app.mk.clearQueue().then(function (){ - // var playlistId = id - // const params = { - // include: "tracks", - // platform: "web", - // "include[library-playlists]": "catalog,tracks", - // "fields[playlists]": "curatorName,playlistType,name,artwork,url", - // "include[library-songs]": "catalog,artists,albums", - // "fields[catalog]": "artistUrl,albumUrl", - // "fields[songs]": "artistUrl,albumUrl" - // } - // var playlistId = '' + // else if (kind.includes("playlist") && (id.startsWith("p.") || id.startsWith("pl."))){ + // /* Randomize array in-place using Durstenfeld shuffle algorithm */ + // function shuffleArray(array) { + // for (var i = array.length - 1; i > 0; i--) { + // var j = Math.floor(Math.random() * (i + 1)); + // var temp = array[i]; + // array[i] = array[j]; + // array[j] = temp; + // } + // } + // app.mk.clearQueue().then(function () { { + // app.mk.setQueue({[truekind]: [item.attributes.playParams.id ?? item.id]}).then(function () { + // app.mk.play().then(function (){ + // app.mk.clearQueue().then(function (){ + // var playlistId = id + // const params = { + // include: "tracks", + // platform: "web", + // "include[library-playlists]": "catalog,tracks", + // "fields[playlists]": "curatorName,playlistType,name,artwork,url", + // "include[library-songs]": "catalog,artists,albums", + // "fields[catalog]": "artistUrl,albumUrl", + // "fields[songs]": "artistUrl,albumUrl" + // } + // var playlistId = '' - // try { - // function getPlaylist(id, params, isLibrary){ - // if (isLibrary){ - // return app.mk.api.library.playlist(id, params) - // } else { return app.mk.api.playlist(id, params)} - // } - // getPlaylist(id, params, isLibrary).then(res => { - // let query = res.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); - // if (app.mk.shuffleMode == 1){shuffleArray(query); console.log('shf')} - // app.mk.queue.append(query) - // if (!res.relationships.tracks.next) { - // return - // } else { - // getPlaylistTracks(res.relationships.tracks.next) - // } + // try { + // function getPlaylist(id, params, isLibrary){ + // if (isLibrary){ + // return app.mk.api.library.playlist(id, params) + // } else { return app.mk.api.playlist(id, params)} + // } + // getPlaylist(id, params, isLibrary).then(res => { + // let query = res.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); + // if (app.mk.shuffleMode == 1){shuffleArray(query); console.log('shf')} + // app.mk.queue.append(query) + // if (!res.relationships.tracks.next) { + // return + // } else { + // getPlaylistTracks(res.relationships.tracks.next) + // } - // function getPlaylistTracks(next) { - // app.apiCall(app.musicBaseUrl + next, res => { - // if (res.id != playlistId) { - // return - // } - // let query = res.data.map(item => new MusicKit.MediaItem(item)) - // if (app.mk.shuffleMode == 1){shuffleArray(query); console.log('shf')} - // app.mk.queue.append(query) + // function getPlaylistTracks(next) { + // app.apiCall(app.musicBaseUrl + next, res => { + // if (res.id != playlistId) { + // return + // } + // let query = res.data.map(item => new MusicKit.MediaItem(item)) + // if (app.mk.shuffleMode == 1){shuffleArray(query); console.log('shf')} + // app.mk.queue.append(query) - // if (res.next) { - // getPlaylistTracks(res.next) - // } - // }) - // } - // }) - // } catch (e) {} + // if (res.next) { + // getPlaylistTracks(res.next) + // } + // }) + // } + // }) + // } catch (e) {} - // }) - // }) - // }) - // } - // }) + // }) + // }) + // }) + // } + // }) // } else { app.playMediaItemById((id), (kind), (isLibrary), item.attributes.url ?? '') @@ -1621,7 +1651,7 @@ const app = new Vue({ searchLibrarySongs() { let self = this let prefs = this.cfg.libraryPrefs.songs - let albumAdded = self.library?.albums?.listing?.map(function(i){return {[i.id]: i.attributes?.dateAdded}}) + let albumAdded = self.library?.albums?.listing?.map(function (i) { return { [i.id]: i.attributes?.dateAdded } }) let startTime = new Date().getTime() function sortSongs() { // sort this.library.songs.displayListing by song.attributes[self.library.songs.sorting] in descending or ascending order based on alphabetical order and numeric order @@ -1633,11 +1663,11 @@ const app = new Vue({ aa = a.attributes.genreNames[0] bb = b.attributes.genreNames[0] } - if (prefs.sort == "dateAdded"){ - let albumida = a.relationships?.albums?.data[0]?.id ?? '1970-01-01T00:01:01Z' - let albumidb = b.relationships?.albums?.data[0]?.id ?? '1970-01-01T00:01:01Z' - aa = startTime - new Date(((albumAdded.find(i => i[albumida]))?? [])[albumida] ?? '1970-01-01T00:01:01Z').getTime() - bb = startTime - new Date(((albumAdded.find(i => i[albumidb]))?? [])[albumidb] ?? '1970-01-01T00:01:01Z').getTime() + if (prefs.sort == "dateAdded") { + let albumida = a.relationships?.albums?.data[0]?.id ?? '1970-01-01T00:01:01Z' + let albumidb = b.relationships?.albums?.data[0]?.id ?? '1970-01-01T00:01:01Z' + aa = startTime - new Date(((albumAdded.find(i => i[albumida])) ?? [])[albumida] ?? '1970-01-01T00:01:01Z').getTime() + bb = startTime - new Date(((albumAdded.find(i => i[albumidb])) ?? [])[albumidb] ?? '1970-01-01T00:01:01Z').getTime() } if (aa == null) { aa = "" @@ -2060,7 +2090,7 @@ const app = new Vue({ } if (downloaded.meta.total > library.length || typeof downloaded.meta.next != "undefined") { console.log(`downloading next chunk - ${library.length - } albums so far`) + } albums so far`) downloadChunk() } else { self.library.albums.listing = library @@ -2167,7 +2197,7 @@ const app = new Vue({ } if (downloaded.meta.total > library.length || typeof downloaded.meta.next != "undefined") { console.log(`downloading next chunk - ${library.length - } artists so far`) + } artists so far`) downloadChunk() } else { self.library.artists.listing = library @@ -2184,26 +2214,26 @@ const app = new Vue({ getTotalTime() { try { if (app.showingPlaylist.relationships.tracks.data.length > 0) { - let time = Math.round([].concat(...app.showingPlaylist.relationships.tracks.data).reduce((a, {attributes: {durationInMillis}}) => a + durationInMillis, 0) / 1000); + let time = Math.round([].concat(...app.showingPlaylist.relationships.tracks.data).reduce((a, { attributes: { durationInMillis } }) => a + durationInMillis, 0) / 1000); let hours = Math.floor(time / 3600) let mins = Math.floor(time / 60) % 60 let secs = time % 60 - return app.showingPlaylist.relationships.tracks.data.length + " " + app.getLz('term.tracks', options = {count : app.showingPlaylist.relationships.tracks.data.length}) + ", " - + ((hours > 0) ? (hours + (" " + (app.getLz('term.time.hour', options = {count : hours}) + ", "))) : "") + - ((mins > 0) ? (mins + (" " + app.getLz('term.time.minute', options = {count : mins}) + ", ")) : "") + - secs + (" " + app.getLz('term.time.second', options = {count : secs}) + "."); + return app.showingPlaylist.relationships.tracks.data.length + " " + app.getLz('term.tracks', options = { count: app.showingPlaylist.relationships.tracks.data.length }) + ", " + + ((hours > 0) ? (hours + (" " + (app.getLz('term.time.hour', options = { count: hours }) + ", "))) : "") + + ((mins > 0) ? (mins + (" " + app.getLz('term.time.minute', options = { count: mins }) + ", ")) : "") + + secs + (" " + app.getLz('term.time.second', options = { count: secs }) + "."); } else return "" } catch (err) { return "" } }, async getLibrarySongs() { - let response = await this.mkapi("songs", true, "", {limit: 100, l : this.mklang}, {includeResponseMeta: !0}) + let response = await this.mkapi("songs", true, "", { limit: 100, l: this.mklang }, { includeResponseMeta: !0 }) this.library.songs.listing = response.data.data this.library.songs.meta = response.data.meta }, async getLibraryAlbums() { - let response = await this.mkapi("albums", true, "", {limit: 100, l : this.mklang}, {includeResponseMeta: !0}) + let response = await this.mkapi("albums", true, "", { limit: 100, l: this.mklang }, { includeResponseMeta: !0 }) this.library.albums.listing = response.data.data this.library.albums.meta = response.data.meta }, @@ -2309,13 +2339,13 @@ const app = new Vue({ let self = this this.mk.api.v3.music( "/v1/me/library/playlist-folders/", {}, { - fetchOptions: { - method: "POST", - body: JSON.stringify({ - attributes: {name: name} - }) - } + fetchOptions: { + method: "POST", + body: JSON.stringify({ + attributes: { name: name } + }) } + } ).then((res) => { let playlist = (res.data.data[0]) self.playlists.listing.push({ @@ -2338,7 +2368,7 @@ const app = new Vue({ showSearch() { this.page = "search" }, - loadLyrics() { + loadLyrics() { const musicType = (MusicKit.getInstance().nowPlayingItem != null) ? MusicKit.getInstance().nowPlayingItem["type"] ?? '' : ''; console.log("mt", musicType) if (musicType === "musicVideo") { @@ -2673,15 +2703,15 @@ const app = new Vue({ line: "lrcInstrumental" }); } - preLrc.push({startTime: start, endTime: end, line: element.textContent}); + preLrc.push({ startTime: start, endTime: end, line: element.textContent }); endTimes.push(end); } // first line dot if (preLrc.length > 0) - preLrc.unshift({startTime: 0, endTime: preLrc[0].startTime, line: "lrcInstrumental"}); + preLrc.unshift({ startTime: 0, endTime: preLrc[0].startTime, line: "lrcInstrumental" }); } else { for (element of lyricsLines) { - preLrc.push({startTime: 9999999, endTime: 9999999, line: element.textContent}); + preLrc.push({ startTime: 9999999, endTime: 9999999, line: element.textContent }); } } this.lyrics = preLrc; @@ -2749,17 +2779,17 @@ const app = new Vue({ console.log(id, truekind, isLibrary) try { if (truekind.includes("artist")) { - app.mk.setStationQueue({artist: 'a-' + id}).then(() => { + app.mk.setStationQueue({ artist: 'a-' + id }).then(() => { app.mk.play() }) } else if (truekind == "radioStations") { - this.mk.setStationQueue({url: raurl}).then(function (queue) { + this.mk.setStationQueue({ url: raurl }).then(function (queue) { MusicKit.getInstance().play() }); } else { this.mk.setQueue({ [truekind]: [id], - parameters : {l : this.mklang} + parameters: { l: this.mklang } }).then(function (queue) { MusicKit.getInstance().play() }) @@ -2800,7 +2830,7 @@ const app = new Vue({ if (item) { app.mk.setQueue({ [item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id, - parameters : {l : app.mklang} + parameters: { l: app.mklang } }).then(function () { app.mk.play().then(() => { if (app.mk.shuffleMode == 1) { @@ -2827,7 +2857,7 @@ const app = new Vue({ } else { app.mk.play() } - + } }) } else if (parent.startsWith('listitem-hr')) { @@ -2877,24 +2907,26 @@ const app = new Vue({ let ids = itemsToPlay[kind] if (ids.length > 0) { if (app.mk.queue._itemIDs.length > 0) { - app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] }).then(function () { - ind += 1; - console.log(ind, Object.keys(itemsToPlay).length) - if (ind >= Object.keys(itemsToPlay).length) { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.attributes.playParams.id ?? item.id)) + app.mk.playLater({ [kind + "s"]: itemsToPlay[kind] }).then(function () { + ind += 1; + console.log(ind, Object.keys(itemsToPlay).length) + if (ind >= Object.keys(itemsToPlay).length) { + app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.attributes.playParams.id ?? item.id)) + } } - } - )} else { + ) + } else { app.mk.setQueue({ [kind + "s"]: itemsToPlay[kind] }).then(function () { ind += 1; console.log(ind, Object.keys(itemsToPlay).length) if (ind >= Object.keys(itemsToPlay).length) { app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.attributes.playParams.id ?? item.id)) } - } - )} + } + ) + } } - + } } }) @@ -2904,7 +2936,7 @@ const app = new Vue({ if (truekind == "playlists" && (id.startsWith("p.") || id.startsWith("pl.u"))) { app.mk.setQueue({ [item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id, - parameters : {l : app.mklang} + parameters: { l: app.mklang } }).then(function () { app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1).then(function () { if ((app.showingPlaylist && app.showingPlaylist.id == id)) { @@ -2944,7 +2976,7 @@ const app = new Vue({ } else { this.mk.setQueue({ [truekind]: [id], - parameters : {l : this.mklang} + parameters: { l: this.mklang } }).then(function (queue) { if (item && ((queue._itemIDs[childIndex] != item.id))) { childIndex = queue._itemIDs.indexOf(item.id) @@ -3056,7 +3088,7 @@ const app = new Vue({ with: ["serverBubbles", "lyricSnippet"], "art[url]": "f", "art[social-profiles:url]": "c" - }, {includeResponseMeta: !0}).then(function (results) { + }, { includeResponseMeta: !0 }).then(function (results) { results.data.results["meta"] = results.data.meta self.search.resultsSocial = results.data.results }) @@ -3069,14 +3101,14 @@ const app = new Vue({ if (type.slice(-1) != "s") { type += "s" } - type = type.replace("library-", "") + type = type.replace("library-", "") let id = item.attributes.playParams.catalogId ?? item.attributes.playParams.id ?? item.id let index = types.findIndex(function (type) { return type.type == this }, type) if (index == -1) { - types.push({type: type, id: [id]}) + types.push({ type: type, id: [id] }) } else { types[index].id.push(id) } @@ -3260,8 +3292,8 @@ const app = new Vue({ }, quickPlay(query) { let self = this - MusicKit.getInstance().api.search(query, {limit: 2, types: 'songs'}).then(function (data) { - MusicKit.getInstance().setQueue({song: data["songs"]['data'][0]["id"], parameters : {l : app.mklang}}).then(function (queue) { + MusicKit.getInstance().api.search(query, { limit: 2, types: 'songs' }).then(function (data) { + MusicKit.getInstance().setQueue({ song: data["songs"]['data'][0]["id"], parameters: { l: app.mklang } }).then(function (queue) { MusicKit.getInstance().play() setTimeout(() => { self.$forceUpdate() @@ -3438,7 +3470,7 @@ const app = new Vue({ let data_type = this.mk.nowPlayingItem.playParams.kind let item_id = this.mk.nowPlayingItem.attributes.playParams.id ?? this.mk.nowPlayingItem.id let isLibrary = this.mk.nowPlayingItem.attributes.playParams.isLibrary ?? false - let params = {"fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "t": "1"} + let params = { "fields[songs]": "inLibrary", "fields[albums]": "inLibrary", "relate": "library", "t": "1" } app.selectedMediaItems = [] app.select_selectMediaItem(item_id, data_type, 0, '12344', isLibrary) let useMenu = "normal" @@ -3457,36 +3489,36 @@ const app = new Vue({ app.love(app.mk.nowPlayingItem) } }, - { - "icon": "./assets/feather/heart.svg", - "id": "unlove", - "active": true, - "name": app.getLz('action.unlove'), - "hidden": true, - "action": function () { - app.unlove(app.mk.nowPlayingItem) - } - }, - { - "icon": "./assets/feather/thumbs-down.svg", - "id": "dislike", - "name": app.getLz('action.dislike'), - "hidden": false, - "disabled": true, - "action": function () { - app.dislike(app.mk.nowPlayingItem) - } - }, - { - "icon": "./assets/feather/thumbs-down.svg", - "id": "undo_dislike", - "name": app.getLz('action.undoDislike'), - "active": true, - "hidden": true, - "action": function () { - app.unlove(app.mk.nowPlayingItem) - } - }, + { + "icon": "./assets/feather/heart.svg", + "id": "unlove", + "active": true, + "name": app.getLz('action.unlove'), + "hidden": true, + "action": function () { + app.unlove(app.mk.nowPlayingItem) + } + }, + { + "icon": "./assets/feather/thumbs-down.svg", + "id": "dislike", + "name": app.getLz('action.dislike'), + "hidden": false, + "disabled": true, + "action": function () { + app.dislike(app.mk.nowPlayingItem) + } + }, + { + "icon": "./assets/feather/thumbs-down.svg", + "id": "undo_dislike", + "name": app.getLz('action.undoDislike'), + "active": true, + "hidden": true, + "action": function () { + app.unlove(app.mk.nowPlayingItem) + } + }, ], items: [{ "icon": "./assets/feather/list.svg", @@ -3495,43 +3527,43 @@ const app = new Vue({ app.promptAddToPlaylist() } }, - { - "icon": "./assets/feather/plus.svg", - "id": "addToLibrary", - "name": app.getLz('action.addToLibrary') + " ...", - "disabled": false, - "action": function () { - app.addToLibrary(app.mk.nowPlayingItem.id); - } - }, - { - "icon": "./assets/feather/radio.svg", - "name": app.getLz('action.startRadio'), - "action": function () { - app.mk.setStationQueue({song: app.mk.nowPlayingItem.id}).then(() => { - app.mk.play() - app.selectedMediaItems = [] - }) - } - }, - { - "icon": "./assets/feather/share.svg", - "name": app.getLz('action.share'), - "action": function () { - app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id) ?? '').then(u => { - app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) - }) - } - }, - { - "icon": "./assets/feather/share.svg", - "name": `${app.getLz('action.share')} (song.link)`, - "action": function () { - app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id) ?? '').then(u => { - app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) - }) - } - } + { + "icon": "./assets/feather/plus.svg", + "id": "addToLibrary", + "name": app.getLz('action.addToLibrary') + " ...", + "disabled": false, + "action": function () { + app.addToLibrary(app.mk.nowPlayingItem.id); + } + }, + { + "icon": "./assets/feather/radio.svg", + "name": app.getLz('action.startRadio'), + "action": function () { + app.mk.setStationQueue({ song: app.mk.nowPlayingItem.id }).then(() => { + app.mk.play() + app.selectedMediaItems = [] + }) + } + }, + { + "icon": "./assets/feather/share.svg", + "name": app.getLz('action.share'), + "action": function () { + app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id) ?? '').then(u => { + app.copyToClipboard((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) + }) + } + }, + { + "icon": "./assets/feather/share.svg", + "name": `${app.getLz('action.share')} (song.link)`, + "action": function () { + app.mkapi(app.mk.nowPlayingItem.attributes?.playParams?.kind ?? app.mk.nowPlayingItem.type ?? 'songs', false, app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id) ?? '').then(u => { + app.songLinkShare((u.data.data.length && u.data.data.length > 0) ? u.data.data[0].attributes.url : u.data.data.attributes.url) + }) + } + } ] } } @@ -3711,17 +3743,17 @@ const app = new Vue({ } return R; }, - SpacePause() { + SpacePause() { const elems = document.querySelectorAll('input'); - for (elem of elems){ + for (elem of elems) { if (elem === document.activeElement) { return; } } if (!this.isDev) // disable in dev mode to keep my sanity - MusicKitInterop.playPause(); + MusicKitInterop.playPause(); }, - async MKJSLang(){ + async MKJSLang() { let u = this.cfg.general.language; // use MusicKit.getInstance or crash try { @@ -3736,7 +3768,7 @@ const app = new Vue({ sellang = ((u.toLowerCase()).replace('_', "-")).split("-")[0] } if (sellang == "") sellang = (item.data.data[0].attributes.defaultLanguageTag).toLowerCase() - + // Fix weird locales: if (sellang == "iw") sellang = "iw-il" sellang = sellang.replace(/-Han[s|t]/i, "").toLowerCase() @@ -3755,22 +3787,22 @@ const app = new Vue({ } if (sellang.startsWith("en") && this.mk.storefrontId != "us") sellang = "en-gb" return await sellang - } + } }, - skipToNextItem(){ + skipToNextItem() { app.prevButtonBackIndicator = false; // app.mk.skipToNextItem() is buggy somehow so use this - if (this.mk.queue.nextPlayableItemIndex != -1 && this.mk.queue.nextPlayableItemIndex != null) - this.mk.changeToMediaAtIndex(this.mk.queue.nextPlayableItemIndex); + if (this.mk.queue.nextPlayableItemIndex != -1 && this.mk.queue.nextPlayableItemIndex != null) + this.mk.changeToMediaAtIndex(this.mk.queue.nextPlayableItemIndex); }, - skipToPreviousItem(){ + skipToPreviousItem() { // app.mk.skipToPreviousItem() is buggy somehow so use this if (this.mk.queue.previousPlayableItemIndex != -1 && this.mk.queue.previousPlayableItemIndex != null) - this.mk.changeToMediaAtIndex(this.mk.queue.previousPlayableItemIndex); + this.mk.changeToMediaAtIndex(this.mk.queue.previousPlayableItemIndex); }, - mediaKeyFixes(){ - navigator.mediaSession.setActionHandler('previoustrack', function() { app.prevButton() }); - navigator.mediaSession.setActionHandler('nexttrack', function() { app.skipToNextItem() }); + mediaKeyFixes() { + navigator.mediaSession.setActionHandler('previoustrack', function () { app.prevButton() }); + navigator.mediaSession.setActionHandler('nexttrack', function () { app.skipToNextItem() }); } } }) @@ -3778,7 +3810,7 @@ const app = new Vue({ Vue.component('animated-number', { template: "
{{ displayNumber }}
", - props: {'number': {default: 0}}, + props: { 'number': { default: 0 } }, data() { return { @@ -4044,7 +4076,7 @@ webGPU().then() let screenWidth = screen.width; let screenHeight = screen.height; -window.onerror = function(error) { +window.onerror = function (error) { console.log(error) bootbox.alert("Error occured: " + error) }; diff --git a/src/renderer/views/pages/settings.ejs b/src/renderer/views/pages/settings.ejs index 4d944a0b..a48fedb9 100644 --- a/src/renderer/views/pages/settings.ejs +++ b/src/renderer/views/pages/settings.ejs @@ -23,6 +23,23 @@ +
+
+ Resume behavior
+ + Resume behavior affects how Cider will resume your session when you return to the app.
+ Locally: Cider will resume your last session on this machine.
+ History: Cider will queue the last song from your overall Apple Music history, across devices. +
+
+
+ +
+
{{$root.getLz('settings.header.audio')}}