Last active
February 14, 2022 03:54
-
-
Save RealityRipple/ac04ad2efe3ea55d224defedcb4b0262 to your computer and use it in GitHub Desktop.
Track Display for Streamer Song List
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<script> | |
var userID = 'your_channel'; /* twitch channel, lowercase */ | |
var index = 1; /* queue index, starting from 1 for the next song and counting up */ | |
var fadePad = 32; /* left and right margin */ | |
var scrollRate = 20; /* lower is faster */ | |
var interval = 2; /* update time in seconds */ | |
var fadeTime = 0.5; /* fade speed in seconds */ | |
var normPad = 8; /* label padding. must equal #label's left and right padding value */ | |
var scrollPad = 6; /* padding between label and track name when scrolling */ | |
var label = 'Next Up:'; /* use '' for no label */ | |
var fitScroll = false; /* set to true to scroll text that fits */ | |
var fitScrollRate = 15; /* lower is faster */ | |
var trackDisp = '%DISP_ARTIST%%DISP_TITLE%%DISP_USER%'; /* display of below variables */ | |
var artistDisp = '%ARTIST% - '; /* artist name display (with text shown when an artist is provided, empty if no artist or live learn) */ | |
var titleDisp = '%TITLE%'; /* title display */ | |
var userDisp = ' for %USER%'; /* requester username display (with text shown when a song is by request, empty if no requester) */ | |
var emptyOpenDisp = 'The queue is empty! %TYPE% can add a song with the !sr command.' /* message to display when the queue does not have enough songs to reach this index and song requests are open */ | |
var emptyClosedDisp = 'None! Last Song'; /* message to display when the queue does not have enough songs to reach this index and song requests are closed */ | |
/* | |
* Example Track Displays: | |
* | |
* trackDisp = '%DISP_ARTIST%%DISP_TITLE%%DISP_USER%' | |
* artistDisp = '%ARTIST% - ' | |
* titleDisp = '%TITLE%' | |
* userDisp = 'for %USER' | |
* => Pink Floyd - Wish You Were Here for RealityRipple | |
* | |
* trackDisp = '%DISP_USER%%DISP_TITLE%%DISP_ARTIST%' | |
* artistDisp = ' by %ARTIST%' | |
* titleDisp = '%TITLE%' | |
* userDisp = '%USER%\'s Request: ' | |
* => RealityRipple's Request: Wish You Were Here by Pink Floyd | |
* | |
* trackDisp = '%DISP_TITLE%' | |
* artistDisp = ''; | |
* titleDisp = '%TITLE%'; | |
* userDisp = ''; | |
* => Wish You Were Here | |
*/ | |
var trackStyle = { | |
'style1': {title: 'Stairway to Heaven'}, | |
'style2': {artist: 'Led Zeppelin'}, | |
'style3': {attribute: '70s Rock'}, | |
'style4': {livelearn: true}, | |
'style5': {user: 'RealityRipple'} | |
}; | |
</script> | |
<style> | |
.text | |
{ | |
font-size: 32px; | |
line-height: 36px; /* adjust as needed for the text-shadow */ | |
color: #FFFFFF; | |
text-shadow: 2px 2px 3px #000000; | |
/* font-family: 'Comic Sans MS'; */ | |
} | |
.style1 | |
{ | |
color: #FFFF00; | |
} | |
.style2 | |
{ | |
font-style: italic; | |
} | |
.style3 | |
{ | |
font-weight: bold; | |
background: linear-gradient(to top, #FF0000, #FFFF00); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
text-shadow: none; | |
} | |
.style4 | |
{ | |
color: #00FFFF; | |
} | |
.style5 | |
{ | |
color: #008000; | |
} | |
</style> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<title>Track Display for StreamerSongList</title> | |
<style> | |
:root | |
{ | |
--pos: 0px; | |
} | |
body | |
{ | |
text-align: left; | |
margin: 0; | |
} | |
table | |
{ | |
border: 0; | |
visibility: hidden; | |
position: fixed; | |
opacity: 0; | |
} | |
#label | |
{ | |
margin: 0; | |
background-color: transparent; | |
padding: 2px 8px 8px; | |
white-space: nowrap; | |
} | |
#trackBox | |
{ | |
width: 100%; | |
overflow: hidden; | |
position: relative; | |
} | |
.track | |
{ | |
margin: 0; | |
top: 0; | |
display: none; | |
position: absolute; | |
background-color: transparent; | |
padding: 2px 0; | |
white-space: nowrap; | |
animation-name: fullWidth; | |
animation-timing-function: ease-in-out; | |
animation-direction: alternate; | |
animation-iteration-count: infinite; | |
visibility: hidden; | |
opacity: 0; | |
} | |
@keyframes fullWidth | |
{ | |
from | |
{ | |
transform: translate(0, 0); | |
} | |
to | |
{ | |
transform: translate(var(--pos), 0); | |
} | |
} | |
</style> | |
<script> | |
var sTitle = false; | |
var sArtist = false; | |
var sUser = false; | |
var iAttr = []; | |
var lastW = 0; | |
var lastD = 0; | |
var attrs = {}; | |
var queueOpen = false; | |
var queueMode = false; | |
function sleep(ms) | |
{ | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
function loadUser() | |
{ | |
let p = new Promise((resolve, reject) => | |
{ | |
let x = new XMLHttpRequest(); | |
x.open('GET', 'https://api.streamersonglist.com/v1/streamers/' + userID + '?platform=twitch', true); | |
x.onreadystatechange = function() | |
{ | |
if(x.readyState !== 4) | |
return; | |
if (x.status !== 200 && x.status !== 0) | |
return; | |
if (x.responseText === '') | |
return; | |
parseAttributes(x.responseText); | |
parseRequests(x.responseText); | |
resolve(true); | |
} | |
x.send(null); | |
} | |
); | |
return p; | |
} | |
function parseAttributes(sJSON) | |
{ | |
attrs = {}; | |
let j = JSON.parse(sJSON); | |
if (!j.hasOwnProperty('attributes')) | |
return; | |
if (!Array.isArray(j.attributes)) | |
return; | |
for (let i = 0; i < j.attributes.length; i++) | |
{ | |
if (!j.attributes[i].hasOwnProperty('id')) | |
continue; | |
if (!j.attributes[i].hasOwnProperty('name')) | |
continue; | |
attrs[j.attributes[i].id] = j.attributes[i].name; | |
} | |
} | |
function parseRequests(sJSON) | |
{ | |
queueOpen = false; | |
queueMode = false; | |
let j = JSON.parse(sJSON); | |
if (j.hasOwnProperty('requestsActive')) | |
queueOpen = j.requestsActive; | |
if (j.hasOwnProperty('canAnonymousRequest') && j.canAnonymousRequest) | |
{ | |
queueMode = 'Anyone'; | |
return; | |
} | |
if (j.hasOwnProperty('canUserRequest') && j.canUserRequest) | |
{ | |
queueMode = 'Users'; | |
return; | |
} | |
if (j.hasOwnProperty('canFollowerRequest') && j.canFollowerRequest) | |
{ | |
queueMode = 'Followers'; | |
return; | |
} | |
if (j.hasOwnProperty('canSubscriberRequest') && j.canFollowerRequest) | |
{ | |
queueMode = 'Subscribers'; | |
return; | |
} | |
if (j.hasOwnProperty('canSubscriberT2Request') && j.canFollowerRequest) | |
{ | |
queueMode = 'Tier 2 Subscribers'; | |
return; | |
} | |
if (j.hasOwnProperty('canSubscriberT3Request') && j.canFollowerRequest) | |
{ | |
queueMode = 'Tier 3 Subscribers'; | |
return; | |
} | |
queueMode = 'Moderators'; | |
} | |
function updateTrack() | |
{ | |
sTitle = false; | |
sArtist = false; | |
sUser = false; | |
iAttr = []; | |
let x = new XMLHttpRequest(); | |
x.open('GET', 'https://api.streamersonglist.com/v1/streamers/' + userID +'/queue', true); | |
x.onreadystatechange = function() | |
{ | |
if(x.readyState !== 4) | |
return; | |
if (x.status !== 200 && x.status !== 0) | |
return; | |
if (x.responseText === '') | |
return; | |
parseTrack(x.responseText); | |
displayTrack(); | |
} | |
x.send(null); | |
} | |
function parseTrack(sJSON) | |
{ | |
let j = JSON.parse(sJSON); | |
if (!j.hasOwnProperty('list') || !Array.isArray(j.list) || j.list.length < index + 1) | |
{ | |
sTitle = false; | |
if (queueOpen) | |
{ | |
if (emptyOpenDisp !== null && emptyOpenDisp !== '') | |
sTitle = emptyOpenDisp.replace('%TYPE%', queueMode); | |
} | |
else | |
{ | |
if (emptyClosedDisp !== null && emptyClosedDisp !== '') | |
sTitle = emptyClosedDisp; | |
} | |
sArtist = false; | |
sUser = false; | |
iAttr = []; | |
return; | |
} | |
if (j.list[index].hasOwnProperty('requests') && Array.isArray(j.list[index].requests) && j.list[index].requests.length > 0) | |
{ | |
let sUsers = []; | |
for (let i = 0; i < j.list[index].requests.length; i++) | |
{ | |
if (!j.list[index].requests[i].hasOwnProperty('name') || j.list[index].requests[i].name === '') | |
continue; | |
sUsers.push(j.list[index].requests[i].name); | |
} | |
if (sUsers.length === 0) | |
sUser = false; | |
else | |
sUser = sUsers.join(', '); | |
} | |
if (j.list[index].hasOwnProperty('nonlistSong') && j.list[index].nonlistSong !== null && j.list[index].nonlistSong !== '') | |
{ | |
sTitle = j.list[index].nonlistSong; | |
sArtist = false; | |
iAttr = ['livelearn']; | |
return; | |
} | |
else if (j.list[index].hasOwnProperty('song') && j.list[index].song !== null) | |
{ | |
if (j.list[index].song.hasOwnProperty('title') && j.list[index].song.title !== '') | |
sTitle = j.list[index].song.title; | |
else | |
sTitle = false; | |
if (j.list[index].song.hasOwnProperty('artist') && j.list[index].song.artist !== '') | |
sArtist = j.list[index].song.artist; | |
else | |
sArtist = false; | |
iAttr = []; | |
if (j.list[index].song.hasOwnProperty('attributeIds') && Array.isArray(j.list[index].song.attributeIds)) | |
{ | |
for (let n = 0; n < j.list[index].song.attributeIds.length; n++) | |
{ | |
iAttr.push(attrs[j.list[index].song.attributeIds[n]].toLowerCase()); | |
} | |
} | |
} | |
} | |
async function showTable() | |
{ | |
let tbl = document.getElementById('trackTable'); | |
if (tbl.style.visibility === 'visible') | |
return; | |
tbl.style.opacity = '0'; | |
tbl.style.visibility = 'visible'; | |
tbl.style.transitionProperty = 'opacity'; | |
tbl.style.transitionDuration = fadeTime + 's'; | |
tbl.style.opacity = '1'; | |
} | |
async function hideTable() | |
{ | |
let tbl = document.getElementById('trackTable'); | |
if (tbl.style.visibility !== 'visible') | |
return; | |
tbl.style.transitionProperty = 'opacity'; | |
tbl.style.transitionDuration = fadeTime + 's'; | |
tbl.style.opacity = '0'; | |
await sleep(fadeTime * 1000); | |
tbl.style.transitionProperty = ''; | |
tbl.style.transitionDuration = ''; | |
tbl.style.visibility = ''; | |
tbl.style.opacity = ''; | |
} | |
function showFade() | |
{ | |
let tb = document.getElementById('trackBox'); | |
if (!tb.hasAttribute('style')) | |
tb.setAttribute('style', '-webkit-mask-image: linear-gradient(to right, transparent 0, black ' + fadePad + 'px, black calc(100% - ' + fadePad + 'px), transparent 100%);'); | |
} | |
function hideFade() | |
{ | |
let tb = document.getElementById('trackBox'); | |
if (tb.hasAttribute('style')) | |
tb.removeAttribute('style'); | |
} | |
async function showTrack() | |
{ | |
let t = document.getElementById('track'); | |
if (t.style.visibility === 'visible') | |
return; | |
t.style.visibility = 'visible'; | |
t.style.opacity = '0'; | |
t.style.transitionProperty = 'opacity'; | |
t.style.transitionDuration = fadeTime + 's'; | |
t.style.opacity = '1'; | |
await sleep(fadeTime * 1000); | |
t.style.transitionProperty = ''; | |
t.style.transitionDuration = ''; | |
} | |
function styleTrack(measureOnly) | |
{ | |
if (trackStyle === false) | |
return; | |
for (let s in trackStyle) | |
{ | |
if (!measureOnly) | |
{ | |
if (document.getElementById('track').classList.contains(s)) | |
document.getElementById('track').classList.remove(s); | |
} | |
if (document.getElementById('measure').classList.contains(s)) | |
document.getElementById('measure').classList.remove(s); | |
if (trackStyle[s].hasOwnProperty('user')) | |
{ | |
if (sUser === false) | |
continue; | |
if (!sUser.toLowerCase().split(', ').includes(trackStyle[s].user.toLowerCase())) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('title')) | |
{ | |
if (sTitle === false) | |
continue; | |
if (sTitle.toLowerCase() !== trackStyle[s].title.toLowerCase()) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('artist')) | |
{ | |
if (sArtist === false) | |
continue; | |
if (sArtist.toLowerCase() !== trackStyle[s].artist.toLowerCase()) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('attribute')) | |
{ | |
if (iAttr.length === 0) | |
continue; | |
if (!iAttr.includes(trackStyle[s].attribute.toLowerCase())) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('livelearn')) | |
{ | |
if (iAttr.length === 0) | |
continue; | |
if (!iAttr.includes('livelearn')) | |
continue; | |
} | |
if (!measureOnly) | |
document.getElementById('track').classList.add(s); | |
document.getElementById('measure').classList.add(s); | |
} | |
} | |
async function hideTrack() | |
{ | |
let t = document.getElementById('track'); | |
if (t.style.display !== 'inline-block') | |
{ | |
t.style.opacity = '0'; | |
t.style.display = 'inline-block'; | |
} | |
else | |
{ | |
t.style.transitionProperty = 'opacity'; | |
t.style.transitionDuration = fadeTime + 's'; | |
t.style.opacity = '0'; | |
await sleep(fadeTime * 1000); | |
t.style.transitionProperty = ''; | |
t.style.transitionDuration = ''; | |
} | |
t.style.opacity = ''; | |
t.style.visibility = ''; | |
t.innerHTML = ''; | |
} | |
function measureTrack(s) | |
{ | |
styleTrack(true); | |
let t = document.getElementById('measure'); | |
t.style.display = 'inline-block'; | |
t.innerHTML = s; | |
let w = t.getBoundingClientRect()['width']; | |
t.style.display = ''; | |
t.innerHTML = ''; | |
return w; | |
} | |
async function displayTrack() | |
{ | |
let t = document.getElementById('track'); | |
let l = document.getElementById('label'); | |
if (sTitle === false) | |
{ | |
lastW = 0; | |
lastD = 0; | |
await hideTable() | |
if (t.hasAttribute('style')) | |
t.removeAttribute('style'); | |
t.innerHTML = ''; | |
return; | |
} | |
let w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
let dTitle = titleDisp.replace('%TITLE%', sTitle); | |
let dArtist = ''; | |
if (artistDisp !== false && sArtist !== false) | |
dArtist = artistDisp.replace('%ARTIST%', sArtist); | |
let dUser = ''; | |
if (userDisp !== false && sUser !== false) | |
dUser = userDisp.replace('%USER%', sUser); | |
let track = trackDisp.replace('%DISP_TITLE%', dTitle).replace('%DISP_ARTIST%', dArtist).replace('%DISP_USER%', dUser); | |
let d = measureTrack(track); | |
let h = false; | |
let range = 0; | |
if (l.style.paddingRight === scrollPad + 'px') | |
range = Math.abs((normPad * 2) - (normPad + scrollPad)); | |
if (label !== '') | |
{ | |
if (d + (normPad * 2) > w - range) | |
{ | |
if (l.style.paddingRight !== scrollPad + 'px') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = scrollPad + 'px'; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
else | |
{ | |
if (fitScroll) | |
{ | |
if (l.style.paddingRight !== scrollPad + 'px') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = scrollPad + 'px'; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
else | |
{ | |
if (l.style.paddingRight !== '') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = ''; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
} | |
} | |
if (!h && w === lastW && d === lastD) | |
return; | |
lastW = w; | |
lastD = d; | |
if (!h) | |
await hideTrack(); | |
styleTrack(false); | |
range = 0; | |
if (l.style.paddingRight === scrollPad + 'px') | |
range = Math.abs((normPad * 2) - (normPad + scrollPad)); | |
if (d + (normPad * 2) > w - range) | |
{ | |
d -= w; | |
d += fadePad * 2; | |
let u = Math.ceil(d * scrollRate); | |
if (u < 2000) | |
u = 2000; | |
if (l.style.paddingRight !== scrollPad + 'px' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = scrollPad + 'px'; | |
showFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', '-' + Math.ceil(d) + 'px'); | |
t.style.marginLeft = fadePad + 'px'; | |
t.style.marginRight = fadePad + 'px'; | |
t.style.animationDuration = u + 'ms'; | |
await showTable(); | |
await showTrack(); | |
} | |
else | |
{ | |
if (fitScroll) | |
{ | |
let m = w - d; | |
m -= normPad; | |
let u = Math.ceil(m * fitScrollRate); | |
if (u < 2000) | |
u = 2000; | |
if (l.style.paddingRight !== scrollPad + 'px' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = scrollPad + 'px'; | |
hideFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', Math.ceil(m) + 'px'); | |
t.style.marginLeft = ''; | |
t.style.marginRight = ''; | |
t.style.animationDuration = u + 'ms'; | |
await showTable(); | |
await showTrack(); | |
} | |
else | |
{ | |
if (l.style.paddingRight !== '' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = ''; | |
hideFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', '0px'); | |
t.style.marginLeft = ''; | |
t.style.marginRight = ''; | |
t.style.animationDuration = ''; | |
await showTable(); | |
await showTrack(); | |
} | |
} | |
} | |
function showLabel() | |
{ | |
let l = document.getElementById('label'); | |
if (label === '') | |
{ | |
l.style.paddingLeft = '0px'; | |
l.style.paddingRight = '0px'; | |
l.style.width = '1px'; | |
l.innerHTML = '​'; | |
} | |
else | |
l.innerHTML = label; | |
} | |
</script> | |
</head> | |
<body> | |
<table id="trackTable"> | |
<tr> | |
<td id="label" class="text"></td> | |
<td id="trackBox"><div id="track" class="track text"></div></td> | |
</tr> | |
</table> | |
<div id="measure" class="track text"></div> | |
<script> | |
async function init() | |
{ | |
await loadUser(); | |
window.setInterval(loadUser, interval * 1000); | |
showLabel(); | |
window.setInterval(updateTrack, interval * 1000); | |
updateTrack(); | |
} | |
init(); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<script> | |
var userID = 'your_channel'; /* twitch channel, lowercase */ | |
var index = 2; /* queue index, starting from 1 for the next song and counting up */ | |
var fadePad = 32; /* left and right margin */ | |
var scrollRate = 20; /* lower is faster */ | |
var interval = 2; /* update time in seconds */ | |
var fadeTime = 0.5; /* fade speed in seconds */ | |
var normPad = 8; /* label padding. must equal #label's left and right padding value */ | |
var scrollPad = 6; /* padding between label and track name when scrolling */ | |
var label = 'Coming Up:'; /* use '' for no label */ | |
var fitScroll = false; /* set to true to scroll text that fits */ | |
var fitScrollRate = 15; /* lower is faster */ | |
var trackDisp = '%DISP_ARTIST%%DISP_TITLE%%DISP_USER%'; /* display of below variables */ | |
var artistDisp = '%ARTIST% - '; /* artist name display (with text shown when an artist is provided, empty if no artist or live learn) */ | |
var titleDisp = '%TITLE%'; /* title display */ | |
var userDisp = ' for %USER%'; /* requester username display (with text shown when a song is by request, empty if no requester) */ | |
var emptyOpenDisp = '' /* message to display when the queue does not have enough songs to reach this index and song requests are open */ | |
var emptyClosedDisp = ''; /* message to display when the queue does not have enough songs to reach this index and song requests are closed */ | |
/* | |
* Example Track Displays: | |
* | |
* trackDisp = '%DISP_ARTIST%%DISP_TITLE%%DISP_USER%' | |
* artistDisp = '%ARTIST% - ' | |
* titleDisp = '%TITLE%' | |
* userDisp = 'for %USER' | |
* => Pink Floyd - Wish You Were Here for RealityRipple | |
* | |
* trackDisp = '%DISP_USER%%DISP_TITLE%%DISP_ARTIST%' | |
* artistDisp = ' by %ARTIST%' | |
* titleDisp = '%TITLE%' | |
* userDisp = '%USER%\'s Request: ' | |
* => RealityRipple's Request: Wish You Were Here by Pink Floyd | |
* | |
* trackDisp = '%DISP_TITLE%' | |
* artistDisp = ''; | |
* titleDisp = '%TITLE%'; | |
* userDisp = ''; | |
* => Wish You Were Here | |
*/ | |
var trackStyle = { | |
'style1': {title: 'Stairway to Heaven'}, | |
'style2': {artist: 'Led Zeppelin'}, | |
'style3': {attribute: '70s Rock'}, | |
'style4': {livelearn: true}, | |
'style5': {user: 'RealityRipple'} | |
}; | |
</script> | |
<style> | |
.text | |
{ | |
font-size: 32px; | |
line-height: 36px; /* adjust as needed for the text-shadow */ | |
color: #FFFFFF; | |
text-shadow: 2px 2px 3px #000000; | |
/* font-family: 'Comic Sans MS'; */ | |
} | |
.style1 | |
{ | |
color: #FFFF00; | |
} | |
.style2 | |
{ | |
font-style: italic; | |
} | |
.style3 | |
{ | |
font-weight: bold; | |
background: linear-gradient(to top, #FF0000, #FFFF00); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
text-shadow: none; | |
} | |
.style4 | |
{ | |
color: #00FFFF; | |
} | |
.style5 | |
{ | |
color: #008000; | |
} | |
</style> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<title>Track Display for StreamerSongList</title> | |
<style> | |
:root | |
{ | |
--pos: 0px; | |
} | |
body | |
{ | |
text-align: left; | |
margin: 0; | |
} | |
table | |
{ | |
border: 0; | |
visibility: hidden; | |
position: fixed; | |
opacity: 0; | |
} | |
#label | |
{ | |
margin: 0; | |
background-color: transparent; | |
padding: 2px 8px 8px; | |
white-space: nowrap; | |
} | |
#trackBox | |
{ | |
width: 100%; | |
overflow: hidden; | |
position: relative; | |
} | |
.track | |
{ | |
margin: 0; | |
top: 0; | |
display: none; | |
position: absolute; | |
background-color: transparent; | |
padding: 2px 0; | |
white-space: nowrap; | |
animation-name: fullWidth; | |
animation-timing-function: ease-in-out; | |
animation-direction: alternate; | |
animation-iteration-count: infinite; | |
visibility: hidden; | |
opacity: 0; | |
} | |
@keyframes fullWidth | |
{ | |
from | |
{ | |
transform: translate(0, 0); | |
} | |
to | |
{ | |
transform: translate(var(--pos), 0); | |
} | |
} | |
</style> | |
<script> | |
var sTitle = false; | |
var sArtist = false; | |
var sUser = false; | |
var iAttr = []; | |
var lastW = 0; | |
var lastD = 0; | |
var attrs = {}; | |
var queueOpen = false; | |
var queueMode = false; | |
function sleep(ms) | |
{ | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
function loadUser() | |
{ | |
let p = new Promise((resolve, reject) => | |
{ | |
let x = new XMLHttpRequest(); | |
x.open('GET', 'https://api.streamersonglist.com/v1/streamers/' + userID + '?platform=twitch', true); | |
x.onreadystatechange = function() | |
{ | |
if(x.readyState !== 4) | |
return; | |
if (x.status !== 200 && x.status !== 0) | |
return; | |
if (x.responseText === '') | |
return; | |
parseAttributes(x.responseText); | |
parseRequests(x.responseText); | |
resolve(true); | |
} | |
x.send(null); | |
} | |
); | |
return p; | |
} | |
function parseAttributes(sJSON) | |
{ | |
attrs = {}; | |
let j = JSON.parse(sJSON); | |
if (!j.hasOwnProperty('attributes')) | |
return; | |
if (!Array.isArray(j.attributes)) | |
return; | |
for (let i = 0; i < j.attributes.length; i++) | |
{ | |
if (!j.attributes[i].hasOwnProperty('id')) | |
continue; | |
if (!j.attributes[i].hasOwnProperty('name')) | |
continue; | |
attrs[j.attributes[i].id] = j.attributes[i].name; | |
} | |
} | |
function parseRequests(sJSON) | |
{ | |
queueOpen = false; | |
queueMode = false; | |
let j = JSON.parse(sJSON); | |
if (j.hasOwnProperty('requestsActive')) | |
queueOpen = j.requestsActive; | |
if (j.hasOwnProperty('canAnonymousRequest') && j.canAnonymousRequest) | |
{ | |
queueMode = 'Anyone'; | |
return; | |
} | |
if (j.hasOwnProperty('canUserRequest') && j.canUserRequest) | |
{ | |
queueMode = 'Users'; | |
return; | |
} | |
if (j.hasOwnProperty('canFollowerRequest') && j.canFollowerRequest) | |
{ | |
queueMode = 'Followers'; | |
return; | |
} | |
if (j.hasOwnProperty('canSubscriberRequest') && j.canFollowerRequest) | |
{ | |
queueMode = 'Subscribers'; | |
return; | |
} | |
if (j.hasOwnProperty('canSubscriberT2Request') && j.canFollowerRequest) | |
{ | |
queueMode = 'Tier 2 Subscribers'; | |
return; | |
} | |
if (j.hasOwnProperty('canSubscriberT3Request') && j.canFollowerRequest) | |
{ | |
queueMode = 'Tier 3 Subscribers'; | |
return; | |
} | |
queueMode = 'Moderators'; | |
} | |
function updateTrack() | |
{ | |
sTitle = false; | |
sArtist = false; | |
sUser = false; | |
iAttr = []; | |
let x = new XMLHttpRequest(); | |
x.open('GET', 'https://api.streamersonglist.com/v1/streamers/' + userID +'/queue', true); | |
x.onreadystatechange = function() | |
{ | |
if(x.readyState !== 4) | |
return; | |
if (x.status !== 200 && x.status !== 0) | |
return; | |
if (x.responseText === '') | |
return; | |
parseTrack(x.responseText); | |
displayTrack(); | |
} | |
x.send(null); | |
} | |
function parseTrack(sJSON) | |
{ | |
let j = JSON.parse(sJSON); | |
if (!j.hasOwnProperty('list') || !Array.isArray(j.list) || j.list.length < index + 1) | |
{ | |
sTitle = false; | |
if (queueOpen) | |
{ | |
if (emptyOpenDisp !== null && emptyOpenDisp !== '') | |
sTitle = emptyOpenDisp.replace('%TYPE%', queueMode); | |
} | |
else | |
{ | |
if (emptyClosedDisp !== null && emptyClosedDisp !== '') | |
sTitle = emptyClosedDisp; | |
} | |
sArtist = false; | |
sUser = false; | |
iAttr = []; | |
return; | |
} | |
if (j.list[index].hasOwnProperty('requests') && Array.isArray(j.list[index].requests) && j.list[index].requests.length > 0) | |
{ | |
let sUsers = []; | |
for (let i = 0; i < j.list[index].requests.length; i++) | |
{ | |
if (!j.list[index].requests[i].hasOwnProperty('name') || j.list[index].requests[i].name === '') | |
continue; | |
sUsers.push(j.list[index].requests[i].name); | |
} | |
if (sUsers.length === 0) | |
sUser = false; | |
else | |
sUser = sUsers.join(', '); | |
} | |
if (j.list[index].hasOwnProperty('nonlistSong') && j.list[index].nonlistSong !== null && j.list[index].nonlistSong !== '') | |
{ | |
sTitle = j.list[index].nonlistSong; | |
sArtist = false; | |
iAttr = ['livelearn']; | |
return; | |
} | |
else if (j.list[index].hasOwnProperty('song') && j.list[index].song !== null) | |
{ | |
if (j.list[index].song.hasOwnProperty('title') && j.list[index].song.title !== '') | |
sTitle = j.list[index].song.title; | |
else | |
sTitle = false; | |
if (j.list[index].song.hasOwnProperty('artist') && j.list[index].song.artist !== '') | |
sArtist = j.list[index].song.artist; | |
else | |
sArtist = false; | |
iAttr = []; | |
if (j.list[index].song.hasOwnProperty('attributeIds') && Array.isArray(j.list[index].song.attributeIds)) | |
{ | |
for (let n = 0; n < j.list[index].song.attributeIds.length; n++) | |
{ | |
iAttr.push(attrs[j.list[index].song.attributeIds[n]].toLowerCase()); | |
} | |
} | |
} | |
} | |
async function showTable() | |
{ | |
let tbl = document.getElementById('trackTable'); | |
if (tbl.style.visibility === 'visible') | |
return; | |
tbl.style.opacity = '0'; | |
tbl.style.visibility = 'visible'; | |
tbl.style.transitionProperty = 'opacity'; | |
tbl.style.transitionDuration = fadeTime + 's'; | |
tbl.style.opacity = '1'; | |
} | |
async function hideTable() | |
{ | |
let tbl = document.getElementById('trackTable'); | |
if (tbl.style.visibility !== 'visible') | |
return; | |
tbl.style.transitionProperty = 'opacity'; | |
tbl.style.transitionDuration = fadeTime + 's'; | |
tbl.style.opacity = '0'; | |
await sleep(fadeTime * 1000); | |
tbl.style.transitionProperty = ''; | |
tbl.style.transitionDuration = ''; | |
tbl.style.visibility = ''; | |
tbl.style.opacity = ''; | |
} | |
function showFade() | |
{ | |
let tb = document.getElementById('trackBox'); | |
if (!tb.hasAttribute('style')) | |
tb.setAttribute('style', '-webkit-mask-image: linear-gradient(to right, transparent 0, black ' + fadePad + 'px, black calc(100% - ' + fadePad + 'px), transparent 100%);'); | |
} | |
function hideFade() | |
{ | |
let tb = document.getElementById('trackBox'); | |
if (tb.hasAttribute('style')) | |
tb.removeAttribute('style'); | |
} | |
async function showTrack() | |
{ | |
let t = document.getElementById('track'); | |
if (t.style.visibility === 'visible') | |
return; | |
t.style.visibility = 'visible'; | |
t.style.opacity = '0'; | |
t.style.transitionProperty = 'opacity'; | |
t.style.transitionDuration = fadeTime + 's'; | |
t.style.opacity = '1'; | |
await sleep(fadeTime * 1000); | |
t.style.transitionProperty = ''; | |
t.style.transitionDuration = ''; | |
} | |
function styleTrack(measureOnly) | |
{ | |
if (trackStyle === false) | |
return; | |
for (let s in trackStyle) | |
{ | |
if (!measureOnly) | |
{ | |
if (document.getElementById('track').classList.contains(s)) | |
document.getElementById('track').classList.remove(s); | |
} | |
if (document.getElementById('measure').classList.contains(s)) | |
document.getElementById('measure').classList.remove(s); | |
if (trackStyle[s].hasOwnProperty('user')) | |
{ | |
if (sUser === false) | |
continue; | |
if (!sUser.toLowerCase().split(', ').includes(trackStyle[s].user.toLowerCase())) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('title')) | |
{ | |
if (sTitle === false) | |
continue; | |
if (sTitle.toLowerCase() !== trackStyle[s].title.toLowerCase()) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('artist')) | |
{ | |
if (sArtist === false) | |
continue; | |
if (sArtist.toLowerCase() !== trackStyle[s].artist.toLowerCase()) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('attribute')) | |
{ | |
if (iAttr.length === 0) | |
continue; | |
if (!iAttr.includes(trackStyle[s].attribute.toLowerCase())) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('livelearn')) | |
{ | |
if (iAttr.length === 0) | |
continue; | |
if (!iAttr.includes('livelearn')) | |
continue; | |
} | |
if (!measureOnly) | |
document.getElementById('track').classList.add(s); | |
document.getElementById('measure').classList.add(s); | |
} | |
} | |
async function hideTrack() | |
{ | |
let t = document.getElementById('track'); | |
if (t.style.display !== 'inline-block') | |
{ | |
t.style.opacity = '0'; | |
t.style.display = 'inline-block'; | |
} | |
else | |
{ | |
t.style.transitionProperty = 'opacity'; | |
t.style.transitionDuration = fadeTime + 's'; | |
t.style.opacity = '0'; | |
await sleep(fadeTime * 1000); | |
t.style.transitionProperty = ''; | |
t.style.transitionDuration = ''; | |
} | |
t.style.opacity = ''; | |
t.style.visibility = ''; | |
t.innerHTML = ''; | |
} | |
function measureTrack(s) | |
{ | |
styleTrack(true); | |
let t = document.getElementById('measure'); | |
t.style.display = 'inline-block'; | |
t.innerHTML = s; | |
let w = t.getBoundingClientRect()['width']; | |
t.style.display = ''; | |
t.innerHTML = ''; | |
return w; | |
} | |
async function displayTrack() | |
{ | |
let t = document.getElementById('track'); | |
let l = document.getElementById('label'); | |
if (sTitle === false) | |
{ | |
lastW = 0; | |
lastD = 0; | |
await hideTable() | |
if (t.hasAttribute('style')) | |
t.removeAttribute('style'); | |
t.innerHTML = ''; | |
return; | |
} | |
let w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
let dTitle = titleDisp.replace('%TITLE%', sTitle); | |
let dArtist = ''; | |
if (artistDisp !== false && sArtist !== false) | |
dArtist = artistDisp.replace('%ARTIST%', sArtist); | |
let dUser = ''; | |
if (userDisp !== false && sUser !== false) | |
dUser = userDisp.replace('%USER%', sUser); | |
let track = trackDisp.replace('%DISP_TITLE%', dTitle).replace('%DISP_ARTIST%', dArtist).replace('%DISP_USER%', dUser); | |
let d = measureTrack(track); | |
let h = false; | |
let range = 0; | |
if (l.style.paddingRight === scrollPad + 'px') | |
range = Math.abs((normPad * 2) - (normPad + scrollPad)); | |
if (label !== '') | |
{ | |
if (d + (normPad * 2) > w - range) | |
{ | |
if (l.style.paddingRight !== scrollPad + 'px') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = scrollPad + 'px'; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
else | |
{ | |
if (fitScroll) | |
{ | |
if (l.style.paddingRight !== scrollPad + 'px') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = scrollPad + 'px'; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
else | |
{ | |
if (l.style.paddingRight !== '') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = ''; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
} | |
} | |
if (!h && w === lastW && d === lastD) | |
return; | |
lastW = w; | |
lastD = d; | |
if (!h) | |
await hideTrack(); | |
styleTrack(false); | |
range = 0; | |
if (l.style.paddingRight === scrollPad + 'px') | |
range = Math.abs((normPad * 2) - (normPad + scrollPad)); | |
if (d + (normPad * 2) > w - range) | |
{ | |
d -= w; | |
d += fadePad * 2; | |
let u = Math.ceil(d * scrollRate); | |
if (u < 2000) | |
u = 2000; | |
if (l.style.paddingRight !== scrollPad + 'px' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = scrollPad + 'px'; | |
showFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', '-' + Math.ceil(d) + 'px'); | |
t.style.marginLeft = fadePad + 'px'; | |
t.style.marginRight = fadePad + 'px'; | |
t.style.animationDuration = u + 'ms'; | |
await showTable(); | |
await showTrack(); | |
} | |
else | |
{ | |
if (fitScroll) | |
{ | |
let m = w - d; | |
m -= normPad; | |
let u = Math.ceil(m * fitScrollRate); | |
if (u < 2000) | |
u = 2000; | |
if (l.style.paddingRight !== scrollPad + 'px' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = scrollPad + 'px'; | |
hideFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', Math.ceil(m) + 'px'); | |
t.style.marginLeft = ''; | |
t.style.marginRight = ''; | |
t.style.animationDuration = u + 'ms'; | |
await showTable(); | |
await showTrack(); | |
} | |
else | |
{ | |
if (l.style.paddingRight !== '' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = ''; | |
hideFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', '0px'); | |
t.style.marginLeft = ''; | |
t.style.marginRight = ''; | |
t.style.animationDuration = ''; | |
await showTable(); | |
await showTrack(); | |
} | |
} | |
} | |
function showLabel() | |
{ | |
let l = document.getElementById('label'); | |
if (label === '') | |
{ | |
l.style.paddingLeft = '0px'; | |
l.style.paddingRight = '0px'; | |
l.style.width = '1px'; | |
l.innerHTML = '​'; | |
} | |
else | |
l.innerHTML = label; | |
} | |
</script> | |
</head> | |
<body> | |
<table id="trackTable"> | |
<tr> | |
<td id="label" class="text"></td> | |
<td id="trackBox"><div id="track" class="track text"></div></td> | |
</tr> | |
</table> | |
<div id="measure" class="track text"></div> | |
<script> | |
async function init() | |
{ | |
await loadUser(); | |
window.setInterval(loadUser, interval * 1000); | |
showLabel(); | |
window.setInterval(updateTrack, interval * 1000); | |
updateTrack(); | |
} | |
init(); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<script> | |
var userID = 'your_channel'; /* twitch channel, lowercase */ | |
var fadePad = 32; /* left and right margin */ | |
var scrollRate = 20; /* lower is faster */ | |
var interval = 2; /* update time in seconds */ | |
var fadeTime = 0.5; /* fade speed in seconds */ | |
var normPad = 8; /* label padding. must equal #label's left and right padding value */ | |
var scrollPad = 6; /* padding between label and track name when scrolling */ | |
var label = 'Now Playing:'; /* use '' for no label */ | |
var fitScroll = false; /* set to true to scroll text that fits */ | |
var fitScrollRate = 15; /* lower is faster */ | |
var trackDisp = '%DISP_ARTIST%%DISP_TITLE%%DISP_USER%'; /* display of below variables */ | |
var artistDisp = '%ARTIST% - '; /* artist name display (with text shown when an artist is provided, empty if no artist or live learn) */ | |
var titleDisp = '%TITLE%'; /* title display */ | |
var userDisp = ' for %USER%'; /* requester username display (with text shown when a song is by request, empty if no requester) */ | |
/* | |
* Example Track Displays: | |
* | |
* trackDisp = '%DISP_ARTIST%%DISP_TITLE%%DISP_USER%' | |
* artistDisp = '%ARTIST% - ' | |
* titleDisp = '%TITLE%' | |
* userDisp = 'for %USER' | |
* => Pink Floyd - Wish You Were Here for RealityRipple | |
* | |
* trackDisp = '%DISP_USER%%DISP_TITLE%%DISP_ARTIST%' | |
* artistDisp = ' by %ARTIST%' | |
* titleDisp = '%TITLE%' | |
* userDisp = '%USER%\'s Request: ' | |
* => RealityRipple's Request: Wish You Were Here by Pink Floyd | |
* | |
* trackDisp = '%DISP_TITLE%' | |
* artistDisp = ''; | |
* titleDisp = '%TITLE%'; | |
* userDisp = ''; | |
* => Wish You Were Here | |
*/ | |
var trackStyle = { | |
'style1': {title: 'Stairway to Heaven'}, | |
'style2': {artist: 'Led Zeppelin'}, | |
'style3': {attribute: '70s Rock'}, | |
'style4': {livelearn: true}, | |
'style5': {user: 'RealityRipple'} | |
}; | |
</script> | |
<style> | |
.text | |
{ | |
font-size: 32px; | |
line-height: 36px; /* adjust as needed for the text-shadow */ | |
color: #FFFFFF; | |
text-shadow: 2px 2px 3px #000000; | |
/* font-family: 'Comic Sans MS'; */ | |
} | |
.style1 | |
{ | |
color: #FFFF00; | |
} | |
.style2 | |
{ | |
font-style: italic; | |
} | |
.style3 | |
{ | |
font-weight: bold; | |
background: linear-gradient(to top, #FF0000, #FFFF00); | |
-webkit-background-clip: text; | |
-webkit-text-fill-color: transparent; | |
text-shadow: none; | |
} | |
.style4 | |
{ | |
color: #00FFFF; | |
} | |
.style5 | |
{ | |
color: #008000; | |
} | |
</style> | |
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |
<title>Track Display for StreamerSongList</title> | |
<style> | |
:root | |
{ | |
--pos: 0px; | |
} | |
body | |
{ | |
text-align: left; | |
margin: 0; | |
} | |
table | |
{ | |
border: 0; | |
visibility: hidden; | |
position: fixed; | |
opacity: 0; | |
} | |
#label | |
{ | |
margin: 0; | |
background-color: transparent; | |
padding: 2px 8px 8px; | |
white-space: nowrap; | |
} | |
#trackBox | |
{ | |
width: 100%; | |
overflow: hidden; | |
position: relative; | |
} | |
.track | |
{ | |
margin: 0; | |
top: 0; | |
display: none; | |
position: absolute; | |
background-color: transparent; | |
padding: 2px 0; | |
white-space: nowrap; | |
animation-name: fullWidth; | |
animation-timing-function: ease-in-out; | |
animation-direction: alternate; | |
animation-iteration-count: infinite; | |
visibility: hidden; | |
opacity: 0; | |
} | |
@keyframes fullWidth | |
{ | |
from | |
{ | |
transform: translate(0, 0); | |
} | |
to | |
{ | |
transform: translate(var(--pos), 0); | |
} | |
} | |
</style> | |
<script> | |
var sTitle = false; | |
var sArtist = false; | |
var sUser = false; | |
var iAttr = []; | |
var lastW = 0; | |
var lastD = 0; | |
var attrs = {}; | |
function sleep(ms) | |
{ | |
return new Promise(resolve => setTimeout(resolve, ms)); | |
} | |
function loadUser() | |
{ | |
let p = new Promise((resolve, reject) => | |
{ | |
let x = new XMLHttpRequest(); | |
x.open('GET', 'https://api.streamersonglist.com/v1/streamers/' + userID + '?platform=twitch', true); | |
x.onreadystatechange = function() | |
{ | |
if(x.readyState !== 4) | |
return; | |
if (x.status !== 200 && x.status !== 0) | |
return; | |
if (x.responseText === '') | |
return; | |
parseAttributes(x.responseText); | |
resolve(true); | |
} | |
x.send(null); | |
} | |
); | |
return p; | |
} | |
function parseAttributes(sJSON) | |
{ | |
attrs = {}; | |
let j = JSON.parse(sJSON); | |
if (!j.hasOwnProperty('attributes')) | |
return; | |
if (!Array.isArray(j.attributes)) | |
return; | |
for (let i = 0; i < j.attributes.length; i++) | |
{ | |
if (!j.attributes[i].hasOwnProperty('id')) | |
continue; | |
if (!j.attributes[i].hasOwnProperty('name')) | |
continue; | |
attrs[j.attributes[i].id] = j.attributes[i].name; | |
} | |
} | |
function updateTrack() | |
{ | |
sTitle = false; | |
sArtist = false; | |
sUser = false; | |
iAttr = []; | |
let x = new XMLHttpRequest(); | |
x.open('GET', 'https://api.streamersonglist.com/v1/streamers/' + userID +'/queue', true); | |
x.onreadystatechange = function() | |
{ | |
if(x.readyState !== 4) | |
return; | |
if (x.status !== 200 && x.status !== 0) | |
return; | |
if (x.responseText === '') | |
return; | |
parseTrack(x.responseText); | |
displayTrack(); | |
} | |
x.send(null); | |
} | |
function parseTrack(sJSON) | |
{ | |
let j = JSON.parse(sJSON); | |
if (!j.hasOwnProperty('list') || !Array.isArray(j.list) || j.list.length < 1) | |
{ | |
sTitle = false; | |
sArtist = false; | |
sUser = false; | |
iAttr = []; | |
return; | |
} | |
if (j.list[0].hasOwnProperty('requests') && Array.isArray(j.list[0].requests) && j.list[0].requests.length > 0) | |
{ | |
let sUsers = []; | |
for (let i = 0; i < j.list[0].requests.length; i++) | |
{ | |
if (!j.list[0].requests[i].hasOwnProperty('name') || j.list[0].requests[i].name === '') | |
continue; | |
sUsers.push(j.list[0].requests[i].name); | |
} | |
if (sUsers.length === 0) | |
sUser = false; | |
else | |
sUser = sUsers.join(', '); | |
} | |
if (j.list[0].hasOwnProperty('nonlistSong') && j.list[0].nonlistSong !== null && j.list[0].nonlistSong !== '') | |
{ | |
sTitle = j.list[0].nonlistSong; | |
sArtist = false; | |
iAttr = ['livelearn']; | |
return; | |
} | |
else if (j.list[0].hasOwnProperty('song') && j.list[0].song !== null) | |
{ | |
if (j.list[0].song.hasOwnProperty('title') && j.list[0].song.title !== '') | |
sTitle = j.list[0].song.title; | |
else | |
sTitle = false; | |
if (j.list[0].song.hasOwnProperty('artist') && j.list[0].song.artist !== '') | |
sArtist = j.list[0].song.artist; | |
else | |
sArtist = false; | |
iAttr = []; | |
if (j.list[0].song.hasOwnProperty('attributeIds') && Array.isArray(j.list[0].song.attributeIds)) | |
{ | |
for (let n = 0; n < j.list[0].song.attributeIds.length; n++) | |
{ | |
iAttr.push(attrs[j.list[0].song.attributeIds[n]].toLowerCase()); | |
} | |
} | |
} | |
} | |
async function showTable() | |
{ | |
let tbl = document.getElementById('trackTable'); | |
if (tbl.style.visibility === 'visible') | |
return; | |
tbl.style.opacity = '0'; | |
tbl.style.visibility = 'visible'; | |
tbl.style.transitionProperty = 'opacity'; | |
tbl.style.transitionDuration = fadeTime + 's'; | |
tbl.style.opacity = '1'; | |
} | |
async function hideTable() | |
{ | |
let tbl = document.getElementById('trackTable'); | |
if (tbl.style.visibility !== 'visible') | |
return; | |
tbl.style.transitionProperty = 'opacity'; | |
tbl.style.transitionDuration = fadeTime + 's'; | |
tbl.style.opacity = '0'; | |
await sleep(fadeTime * 1000); | |
tbl.style.transitionProperty = ''; | |
tbl.style.transitionDuration = ''; | |
tbl.style.visibility = ''; | |
tbl.style.opacity = ''; | |
} | |
function showFade() | |
{ | |
let tb = document.getElementById('trackBox'); | |
if (!tb.hasAttribute('style')) | |
tb.setAttribute('style', '-webkit-mask-image: linear-gradient(to right, transparent 0, black ' + fadePad + 'px, black calc(100% - ' + fadePad + 'px), transparent 100%);'); | |
} | |
function hideFade() | |
{ | |
let tb = document.getElementById('trackBox'); | |
if (tb.hasAttribute('style')) | |
tb.removeAttribute('style'); | |
} | |
async function showTrack() | |
{ | |
let t = document.getElementById('track'); | |
if (t.style.visibility === 'visible') | |
return; | |
t.style.visibility = 'visible'; | |
t.style.opacity = '0'; | |
t.style.transitionProperty = 'opacity'; | |
t.style.transitionDuration = fadeTime + 's'; | |
t.style.opacity = '1'; | |
await sleep(fadeTime * 1000); | |
t.style.transitionProperty = ''; | |
t.style.transitionDuration = ''; | |
} | |
function styleTrack(measureOnly) | |
{ | |
if (trackStyle === false) | |
return; | |
for (let s in trackStyle) | |
{ | |
if (!measureOnly) | |
{ | |
if (document.getElementById('track').classList.contains(s)) | |
document.getElementById('track').classList.remove(s); | |
} | |
if (document.getElementById('measure').classList.contains(s)) | |
document.getElementById('measure').classList.remove(s); | |
if (trackStyle[s].hasOwnProperty('user')) | |
{ | |
if (sUser === false) | |
continue; | |
if (!sUser.toLowerCase().split(', ').includes(trackStyle[s].user.toLowerCase())) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('title')) | |
{ | |
if (sTitle === false) | |
continue; | |
if (sTitle.toLowerCase() !== trackStyle[s].title.toLowerCase()) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('artist')) | |
{ | |
if (sArtist === false) | |
continue; | |
if (sArtist.toLowerCase() !== trackStyle[s].artist.toLowerCase()) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('attribute')) | |
{ | |
if (iAttr.length === 0) | |
continue; | |
if (!iAttr.includes(trackStyle[s].attribute.toLowerCase())) | |
continue; | |
} | |
if (trackStyle[s].hasOwnProperty('livelearn')) | |
{ | |
if (iAttr.length === 0) | |
continue; | |
if (!iAttr.includes('livelearn')) | |
continue; | |
} | |
if (!measureOnly) | |
document.getElementById('track').classList.add(s); | |
document.getElementById('measure').classList.add(s); | |
} | |
} | |
async function hideTrack() | |
{ | |
let t = document.getElementById('track'); | |
if (t.style.display !== 'inline-block') | |
{ | |
t.style.opacity = '0'; | |
t.style.display = 'inline-block'; | |
} | |
else | |
{ | |
t.style.transitionProperty = 'opacity'; | |
t.style.transitionDuration = fadeTime + 's'; | |
t.style.opacity = '0'; | |
await sleep(fadeTime * 1000); | |
t.style.transitionProperty = ''; | |
t.style.transitionDuration = ''; | |
} | |
t.style.opacity = ''; | |
t.style.visibility = ''; | |
t.innerHTML = ''; | |
} | |
function measureTrack(s) | |
{ | |
styleTrack(true); | |
let t = document.getElementById('measure'); | |
t.style.display = 'inline-block'; | |
t.innerHTML = s; | |
let w = t.getBoundingClientRect()['width']; | |
t.style.display = ''; | |
t.innerHTML = ''; | |
return w; | |
} | |
async function displayTrack() | |
{ | |
let t = document.getElementById('track'); | |
let l = document.getElementById('label'); | |
if (sTitle === false) | |
{ | |
lastW = 0; | |
lastD = 0; | |
await hideTable() | |
if (t.hasAttribute('style')) | |
t.removeAttribute('style'); | |
t.innerHTML = ''; | |
return; | |
} | |
let w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
let dTitle = titleDisp.replace('%TITLE%', sTitle); | |
let dArtist = ''; | |
if (artistDisp !== false && sArtist !== false) | |
dArtist = artistDisp.replace('%ARTIST%', sArtist); | |
let dUser = ''; | |
if (userDisp !== false && sUser !== false) | |
dUser = userDisp.replace('%USER%', sUser); | |
let track = trackDisp.replace('%DISP_TITLE%', dTitle).replace('%DISP_ARTIST%', dArtist).replace('%DISP_USER%', dUser); | |
let d = measureTrack(track); | |
let h = false; | |
let range = 0; | |
if (l.style.paddingRight === scrollPad + 'px') | |
range = Math.abs((normPad * 2) - (normPad + scrollPad)); | |
if (label !== '') | |
{ | |
if (d + (normPad * 2) > w - range) | |
{ | |
if (l.style.paddingRight !== scrollPad + 'px') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = scrollPad + 'px'; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
else | |
{ | |
if (fitScroll) | |
{ | |
if (l.style.paddingRight !== scrollPad + 'px') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = scrollPad + 'px'; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
else | |
{ | |
if (l.style.paddingRight !== '') | |
{ | |
await hideTrack(); | |
l.style.paddingRight = ''; | |
w = document.getElementById('trackBox').getBoundingClientRect()['width']; | |
h = true; | |
} | |
} | |
} | |
} | |
if (!h && w === lastW && d === lastD) | |
return; | |
lastW = w; | |
lastD = d; | |
if (!h) | |
await hideTrack(); | |
styleTrack(false); | |
range = 0; | |
if (l.style.paddingRight === scrollPad + 'px') | |
range = Math.abs((normPad * 2) - (normPad + scrollPad)); | |
if (d + (normPad * 2) > w - range) | |
{ | |
d -= w; | |
d += fadePad * 2; | |
let u = Math.ceil(d * scrollRate); | |
if (u < 2000) | |
u = 2000; | |
if (l.style.paddingRight !== scrollPad + 'px' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = scrollPad + 'px'; | |
showFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', '-' + Math.ceil(d) + 'px'); | |
t.style.marginLeft = fadePad + 'px'; | |
t.style.marginRight = fadePad + 'px'; | |
t.style.animationDuration = u + 'ms'; | |
await showTable(); | |
await showTrack(); | |
} | |
else | |
{ | |
if (fitScroll) | |
{ | |
let m = w - d; | |
m -= normPad; | |
let u = Math.ceil(m * fitScrollRate); | |
if (u < 2000) | |
u = 2000; | |
if (l.style.paddingRight !== scrollPad + 'px' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = scrollPad + 'px'; | |
hideFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', Math.ceil(m) + 'px'); | |
t.style.marginLeft = ''; | |
t.style.marginRight = ''; | |
t.style.animationDuration = u + 'ms'; | |
await showTable(); | |
await showTrack(); | |
} | |
else | |
{ | |
if (l.style.paddingRight !== '' && l.style.paddingRight !== '0px') | |
l.style.paddingRight = ''; | |
hideFade(); | |
t.innerHTML = track; | |
document.documentElement.style.setProperty('--pos', '0px'); | |
t.style.marginLeft = ''; | |
t.style.marginRight = ''; | |
t.style.animationDuration = ''; | |
await showTable(); | |
await showTrack(); | |
} | |
} | |
} | |
function showLabel() | |
{ | |
let l = document.getElementById('label'); | |
if (label === '') | |
{ | |
l.style.paddingLeft = '0px'; | |
l.style.paddingRight = '0px'; | |
l.style.width = '1px'; | |
l.innerHTML = '​'; | |
} | |
else | |
l.innerHTML = label; | |
} | |
</script> | |
</head> | |
<body> | |
<table id="trackTable"> | |
<tr> | |
<td id="label" class="text"></td> | |
<td id="trackBox"><div id="track" class="track text"></div></td> | |
</tr> | |
</table> | |
<div id="measure" class="track text"></div> | |
<script> | |
async function init() | |
{ | |
await loadUser(); | |
window.setInterval(loadUser, interval * 1000); | |
showLabel(); | |
window.setInterval(updateTrack, interval * 1000); | |
updateTrack(); | |
} | |
init(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment