mirror of
https://github.com/Mastermindzh/tidal-hifi.git
synced 2024-11-22 13:32:42 +01:00
Add ListenBrainz implementation
This commit is contained in:
parent
11cc209025
commit
3571289d28
@ -20,6 +20,12 @@ export const settings = {
|
|||||||
disableHardwareMediaKeys: "disableHardwareMediaKeys",
|
disableHardwareMediaKeys: "disableHardwareMediaKeys",
|
||||||
enableCustomHotkeys: "enableCustomHotkeys",
|
enableCustomHotkeys: "enableCustomHotkeys",
|
||||||
enableDiscord: "enableDiscord",
|
enableDiscord: "enableDiscord",
|
||||||
|
ListenBrainz: {
|
||||||
|
root: "ListenBrainz",
|
||||||
|
enabled: "ListenBrainz.enabled",
|
||||||
|
api: "ListenBrainz.api",
|
||||||
|
token: "ListenBrainz.token",
|
||||||
|
},
|
||||||
flags: {
|
flags: {
|
||||||
root: "flags",
|
root: "flags",
|
||||||
disableHardwareMediaKeys: "flags.disableHardwareMediaKeys",
|
disableHardwareMediaKeys: "flags.disableHardwareMediaKeys",
|
||||||
|
83
src/features/listenbrainz/listenbrainz.ts
Normal file
83
src/features/listenbrainz/listenbrainz.ts
Normal file
@ -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<any> {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -25,7 +25,11 @@ let adBlock: HTMLInputElement,
|
|||||||
skippedArtists: HTMLInputElement,
|
skippedArtists: HTMLInputElement,
|
||||||
theme: HTMLSelectElement,
|
theme: HTMLSelectElement,
|
||||||
trayIcon: HTMLInputElement,
|
trayIcon: HTMLInputElement,
|
||||||
updateFrequency: HTMLInputElement;
|
updateFrequency: HTMLInputElement,
|
||||||
|
enableListenBrainz: HTMLInputElement,
|
||||||
|
ListenBrainzAPI: HTMLInputElement,
|
||||||
|
ListenBrainzToken: HTMLInputElement;
|
||||||
|
|
||||||
function getThemeFiles() {
|
function getThemeFiles() {
|
||||||
const selectElement = document.getElementById("themesList") as HTMLSelectElement;
|
const selectElement = document.getElementById("themesList") as HTMLSelectElement;
|
||||||
const builtInThemes = getThemeListFromDirectory(process.resourcesPath);
|
const builtInThemes = getThemeListFromDirectory(process.resourcesPath);
|
||||||
@ -87,6 +91,9 @@ function refreshSettings() {
|
|||||||
skippedArtists.value = settingsStore.get<string, string[]>(settings.skippedArtists).join("\n");
|
skippedArtists.value = settingsStore.get<string, string[]>(settings.skippedArtists).join("\n");
|
||||||
trayIcon.checked = settingsStore.get(settings.trayIcon);
|
trayIcon.checked = settingsStore.get(settings.trayIcon);
|
||||||
updateFrequency.value = settingsStore.get(settings.updateFrequency);
|
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");
|
skippedArtists = get("skippedArtists");
|
||||||
singleInstance = get("singleInstance");
|
singleInstance = get("singleInstance");
|
||||||
updateFrequency = get("updateFrequency");
|
updateFrequency = get("updateFrequency");
|
||||||
|
enableListenBrainz = get("enableListenBrainz");
|
||||||
|
ListenBrainzAPI = get("ListenBrainzAPI");
|
||||||
|
ListenBrainzToken = get("ListenBrainzToken");
|
||||||
|
|
||||||
refreshSettings();
|
refreshSettings();
|
||||||
|
|
||||||
@ -206,4 +216,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||||||
addSelectListener(theme, settings.theme);
|
addSelectListener(theme, settings.theme);
|
||||||
addInputListener(trayIcon, settings.trayIcon);
|
addInputListener(trayIcon, settings.trayIcon);
|
||||||
addInputListener(updateFrequency, settings.updateFrequency);
|
addInputListener(updateFrequency, settings.updateFrequency);
|
||||||
|
addInputListener(enableListenBrainz, settings.ListenBrainz.enabled);
|
||||||
|
addTextAreaListener(ListenBrainzAPI, settings.ListenBrainz.api);
|
||||||
|
addTextAreaListener(ListenBrainzToken, settings.ListenBrainz.token);
|
||||||
});
|
});
|
||||||
|
@ -211,6 +211,30 @@
|
|||||||
<span class="switch__slider"></span>
|
<span class="switch__slider"></span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="group__option">
|
||||||
|
<div class="group__description">
|
||||||
|
<h4>ListenBrainz</h4>
|
||||||
|
<p>Scrobble your listens directly to ListenBrainz.</p>
|
||||||
|
</div>
|
||||||
|
<label class="switch">
|
||||||
|
<input id="enableListenBrainz" type="checkbox" />
|
||||||
|
<span class="switch__slider"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="group__option">
|
||||||
|
<div class="group__description">
|
||||||
|
<h4>ListenBrainz API Url</h4>
|
||||||
|
<p>There are multiple instances for ListenBrainz you can set the corresponding API url below.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea id="ListenBrainzAPI" class="textarea" cols="1" rows="1" spellcheck="false"></textarea>
|
||||||
|
<div class="group__option">
|
||||||
|
<div class="group__description">
|
||||||
|
<h4>ListenBrainz User Token</h4>
|
||||||
|
<p>Provide the user token you can get from the settings page.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea id="ListenBrainzToken" class="textarea" cols="1" rows="1" spellcheck="false"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import { globalEvents } from "./constants/globalEvents";
|
|||||||
import { settings } from "./constants/settings";
|
import { settings } from "./constants/settings";
|
||||||
import { statuses } from "./constants/statuses";
|
import { statuses } from "./constants/statuses";
|
||||||
import { Songwhip } from "./features/songwhip/songwhip";
|
import { Songwhip } from "./features/songwhip/songwhip";
|
||||||
|
import { ListenBrainz } from "./features/listenbrainz/listenbrainz";
|
||||||
import { Options } from "./models/options";
|
import { Options } from "./models/options";
|
||||||
import { downloadFile } from "./scripts/download";
|
import { downloadFile } from "./scripts/download";
|
||||||
import { addHotkey } from "./scripts/hotkeys";
|
import { addHotkey } from "./scripts/hotkeys";
|
||||||
@ -468,6 +469,9 @@ setInterval(function () {
|
|||||||
updateMediaInfo(options, titleOrArtistsChanged);
|
updateMediaInfo(options, titleOrArtistsChanged);
|
||||||
if (titleOrArtistsChanged) {
|
if (titleOrArtistsChanged) {
|
||||||
updateMediaSession(options);
|
updateMediaSession(options);
|
||||||
|
if (settingsStore.get(settings.ListenBrainz.enabled)) {
|
||||||
|
ListenBrainz.scrobble(options.title, options.artists, options.status, convertDuration(options.duration));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -18,6 +18,11 @@ export const settingsStore = new Store({
|
|||||||
disableHardwareMediaKeys: false,
|
disableHardwareMediaKeys: false,
|
||||||
enableCustomHotkeys: false,
|
enableCustomHotkeys: false,
|
||||||
enableDiscord: false,
|
enableDiscord: false,
|
||||||
|
ListenBrainz: {
|
||||||
|
enabled: false,
|
||||||
|
api: "https://api.listenbrainz.org",
|
||||||
|
token: "",
|
||||||
|
},
|
||||||
flags: {
|
flags: {
|
||||||
gpuRasterization: true,
|
gpuRasterization: true,
|
||||||
disableHardwareMediaKeys: false,
|
disableHardwareMediaKeys: false,
|
||||||
|
Loading…
Reference in New Issue
Block a user