diff --git a/scrobblers/chromium-generic/background.js b/scrobblers/chromium-generic/background.js new file mode 100644 index 0000000..441b941 --- /dev/null +++ b/scrobblers/chromium-generic/background.js @@ -0,0 +1,237 @@ + + +chrome.tabs.onUpdated.addListener(onTabUpdated); +chrome.tabs.onRemoved.addListener(onTabRemoved); +//chrome.tabs.onActivated.addListener(onTabChanged); +chrome.runtime.onMessage.addListener(onPlaybackUpdate); + +tabManagers = {} + +pages = { + "plex":{ + "patterns":[ + "https://app.plex.tv", + "http://app.plex.tv", + "https://plex.", + "http://plex." + ], + "script":"plex.js" + }, + "youtube_music":{ + "patterns":[ + "https://music.youtube.com", + "http://music.youtube.com" + ], + "script":"ytmusic.js" + } + +} + + +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.currentLength) { + this.alreadyPlayed = this.alreadyPlayed - this.currentLength + scrobble(this.currentArtist,this.currentTitle,this.currentLength) + } + + 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 + this.currentLength = seconds + console.log(artist + " - " + title + " is playing!") + 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 + while (this.alreadyPlayed > this.currentLength) { + this.alreadyPlayed = this.alreadyPlayed - this.currentLength + scrobble(this.currentArtist,this.currentTitle,this.currentLength) + } + + 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 + } + + +} + + + + +function scrobble(artist,title,seconds) { + console.log("Scrobbling " + artist + " - " + title + "; " + seconds + " seconds playtime") + artiststring = encodeURIComponent(artist) + titlestring = encodeURIComponent(title) + chrome.storage.local.get("apikey",function(result) { + APIKEY = result["apikey"] + chrome.storage.local.get("serverurl",function(result) { + URL = result["serverurl"] + var xhttp = new XMLHttpRequest(); + xhttp.open("POST",URL + "/db/newscrobble",true); + xhttp.send("artist=" + artiststring + "&title=" + titlestring + "&duration=" + seconds + "&key=" + APIKEY) + }); + }); + + +} diff --git a/scrobblers/chromium-generic/icon128.png b/scrobblers/chromium-generic/icon128.png new file mode 100644 index 0000000..e2293c2 Binary files /dev/null and b/scrobblers/chromium-generic/icon128.png differ diff --git a/scrobblers/chromium-generic/icon256.png b/scrobblers/chromium-generic/icon256.png new file mode 100644 index 0000000..2cd97f9 Binary files /dev/null and b/scrobblers/chromium-generic/icon256.png differ diff --git a/scrobblers/chromium-generic/icon48.png b/scrobblers/chromium-generic/icon48.png new file mode 100644 index 0000000..863a541 Binary files /dev/null and b/scrobblers/chromium-generic/icon48.png differ diff --git a/scrobblers/chromium-generic/manifest.json b/scrobblers/chromium-generic/manifest.json new file mode 100644 index 0000000..90c333a --- /dev/null +++ b/scrobblers/chromium-generic/manifest.json @@ -0,0 +1,38 @@ +{ + "name": "Maloja Scrobbler", + "version": "0.1", + "description": "Scrobbles tracks from various sites to your Maloja server", + "manifest_version": 2, + "permissions": ["activeTab", + "declarativeContent", + "tabs", + "storage", + "http://*/", + "https://*/", + "" + ], + "background": + { + "scripts": + [ + "background.js" + ] + }, + + + "browser_action": + { + "default_icon": + { + "128":"icon128.png", + "48":"icon48.png" + }, + "default_popup": "settings.html", + "default_title": "Settings" + }, + "icons": + { + "128":"icon128.png", + "48":"icon48.png" + } +} diff --git a/scrobblers/chromium-generic/settings.html b/scrobblers/chromium-generic/settings.html new file mode 100644 index 0000000..07a8659 --- /dev/null +++ b/scrobblers/chromium-generic/settings.html @@ -0,0 +1,31 @@ + + + + + Wat + + + + + +
+ Server:
+ +

+ API key:
+ +
+ + diff --git a/scrobblers/chromium-generic/settings.js b/scrobblers/chromium-generic/settings.js new file mode 100644 index 0000000..ac403e2 --- /dev/null +++ b/scrobblers/chromium-generic/settings.js @@ -0,0 +1,77 @@ + +document.addEventListener("DOMContentLoaded",function() { + document.getElementById("serverurl").addEventListener("input",updateServer); + document.getElementById("apikey").addEventListener("input",updateAPIKey); + + document.getElementById("serverurl").addEventListener("change",checkServer); + document.getElementById("apikey").addEventListener("change",checkServer); + + + chrome.storage.local.get({"serverurl":"http://localhost:42010"},function(result) { + document.getElementById("serverurl").value = result["serverurl"] + checkServer() + }); + chrome.storage.local.get({"apikey":"BlackPinkInYourArea"},function(result) { + document.getElementById("apikey").value = result["apikey"] + checkServer() + }); + + + +}); + + + +function updateServer() { + + text = document.getElementById("serverurl").value + + + chrome.storage.local.set({"serverurl":text}) +} + +function updateAPIKey() { + text = document.getElementById("apikey").value + chrome.storage.local.set({"apikey":text}) +} + +function checkServer() { + url = document.getElementById("serverurl").value + "/db/test?key=" + document.getElementById("apikey").value + + var xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = createCheckmarks; + try { + xhttp.open("GET",url,true); + xhttp.send(); + } + catch (e) { + //document.getElementById("checkmark_url").innerHTML = "❌" + //document.getElementById("checkmark_key").innerHTML = "❌" + document.getElementById("serverurl").style.backgroundColor = "red" + document.getElementById("apikey").style.backgroundColor = "red" + } + +} + +function createCheckmarks() { + if (this.readyState == 4) { + if ((this.status == 204) || (this.status == 205)) { + //document.getElementById("checkmark_url").innerHTML = "✔️" + //document.getElementById("checkmark_key").innerHTML = "✔️" + document.getElementById("serverurl").style.backgroundColor = "lawngreen" + document.getElementById("apikey").style.backgroundColor = "lawngreen" + } + else if (this.status == 403) { + //document.getElementById("checkmark_url").innerHTML = "✔️" + //document.getElementById("checkmark_key").innerHTML = "❌" + document.getElementById("serverurl").style.backgroundColor = "lawngreen" + document.getElementById("apikey").style.backgroundColor = "red" + } + else { + //document.getElementById("checkmark_url").innerHTML = "❌" + //document.getElementById("checkmark_key").innerHTML = "❌" + document.getElementById("serverurl").style.backgroundColor = "red" + document.getElementById("apikey").style.backgroundColor = "red" + } + } +} diff --git a/scrobblers/chromium-generic/sitescripts/plex.js b/scrobblers/chromium-generic/sitescripts/plex.js new file mode 100644 index 0000000..d4fcfd1 --- /dev/null +++ b/scrobblers/chromium-generic/sitescripts/plex.js @@ -0,0 +1,38 @@ +bar = document.querySelector("div[class*=PlayerControls]") +if (bar == null) { + console.log("Nothing playing right now!") + chrome.runtime.sendMessage({type:"stopPlayback",artist:"",title:""}) + exit() +} + +metadata = bar.querySelector("div[class*=PlayerControlsMetadata-container]") + +title = metadata.querySelector("a[class*=MetadataPosterTitle-singleLineTitle]").getAttribute("title") +artist = metadata.querySelector("span[class*=MetadataPosterTitle-title] > a:nth-child(1)").getAttribute("title") +duration = metadata.querySelector("[data-qa-id=mediaDuration]").innerHTML.split("/")[1] +if (duration.split(":").length == 2) { + durationSeconds = parseInt(duration.split(":")[0]) * 60 + parseInt(duration.split(":")[1]) +} +else { + durationSeconds = parseInt(duration.split(":")[0]) * 60 * 60 + parseInt(duration.split(":")[1]) * 60 + parseInt(duration.split(":")[2]) +} + + +control = bar.querySelector("div[class*=PlayerControls-buttonGroupCenter] > button:nth-child(2)").getAttribute("title") +if (control == "Play") { + console.log("Not playing right now") + chrome.runtime.sendMessage({type:"stopPlayback",artist:artist,title:title}) + //stopPlayback() +} +else if (control == "Pause") { + console.log("Playing " + artist + " - " + title) + chrome.runtime.sendMessage({type:"startPlayback",artist:artist,title:title,duration:durationSeconds}) + //startPlayback(artist,title,durationSeconds) +} + + + + + + + diff --git a/scrobblers/chromium-generic/sitescripts/ytmusic.js b/scrobblers/chromium-generic/sitescripts/ytmusic.js new file mode 100644 index 0000000..b4e9a68 --- /dev/null +++ b/scrobblers/chromium-generic/sitescripts/ytmusic.js @@ -0,0 +1,40 @@ +bar = document.querySelector("ytmusic-player-bar") +if (bar == null) { + console.log("Nothing playing right now!") + chrome.runtime.sendMessage({type:"stopPlayback",artist:"",title:""}) + exit() +} + +metadata = bar.querySelector("div[class*=middle-controls] > div[class*=content-info-wrapper]") + +ctrl = bar.querySelector("div[class*=left-controls]") + +title = metadata.querySelector("yt-formatted-string[class*=title]").getAttribute("title") +artist = metadata.querySelector("span > span[class*=subtitle] > yt-formatted-string > a:nth-child(1)").innerHTML +duration = ctrl.querySelector("[class*=time-info]").innerHTML.split("/")[1] +if (duration.split(":").length == 2) { + durationSeconds = parseInt(duration.split(":")[0]) * 60 + parseInt(duration.split(":")[1]) +} +else { + durationSeconds = parseInt(duration.split(":")[0]) * 60 * 60 + parseInt(duration.split(":")[1]) * 60 + parseInt(duration.split(":")[2]) +} + + +control = ctrl.querySelector("div > paper-icon-button[class*=play-pause-button]").getAttribute("title") +if (control == "Play") { + console.log("Not playing right now") + chrome.runtime.sendMessage({type:"stopPlayback",artist:artist,title:title}) + //stopPlayback() +} +else if (control == "Pause") { + console.log("Playing " + artist + " - " + title) + chrome.runtime.sendMessage({type:"startPlayback",artist:artist,title:title,duration:durationSeconds}) + //startPlayback(artist,title,durationSeconds) +} + + + + + + +