From 3571289d28b66494bcf342af77bdf0fd76ab1a63 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 30 Jul 2023 02:38:01 +0200 Subject: [PATCH 1/9] Add ListenBrainz implementation --- src/constants/settings.ts | 6 ++ src/features/listenbrainz/listenbrainz.ts | 83 +++++++++++++++++++++++ src/pages/settings/preload.ts | 15 +++- src/pages/settings/settings.html | 24 +++++++ src/preload.ts | 4 ++ src/scripts/settings.ts | 5 ++ 6 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 src/features/listenbrainz/listenbrainz.ts diff --git a/src/constants/settings.ts b/src/constants/settings.ts index df2c39f..f437a57 100644 --- a/src/constants/settings.ts +++ b/src/constants/settings.ts @@ -20,6 +20,12 @@ export const settings = { disableHardwareMediaKeys: "disableHardwareMediaKeys", enableCustomHotkeys: "enableCustomHotkeys", enableDiscord: "enableDiscord", + ListenBrainz: { + root: "ListenBrainz", + enabled: "ListenBrainz.enabled", + api: "ListenBrainz.api", + token: "ListenBrainz.token", + }, flags: { root: "flags", disableHardwareMediaKeys: "flags.disableHardwareMediaKeys", diff --git a/src/features/listenbrainz/listenbrainz.ts b/src/features/listenbrainz/listenbrainz.ts new file mode 100644 index 0000000..812680c --- /dev/null +++ b/src/features/listenbrainz/listenbrainz.ts @@ -0,0 +1,83 @@ +import axios from "axios"; +import { settingsStore } from "../../scripts/settings"; +import { settings } from "../../constants/settings"; +import { MediaStatus } from "../../models/mediaStatus"; +import Store from "electron-store"; + +const ListenBrainzStore = new Store(); + +export class ListenBrainz { + /** + * Call the ListenBrainz API and create playing now payload + * @param title + * @param artists + * @param status + * @param duration + */ + public static async scrobble(title: string, artists: string, status: string, duration: number): Promise { + try { + if (status == MediaStatus.paused) { + return false; + } else { + // Fetches the OldData required for scrobbling and proceeds to construct a playing_now data payload for the Playing Now area + const OldData = ListenBrainzStore.get("OldData") as string[]; + const playing_data = { + listen_type: "playing_now", + payload: [ + { + track_metadata: { + additional_info: { + media_player: "Tidal Hi-Fi", + submission_client: "Tidal Hi-Fi", + music_service: "listen.tidal.com", + duration: duration, + }, + artist_name: artists, + track_name: title, + } + } + ] + }; + + await axios.post(`${settingsStore.get(settings.ListenBrainz.api)}/1/submit-listens`, playing_data, { + headers:{ + "Content-Type": "application/json", + "Authorization": `Token ${settingsStore.get(settings.ListenBrainz.token)}` + } + }); + if (!OldData) { + ListenBrainzStore.set("OldData", [Math.floor(new Date().getTime() / 1000), title, artists, duration]); + } else if (OldData[1] != title) { + // This constructs the data required to scrobble the data after the song finishes + const scrobble_data = { + listen_type: "single", + payload: [ + { + listened_at: OldData[0], + track_metadata: { + additional_info: { + media_player: "Tidal Hi-Fi", + submission_client: "Tidal Hi-Fi", + music_service: "listen.tidal.com", + duration: OldData[3], + }, + artist_name: OldData[2], + track_name: OldData[1], + } + } + ] + }; + await axios.post(`${settingsStore.get(settings.ListenBrainz.api)}/1/submit-listens`, scrobble_data, { + headers:{ + "Content-Type": "application/json", + "Authorization": `Token ${settingsStore.get(settings.ListenBrainz.token)}` + } + }); + ListenBrainzStore.set("OldData", [Math.floor(new Date().getTime() / 1000), title, artists, duration]); + } + } + } catch (error) { + console.log(JSON.stringify(error)); + } + } +} diff --git a/src/pages/settings/preload.ts b/src/pages/settings/preload.ts index 53ad096..ec2ed8e 100644 --- a/src/pages/settings/preload.ts +++ b/src/pages/settings/preload.ts @@ -25,7 +25,11 @@ let adBlock: HTMLInputElement, skippedArtists: HTMLInputElement, theme: HTMLSelectElement, trayIcon: HTMLInputElement, - updateFrequency: HTMLInputElement; + updateFrequency: HTMLInputElement, + enableListenBrainz: HTMLInputElement, + ListenBrainzAPI: HTMLInputElement, + ListenBrainzToken: HTMLInputElement; + function getThemeFiles() { const selectElement = document.getElementById("themesList") as HTMLSelectElement; const builtInThemes = getThemeListFromDirectory(process.resourcesPath); @@ -87,6 +91,9 @@ function refreshSettings() { skippedArtists.value = settingsStore.get(settings.skippedArtists).join("\n"); trayIcon.checked = settingsStore.get(settings.trayIcon); updateFrequency.value = settingsStore.get(settings.updateFrequency); + enableListenBrainz.checked = settingsStore.get(settings.ListenBrainz.enabled); + ListenBrainzAPI.value = settingsStore.get(settings.ListenBrainz.api); + ListenBrainzToken.value = settingsStore.get(settings.ListenBrainz.token); } /** @@ -183,6 +190,9 @@ window.addEventListener("DOMContentLoaded", () => { skippedArtists = get("skippedArtists"); singleInstance = get("singleInstance"); updateFrequency = get("updateFrequency"); + enableListenBrainz = get("enableListenBrainz"); + ListenBrainzAPI = get("ListenBrainzAPI"); + ListenBrainzToken = get("ListenBrainzToken"); refreshSettings(); @@ -206,4 +216,7 @@ window.addEventListener("DOMContentLoaded", () => { addSelectListener(theme, settings.theme); addInputListener(trayIcon, settings.trayIcon); addInputListener(updateFrequency, settings.updateFrequency); + addInputListener(enableListenBrainz, settings.ListenBrainz.enabled); + addTextAreaListener(ListenBrainzAPI, settings.ListenBrainz.api); + addTextAreaListener(ListenBrainzToken, settings.ListenBrainz.token); }); diff --git a/src/pages/settings/settings.html b/src/pages/settings/settings.html index 583b24b..5581777 100644 --- a/src/pages/settings/settings.html +++ b/src/pages/settings/settings.html @@ -211,6 +211,30 @@

Discord RPC

+
+
+

ListenBrainz

+

Scrobble your listens directly to ListenBrainz.

+
+ +
+
+
+

ListenBrainz API Url

+

There are multiple instances for ListenBrainz you can set the corresponding API url below.

+
+
+ +
+
+

ListenBrainz User Token

+

Provide the user token you can get from the settings page.

+
+
+ diff --git a/src/preload.ts b/src/preload.ts index dffedb6..40678a3 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -6,6 +6,7 @@ import { globalEvents } from "./constants/globalEvents"; import { settings } from "./constants/settings"; import { statuses } from "./constants/statuses"; import { Songwhip } from "./features/songwhip/songwhip"; +import { ListenBrainz } from "./features/listenbrainz/listenbrainz"; import { Options } from "./models/options"; import { downloadFile } from "./scripts/download"; import { addHotkey } from "./scripts/hotkeys"; @@ -468,6 +469,9 @@ setInterval(function () { updateMediaInfo(options, titleOrArtistsChanged); if (titleOrArtistsChanged) { updateMediaSession(options); + if (settingsStore.get(settings.ListenBrainz.enabled)) { + ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration)); + } } }); diff --git a/src/scripts/settings.ts b/src/scripts/settings.ts index 614f8d1..086504e 100644 --- a/src/scripts/settings.ts +++ b/src/scripts/settings.ts @@ -18,6 +18,11 @@ export const settingsStore = new Store({ disableHardwareMediaKeys: false, enableCustomHotkeys: false, enableDiscord: false, + ListenBrainz: { + enabled: false, + api: "https://api.listenbrainz.org", + token: "", + }, flags: { gpuRasterization: true, disableHardwareMediaKeys: false, From c0110632e6035de63c1299ebbf61209b9e84ca72 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 30 Jul 2023 10:41:16 +0200 Subject: [PATCH 2/9] Seperate old ListenBrainz data from config --- src/features/listenbrainz/listenbrainz.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/listenbrainz/listenbrainz.ts b/src/features/listenbrainz/listenbrainz.ts index 812680c..bbb4416 100644 --- a/src/features/listenbrainz/listenbrainz.ts +++ b/src/features/listenbrainz/listenbrainz.ts @@ -4,7 +4,7 @@ import { settings } from "../../constants/settings"; import { MediaStatus } from "../../models/mediaStatus"; import Store from "electron-store"; -const ListenBrainzStore = new Store(); +const ListenBrainzStore = new Store({name: "listenbrainz"}); export class ListenBrainz { /** From d81912db0c19bf3539f0d736903f99347e560785 Mon Sep 17 00:00:00 2001 From: Marie Date: Sun, 30 Jul 2023 11:46:27 +0200 Subject: [PATCH 3/9] Fix music_service domain --- src/features/listenbrainz/listenbrainz.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/listenbrainz/listenbrainz.ts b/src/features/listenbrainz/listenbrainz.ts index bbb4416..1107249 100644 --- a/src/features/listenbrainz/listenbrainz.ts +++ b/src/features/listenbrainz/listenbrainz.ts @@ -29,7 +29,7 @@ export class ListenBrainz { additional_info: { media_player: "Tidal Hi-Fi", submission_client: "Tidal Hi-Fi", - music_service: "listen.tidal.com", + music_service: "tidal.com", duration: duration, }, artist_name: artists, From e9434cc5ea4d353709517cc74302fdab196e644b Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 30 Jul 2023 21:17:03 +0200 Subject: [PATCH 4/9] Hide/Show ListenBrainz settings --- src/features/listenbrainz/listenbrainz.ts | 2 +- src/pages/settings/preload.ts | 5 +++++ src/pages/settings/settings.html | 24 ++++++++++++----------- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/features/listenbrainz/listenbrainz.ts b/src/features/listenbrainz/listenbrainz.ts index 1107249..f7a6e1d 100644 --- a/src/features/listenbrainz/listenbrainz.ts +++ b/src/features/listenbrainz/listenbrainz.ts @@ -8,7 +8,7 @@ const ListenBrainzStore = new Store({name: "listenbrainz"}); export class ListenBrainz { /** - * Call the ListenBrainz API and create playing now payload + * Call the ListenBrainz API and create playing now payload and scrobble old song * @param title * @param artists * @param status diff --git a/src/pages/settings/preload.ts b/src/pages/settings/preload.ts index ec2ed8e..11bd9c5 100644 --- a/src/pages/settings/preload.ts +++ b/src/pages/settings/preload.ts @@ -144,6 +144,10 @@ window.addEventListener("DOMContentLoaded", () => { } else { settingsStore.set(key, source.value); } + // Live update the view for ListenBrainz input, hide if disabled/show if enabled + if (source.value === "on" && source.id === "enableListenBrainz") { + source.checked ? document.getElementById("listenbrainz__options").hidden = false : document.getElementById("listenbrainz__options").hidden = true; + } ipcRenderer.send(globalEvents.storeChanged); }); } @@ -195,6 +199,7 @@ window.addEventListener("DOMContentLoaded", () => { ListenBrainzToken = get("ListenBrainzToken"); refreshSettings(); + enableListenBrainz.checked ? document.getElementById("listenbrainz__options").hidden = false : document.getElementById("listenbrainz__options").hidden = true; addInputListener(adBlock, settings.adBlock); addInputListener(api, settings.api); diff --git a/src/pages/settings/settings.html b/src/pages/settings/settings.html index 5581777..454608c 100644 --- a/src/pages/settings/settings.html +++ b/src/pages/settings/settings.html @@ -221,20 +221,22 @@

ListenBrainz

-
-
-

ListenBrainz API Url

-

There are multiple instances for ListenBrainz you can set the corresponding API url below.

+ - -
-
-

ListenBrainz User Token

-

Provide the user token you can get from the settings page.

+ +
+
+

ListenBrainz User Token

+

Provide the user token you can get from the settings page.

+
+
-
From ffe8278c8c78210306d79f8c29899a54725b3354 Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 30 Jul 2023 21:22:38 +0200 Subject: [PATCH 5/9] Fix complainy by sonarcloud --- src/pages/settings/preload.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/preload.ts b/src/pages/settings/preload.ts index 11bd9c5..d9d53d4 100644 --- a/src/pages/settings/preload.ts +++ b/src/pages/settings/preload.ts @@ -146,7 +146,7 @@ window.addEventListener("DOMContentLoaded", () => { } // Live update the view for ListenBrainz input, hide if disabled/show if enabled if (source.value === "on" && source.id === "enableListenBrainz") { - source.checked ? document.getElementById("listenbrainz__options").hidden = false : document.getElementById("listenbrainz__options").hidden = true; + source.checked ? document.getElementById("listenbrainz__options").setAttribute("hidden", "false") : document.getElementById("listenbrainz__options").setAttribute("hidden", "true"); } ipcRenderer.send(globalEvents.storeChanged); }); From ed6f04b6d4ae4815ec1ea32fcf8c681c2eec1a5f Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Sun, 30 Jul 2023 21:25:35 +0200 Subject: [PATCH 6/9] Fix bug where it does not unhide --- src/pages/settings/preload.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/settings/preload.ts b/src/pages/settings/preload.ts index d9d53d4..42f2e7b 100644 --- a/src/pages/settings/preload.ts +++ b/src/pages/settings/preload.ts @@ -146,7 +146,7 @@ window.addEventListener("DOMContentLoaded", () => { } // Live update the view for ListenBrainz input, hide if disabled/show if enabled if (source.value === "on" && source.id === "enableListenBrainz") { - source.checked ? document.getElementById("listenbrainz__options").setAttribute("hidden", "false") : document.getElementById("listenbrainz__options").setAttribute("hidden", "true"); + source.checked ? document.getElementById("listenbrainz__options").removeAttribute("hidden") : document.getElementById("listenbrainz__options").setAttribute("hidden", "true"); } ipcRenderer.send(globalEvents.storeChanged); }); @@ -199,7 +199,7 @@ window.addEventListener("DOMContentLoaded", () => { ListenBrainzToken = get("ListenBrainzToken"); refreshSettings(); - enableListenBrainz.checked ? document.getElementById("listenbrainz__options").hidden = false : document.getElementById("listenbrainz__options").hidden = true; + enableListenBrainz.checked ? document.getElementById("listenbrainz__options").removeAttribute("hidden") : document.getElementById("listenbrainz__options").setAttribute("hidden", "true"); addInputListener(adBlock, settings.adBlock); addInputListener(api, settings.api); From 38c1f05c35240f01badc0d13772ddab2ed275bde Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 31 Jul 2023 12:06:31 +0200 Subject: [PATCH 7/9] Allow listenbrainz to be triggered on every play --- src/features/listenbrainz/listenbrainz.ts | 2 ++ src/preload.ts | 13 +++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/features/listenbrainz/listenbrainz.ts b/src/features/listenbrainz/listenbrainz.ts index f7a6e1d..303c2eb 100644 --- a/src/features/listenbrainz/listenbrainz.ts +++ b/src/features/listenbrainz/listenbrainz.ts @@ -81,3 +81,5 @@ export class ListenBrainz { } } } + +export { ListenBrainzStore }; \ No newline at end of file diff --git a/src/preload.ts b/src/preload.ts index 40678a3..e1bbbff 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -6,7 +6,7 @@ import { globalEvents } from "./constants/globalEvents"; import { settings } from "./constants/settings"; import { statuses } from "./constants/statuses"; import { Songwhip } from "./features/songwhip/songwhip"; -import { ListenBrainz } from "./features/listenbrainz/listenbrainz"; +import { ListenBrainz, ListenBrainzStore } from "./features/listenbrainz/listenbrainz"; import { Options } from "./models/options"; import { downloadFile } from "./scripts/download"; import { addHotkey } from "./scripts/hotkeys"; @@ -202,6 +202,11 @@ function playPause() { } } +/** + * Clears the old listenbrainz data on launch + */ +ListenBrainzStore.clear(); + /** * Add hotkeys for when tidal is focused * Reflects the desktop hotkeys found on: @@ -372,6 +377,9 @@ function updateMediaInfo(options: Options, notify: boolean) { }; player.playbackStatus = options.status == statuses.paused ? "Paused" : "Playing"; } + if (settingsStore.get(settings.ListenBrainz.enabled) && (ListenBrainzStore.get("OldData") as string[][1]) !== options.title) { + ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration)); + } } } @@ -469,9 +477,6 @@ setInterval(function () { updateMediaInfo(options, titleOrArtistsChanged); if (titleOrArtistsChanged) { updateMediaSession(options); - if (settingsStore.get(settings.ListenBrainz.enabled)) { - ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration)); - } } }); From de8a5a1b07fa2b47ac10212553f40186110378ba Mon Sep 17 00:00:00 2001 From: Mar0xy Date: Mon, 31 Jul 2023 12:14:06 +0200 Subject: [PATCH 8/9] Fix bug where it does not run if condition --- src/preload.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/preload.ts b/src/preload.ts index e1bbbff..f580ba4 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -377,8 +377,13 @@ function updateMediaInfo(options: Options, notify: boolean) { }; player.playbackStatus = options.status == statuses.paused ? "Paused" : "Playing"; } - if (settingsStore.get(settings.ListenBrainz.enabled) && (ListenBrainzStore.get("OldData") as string[][1]) !== options.title) { - ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration)); + if (settingsStore.get(settings.ListenBrainz.enabled)) { + const data = ListenBrainzStore.get("OldData") as string[]; + if (data && data[1] !== options.title) { + ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration)); + } else if (!data) { + ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration)); + } } } } From 586f7b595b0edc11614d8753cd3d4a306b70f132 Mon Sep 17 00:00:00 2001 From: Mastermindzh Date: Mon, 31 Jul 2023 13:43:32 +0200 Subject: [PATCH 9/9] various code improvements and some boyscout rule fixes :) --- .vscode/settings.json | 4 + src/constants/statuses.ts | 4 - src/features/listenbrainz/listenbrainz.ts | 163 ++++++++++++------ src/features/listenbrainz/models/storeData.ts | 9 + src/features/logger.ts | 3 +- src/main.ts | 2 +- src/pages/settings/settings.html | 5 +- src/preload.ts | 79 +++++---- src/scripts/express.ts | 6 +- src/scripts/mediaInfo.ts | 4 +- 10 files changed, 180 insertions(+), 99 deletions(-) delete mode 100644 src/constants/statuses.ts create mode 100644 src/features/listenbrainz/models/storeData.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index f5bd08c..d25d0fe 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,14 @@ { "cSpell.words": [ + "Brainz", "flac", "geqnfr", "hifi", + "listenbrainz", "playpause", "rescrobbler", + "scrobble", + "scrobbling", "Songwhip", "trackid", "tracklist", diff --git a/src/constants/statuses.ts b/src/constants/statuses.ts deleted file mode 100644 index 3209307..0000000 --- a/src/constants/statuses.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const statuses = { - playing: "playing", - paused: "paused", -}; diff --git a/src/features/listenbrainz/listenbrainz.ts b/src/features/listenbrainz/listenbrainz.ts index 303c2eb..1032a72 100644 --- a/src/features/listenbrainz/listenbrainz.ts +++ b/src/features/listenbrainz/listenbrainz.ts @@ -1,12 +1,35 @@ import axios from "axios"; -import { settingsStore } from "../../scripts/settings"; +import { ipcRenderer } from "electron"; +import Store from "electron-store"; import { settings } from "../../constants/settings"; import { MediaStatus } from "../../models/mediaStatus"; -import Store from "electron-store"; +import { settingsStore } from "../../scripts/settings"; +import { Logger } from "../logger"; +import { StoreData } from "./models/storeData"; -const ListenBrainzStore = new Store({name: "listenbrainz"}); +const ListenBrainzStore = new Store({ name: "listenbrainz" }); + +export const ListenBrainzConstants = { + oldData: "oldData", +}; export class ListenBrainz { + /** + * Create the object to store old information in the Store :) + * @param title + * @param artists + * @param duration + * @returns data passed along in an object + a "listenedAt" key with the current time + */ + private static constructStoreData(title: string, artists: string, duration: number): StoreData { + return { + listenedAt: Math.floor(new Date().getTime() / 1000), + title, + artists, + duration, + }; + } + /** * Call the ListenBrainz API and create playing now payload and scrobble old song * @param title @@ -14,72 +37,98 @@ export class ListenBrainz { * @param status * @param duration */ - public static async scrobble(title: string, artists: string, status: string, duration: number): Promise { + public static async scrobble( + title: string, + artists: string, + status: string, + duration: number + ): Promise { try { - if (status == MediaStatus.paused) { - return false; + if (status === MediaStatus.paused) { + return; } else { - // Fetches the OldData required for scrobbling and proceeds to construct a playing_now data payload for the Playing Now area - const OldData = ListenBrainzStore.get("OldData") as string[]; + // Fetches the oldData required for scrobbling and proceeds to construct a playing_now data payload for the Playing Now area + const oldData = ListenBrainzStore.get(ListenBrainzConstants.oldData) as StoreData; const playing_data = { - listen_type: "playing_now", - payload: [ - { - track_metadata: { - additional_info: { - media_player: "Tidal Hi-Fi", - submission_client: "Tidal Hi-Fi", - music_service: "tidal.com", - duration: duration, - }, - artist_name: artists, - track_name: title, - } - } - ] + listen_type: "playing_now", + payload: [ + { + track_metadata: { + additional_info: { + media_player: "Tidal Hi-Fi", + submission_client: "Tidal Hi-Fi", + music_service: "tidal.com", + duration: duration, + }, + artist_name: artists, + track_name: title, + }, + }, + ], }; - await axios.post(`${settingsStore.get(settings.ListenBrainz.api)}/1/submit-listens`, playing_data, { - headers:{ - "Content-Type": "application/json", - "Authorization": `Token ${settingsStore.get(settings.ListenBrainz.token)}` - } - }); - if (!OldData) { - ListenBrainzStore.set("OldData", [Math.floor(new Date().getTime() / 1000), title, artists, duration]); - } else if (OldData[1] != title) { + await axios.post( + `${settingsStore.get(settings.ListenBrainz.api)}/1/submit-listens`, + playing_data, + { + headers: { + "Content-Type": "application/json", + Authorization: `Token ${settingsStore.get( + settings.ListenBrainz.token + )}`, + }, + } + ); + if (!oldData) { + ListenBrainzStore.set( + ListenBrainzConstants.oldData, + this.constructStoreData(title, artists, duration) + ); + } else { + if (oldData.title !== title) { // This constructs the data required to scrobble the data after the song finishes const scrobble_data = { - listen_type: "single", - payload: [ - { - listened_at: OldData[0], - track_metadata: { - additional_info: { - media_player: "Tidal Hi-Fi", - submission_client: "Tidal Hi-Fi", - music_service: "listen.tidal.com", - duration: OldData[3], - }, - artist_name: OldData[2], - track_name: OldData[1], - } - } - ] + listen_type: "single", + payload: [ + { + listened_at: oldData.listenedAt, + track_metadata: { + additional_info: { + media_player: "Tidal Hi-Fi", + submission_client: "Tidal Hi-Fi", + music_service: "listen.tidal.com", + duration: oldData.duration, + }, + artist_name: oldData.artists, + track_name: oldData.title, + }, + }, + ], }; - await axios.post(`${settingsStore.get(settings.ListenBrainz.api)}/1/submit-listens`, scrobble_data, { - headers:{ - "Content-Type": "application/json", - "Authorization": `Token ${settingsStore.get(settings.ListenBrainz.token)}` - } - }); - ListenBrainzStore.set("OldData", [Math.floor(new Date().getTime() / 1000), title, artists, duration]); + await axios.post( + `${settingsStore.get(settings.ListenBrainz.api)}/1/submit-listens`, + scrobble_data, + { + headers: { + "Content-Type": "application/json", + Authorization: `Token ${settingsStore.get( + settings.ListenBrainz.token + )}`, + }, + } + ); + ListenBrainzStore.set( + ListenBrainzConstants.oldData, + this.constructStoreData(title, artists, duration) + ); + } } } } catch (error) { - console.log(JSON.stringify(error)); + const logger = new Logger(ipcRenderer); + logger.log(JSON.stringify(error)); } } } -export { ListenBrainzStore }; \ No newline at end of file +export { ListenBrainzStore }; diff --git a/src/features/listenbrainz/models/storeData.ts b/src/features/listenbrainz/models/storeData.ts new file mode 100644 index 0000000..3501c69 --- /dev/null +++ b/src/features/listenbrainz/models/storeData.ts @@ -0,0 +1,9 @@ +/** + * Data saved for ListenBrainz + */ +export interface StoreData { + listenedAt: number; + title: string; + artists: string; + duration: number; +} diff --git a/src/features/logger.ts b/src/features/logger.ts index 020a3cc..11868f0 100644 --- a/src/features/logger.ts +++ b/src/features/logger.ts @@ -26,8 +26,7 @@ export class Logger { public log(content: string, object: object = {}) { if (this.ipcRenderer) { this.ipcRenderer.send(globalEvents.log, { content, object }); - } else { - console.log(`${content} \n ${JSON.stringify(object, null, 2)}`); } + console.log(`${content} \n ${JSON.stringify(object, null, 2)}`); } } diff --git a/src/main.ts b/src/main.ts index 7de3b94..130a7a5 100644 --- a/src/main.ts +++ b/src/main.ts @@ -58,7 +58,7 @@ function setFlags() { } /** - * Update the menuBarVisbility according to the store value + * Update the menuBarVisibility according to the store value * */ function syncMenuBarWithStore() { diff --git a/src/pages/settings/settings.html b/src/pages/settings/settings.html index 454608c..6b90c07 100644 --- a/src/pages/settings/settings.html +++ b/src/pages/settings/settings.html @@ -211,9 +211,12 @@

Discord RPC

+
+
+

ListenBrainz

-

ListenBrainz

+

Enable ListenBrainz

Scrobble your listens directly to ListenBrainz.