1
0
mirror of https://github.com/krateng/maloja.git synced 2023-08-10 21:12:55 +03:00

Added questionably performing YouTube Music scrobbler

This commit is contained in:
Krateng 2019-03-14 19:05:47 +01:00
parent 25d290df39
commit 15ccc006a0
20 changed files with 398 additions and 0 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

1
scrobblers/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.xcf

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,231 @@
chrome.tabs.onUpdated.addListener(onTabUpdated);
chrome.tabs.onRemoved.addListener(onTabRemoved);
chrome.tabs.onActivated.addListener(onTabChanged);
chrome.runtime.onMessage.addListener(onPlaybackUpdate);
function onTabUpdated(tabId, changeInfo, tab) {
console.log("Update")
chrome.tabs.get(tabId,party)
}
function onTabRemoved() {
}
function onTabChanged(activeInfo) {
}
function party(tab) {
var patterns = [
"https://music.youtube.com",
"http://music.youtube.com"
];
importantPage = false
for (var i=0;i<patterns.length;i++) {
if (tab.url.startsWith(patterns[i])) {
importantPage = true
}
}
if (importantPage) {
chrome.tabs.executeScript(tab.id,{"file":"contentScript.js"})
}
}
function onPlaybackUpdate(request,sender) {
//console.log("Got update from Plex Web!")
if (request.type == "stopPlayback" && currentlyPlaying) {
stopPlayback(request.artist,request.title);
}
else if (request.type == "startPlayback") {
startPlayback(request.artist,request.title,request.duration);
}
}
var currentTitle;
var currentArtist;
var currentLength;
var alreadyPlayed;
var currentlyPlaying = false;
var lastUpdate = 0;
var alreadyScrobbled = false;
function startPlayback(artist,title,seconds) {
// CASE 1: Resuming playback of previously played title
if (artist == currentArtist && title == currentTitle && !currentlyPlaying) {
console.log("Resuming playback")
// Already played full song
while (alreadyPlayed > currentLength) {
alreadyPlayed = alreadyPlayed - currentLength
scrobble(currentArtist,currentTitle,currentLength)
}
setUpdate()
currentlyPlaying = true
}
// CASE 2: New track is being played
else if (artist != currentArtist || title != currentTitle) {
//first inform ourselves that the previous track has now been stopped for good
stopPlayback(artist,title)
//then initialize new playback
console.log("New track")
setUpdate()
alreadyPlayed = 0
currentTitle = title
currentArtist = artist
currentLength = seconds
console.log(artist + " - " + title + " is playing!")
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
function stopPlayback(artist,title) {
//CASE 1: Playback just paused OR CASE 2: Playback ended
if (currentlyPlaying) {
d = setUpdate()
alreadyPlayed = alreadyPlayed + d
console.log(d + " seconds played since last update, " + alreadyPlayed + " seconds played overall")
}
// Already played full song
while (alreadyPlayed > currentLength) {
alreadyPlayed = alreadyPlayed - currentLength
scrobble(currentArtist,currentTitle,currentLength)
}
currentlyPlaying = false
//ONLY CASE 2: Playback ended
if (artist != currentArtist || title != currentTitle) {
if (alreadyPlayed > currentLength / 2) {
scrobble(currentArtist,currentTitle,alreadyPlayed)
alreadyPlayed = 0
}
}
}
// One problem here: Closing the player while it's paused does not cause an event, so the track will only be scrobbled the next time we play something.
// Also potentially problematic: Pausing a track and just leaving it should probably trigger a scrobble after some time because we can assume the user just stopped listening but didn't bother to press the X
// We could simply check for scrobblability when the track is paused, but this would remove the ability to send listening time with the scrobble
function ostopPlayback(artist,title) {
currentlyPlaying = false
console.log("Playback stopped!")
d = new Date()
t = Math.floor(d.getTime()/1000)
delta = t - lastUpdate
console.log("Since the last update, " + delta + " seconds of music have been played")
alreadyPlayed = alreadyPlayed + delta
console.log(alreadyPlayed + " seconds of this track have been played overall")
if ((alreadyPlayed > currentLength/2) && !alreadyScrobbled) {
console.log("Enough to scrobble: " + currentArtist + " - " + currentTitle)
scrobble(currentArtist,currentTitle)
alreadyScrobbled = true
}
}
function ostartPlayback(artist,title,seconds) {
console.log("Playback started!")
if (artist == currentArtist && title == currentTitle && !currentlyPlaying) {
console.log("Still previous track!")
while (alreadyPlayed > currentLength) {
console.log("This song is being played several times in a row!")
if (!alreadyScrobbled) {
scrobble(currentArtist,currentTitle)
//alreadyScrobbled = true
}
alreadyPlayed = alreadyPlayed - currentLength
alreadyScrobbled = false
}
d = new Date()
t = Math.floor(d.getTime()/1000)
lastUpdate = t
currentlyPlaying = true
}
else if (artist != currentArtist || title != currentTitle) {
console.log("New track!")
if (currentlyPlaying) {
console.log("We were playing another track before, so let's check if we should scrobble that.")
d = new Date()
t = Math.floor(d.getTime()/1000)
delta = t - lastUpdate
console.log("Since the last update, " + delta + " seconds of music have been played")
alreadyPlayed = alreadyPlayed + delta
}
console.log("The previous track was played for " + alreadyPlayed + " seconds, that's " + Math.floor(alreadyPlayed/currentLength * 100) + "% of its length.")
if (alreadyPlayed > currentLength/2 && !alreadyScrobbled) {
console.log("Enough to scrobble: " + currentArtist + " - " + currentTitle)
scrobble(currentArtist,currentTitle)
}
else if (alreadyScrobbled) {
console.log("We already scrobbled this track tho.")
alreadyScrobbled = false
}
console.log("But now, new track!")
d = new Date()
t = Math.floor(d.getTime()/1000)
lastUpdate = t
alreadyPlayed = 0
currentTitle = title
currentArtist = artist
currentLength = seconds
console.log(artist + " - " + title + " is playing!")
currentlyPlaying = true
}
}
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)
});
});
}
function setUpdate() {
d = new Date()
t = Math.floor(d.getTime()/1000)
delta = t - lastUpdate
lastUpdate = t
return delta
}

View File

@ -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)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,31 @@
{
"name": "Youtoja",
"version": "0.1",
"description": "Scrobbles tracks from YouTube Music to your Maloja server",
"manifest_version": 2,
"permissions": ["activeTab", "declarativeContent","tabs","storage","http://music.youtube.com/*","https://music.youtube.com/*"],
"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"
}
}

View File

@ -0,0 +1,18 @@
<!doctype html />
<html>
<head>
<title>Wat</title>
<script type="text/javascript" src="settings.js"></script>
<meta charset="UTF-8">
</head>
<body style="width:300px">
<div id="wat">
<span id="checkmark_url"></span> <span style="line-height:20px">Server:</span><br />
<input style="width:270px" type="text" id="serverurl" value="http://localhost:42010" />
<br /><br />
<span id="checkmark_key"></span> <span style="line-height:20px">API key:</span><br />
<input style="width:270px" type="text" id="apikey" />
</div>
</body>
</html>

View File

@ -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"
}
}
}