diff --git a/src/main/base/wsapi.ts b/src/main/base/wsapi.ts index a10fd529..58f1affd 100644 --- a/src/main/base/wsapi.ts +++ b/src/main/base/wsapi.ts @@ -64,6 +64,15 @@ export class wsapi { electron.ipcMain.on('wsapi-returnvolumeMax', (_event: any, arg: any) => { this.returnmaxVolume(JSON.parse(arg)); }); + electron.ipcMain.on('wsapi-libraryStatus', (_event: any, inLibrary: boolean, rating: number) => { + this.returnLibraryStatus(inLibrary, rating); + }); + electron.ipcMain.on('wsapi-rate', (_event: any, kind: string, id: string, rating: number) => { + this.returnRatingStatus(kind, id, rating); + }); + electron.ipcMain.on('wsapi-change-library', (_event: any, kind: string, id: string, shouldAdd: boolean) => { + this.returnLibraryChange(kind, id, shouldAdd); + }); this.wss = new WebSocketServer({ port: this.port, perMessageDeflate: { @@ -242,6 +251,15 @@ export class wsapi { case "get-currentmediaitem": this._win.webContents.executeJavaScript(`wsapi.getPlaybackState()`); break; + case "library-status": + this._win.webContents.executeJavaScript(`wsapi.getLibraryStatus("${data.type}", "${data.id}")`); + break; + case "rating": + this._win.webContents.executeJavaScript(`wsapi.rate("${data.type}", "${data.id}", ${data.rating})`); + break; + case "change-library": + this._win.webContents.executeJavaScript(`wsapi.changeLibrary("${data.type}", "${data.id}", ${data.add})`); + break; case "quit": electron.app.quit(); break; @@ -317,4 +335,35 @@ export class wsapi { client.send(JSON.stringify(response)); }); } + + returnLibraryStatus(inLibrary: boolean, rating: number) { + const response: standardResponse = { + status: 0, data: { + inLibrary, rating + }, message: "OK", type: "libraryStatus" + } + this.clients.forEach(function each(client: any) { + client.send(JSON.stringify(response)); + }); + } + + returnRatingStatus(kind: string, id: string, rating: number) { + const response: standardResponse = { + status: 0, data: { kind, id, rating }, + message: "OK", type: "rate" + }; + this.clients.forEach(function each(client: any) { + client.send(JSON.stringify(response)); + }); + } + + returnLibraryChange(kind: string, id: string, shouldAdd: boolean) { + const response: standardResponse = { + status: 0, data: { kind, id, add: shouldAdd }, + message: "OK", type: "change-library" + }; + this.clients.forEach(function each(client: any) { + client.send(JSON.stringify(response)); + }); + } } \ No newline at end of file diff --git a/src/renderer/main/wsapi_interop.js b/src/renderer/main/wsapi_interop.js index 4439d956..c0bd0954 100644 --- a/src/renderer/main/wsapi_interop.js +++ b/src/renderer/main/wsapi_interop.js @@ -118,6 +118,76 @@ const wsapi = { }, getmaxVolume() { ipcRenderer.send('wsapi-returnvolumeMax',JSON.stringify(app.cfg.audio.maxVolume)); + }, + getLibraryStatus(kind, id) { + if (kind === undefined || id === "no-id-found") return; + + let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; + app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${id}`, { + relate: "library", + fields: "inLibrary" + }).then(data => { + const res = data.data.data[0]; + const inLibrary = res && res.attributes && res.attributes.inLibrary; + + app.getRating({ type: truekind, id: id }).then(rating => { + ipcRenderer.send('wsapi-libraryStatus', inLibrary, rating); + }) + }) + }, + rate(kind, id, rating) { + if (kind === undefined || id === "no-id-found") return; + + let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; + + if (rating === 0) { + app.mk.api.v3.music(`/v1/me/ratings/${truekind}/${id}`, {}, { + fetchOptions: { + method: "DELETE", + } + }).then(function () { + ipcRenderer.send('wsapi-rate', kind, id, rating); + }) + } else { + app.mk.api.v3.music(`/v1/me/ratings/${truekind}/${id}`, {}, { + fetchOptions: { + method: "PUT", + body: JSON.stringify({ + "type": "rating", + "attributes": { + "value": rating + } + }) + } + }).then(function () { + ipcRenderer.send('wsapi-rate', kind, id, rating); + }) + } + }, + changeLibrary(kind, id, shouldAdd) { + if (shouldAdd) { + app.addToLibrary(id); + ipcRenderer.send('wsapi-change-library', kind, id, shouldAdd); + } else { + let truekind = (!kind.endsWith("s")) ? (kind + "s") : kind; + + app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/?ids[${truekind}]=${id}`, { + relate: "library", + fields: "inLibrary" + }) + .then(res => { + res = res.data.data[0] + if (res && res.relationships && res.relationships.library && res.relationships.library.data) { + const item = res.relationships.library.data[0]; + + if (item) { + app.removeFromLibrary(kind, item.id) + } + + ipcRenderer.send('wsapi-change-library', kind, id, shouldAdd); + } + }); + } } } diff --git a/src/web-remote/index.js b/src/web-remote/index.js index 2e645485..d39cc216 100644 --- a/src/web-remote/index.js +++ b/src/web-remote/index.js @@ -24,7 +24,11 @@ var app = new Vue({ lyricsScrollingBlocked: false, queue: {}, lowerPanelState: "controls", - userInteraction: false + userInteraction: false, + status: { + inLibrary: false, + rating: 0 + } }, queue: { temp: [] @@ -246,6 +250,17 @@ var app = new Vue({ id: id })) }, + getLibraryStatus(type, id) { + if (type !== undefined && id !== "no-id-found") { + socket.send(JSON.stringify({ + action: "library-status", + type: type, + id: id + })) + } else { + this.player.status = {}; + } + }, searchQuery() { if (this.search.query.length == 0) { this.search.state = 0; @@ -412,8 +427,8 @@ var app = new Vue({ this.getQueue() }, queueMove(evt) { - console.log(evt) - console.log(`new: ${evt.moved.newIndex} old: ${evt.moved.oldIndex}`) + // console.log(evt) + // console.log(`new: ${evt.moved.newIndex} old: ${evt.moved.oldIndex}`) this.queue.temp.splice(evt.moved.newIndex, 0, this.queue.temp.splice(evt.moved.oldIndex, 1)[0]) socket.send(JSON.stringify({ action: "queue-move", @@ -557,11 +572,9 @@ var app = new Vue({ } socket.onmessage = (e) => { - console.log(e.data) const response = JSON.parse(e.data); switch (response.type) { - default: console.log(response); - break; + default: break; case "musickitapi.search": self.showArtist(response.data["artists"][0]["id"]); break; @@ -577,7 +590,8 @@ var app = new Vue({ } break; case "queue": - self.player.queue = response.data; + // console.log(response.data); + self.player.queue = response.data; self.queue.temp = response.data["_queueItems"]; self.$forceUpdate() break; @@ -601,6 +615,27 @@ var app = new Vue({ case "maxVolume": this.player.maxVolume = response.data; break; + case "libraryStatus": + this.player.status = response.data; + break; + case "rate": + var params = this.player.currentMediaItem.playParams; + if (params && params.id === response.data.id && params.kind === response.data.kind) { + this.player.status = { + rating: response.data.rating, + inLibrary: this.player.status.inLibrary + } + } + break; + case "change-library": + var params = this.player.currentMediaItem.playParams; + if (params && params.id === response.data.id && params.kind === response.data.kind) { + this.player.status = { + rating: this.player.status.rating, + inLibrary: response.data.add + } + } + break; } // console.log(e.data); } @@ -608,6 +643,8 @@ var app = new Vue({ updatePlaybackState(mediaitem) { var lyricsDisplayed = this.screen == "lyrics" || this.player.lowerPanelState == "lyrics" if (this.player.currentMediaItem["isrc"] != mediaitem["isrc"]) { + this.getLibraryStatus(mediaitem.playParams.kind, mediaitem.playParams.id) + if (lyricsDisplayed) { this.getLyrics() } @@ -617,6 +654,39 @@ var app = new Vue({ } this.player.currentMediaItem = mediaitem }, + openSongMenu() { + const params = this.player.currentMediaItem.playParams; + + if (params) { + this.getLibraryStatus(params.kind, params.id); + } + + this.player.songActions = true; + }, + rate(rating) { + const params = this.player.currentMediaItem.playParams; + + if (params && params.kind !== undefined && params.id !== "no-id-found") { + socket.send(JSON.stringify({ + action: "rating", + type: params.kind, + id: params.id, + rating: rating + })) + } + }, + toLibrary(shouldAdd) { + const params = this.player.currentMediaItem.playParams; + + if (params && params.kind !== undefined && params.id !== "no-id-found") { + socket.send(JSON.stringify({ + action: "change-library", + type: params.kind, + id: params.id, + add: shouldAdd + })) + } + }, quit() { socket.send(JSON.stringify({ action: "quit" diff --git a/src/web-remote/style.css b/src/web-remote/style.css index c1d4fe9e..d75e9d1c 100644 --- a/src/web-remote/style.css +++ b/src/web-remote/style.css @@ -838,6 +838,15 @@ input[type=range].web-slider::-webkit-slider-runnable-track { cursor: pointer; } +.context-menu .context-menu-item:disabled { + cursor: default; + filter: brightness(125%); +} + +.context-menu .context-menu-item:active:disabled { + filter: brightness(125%); +} + .context-menu .context-menu-item:active { filter: brightness(75%); } diff --git a/src/web-remote/views/index.ejs b/src/web-remote/views/index.ejs index 15a8264c..3c036d1a 100644 --- a/src/web-remote/views/index.ejs +++ b/src/web-remote/views/index.ejs @@ -130,8 +130,8 @@ {{ player.currentMediaItem.artistName }} -