LastFM Scrobbling
This commit is contained in:
parent
df6ba93242
commit
130cfed2b4
7 changed files with 331 additions and 22 deletions
66
index.js
66
index.js
|
@ -1,5 +1,7 @@
|
||||||
require('v8-compile-cache');
|
require('v8-compile-cache');
|
||||||
const { app } = require('electron');
|
const { app } = require('electron'),
|
||||||
|
{resolve} = require("path"),
|
||||||
|
CiderBase = require ('./src/main/cider-base');
|
||||||
|
|
||||||
// Analytics for debugging.
|
// Analytics for debugging.
|
||||||
const ElectronSentry = require("@sentry/electron");
|
const ElectronSentry = require("@sentry/electron");
|
||||||
|
@ -33,9 +35,11 @@ const configSchema = {
|
||||||
"enable_yt": false,
|
"enable_yt": false,
|
||||||
},
|
},
|
||||||
"lastfm": {
|
"lastfm": {
|
||||||
"enabled": true,
|
"enabled": false,
|
||||||
"scrobble_after": 30,
|
"scrobble_after": 30,
|
||||||
"auth_token": ""
|
"auth_token": "",
|
||||||
|
"enabledRemoveFeaturingArtists" : true,
|
||||||
|
"NowPlaying": "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,3 +124,59 @@ app.on('widevine-error', (error) => {
|
||||||
console.log('[Cider][Widevine] Widevine installation encountered an error: ' + error)
|
console.log('[Cider][Widevine] Widevine installation encountered an error: ' + error)
|
||||||
app.exit()
|
app.exit()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (process.defaultApp) {
|
||||||
|
if (process.argv.length >= 2) {
|
||||||
|
app.setAsDefaultProtocolClient('cider', process.execPath, [resolve(process.argv[1])])
|
||||||
|
app.setAsDefaultProtocolClient('ame', process.execPath, [resolve(process.argv[1])])
|
||||||
|
app.setAsDefaultProtocolClient('itms', process.execPath, [resolve(process.argv[1])])
|
||||||
|
app.setAsDefaultProtocolClient('itmss', process.execPath, [resolve(process.argv[1])])
|
||||||
|
app.setAsDefaultProtocolClient('musics', process.execPath, [resolve(process.argv[1])])
|
||||||
|
app.setAsDefaultProtocolClient('music', process.execPath, [resolve(process.argv[1])])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
app.setAsDefaultProtocolClient('cider') // Custom AME Protocol
|
||||||
|
app.setAsDefaultProtocolClient('ame') // Custom AME Protocol
|
||||||
|
app.setAsDefaultProtocolClient('itms') // iTunes HTTP Protocol
|
||||||
|
app.setAsDefaultProtocolClient('itmss') // iTunes HTTPS Protocol
|
||||||
|
app.setAsDefaultProtocolClient('musics') // macOS Client Protocol
|
||||||
|
app.setAsDefaultProtocolClient('music') // macOS Client Protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
app.on('open-url', (event, url) => {
|
||||||
|
event.preventDefault()
|
||||||
|
if (url.includes('ame://') || url.includes('itms://') || url.includes('itmss://') || url.includes('musics://') || url.includes('music://')) {
|
||||||
|
CiderBase.LinkHandler(url)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('second-instance', (_e, argv) => {
|
||||||
|
console.warn(`[InstanceHandler][SecondInstanceHandler] Second Instance Started with args: [${argv.join(', ')}]`)
|
||||||
|
|
||||||
|
// Checks if first instance is authorized and if second instance has protocol args
|
||||||
|
argv.forEach((value) => {
|
||||||
|
if (value.includes('ame://') || value.includes('itms://') || value.includes('itmss://') || value.includes('musics://') || value.includes('music://')) {
|
||||||
|
console.warn(`[InstanceHandler][SecondInstanceHandler] Found Protocol!`)
|
||||||
|
CiderBase.LinkHandler(value);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (argv.includes("--force-quit")) {
|
||||||
|
console.warn('[InstanceHandler][SecondInstanceHandler] Force Quit found. Quitting App.');
|
||||||
|
// app.isQuiting = true
|
||||||
|
app.quit()
|
||||||
|
} else if (CiderBase.win && true) { // If a Second Instance has Been Started
|
||||||
|
console.warn('[InstanceHandler][SecondInstanceHandler] Showing window.');
|
||||||
|
app.win.show()
|
||||||
|
app.win.focus()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!app.requestSingleInstanceLock() && true) {
|
||||||
|
console.warn("[InstanceHandler] Existing Instance is Blocking Second Instance.");
|
||||||
|
app.quit();
|
||||||
|
// app.isQuiting = true
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
"electron-window-state": "^5.0.3",
|
"electron-window-state": "^5.0.3",
|
||||||
"express": "^4.17.2",
|
"express": "^4.17.2",
|
||||||
"get-port": "^5.1.1",
|
"get-port": "^5.1.1",
|
||||||
|
"lastfmapi": "^0.1.1",
|
||||||
"mpris-service": "^2.1.2",
|
"mpris-service": "^2.1.2",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
|
4
resources/lfmApiCredentials.json
Normal file
4
resources/lfmApiCredentials.json
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"key": "174905d201451602407b428a86e8344d",
|
||||||
|
"secret": "be61d4081f6adec150f0130939f854bb"
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ const windowStateKeeper = require("electron-window-state");
|
||||||
const os = require('os');
|
const os = require('os');
|
||||||
const yt = require('youtube-search-without-api-key');
|
const yt = require('youtube-search-without-api-key');
|
||||||
const discord = require('./discordrpc');
|
const discord = require('./discordrpc');
|
||||||
|
const lastfm = require('./lastfm');
|
||||||
const mpris = require('./mpris');
|
const mpris = require('./mpris');
|
||||||
|
|
||||||
// Analytics for debugging.
|
// Analytics for debugging.
|
||||||
|
@ -14,9 +15,10 @@ const ElectronSentry = require("@sentry/electron");
|
||||||
ElectronSentry.init({dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214"});
|
ElectronSentry.init({dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214"});
|
||||||
|
|
||||||
const CiderBase = {
|
const CiderBase = {
|
||||||
|
win: null,
|
||||||
async Start() {
|
async Start() {
|
||||||
this.clientPort = await getPort({port: 9000});
|
this.clientPort = await getPort({port: 9000});
|
||||||
this.CreateBrowserWindow()
|
this.win = this.CreateBrowserWindow()
|
||||||
},
|
},
|
||||||
clientPort: 0,
|
clientPort: 0,
|
||||||
CreateBrowserWindow() {
|
CreateBrowserWindow() {
|
||||||
|
@ -204,15 +206,22 @@ const CiderBase = {
|
||||||
|
|
||||||
mpris.connect(win)
|
mpris.connect(win)
|
||||||
|
|
||||||
|
lastfm.authenticate()
|
||||||
// Discord
|
// Discord
|
||||||
discord.connect((app.cfg.get("general.discord_rpc") == 1) ? '911790844204437504' : '886578863147192350');
|
discord.connect((app.cfg.get("general.discord_rpc") == 1) ? '911790844204437504' : '886578863147192350');
|
||||||
ipcMain.on('playbackStateDidChange', (_event, a) => {
|
ipcMain.on('playbackStateDidChange', (_event, a) => {
|
||||||
|
app.media = a;
|
||||||
discord.updateActivity(a)
|
discord.updateActivity(a)
|
||||||
mpris.updateState(a)
|
mpris.updateState(a)
|
||||||
|
lastfm.scrobbleSong(a)
|
||||||
|
lastfm.updateNowPlayingSong(a)
|
||||||
});
|
});
|
||||||
ipcMain.on('nowPlayingItemDidChange', (_event, a) => {
|
ipcMain.on('nowPlayingItemDidChange', (_event, a) => {
|
||||||
|
app.media = a;
|
||||||
discord.updateActivity(a)
|
discord.updateActivity(a)
|
||||||
mpris.updateAttributes(a)
|
mpris.updateAttributes(a)
|
||||||
|
lastfm.scrobbleSong(a)
|
||||||
|
lastfm.updateNowPlayingSong(a)
|
||||||
});
|
});
|
||||||
|
|
||||||
return win
|
return win
|
||||||
|
@ -224,6 +233,31 @@ const CiderBase = {
|
||||||
dev: app.isPackaged
|
dev: app.isPackaged
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
LinkHandler: (startArgs) => {
|
||||||
|
if (!startArgs) return;
|
||||||
|
console.log("lfmtoken",String(startArgs))
|
||||||
|
if (String(startArgs).includes('auth')) {
|
||||||
|
let authURI = String(startArgs).split('/auth/')[1]
|
||||||
|
if (authURI.startsWith('lastfm')) { // If we wanted more auth options
|
||||||
|
const authKey = authURI.split('lastfm?token=')[1];
|
||||||
|
app.cfg.set('lastfm.enabled', true);
|
||||||
|
app.cfg.set('lastfm.auth_token', authKey);
|
||||||
|
CiderBase.win.webContents.send('LastfmAuthenticated', authKey);
|
||||||
|
lastfm.authenticate()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const formattedSongID = startArgs.replace('ame://', '').replace('/', '');
|
||||||
|
console.warn(`[LinkHandler] Attempting to load song id: ${formattedSongID}`);
|
||||||
|
|
||||||
|
// setQueue can be done with album, song, url, playlist id
|
||||||
|
this.win.webContents.executeJavaScript(`
|
||||||
|
MusicKit.getInstance().setQueue({ song: '${formattedSongID}'}).then(function(queue) {
|
||||||
|
MusicKit.getInstance().play();
|
||||||
|
});
|
||||||
|
`).catch((err) => console.error(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
async InitWebServer() {
|
async InitWebServer() {
|
||||||
const webapp = express();
|
const webapp = express();
|
||||||
|
|
153
src/main/lastfm.js
Normal file
153
src/main/lastfm.js
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
const {app, Notification} = require('electron'),
|
||||||
|
fs = require('fs'),
|
||||||
|
{resolve} = require('path'),
|
||||||
|
sessionPath = resolve(app.getPath('userData'), 'session.json'),
|
||||||
|
apiCredentials = require('../../resources/lfmApiCredentials.json'),
|
||||||
|
LastfmAPI = require('lastfmapi');
|
||||||
|
|
||||||
|
const lfm = {
|
||||||
|
authenticateFromFile: function () {
|
||||||
|
let sessionData = require(sessionPath)
|
||||||
|
console.log("[LastFM][authenticateFromFile] Logging in with Session Info.")
|
||||||
|
app.lastfm.setSessionCredentials(sessionData.name, sessionData.key)
|
||||||
|
console.log("[LastFM][authenticateFromFile] Logged in.")
|
||||||
|
},
|
||||||
|
|
||||||
|
authenticate: function () {
|
||||||
|
if (app.cfg.get('lastfm.auth_token')) {
|
||||||
|
app.cfg.set('lastfm.enabled', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!app.cfg.get('lastfm.enabled') || !app.cfg.get('lastfm.auth_token')) {
|
||||||
|
app.cfg.set('lastfm.enabled', false);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const lfmAPI = new LastfmAPI({
|
||||||
|
'api_key': apiCredentials.key,
|
||||||
|
'secret': apiCredentials.secret
|
||||||
|
});
|
||||||
|
|
||||||
|
app.lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false});
|
||||||
|
|
||||||
|
fs.stat(sessionPath, function (err) {
|
||||||
|
if (err) {
|
||||||
|
console.error("[LastFM][Session] Session file couldn't be opened or doesn't exist,", err)
|
||||||
|
console.log("[LastFM][Auth] Beginning authentication from configuration")
|
||||||
|
app.lastfm.authenticate(app.cfg.get('lastfm.auth_token'), function (err, session) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
console.log("[LastFM] Successfully obtained LastFM session info,", session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"}
|
||||||
|
console.log("[LastFM] Saving session info to disk.")
|
||||||
|
let tempData = JSON.stringify(session)
|
||||||
|
fs.writeFile(sessionPath, tempData, (err) => {
|
||||||
|
if (err)
|
||||||
|
console.log("[LastFM][fs]", err)
|
||||||
|
else {
|
||||||
|
console.log("[LastFM][fs] File was written successfully.")
|
||||||
|
lfm.authenticateFromFile()
|
||||||
|
new Notification({
|
||||||
|
title: app.getName(),
|
||||||
|
body: "Successfully logged into LastFM using Authentication Key."
|
||||||
|
}).show()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
lfm.authenticateFromFile()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
scrobbleSong: async function (attributes) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, app.cfg.get('lastfm.scrobble_after') * 1000));
|
||||||
|
const currentAttributes = app.media;
|
||||||
|
|
||||||
|
if (!app.lastfm || app.lastfm.cachedAttributes === attributes ) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app.lastfm.cachedAttributes) {
|
||||||
|
if (app.lastfm.cachedAttributes.playParams.id === attributes.playParams.id) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentAttributes.status && currentAttributes === attributes) {
|
||||||
|
if (fs.existsSync(sessionPath)) {
|
||||||
|
// Scrobble playing song.
|
||||||
|
if (attributes.status === true) {
|
||||||
|
app.lastfm.track.scrobble({
|
||||||
|
'artist': lfm.filterArtistName(attributes.artistName),
|
||||||
|
'track': attributes.name,
|
||||||
|
'album': attributes.albumName,
|
||||||
|
'albumArtist': this.filterArtistName(attributes.artistName),
|
||||||
|
'timestamp': new Date().getTime() / 1000
|
||||||
|
}, function (err, scrobbled) {
|
||||||
|
if (err) {
|
||||||
|
return console.error('[LastFM] An error occurred while scrobbling', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[LastFM] Successfully scrobbled: ', scrobbled);
|
||||||
|
});
|
||||||
|
app.lastfm.cachedAttributes = attributes
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.authenticate();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return console.log('[LastFM] Did not add ', attributes.name , '-' , lfm.filterArtistName(attributes.artistName), 'because now playing a other song.');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
filterArtistName: function (artist) {
|
||||||
|
if (!app.cfg.get('lastfm.enabledRemoveFeaturingArtists')) return artist;
|
||||||
|
|
||||||
|
artist = artist.split(' ');
|
||||||
|
if (artist.includes('&')) {
|
||||||
|
artist.length = artist.indexOf('&');
|
||||||
|
}
|
||||||
|
if (artist.includes('and')) {
|
||||||
|
artist.length = artist.indexOf('and');
|
||||||
|
}
|
||||||
|
artist = artist.join(' ');
|
||||||
|
if (artist.includes(',')) {
|
||||||
|
artist = artist.split(',')
|
||||||
|
artist = artist[0]
|
||||||
|
}
|
||||||
|
return artist.charAt(0).toUpperCase() + artist.slice(1);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateNowPlayingSong: function (attributes) {
|
||||||
|
if (!app.lastfm ||app.lastfm.cachedNowPlayingAttributes === attributes | !app.cfg.get('lastfm.NowPlaying')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (app.lastfm.cachedNowPlayingAttributes) {
|
||||||
|
if (app.lastfm.cachedNowPlayingAttributes.playParams.id === attributes.playParams.id) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs.existsSync(sessionPath)) {
|
||||||
|
// update Now Playing
|
||||||
|
if (attributes.status === true) {
|
||||||
|
app.lastfm.track.updateNowPlaying({
|
||||||
|
'artist': lfm.filterArtistName(attributes.artistName),
|
||||||
|
'track': attributes.name,
|
||||||
|
'album': attributes.albumName,
|
||||||
|
'albumArtist': this.filterArtistName(attributes.artistName)
|
||||||
|
}, function (err, nowPlaying) {
|
||||||
|
if (err) {
|
||||||
|
return console.error('[LastFM] An error occurred while updating nowPlayingSong', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying);
|
||||||
|
});
|
||||||
|
app.lastfm.cachedNowPlayingAttributes = attributes
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.authenticate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = lfm;
|
|
@ -2425,6 +2425,37 @@ const app = new Vue({
|
||||||
}
|
}
|
||||||
CiderContextMenu.Create(event, menus[useMenu])
|
CiderContextMenu.Create(event, menus[useMenu])
|
||||||
},
|
},
|
||||||
|
LastFMDeauthorize() {
|
||||||
|
ipcRenderer.invoke('setStoreValue', 'lastfm.enabled', false).catch((e) => console.error(e));
|
||||||
|
ipcRenderer.invoke('setStoreValue', 'lastfm.auth_token', '').catch((e) => console.error(e));
|
||||||
|
app.cfg.lastfm.auth_token = "";
|
||||||
|
app.cfg.lastfm.enabled = false;
|
||||||
|
const element = document.getElementById('lfmConnect');
|
||||||
|
element.innerHTML = 'Connect';
|
||||||
|
element.onclick = app.LastFMAuthenticate;
|
||||||
|
},
|
||||||
|
LastFMAuthenticate() {
|
||||||
|
console.log("wag")
|
||||||
|
const element = document.getElementById('lfmConnect');
|
||||||
|
window.open('https://www.last.fm/api/auth?api_key=174905d201451602407b428a86e8344d&cb=ame://auth/lastfm');
|
||||||
|
element.innerText = 'Connecting...';
|
||||||
|
|
||||||
|
/* Just a timeout for the button */
|
||||||
|
setTimeout(() => {
|
||||||
|
if (element.innerText === 'Connecting...') {
|
||||||
|
element.innerText = 'Connect';
|
||||||
|
console.warn('[LastFM] Attempted connection timed out.');
|
||||||
|
}
|
||||||
|
}, 20000);
|
||||||
|
|
||||||
|
ipcRenderer.on('LastfmAuthenticated', function (_event, lfmAuthKey) {
|
||||||
|
app.cfg.lastfm.auth_token = lfmAuthKey;
|
||||||
|
app.cfg.lastfm.enabled = true;
|
||||||
|
element.innerHTML = `Disconnect\n<p style="font-size: 8px"><i>(Authed: ${lfmAuthKey})</i></p>`;
|
||||||
|
element.onclick = app.LastFMDeauthorize;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -396,7 +396,7 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="md-option-line">
|
<div class="md-option-line" v-show="app.cfg.general.discord_rpc != 0">
|
||||||
<div class="md-option-segment">
|
<div class="md-option-segment">
|
||||||
Clear Discord RPC on Pause
|
Clear Discord RPC on Pause
|
||||||
</div>
|
</div>
|
||||||
|
@ -407,6 +407,39 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="md-option-line">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
LastFM Scrobbling
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto">
|
||||||
|
<label class="list-button list-element" id="lfmConnect" ref="lfmConnect"
|
||||||
|
onclick="app.LastFMAuthenticate()">Connect</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-option-line" v-show ="app.cfg.lastfm.enabled">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
LastFM Scrobble Delay
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto" >
|
||||||
|
<input type="number" v-model="app.cfg.lastfm.scrobble_after"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-option-line" v-show ="app.cfg.lastfm.enabled">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
Enable LastFM Now Playing
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto" >
|
||||||
|
<input type="checkbox" v-model="app.cfg.lastfm.NowPlaying" switch/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="md-option-line" v-show ="app.cfg.lastfm.enabled">
|
||||||
|
<div class="md-option-segment">
|
||||||
|
Remove featuring artists from song title (LastFM)
|
||||||
|
</div>
|
||||||
|
<div class="md-option-segment md-option-segment_auto" >
|
||||||
|
<input type="checkbox" v-model="app.cfg.lastfm.enabledRemoveFeaturingArtists" switch/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="md-option-header">
|
<div class="md-option-header">
|
||||||
<span>Unfinished / Non Functional</span>
|
<span>Unfinished / Non Functional</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -420,22 +453,6 @@
|
||||||
<input type="checkbox" switch/>
|
<input type="checkbox" switch/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="md-option-line">
|
|
||||||
<div class="md-option-segment">
|
|
||||||
LastFM Scrobbling
|
|
||||||
</div>
|
|
||||||
<div class="md-option-segment md-option-segment_auto">
|
|
||||||
<input type="checkbox" switch/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="md-option-line">
|
|
||||||
<div class="md-option-segment">
|
|
||||||
LastFM Scrobble Delay
|
|
||||||
</div>
|
|
||||||
<div class="md-option-segment md-option-segment_auto">
|
|
||||||
<input type="checkbox" switch/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="md-option-line">
|
<div class="md-option-line">
|
||||||
<div class="md-option-segment">
|
<div class="md-option-segment">
|
||||||
Theme
|
Theme
|
||||||
|
@ -520,6 +537,15 @@
|
||||||
app: this.$root
|
app: this.$root
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted: function () {
|
||||||
|
if (app.cfg.lastfm.enabled){
|
||||||
|
const element = document.getElementById('lfmConnect');
|
||||||
|
if (element){
|
||||||
|
element.innerHTML = `Disconnect\n<p style="font-size: 8px"><i>(Authed: ${app.cfg.lastfm.auth_token})</i></p>`;
|
||||||
|
element.onclick = app.LastFMDeauthorize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue