chrome.tabs.onUpdated.addListener(onTabUpdated); chrome.tabs.onRemoved.addListener(onTabRemoved); //chrome.tabs.onActivated.addListener(onTabChanged); chrome.runtime.onMessage.addListener(onInternalMessage); tabManagers = {} const ALWAYS_SCROBBLE_SECONDS = 60*3; // Longer songs are always scrobbled when playing at least 2 minutes pages = { "plex":{ "name":"Plex", "patterns":[ "https://app.plex.tv", "http://app.plex.tv", "https://plex.", "http://plex." ], "script":"plex.js" }, "ytmusic":{ "name":"YouTube Music", "patterns":[ "https://music.youtube.com" ], "script":"ytmusic.js" }, "spotify":{ "name":"Spotify", "patterns":[ "https://open.spotify.com" ], "script":"spotify.js" }, "bandcamp":{ "name":"Bandcamp", "patterns":[ "bandcamp.com" ], "script":"bandcamp.js" }, "soundcloud":{ "name":"Soundcloud", "patterns":[ "https://soundcloud.com" ], "script":"soundcloud.js" }, "navidrome":{ "name":"Navidrome", "patterns":[ "https://navidrome.", "http://navidrome." ], "script":"navidrome.js" } } function updateTabNum() { var amount = Object.keys(tabManagers).length; chrome.browserAction.setBadgeText({"text":amount.toString()}); chrome.browserAction.setBadgeBackgroundColor({"color":"#333337"}); } function onTabUpdated(tabId, changeInfo, tab) { // still same page? //console.log("Update to tab " + tabId + "!") if (tabManagers.hasOwnProperty(tabId)) { //console.log("Yes!") page = tabManagers[tabId].page; patterns = pages[page]["patterns"]; //console.log("Page was managed by a " + page + " manager") for (var i=0;i { this.actuallyupdate(); },800); //this.actuallyupdate(); } } actuallyupdate() { this.messageID++; //console.log("Update! Our page is " + this.page + ", our tab id " + this.tabId) try { chrome.tabs.executeScript(this.tabId,{"file":"sites/" + pages[this.page]["script"]}); chrome.tabs.executeScript(this.tabId,{"file":"sitescript.js"}); } catch (e) { console.log("Could not run site script. Tab probably closed or something idk.") } this.alreadyQueued = false; } // an actual update message from the script has arrived playbackUpdate(request) { if (request.time < self.lastMessage) { console.log("Got message out of order, discarding!") return } self.lastMessage = request.time //console.log("Update message from our tab " + this.tabId + " (" + this.page + ")") if (request.type == "stopPlayback" && this.currentlyPlaying) { this.stopPlayback(request.artist,request.title); } else if (request.type == "startPlayback") { this.startPlayback(request.artist,request.title,request.duration); } } backlog_scrobble() { while (this.alreadyPlayed > this.currentLength) { this.alreadyPlayed = this.alreadyPlayed - this.currentLength var secondsago = this.alreadyPlayed scrobble(this.currentArtist,this.currentTitle,this.currentLength,secondsago) } } startPlayback(artist,title,seconds) { // CASE 1: Resuming playback of previously played title if (artist == this.currentArtist && title == this.currentTitle && !this.currentlyPlaying) { console.log("Resuming playback of " + this.currentTitle) // Already played full song? this.backlog_scrobble() this.setUpdate() this.currentlyPlaying = true } // CASE 2: New track is being played else if (artist != this.currentArtist || title != this.currentTitle) { //first inform ourselves that the previous track has now been stopped for good this.stopPlayback(artist,title); //then initialize new playback console.log("New track"); this.setUpdate(); this.alreadyPlayed = 0; this.currentTitle = title; this.currentArtist = artist; if (Number.isInteger(seconds)) { this.currentLength = seconds; } else { this.currentLength = 300; // avoid excessive scrobbling when the selector breaks } console.log(artist + " - " + title + " is playing! (" + this.currentLength + " seconds)"); this.currentlyPlaying = true; } } // the artist and title arguments are not attributes of the track being stopped, but of the track active now // they are here to recognize whether the playback has been paused or completely ended / replaced stopPlayback(artist,title) { //CASE 1: Playback just paused OR CASE 2: Playback ended if (this.currentlyPlaying) { var d = this.setUpdate() this.alreadyPlayed = this.alreadyPlayed + d console.log(d + " seconds played since last update, " + this.alreadyPlayed + " seconds played overall") } // Already played full song? this.backlog_scrobble() this.currentlyPlaying = false //ONLY CASE 2: Playback ended if (artist != this.currentArtist || title != this.currentTitle) { if ((this.alreadyPlayed > this.currentLength / 2) || (this.alreadyPlayed > ALWAYS_SCROBBLE_SECONDS)) { scrobble(this.currentArtist,this.currentTitle,this.alreadyPlayed) this.alreadyPlayed = 0 } } } // sets last updated to now and returns how long since then setUpdate() { var d = new Date() var t = Math.floor(d.getTime()/1000) var delta = t - this.lastUpdate this.lastUpdate = t return delta } } function scrobble(artist,title,seconds,secondsago=0) { console.log("Scrobbling " + artist + " - " + title + "; " + seconds + " seconds playtime, " + secondsago + " seconds ago") var d = new Date() var time = Math.floor(d.getTime()/1000) - secondsago //console.log("Time: " + time) var payload = { "artist":artist, "title":title, "duration":seconds, "time":time } chrome.storage.local.get(["serverurl","apikey"],function(result) { payload["key"] = result["apikey"]; var xhttp = new XMLHttpRequest(); xhttp.open("POST",result["serverurl"] + "/apis/mlj_1/newscrobble",true); xhttp.setRequestHeader("Content-Type", "application/json"); //xhttp.send(requestbody + "&key=" + APIKEY) var body = JSON.stringify(payload); xhttp.send(body) //console.log("Sent: " + body) }); }