diff --git a/package.json b/package.json index 944f6bf3..138fc8d0 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "@sentry/electron": "^2.5.4", "discord-rpc": "^4.0.1", "ejs": "^3.1.6", - "electron-acrylic-window": "^0.5.11", "electron-fetch": "^1.7.4", "electron-log": "^4.4.4", "electron-store": "^8.0.1", @@ -37,6 +36,7 @@ "lastfmapi": "^0.1.1", "mpris-service": "^2.1.2", "music-metadata": "^7.11.4", + "qrcode-terminal": "^0.12.0", "react": "^17.0.2", "react-dom": "^17.0.2", "source-map-support": "^0.5.21", diff --git a/src/renderer/apple-hls.js b/src/renderer/apple-hls.js index e4936dda..1f920850 100644 --- a/src/renderer/apple-hls.js +++ b/src/renderer/apple-hls.js @@ -23260,9 +23260,36 @@ } if (null != (l = "string" != typeof (h = g.pathwayID) ? im("invalid steering manifest PATHWAY-PRIORITY list item data type") : /^[\w\-\.]+$/.test(h) ? void 0 : im("steering manifest contains invalid pathway ID: " + h))) break; - if (g.hdcpLevel === "NONE"){ - n.push(g)} + let cpc = g.allowedCPCMap ? JSON.stringify(g.allowedCPCMap) : "null"; + if (!cpc.includes("WIDEVINE_HARDWARE") && !g.url.includes('trickPlay') && !g.videoCodec.includes("hvc1")) + n.push(g) } + + + + try{ + // console.log(n, window.screen.width) + let ok = (n.map( function(item){return{height : item.height, content: item}})); + let screenHeight = (app.cfg.visual.videoRes ?? window.screen.height) ; + ok.sort(function (a, b) { + return a.height - b.height; + }); + for (var i = 0; i < ok.length; i++){ + if (ok[i].height > screenHeight){ + if (i == 0){n.splice(0,n.length);n.push(ok[i].content)} + else{n.splice(0,n.length);n.push(ok[i-1].content)} + console.log('selected' , n[0].height) + break; + + } + + } + if (n.length > 1){ + n.splice(0,n.length - 1); + } + // console.log(n) + // console.log(ok) + } catch (e){ console.log(e)} return { variantMediaOptions: n, contentSteeringOption: u, diff --git a/src/renderer/assets/arrow-bend-down.svg b/src/renderer/assets/arrow-bend-down.svg new file mode 100644 index 00000000..cbfa2e8a --- /dev/null +++ b/src/renderer/assets/arrow-bend-down.svg @@ -0,0 +1,26 @@ + + + + \ No newline at end of file diff --git a/src/renderer/assets/arrow-bend-up.svg b/src/renderer/assets/arrow-bend-up.svg new file mode 100644 index 00000000..64fd7119 --- /dev/null +++ b/src/renderer/assets/arrow-bend-up.svg @@ -0,0 +1,25 @@ + + + \ No newline at end of file diff --git a/src/renderer/assets/banner.png b/src/renderer/assets/banner.png new file mode 100644 index 00000000..1edba696 Binary files /dev/null and b/src/renderer/assets/banner.png differ diff --git a/src/renderer/assets/ko_fi.svg b/src/renderer/assets/ko_fi.svg new file mode 100644 index 00000000..8630f586 --- /dev/null +++ b/src/renderer/assets/ko_fi.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/renderer/assets/open_collective.svg b/src/renderer/assets/open_collective.svg new file mode 100644 index 00000000..ea86a543 --- /dev/null +++ b/src/renderer/assets/open_collective.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/renderer/index.js b/src/renderer/index.js index f1320cae..d6071209 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -52,7 +52,7 @@ var CiderContextMenu = { } item.tabIndex = 0 item.classList.add("context-menu-item") - if(menudata.items[i]["icon"]) { + if (menudata.items[i]["icon"]) { item.innerHTML += `
` } item.innerHTML += menudata.items[i].name @@ -290,7 +290,18 @@ const app = new Vue({ }, socialBadges: { badgeMap: {}, - version: "" + version: "", + mediaItems: [], + mediaItemDLState: 0 // 0 = not started, 1 = in progress, 2 = complete + }, + menuPanel: { + visible: false, + event: null, + content: { + name: "", + items: {}, + headerItems: {} + } } }, watch: { @@ -315,6 +326,53 @@ const app = new Vue({ }, }, methods: { + async showSocialListeningTo() { + let contentIds = Object.keys(app.socialBadges.badgeMap) + app.showCollection({data: this.socialBadges.mediaItems}, "Friends Listening To", "albums") + if(this.socialBadges.mediaItemDLState == 1 || this.socialBadges.mediaItemDLState == 2) { + return + } + this.socialBadges.mediaItemDLState = 2 + await asyncForEach(contentIds, async (item)=>{ + try { + let type = "albums" + if(item.includes("pl.")) { + type = "playlists" + } + if(item.includes("ra.")) { + type = "stations" + } + let found = await app.mk.api.v3.music(`/v1/catalog/us/${type}/${item}`) + this.socialBadges.mediaItems.push(found.data.data[0]) + }catch(e){ + + } + }) + }, + async openAppleMusicURL(url) { + let properties = MusicKit.formattedMediaURL(url) + let item = { + id: properties.contentId, + attributes: { + playParams: { + id: properties.contentId, + kind: properties.kind, + } + }, + type: properties.kind, + kind: properties.kind + } + app.routeView(item) + }, + async showMenuPanel(data, event) { + app.menuPanel.visible = true; + app.menuPanel.content.name = data.name ?? ""; + app.menuPanel.content.items = data.items ?? {}; + app.menuPanel.content.headerItems = data.headerItems ?? {}; + if(event) { + app.menuPanel.event = event; + } + }, async getSvgIcon(url) { let response = await fetch(url); let data = await response.text(); @@ -353,22 +411,11 @@ const app = new Vue({ history.forward() }, getHTMLStyle() { - switch (this.cfg.visual.window_transparency) { - case "acrylic": - default: - document.querySelector("html").style.background = ""; - document.querySelector("body").style.background = ""; - document.querySelector("body").classList.remove("notransparency") - break; - case "disabled": - document.querySelector("html").style.background = "#222"; - document.querySelector("body").classList.add("notransparency") - - // document.querySelector("body").style.background = "#222"; - break; - } + document.querySelector("html").style.background = "#222"; + document.querySelector("body").classList.add("notransparency") }, resetState() { + this.menuPanel.visible = false; app.selectedMediaItems = []; for (let key in app.modals) { app.modals[key] = false; @@ -387,10 +434,12 @@ const app = new Vue({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind }) - } else if ((self.selectedMediaItems[i].kind == "album" || self.selectedMediaItems[i].kind == "albums") && self.selectedMediaItems[i].isLibrary != true ) { + } else if ((self.selectedMediaItems[i].kind == "album" || self.selectedMediaItems[i].kind == "albums") && self.selectedMediaItems[i].isLibrary != true) { self.selectedMediaItems[i].kind = "albums" - let res = await self.mk.api.albumRelationship(self.selectedMediaItems[i].id,"tracks"); - let ids = res.map(function(i) {return {id:i.id, type: i.type}}) + let res = await self.mk.api.albumRelationship(self.selectedMediaItems[i].id, "tracks"); + let ids = res.map(function (i) { + 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") { self.selectedMediaItems[i].kind = "library-songs" @@ -398,10 +447,12 @@ const app = new Vue({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind }) - } else if ((self.selectedMediaItems[i].kind == "library-album" || self.selectedMediaItems[i].kind == "library-albums") || (self.selectedMediaItems[i].kind == "album" && self.selectedMediaItems[i].isLibrary == true )) { + } else if ((self.selectedMediaItems[i].kind == "library-album" || self.selectedMediaItems[i].kind == "library-albums") || (self.selectedMediaItems[i].kind == "album" && self.selectedMediaItems[i].isLibrary == true)) { self.selectedMediaItems[i].kind = "library-albums" - let res = await self.mk.api.library.albumRelationship(self.selectedMediaItems[i].id,"tracks"); - let ids = res.map(function(i) {return {id:i.id, type: i.type}}) + let res = await self.mk.api.library.albumRelationship(self.selectedMediaItems[i].id, "tracks"); + let ids = res.map(function (i) { + return {id: i.id, type: i.type} + }) pl_items = pl_items.concat(ids) } else { pl_items.push({ @@ -635,6 +686,11 @@ const app = new Vue({ this.$forceUpdate() }, 500) }, + getAppClasses() { + if (this.cfg.advanced.experiments.includes('compactui')) { + return {compact: true} + } + }, invokeDrawer(panel) { if (this.drawer.panel == panel && this.drawer.open) { if (panel == "lyrics") { @@ -721,7 +777,7 @@ const app = new Vue({ } ] } - CiderContextMenu.Create(event, menu) + this.showMenuPanel(menu, event) }, async editPlaylistFolder(id, name = "New Playlist") { let self = this @@ -754,8 +810,8 @@ const app = new Vue({ } } ).then(res => { - self.refreshPlaylists() - }) + self.refreshPlaylists() + }) }, copyToClipboard(str) { navigator.clipboard.writeText(str) @@ -886,7 +942,9 @@ const app = new Vue({ "fields[catalog]": "artistUrl,albumUrl", "fields[songs]": "artistUrl,albumUrl" } - if (!transient) {this.playlists.loadingState = 0;} + if (!transient) { + this.playlists.loadingState = 0; + } let playlistId = '' try { @@ -991,6 +1049,7 @@ const app = new Vue({ return hash; }, appRoute(route) { + console.log(route) if (route == "" || route == "#" || route == "/") { return; } @@ -1004,12 +1063,13 @@ const app = new Vue({ let hash = route.split("/") let page = hash[0] let id = hash[1] - console.log(`page: ${page} id: ${id}`) + let isLibrary = hash[2] ?? false + console.log(`page: ${page} id: ${id} isLibrary: ${isLibrary}`) this.routeView({ kind: page, id: id, attributes: { - playParams: {kind: page, id: id} + playParams: {kind: page, id: id, isLibrary: isLibrary} } }) }, @@ -1036,7 +1096,7 @@ const app = new Vue({ document.querySelector("#app-content").scrollTop = 0 } else if (kind.toString().includes("artist")) { app.getArtistInfo(id, isLibrary) - window.location.hash = `${kind}/${id}` + window.location.hash = `${kind}/${id}${isLibrary ? "/" + isLibrary : ''}` document.querySelector("#app-content").scrollTop = 0 } else if (kind.toString().includes("record-label") || kind.toString().includes("curator")) { @@ -1057,7 +1117,7 @@ const app = new Vue({ let params = {extend: "editorialVideo"} app.page = (kind) + "_" + (id); app.getTypeFromID((kind), (id), (isLibrary), params); - window.location.hash = `${kind}/${id}` + window.location.hash = `${kind}/${id}${isLibrary ? "/" + isLibrary : ''}` document.querySelector("#app-content").scrollTop = 0 } else { app.playMediaItemById((id), (kind), (isLibrary), item.attributes.url ?? '') @@ -1198,81 +1258,81 @@ const app = new Vue({ let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; console.log(kind, id, isLibrary) app.mk.stop().then(() => { - if (kind.includes("artist")) { - 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 = '' + if (kind.includes("artist")) { + 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 = '' - // 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 ?? '') - } - }) + // }) + // }) + // }) + // } + // }) + // } + else { + app.playMediaItemById((id), (kind), (isLibrary), item.attributes.url ?? '') + } + }) }, async getTypeFromID(kind, id, isLibrary = false, params = {}, params2 = {}) { let a; @@ -1306,13 +1366,14 @@ const app = new Vue({ }, searchLibrarySongs() { let self = this + let prefs = this.cfg.libraryPrefs.songs 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 // check if song.attributes[self.library.songs.sorting] is a number and if so, sort by number if not, sort by alphabetical order ignoring case self.library.songs.displayListing.sort((a, b) => { - let aa = a.attributes[self.library.songs.sorting] - let bb = b.attributes[self.library.songs.sorting] + let aa = a.attributes[prefs.sort] + let bb = b.attributes[prefs.sort] if (self.library.songs.sorting == "genre") { aa = a.attributes.genreNames[0] bb = b.attributes.genreNames[0] @@ -1323,13 +1384,13 @@ const app = new Vue({ if (bb == null) { bb = "" } - if (self.library.songs.sortOrder == "asc") { + if (prefs.sortOrder == "asc") { if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { return aa - bb } else { return aa.toString().toLowerCase().localeCompare(bb.toString().toLowerCase()) } - } else if (self.library.songs.sortOrder == "desc") { + } else if (prefs.sortOrder == "desc") { if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { return bb - aa } else { @@ -1570,9 +1631,10 @@ const app = new Vue({ } else { if (downloaded.next != null && typeof downloaded.next === "function") { - downloaded.next("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) } else { + downloaded.next("", params, {includeResponseMeta: !0}).then((response) => { + processChunk(response) + }) + } else { console.log("Download next", downloaded.next) } } @@ -1648,10 +1710,11 @@ const app = new Vue({ processChunk(response) }) } else { - if (downloaded.next != null && typeof downloaded.next === "function") { - downloaded.next("", params, {includeResponseMeta: !0}).then((response) => { - processChunk(response) - }) } else { + if (downloaded.next != null && typeof downloaded.next === "function") { + downloaded.next("", params, {includeResponseMeta: !0}).then((response) => { + processChunk(response) + }) + } else { console.log("Download next", downloaded.next) } } @@ -1729,12 +1792,13 @@ const app = new Vue({ }) } else { if (downloaded.next != null && typeof downloaded.next === "function") { - downloaded.next("", "artists", {includeResponseMeta: !0}).then((response) => { + downloaded.next("", "artists", {includeResponseMeta: !0}).then((response) => { processChunk(response) - }) } else { - console.log("Download next", downloaded.next) - } - + }) + } else { + console.log("Download next", downloaded.next) + } + } } @@ -1780,7 +1844,7 @@ const app = new Vue({ let hours = Math.floor(time / 3600) let mins = Math.floor(time / 60) % 60 let secs = time % 60 - return app.showingPlaylist.relationships.tracks.data.length + " tracks, " + ((hours > 0) ? (hours + (" hour" + ((hours > 1) ? "s, " : ", "))) : "") + ((mins > 0) ? (mins + (" minute" + ((mins > 1) ? "s, " : ", "))) : "") + secs + (" second" + ((secs > 1) ? "s." : ".")); + return app.showingPlaylist.relationships.tracks.data.length + " track" + (app.showingPlaylist.relationships.tracks.data.length > 1 ? "s" : "") + ", " + ((hours > 0) ? (hours + (" hour" + ((hours > 1) ? "s, " : ", "))) : "") + ((mins > 0) ? (mins + (" minute" + ((mins > 1) ? "s, " : ", "))) : "") + secs + (" second" + ((secs > 1) ? "s." : ".")); } else return "" } catch (err) { return "" @@ -2354,76 +2418,84 @@ const app = new Vue({ array[j] = temp; } } + let kind = parent.substring(0, parent.indexOf(":")) let id = parent.substring(parent.indexOf(":") + 1, parent.length) let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; console.log(truekind, id) try { - if (app.library.songs.listing.length > childIndex && parent == "librarysongs") { + if (app.library.songs.displayListing.length > childIndex && parent == "librarysongs") { console.log(item) - if (item && ((app.library.songs.listing[childIndex].id != item.id))) { - childIndex = app.library.songs.listing.indexOf(item) + if (item && ((app.library.songs.displayListing[childIndex].id != item.id))) { + childIndex = app.library.songs.displayListing.indexOf(item) } - let query = app.library.songs.listing.map(item => new MusicKit.MediaItem(item)); - try { - app.mk.stop() - } catch (e) { - } - this.mk.clearQueue().then(function (_) { - if (app.mk.shuffleMode == 1){ shuffleArray(query)} - app.mk.queue.append(query) - if (childIndex != -1) { - app.mk.changeToMediaAtIndex(childIndex) - } else if (item) { - app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) + let query = app.library.songs.displayListing.map(item => new MusicKit.MediaItem(item)); + + + app.mk.stop().then(() => { + this.mk.clearQueue().then(function (_) { + if (app.mk.shuffleMode == 1) { + shuffleArray(query) + } + app.mk.queue.append(query) + if (childIndex != -1) { + app.mk.changeToMediaAtIndex(childIndex) + } else if (item) { + app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { + app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) + app.mk.play() + }) + } else { app.mk.play() - }) - } else { - app.mk.play() - } + } + }) }) } else { app.mk.stop().then(() => { - 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}).then(function () { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1).then(function(){ - if ((app.showingPlaylist && app.showingPlaylist.id == id)) { - let query = app.showingPlaylist.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); - if (query.length > 100) { - let u = query.slice(100); if (app.mk.shuffleMode == 1) { shuffleArray(u) } - app.mk.queue.append(u)} - } else { - app.getPlaylistFromID(id, true).then(function () { + 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}).then(function () { + app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1).then(function () { + if ((app.showingPlaylist && app.showingPlaylist.id == id)) { let query = app.showingPlaylist.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); - if (query.length > 100) { - let u = query.slice(100); if (app.mk.shuffleMode == 1) { shuffleArray(u) } - app.mk.queue.append(u)} - }) - } - }) + let u = query; + if (app.mk.shuffleMode == 1) { + shuffleArray(u) + } + app.mk.queue.append(u) + } else { + app.getPlaylistFromID(id, true).then(function () { + let query = app.showingPlaylist.relationships.tracks.data.map(item => new MusicKit.MediaItem(item)); + let u = query; + if (app.mk.shuffleMode == 1) { + shuffleArray(u) + } + app.mk.queue.append(u) + }) + } + }) - }) - } - else{ - this.mk.setQueue({[truekind]: [id]}).then(function (queue) { - if (item && ((queue._itemIDs[childIndex] != item.id))) { - childIndex = queue._itemIDs.indexOf(item.id) - } - if (childIndex != -1) { - app.mk.changeToMediaAtIndex(childIndex) - } else if (item) { - app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { - app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) - app.mk.play() }) } else { - app.mk.play() + this.mk.setQueue({[truekind]: [id]}).then(function (queue) { + if (item && ((queue._itemIDs[childIndex] != item.id))) { + childIndex = queue._itemIDs.indexOf(item.id) + } + if (childIndex != -1) { + app.mk.changeToMediaAtIndex(childIndex) + } else if (item) { + app.mk.playNext({[item.attributes.playParams.kind ?? item.type]: item.attributes.playParams.id ?? item.id}).then(function () { + app.mk.changeToMediaAtIndex(app.mk.queue._itemIDs.indexOf(item.id) ?? 1) + app.mk.play() + }) + } else { + app.mk.play() + } + }) } - })} - })} + }) + } } catch (err) { console.log(err) try { @@ -2524,7 +2596,8 @@ const app = new Vue({ if (type.slice(-1) != "s") { type += "s" } - let id = item.playParams.catalogId ? item.playParams.catalogId : item.id + type = type.replace("library-", "") + let id = item.attributes.playParams.catalogId ?? item.id let index = types.findIndex(function (type) { return type.type == this @@ -2535,7 +2608,11 @@ const app = new Vue({ types[index].id.push(id) } } - return await this.mk.api.catalogResources(types, {"omit[resource]": "autos", relate: "library", fields: "inLibrary"}) + return await this.mk.api.catalogResources(types, { + "omit[resource]": "autos", + relate: "library", + fields: "inLibrary" + }) }, isInLibrary(playParams) { let self = this @@ -2572,7 +2649,7 @@ const app = new Vue({ } }, getMediaItemArtwork(url, height = 64, width) { - if(typeof url == "undefined" || url == "") { + if (typeof url == "undefined" || url == "") { return "https://beta.music.apple.com/assets/product/MissingArtworkMusic.svg" } let newurl = `${url.replace('{w}', width ?? height).replace('{h}', height).replace('{f}', "webp").replace('{c}', ((width === 900) ? "sr" : "cc"))}`; @@ -2582,7 +2659,7 @@ const app = new Vue({ } return newurl }, - _rgbToRgb(rgb = [0,0,0]) { + _rgbToRgb(rgb = [0, 0, 0]) { // if rgb return `rgb(${rgb[0]},${rgb[1]},${rgb[2]})` }, @@ -2602,7 +2679,7 @@ const app = new Vue({ this.currentTrackID = this.mk.nowPlayingItem["id"]; document.querySelector('.bg-artwork').src = ""; if (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"]) { - getBase64FromUrl(this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"].replace('{w}', size).replace('{h}', size)).then(img =>{ + getBase64FromUrl(this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"].replace('{w}', size).replace('{h}', size)).then(img => { document.querySelectorAll('.bg-artwork').forEach(artwork => { artwork.src = img; }) @@ -2690,29 +2767,32 @@ const app = new Vue({ // }, - async getCurrentArtURL(){ - try{ + async getCurrentArtURL() { + try { this.currentArtUrl = ''; - if (app.mk.nowPlayingItem != null && app.mk.nowPlayingItem.attributes != null && app.mk.nowPlayingItem.attributes.artwork != null && app.mk.nowPlayingItem.attributes.artwork.url != null && app.mk.nowPlayingItem.attributes.artwork.url!= '' ) - { + if (app.mk.nowPlayingItem != null && app.mk.nowPlayingItem.attributes != null && app.mk.nowPlayingItem.attributes.artwork != null && app.mk.nowPlayingItem.attributes.artwork.url != null && app.mk.nowPlayingItem.attributes.artwork.url != '') { this.currentArtUrl = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? '').replace('{w}', 50).replace('{h}', 50); - try{ - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);} - catch (e) {} + try { + document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`); + } catch (e) { + } } else { let data = await this.mk.api.library.song(this.mk.nowPlayingItem.id); if (data != null && data !== "" && data.attributes != null && data.attributes.artwork != null) { this.currentArtUrl = (data["attributes"]["artwork"]["url"] ?? '').replace('{w}', 50).replace('{h}', 50); - try{ - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);} - catch (e) {} - } else {this.currentArtUrl = ''; - try{ - document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`);} - catch (e) {} + try { + document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`); + } catch (e) { + } + } else { + this.currentArtUrl = ''; + try { + document.querySelector('.app-playback-controls .artwork').style.setProperty('--artwork', `url("${this.currentArtUrl}")`); + } catch (e) { + } + } } - } - }catch(e){ + } catch (e) { } }, @@ -2737,7 +2817,7 @@ const app = new Vue({ const data = await this.mk.api.library.song(this.mk.nowPlayingItem.id) if (data != null && data !== "") { - getBase64FromUrl((data["attributes"]["artwork"]["url"]).toString()).then(img =>{ + getBase64FromUrl((data["attributes"]["artwork"]["url"]).toString()).then(img => { document.querySelector('.bg-artwork').forEach(artwork => { artwork.src = img; }) @@ -2763,16 +2843,16 @@ const app = new Vue({ let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { + if (!type.startsWith("library-")) { type = "library-" + type } id = item.id } let response = await this.mk.api.v3.music(`/v1/me/ratings/${type}?platform=web&ids=${id}`) - if(response.data.data.length != 0) { + if (response.data.data.length != 0) { let value = response.data.data[0].attributes.value return value - }else{ + } else { return 0 } }, @@ -2780,7 +2860,7 @@ const app = new Vue({ let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { + if (!type.startsWith("library-")) { type = "library-" + type } id = item.id @@ -2804,7 +2884,7 @@ const app = new Vue({ let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { + if (!type.startsWith("library-")) { type = "library-" + type } id = item.id @@ -2828,7 +2908,7 @@ const app = new Vue({ let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id if (item.id.startsWith("i.")) { - if(!type.startsWith("library-")) { + if (!type.startsWith("library-")) { type = "library-" + type } id = item.id @@ -2842,16 +2922,20 @@ const app = new Vue({ }, volumeWheel(event) { if (event.deltaY < 0) { - if(this.mk.volume < 1){ + if (this.mk.volume < 1) { if (this.mk.volume <= 0.9) { this.mk.volume += 0.1 - } else { this.mk.volume = 1 } + } else { + this.mk.volume = 1 + } } } else if (event.deltaY > 0) { - if(this.mk.volume > 0){ - if (this.mk.volume >= 0.1){ - this.mk.volume -= 0.1 - } else {this.mk.volume = 0} + if (this.mk.volume > 0) { + if (this.mk.volume >= 0.1) { + this.mk.volume -= 0.1 + } else { + this.mk.volume = 0 + } } } }, @@ -2921,10 +3005,53 @@ const app = new Vue({ items: [] }, normal: { + headerItems: [ + { + "icon": "./assets/feather/heart.svg", + "id": "love", + "name": "Love", + "hidden": false, + "disabled": true, + "action": function () { + app.love(app.mk.nowPlayingItem) + } + }, + { + "icon": "./assets/feather/heart.svg", + "id": "unlove", + "active": true, + "name": "Unlove", + "hidden": true, + "action": function () { + app.unlove(app.mk.nowPlayingItem) + } + }, + { + "icon": "./assets/feather/thumbs-down.svg", + "id": "dislike", + "name": "Dislike", + "hidden": false, + "disabled": true, + "action": function () { + app.dislike(app.mk.nowPlayingItem) + } + }, + { + "icon": "./assets/feather/thumbs-down.svg", + "id": "undo_dislike", + "name": "Undo dislike", + "active": true, + "hidden": true, + "action": function () { + app.unlove(app.mk.nowPlayingItem) + } + }, + ], items: [ { "icon": "./assets/feather/list.svg", "name": "Add to Playlist...", + "hidden": true, "action": function () { app.promptAddToPlaylist() } @@ -2935,51 +3062,15 @@ const app = new Vue({ "name": "Add to Library...", "disabled": false, "action": function () { - app.addToLibrary(item_id); + app.addToLibrary(app.mk.nowPlayingItem.id); // if (!isLibrary) {app.addToLibrary(item_id); this.mk.nowPlayingItem.attributes.playParams["isLibrary"] = true} else { app.removeFromLibrary(data_type,item_id); this.mk.nowPlayingItem.attributes.playParams["isLibrary"] = false}; } }, - { - "icon": "./assets/feather/heart.svg", - "id": "love", - "name": "Love", - "disabled": true, - "action": function () { - app.love(app.mk.nowPlayingItem) - } - }, - { - "icon": "./assets/feather/unheart.svg", - "id": "unlove", - "name": "Unlove", - "disabled": true, - "action": function () { - app.unlove(app.mk.nowPlayingItem) - } - }, - { - "icon": "./assets/feather/thumbs-down.svg", - "id": "dislike", - "name": "Dislike", - "disabled": true, - "action": function () { - app.dislike(app.mk.nowPlayingItem) - } - }, - { - "icon": "./assets/feather/x-circle.svg", - "id": "undo_dislike", - "name": "Undo dislike", - "disabled": true, - "action": function () { - app.unlove(app.mk.nowPlayingItem) - } - }, { "icon": "./assets/feather/radio.svg", "name": "Start Radio", "action": function () { - app.mk.setStationQueue({song: item_id}).then(() => { + app.mk.setStationQueue({song: app.mk.nowPlayingItem.id}).then(() => { app.mk.play() app.selectedMediaItems = [] }) @@ -3004,17 +3095,23 @@ const app = new Vue({ // }else{ // menus.normal.items.find(x => x.id == "addToLibrary").disabled = true // } + this.showMenuPanel(menus[useMenu], event) + + try{ + let rating = await app.getRating(app.mk.nowPlayingItem) + if (rating == 0) { + menus.normal.headerItems.find(x => x.id == 'love').disabled = false + menus.normal.headerItems.find(x => x.id == 'dislike').disabled = false + } else if (rating == 1) { + menus.normal.headerItems.find(x => x.id == 'unlove').hidden = false + menus.normal.headerItems.find(x => x.id == 'love').hidden = true + } else if (rating == -1) { + menus.normal.headerItems.find(x => x.id == 'undo_dislike').hidden = false + menus.normal.headerItems.find(x => x.id == 'dislike').hidden = true + } + } catch(err) { - let rating = await app.getRating(app.mk.nowPlayingItem) - if(rating == 0) { - menus.normal.items.find(x => x.id == 'love').disabled = false - menus.normal.items.find(x => x.id == 'dislike').disabled = false - }else if(rating == 1) { - menus.normal.items.find(x => x.id == 'unlove').disabled = false - }else if(rating == -1) { - menus.normal.items.find(x => x.id == 'undo_dislike').disabled = false } - CiderContextMenu.Create(event, menus[useMenu]) }, LastFMDeauthorize() { ipcRenderer.invoke('setStoreValue', 'lastfm.enabled', false).catch((e) => console.error(e)); @@ -3061,10 +3158,14 @@ const app = new Vue({ peak: peak } }, - fullscreen(flag){ + fullscreen(flag) { if (flag) { ipcRenderer.send('setFullScreen', true); - app.appMode = 'fullscreen'; + if (app.mk.nowPlayingItem.type && app.mk.nowPlayingItem.type.toLowerCase().includes("video")) { + document.querySelector('video#apple-music-video-player').requestFullscreen() + } else { + app.appMode = 'fullscreen'; + } document.addEventListener('keydown', event => { if (event.key === 'Escape' && app.appMode === 'fullscreen') { this.fullscreen(false); @@ -3079,6 +3180,41 @@ const app = new Vue({ } }) +Vue.component('animated-number', { + + template: "