From ad9764a14983326558ab6f14cbe15a0edb82fc2d Mon Sep 17 00:00:00 2001 From: IrosTheBeggar Date: Mon, 28 Mar 2022 23:12:50 -0400 Subject: [PATCH] new scrobble api --- src/api/scanner.js | 2 +- src/api/scrobbler.js | 56 ++++++++++++++++++++++++++++++ webapp/alpha/api.js | 4 +++ webapp/alpha/m.js | 7 ---- webapp/assets/js/mstream.player.js | 22 ++++-------- 5 files changed, 67 insertions(+), 24 deletions(-) diff --git a/src/api/scanner.js b/src/api/scanner.js index aed3877..5ca9685 100644 --- a/src/api/scanner.js +++ b/src/api/scanner.js @@ -24,7 +24,7 @@ exports.setup = (mstream) => { else if (req.body.modTime !== dbFileInfo.modified) { db.getFileCollection().findAndRemove(dbObj); return res.json({}); - } + } // update the record with the new scan ID // This lets us clear out old files wit ha bulk delete at the end of the scan else { diff --git a/src/api/scrobbler.js b/src/api/scrobbler.js index 4ff8829..52d5d62 100644 --- a/src/api/scrobbler.js +++ b/src/api/scrobbler.js @@ -3,7 +3,9 @@ const Joi = require('joi'); const axios = require('axios'); const config = require('../state/config'); const scribble = require('../state/lastfm'); +const db = require('../db/manager'); const { joiValidate } = require('../util/validation'); +const { getVPathInfo } = require('../util/vpath'); const Scrobbler = new scribble(); @@ -37,6 +39,60 @@ exports.setup = (mstream) => { ); }); + mstream.post('/api/v1/lastfm/scrobble-by-filepath', (req, res) => { + const schema = Joi.object({ + filePath: Joi.string().required(), + }); + joiValidate(schema, req.body); + + // lookup metadata + const pathInfo = getVPathInfo(req.body.filePath, req.user); + + const dbObj = { '$and': [ + { 'filepath': { '$eq': pathInfo.relativePath } }, + { 'vpath': { '$eq': pathInfo.vpath } } + ]}; + const dbFileInfo = db.getFileCollection().findOne(dbObj); + + if (!dbFileInfo) { + return res.json({ scrobble: false }); + } + + // log play + const result = db.getUserMetadataCollection().findOne({ '$and':[{ 'hash': dbFileInfo.hash}, { 'user': req.user.username }] }); + + if (!result) { + db.getUserMetadataCollection().insert({ + user: req.user.username, + hash: dbFileInfo.hash, + pc: 1, + lp: Date.now() + }); + } else { + result.pc = result.pc && typeof result.pc === 'number' + ? result.pc + 1 : 1; + result.lp = Date.now(); + + db.getUserMetadataCollection().update(result); + } + + db.saveUserDB(); + res.json({}); + + if (req.user['lastfm-user'] && req.user['lastfm-password']) { + // scrobble on last fm + Scrobbler.Scrobble( + { + artist: dbFileInfo.artist, + album: dbFileInfo.album, + track: dbFileInfo.title + }, + req.user['lastfm-user'], + (post_return_data) => {} + ); + } + }); + mstream.post('/api/v1/lastfm/test-login', async (req, res) => { const schema = Joi.object({ username: Joi.string().required(), diff --git a/webapp/alpha/api.js b/webapp/alpha/api.js index 5c84967..287c9bb 100644 --- a/webapp/alpha/api.js +++ b/webapp/alpha/api.js @@ -120,6 +120,10 @@ const MSTREAMAPI = (() => { return req('POST', mstreamModule.currentServer.host + "api/v1/lastfm/scrobble-by-metadata", { artist: artist, album: album, track: trackName }); } + mstreamModule.scrobbleByFilePath = (filePath) => { + return req('POST', mstreamModule.currentServer.host + "api/v1/lastfm/scrobble-by-filepath", { filePath }); + } + // LOGIN mstreamModule.login = (username, password, url) => { return req('POST', url ? url + "api/v1/auth/login" : "api/v1/auth/login", { username: username, password: password }); diff --git a/webapp/alpha/m.js b/webapp/alpha/m.js index b3f6581..cf6d612 100644 --- a/webapp/alpha/m.js +++ b/webapp/alpha/m.js @@ -90,13 +90,6 @@ myDropzone.on('error', (err, msg, xhr) => { iziToast.error(iziStuff); }); -// Setup scrobbling -MSTREAMPLAYER.scrobble = function () { - if (MSTREAMPLAYER.playerStats.metadata.artist && MSTREAMPLAYER.playerStats.metadata.title) { - MSTREAMAPI.scrobbleByMetadata(MSTREAMPLAYER.playerStats.metadata.artist, MSTREAMPLAYER.playerStats.metadata.album, MSTREAMPLAYER.playerStats.metadata.title); - } -} - ////////////////////////////// Global Variables // These vars track your position within the file explorer var fileExplorerArray = []; diff --git a/webapp/assets/js/mstream.player.js b/webapp/assets/js/mstream.player.js index d52a27a..b1d9a56 100644 --- a/webapp/assets/js/mstream.player.js +++ b/webapp/assets/js/mstream.player.js @@ -40,9 +40,11 @@ const MSTREAMPLAYER = (() => { // Scrobble function // This is a placeholder function that the API layer can take hold of to implement the scrobble call - var scrobbleTimer; - mstreamModule.scrobble = function () { - return false; + let scrobbleTimer; + mstreamModule.scrobble = () => { + MSTREAMAPI.scrobbleByFilePath( + mstreamModule.getCurrentSong().rawFilePath, + (response, error) => {}); } // The audioData looks like this @@ -473,7 +475,7 @@ const MSTREAMPLAYER = (() => { // Scrobble song after 30 seconds clearTimeout(scrobbleTimer); - scrobbleTimer = setTimeout(function () { mstreamModule.scrobble() }, 30000); + scrobbleTimer = setTimeout(() => { mstreamModule.scrobble() }, 30000); } // Should be called whenever the "metadata" field of the current song is changed, or @@ -749,18 +751,6 @@ const MSTREAMPLAYER = (() => { lPlayer.playerObject.currentTime = seektime; } - // var timers = {}; - // startTime(100); - // function startTime(interval) { - // if (timers.sliderUpdateInterval) { clearInterval(timers.sliderUpdateInterval); } - - // timers.sliderUpdateInterval = setInterval(() => { - // const lPlayer = getCurrentPlayer(); - // mstreamModule.playerStats.currentTime = lPlayer.playerObject.currentTime; - // mstreamModule.playerStats.duration = lPlayer.playerObject.duration; - // }, interval); - // } - // Timer for caching. Helps prevent excess caching due to button mashing var cacheTimer; function setCachedSong(position) {