2019-04-07 14:13:12 +03:00
|
|
|
|
|
|
|
|
|
|
|
chrome.tabs.onUpdated.addListener(onTabUpdated);
|
|
|
|
chrome.tabs.onRemoved.addListener(onTabRemoved);
|
|
|
|
//chrome.tabs.onActivated.addListener(onTabChanged);
|
2019-04-07 18:14:50 +03:00
|
|
|
chrome.runtime.onMessage.addListener(onInternalMessage);
|
2019-04-07 14:13:12 +03:00
|
|
|
|
|
|
|
tabManagers = {}
|
|
|
|
|
|
|
|
pages = {
|
2019-04-07 18:14:50 +03:00
|
|
|
"Plex Web":{
|
2019-04-07 14:13:12 +03:00
|
|
|
"patterns":[
|
|
|
|
"https://app.plex.tv",
|
|
|
|
"http://app.plex.tv",
|
|
|
|
"https://plex.",
|
|
|
|
"http://plex."
|
|
|
|
],
|
|
|
|
"script":"plex.js"
|
|
|
|
},
|
2019-04-07 18:14:50 +03:00
|
|
|
"YouTube Music":{
|
2019-04-07 14:13:12 +03:00
|
|
|
"patterns":[
|
2019-05-17 18:56:29 +03:00
|
|
|
"https://music.youtube.com"
|
2019-04-07 14:13:12 +03:00
|
|
|
],
|
|
|
|
"script":"ytmusic.js"
|
2019-05-17 18:56:29 +03:00
|
|
|
},
|
|
|
|
"Spotify Web":{
|
|
|
|
"patterns":[
|
|
|
|
"https://open.spotify.com"
|
|
|
|
],
|
|
|
|
"script":"spotify.js"
|
2019-06-25 17:05:36 +03:00
|
|
|
},
|
|
|
|
"Bandcamp":{
|
|
|
|
"patterns":[
|
|
|
|
"bandcamp.com"
|
|
|
|
],
|
|
|
|
"script":"bandcamp.js"
|
2019-06-25 17:50:09 +03:00
|
|
|
},
|
|
|
|
"Soundcloud":{
|
|
|
|
"patterns":[
|
|
|
|
"https://soundcloud.com"
|
|
|
|
],
|
|
|
|
"script":"soundcloud.js"
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-05-19 12:09:35 +03:00
|
|
|
function updateTabNum() {
|
|
|
|
|
|
|
|
var amount = Object.keys(tabManagers).length;
|
|
|
|
chrome.browserAction.setBadgeText({"text":amount.toString()});
|
2019-05-20 18:38:05 +03:00
|
|
|
chrome.browserAction.setBadgeBackgroundColor({"color":"#333337"});
|
2019-05-19 12:09:35 +03:00
|
|
|
}
|
|
|
|
|
2019-04-07 14:13:12 +03:00
|
|
|
|
|
|
|
function onTabUpdated(tabId, changeInfo, tab) {
|
|
|
|
|
|
|
|
|
|
|
|
// still same page?
|
|
|
|
//console.log("Update to tab " + tabId + "!")
|
|
|
|
if (tabManagers.hasOwnProperty(tabId)) {
|
|
|
|
//console.log("Yes!")
|
2019-05-19 12:09:35 +03:00
|
|
|
page = tabManagers[tabId].page;
|
|
|
|
patterns = pages[page]["patterns"];
|
2019-04-07 14:13:12 +03:00
|
|
|
//console.log("Page was managed by a " + page + " manager")
|
|
|
|
for (var i=0;i<patterns.length;i++) {
|
2019-06-25 17:05:36 +03:00
|
|
|
if (tab.url.includes(patterns[i])) {
|
2019-04-07 14:13:12 +03:00
|
|
|
//console.log("Still on same page!")
|
2019-05-19 12:09:35 +03:00
|
|
|
tabManagers[tabId].update();
|
2019-05-13 14:18:22 +03:00
|
|
|
|
2019-04-07 14:13:12 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2019-05-19 12:09:35 +03:00
|
|
|
console.log("Page on tab " + tabId + " changed, removing old " + page + " manager!");
|
|
|
|
delete tabManagers[tabId];
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//check if pattern matches
|
|
|
|
for (var key in pages) {
|
|
|
|
if (pages.hasOwnProperty(key)) {
|
2019-05-19 12:09:35 +03:00
|
|
|
patterns = pages[key]["patterns"];
|
2019-04-07 14:13:12 +03:00
|
|
|
for (var i=0;i<patterns.length;i++) {
|
2019-06-25 17:05:36 +03:00
|
|
|
if (tab.url.includes(patterns[i])) {
|
2019-05-19 12:09:35 +03:00
|
|
|
console.log("New page on tab " + tabId + " will be handled by new " + key + " manager!");
|
|
|
|
tabManagers[tabId] = new Controller(tabId,key);
|
|
|
|
updateTabNum();
|
2019-04-07 14:13:12 +03:00
|
|
|
return
|
|
|
|
//chrome.tabs.executeScript(tab.id,{"file":"sitescripts/" + pages[key]["script"]})
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function onTabRemoved(tabId,removeInfo) {
|
|
|
|
|
|
|
|
if (tabManagers.hasOwnProperty(tabId)) {
|
2019-05-19 12:09:35 +03:00
|
|
|
page = tabManagers[tabId].page;
|
|
|
|
console.log("closed tab was " + page + ", now removing manager");
|
|
|
|
tabManagers[tabId].stopPlayback("",""); //in case we want to scrobble the playing track
|
|
|
|
delete tabManagers[tabId];
|
|
|
|
updateTabNum();
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-04-07 18:14:50 +03:00
|
|
|
function onInternalMessage(request,sender) {
|
|
|
|
// message from settings menu
|
|
|
|
if (request.type == "query") {
|
|
|
|
answer = [];
|
|
|
|
for (tabId in tabManagers) {
|
|
|
|
manager = tabManagers[tabId]
|
|
|
|
if (manager.currentlyPlaying) {
|
2019-05-19 12:09:35 +03:00
|
|
|
answer.push([manager.page,manager.currentArtist,manager.currentTitle]);
|
2019-04-07 18:14:50 +03:00
|
|
|
}
|
|
|
|
else {
|
2019-05-19 12:09:35 +03:00
|
|
|
answer.push([manager.page,null]);
|
2019-04-07 18:14:50 +03:00
|
|
|
}
|
2019-04-07 14:13:12 +03:00
|
|
|
|
2019-04-07 18:14:50 +03:00
|
|
|
}
|
|
|
|
chrome.runtime.sendMessage({"type":"response","content":answer})
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
2019-04-07 18:14:50 +03:00
|
|
|
|
|
|
|
//message from content script
|
|
|
|
if (request.type == "startPlayback" || request.type == "stopPlayback") {
|
|
|
|
tabId = sender.tab.id
|
|
|
|
//console.log("Message was sent from tab id " + tabId)
|
|
|
|
if (tabManagers.hasOwnProperty(tabId)) {
|
|
|
|
//console.log("This is managed! Seems to be " + tabManagers[tabId].page)
|
2019-05-19 12:09:35 +03:00
|
|
|
tabManagers[tabId].playbackUpdate(request);
|
2019-04-07 18:14:50 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-07 14:13:12 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class Controller {
|
|
|
|
|
|
|
|
constructor(tabId,page) {
|
|
|
|
this.tabId = tabId;
|
|
|
|
this.page = page;
|
|
|
|
|
|
|
|
this.currentTitle;
|
|
|
|
this.currentArtist;
|
|
|
|
this.currentLength;
|
|
|
|
this.alreadyPlayed;
|
|
|
|
this.currentlyPlaying = false;
|
|
|
|
this.lastUpdate = 0;
|
|
|
|
this.alreadyScrobbled = false;
|
|
|
|
|
|
|
|
this.messageID = 0;
|
2019-04-08 16:14:51 +03:00
|
|
|
this.lastMessage = 0;
|
2019-04-07 14:13:12 +03:00
|
|
|
|
2019-05-13 14:18:22 +03:00
|
|
|
this.alreadyQueued = false;
|
|
|
|
// we reject update requests when we're already planning to run an update!
|
|
|
|
|
|
|
|
this.update();
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// the tab has been updated, we need to run the script
|
|
|
|
update() {
|
2019-05-13 14:18:22 +03:00
|
|
|
if (this.alreadyQueued) {
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this.alreadyQueued = true;
|
|
|
|
setTimeout(() => { this.actuallyupdate(); },800);
|
|
|
|
//this.actuallyupdate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
actuallyupdate() {
|
2019-04-07 14:13:12 +03:00
|
|
|
this.messageID++;
|
|
|
|
//console.log("Update! Our page is " + this.page + ", our tab id " + this.tabId)
|
2019-06-26 18:11:46 +03:00
|
|
|
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.")
|
|
|
|
}
|
2019-05-13 14:18:22 +03:00
|
|
|
|
|
|
|
this.alreadyQueued = false;
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// an actual update message from the script has arrived
|
|
|
|
playbackUpdate(request) {
|
2019-04-08 16:14:51 +03:00
|
|
|
|
|
|
|
if (request.time < self.lastMessage) {
|
|
|
|
console.log("Got message out of order, discarding!")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
self.lastMessage = request.time
|
|
|
|
|
2019-04-07 14:13:12 +03:00
|
|
|
//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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
while (this.alreadyPlayed > this.currentLength) {
|
|
|
|
this.alreadyPlayed = this.alreadyPlayed - this.currentLength
|
2019-05-31 17:02:39 +03:00
|
|
|
var secondsago = this.alreadyPlayed
|
|
|
|
scrobble(this.currentArtist,this.currentTitle,this.currentLength,secondsago)
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2019-05-13 14:18:22 +03:00
|
|
|
this.stopPlayback(artist,title);
|
2019-04-07 14:13:12 +03:00
|
|
|
//then initialize new playback
|
2019-05-13 14:18:22 +03:00
|
|
|
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;
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
while (this.alreadyPlayed > this.currentLength) {
|
|
|
|
this.alreadyPlayed = this.alreadyPlayed - this.currentLength
|
2019-05-31 17:02:39 +03:00
|
|
|
var secondsago = this.alreadyPlayed
|
|
|
|
scrobble(this.currentArtist,this.currentTitle,this.currentLength,secondsago)
|
2019-04-07 14:13:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
this.currentlyPlaying = false
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//ONLY CASE 2: Playback ended
|
|
|
|
if (artist != this.currentArtist || title != this.currentTitle) {
|
|
|
|
if (this.alreadyPlayed > this.currentLength / 2) {
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-05-31 17:02:39 +03:00
|
|
|
function scrobble(artist,title,seconds,secondsago=0) {
|
|
|
|
console.log("Scrobbling " + artist + " - " + title + "; " + seconds + " seconds playtime, " + secondsago + " seconds ago")
|
|
|
|
var artiststring = encodeURIComponent(artist)
|
|
|
|
var titlestring = encodeURIComponent(title)
|
|
|
|
var d = new Date()
|
|
|
|
var time = Math.floor(d.getTime()/1000) - secondsago
|
|
|
|
//console.log("Time: " + time)
|
|
|
|
var requestbody = "artist=" + artiststring + "&title=" + titlestring + "&duration=" + seconds + "&time=" + time
|
2019-04-07 14:13:12 +03:00
|
|
|
chrome.storage.local.get("apikey",function(result) {
|
|
|
|
APIKEY = result["apikey"]
|
|
|
|
chrome.storage.local.get("serverurl",function(result) {
|
|
|
|
URL = result["serverurl"]
|
|
|
|
var xhttp = new XMLHttpRequest();
|
2019-05-12 11:20:47 +03:00
|
|
|
xhttp.open("POST",URL + "/api/newscrobble",true);
|
2019-05-31 17:02:39 +03:00
|
|
|
xhttp.send(requestbody + "&key=" + APIKEY)
|
|
|
|
//console.log("Sent: " + requestbody)
|
2019-04-07 14:13:12 +03:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
}
|