diff --git a/.gitignore b/.gitignore index be47e85..970fa80 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ scoreboard/build/ *.crt *.key + +dev_hero_selector/__pycache__/ diff --git a/scoreboard/config.html b/scoreboard/config.html index ac56bb7..2f916fa 100644 --- a/scoreboard/config.html +++ b/scoreboard/config.html @@ -40,6 +40,11 @@ +
diff --git a/scoreboard/config.js b/scoreboard/config.js index a63d583..9f401ed 100644 --- a/scoreboard/config.js +++ b/scoreboard/config.js @@ -1,43 +1,60 @@ const twitch = window.Twitch.ext; -twitch.onContext(function(context) { - if (context.theme === 'dark'){ - // dark mode - use white text - document.body.style.color = '#dad8de'; - } else { - // light mode - use dark text - document.body.style.color = '#19171c'; - } -}); +(function () { + var vertical = false; -twitch.onAuthorized(function(auth) { - fetch('https://api2.overtrack.gg/overwatch_twitch_extension/check_twitch_user', { - // fetch('http://localhost:5001/overwatch_twitch_extension/check_twitch_user', { - method: 'POST', - headers: { - 'content-type': 'application/json', - 'x-extension-jwt': auth.token - }, - body: JSON.stringify({}) - }).then(res => { - let loading = document.getElementsByClassName('loading')[0]; - let found = document.getElementsByClassName('account-found')[0]; - let not_found = document.getElementsByClassName('account-not-found')[0]; - let last_game = document.getElementsByClassName('last-game')[0]; - loading.style.display = 'none'; - if (res.status == 200){ - found.style.display = 'block'; - not_found.style.display = 'none'; - res.json().then(data => { - if (data.overwatch_last_game){ - last_game.src = 'https://overtrack.gg/overwatch/games/' + data.overwatch_last_game + '/card.png'; - } - }); + window.onload = function () { + if (vertical) { + document.getElementById("checkbox").checked = vertical; + } + document.getElementById('saveBtn').addEventListener('click', function () { + if (document.getElementById(verticalBtn).checked) { + twitch.configuration.set("broadcaster", "", true); + } + }); + } + + twitch.onContext(function (context) { + if (context.theme === 'dark') { + // dark mode - use white text + document.body.style.color = '#dad8de'; } else { - found.style.display = 'none'; - not_found.style.display = 'block'; + // light mode - use dark text + document.body.style.color = '#19171c'; } }); -}); -// twitch.configuration.onChanged(function(){}); + twitch.configuration.onChanged(function () { + vertical = twitch.configuration.broadcaster ? twitch.configuration.broadcaster.content : false + }) + + twitch.onAuthorized(function (auth) { + fetch('https://api2.overtrack.gg/overwatch_twitch_extension/check_twitch_user', { + // fetch('http://localhost:5001/overwatch_twitch_extension/check_twitch_user', { + method: 'POST', + headers: { + 'content-type': 'application/json', + 'x-extension-jwt': auth.token + }, + body: JSON.stringify({}) + }).then(res => { + let loading = document.getElementsByClassName('loading')[0]; + let found = document.getElementsByClassName('account-found')[0]; + let not_found = document.getElementsByClassName('account-not-found')[0]; + let last_game = document.getElementsByClassName('last-game')[0]; + loading.style.display = 'none'; + if (res.status == 200) { + found.style.display = 'block'; + not_found.style.display = 'none'; + res.json().then(data => { + if (data.overwatch_last_game) { + last_game.src = 'https://overtrack.gg/overwatch/games/' + data.overwatch_last_game + '/card.png'; + } + }); + } else { + found.style.display = 'none'; + not_found.style.display = 'block'; + } + }); + }); +})() diff --git a/scoreboard/main.js b/scoreboard/main.js index e4a022c..ae8d8db 100644 --- a/scoreboard/main.js +++ b/scoreboard/main.js @@ -1,181 +1,206 @@ // made using http://vanilla-js.com/ +(function () { + const twitch = window.Twitch.ext; + var vertical = false; + + + twitch.configuration.onChanged(function () { + vertical = twitch.configuration.broadcaster ? twitch.configuration.broadcaster.content : false; + updateLayout(); + }); + + function updateLayout() + { + let vertFunc = function (e) { + if (vertical) { + e.classList.add('vertical') + } else { + e.classList.remove('vertical') + } + } + document.querySelectorAll('.scoreboard').forEach(vertFunc) + document.querySelectorAll('.powered-by-container').forEach(vertFunc) + } -/* BEGIN: !twitch */ -function getJSON(url, callback) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, true); - xhr.responseType = 'json'; - xhr.onload = function() { - let status = xhr.status; - if (status === 200) { - callback(xhr.response); - } else { - console.error(status, xhr.response); - } - }; - xhr.send(); -}; - -var lastMessage = null; -var lastDelayedMessage = null; -var start = new Date().getTime() / 1000; -var lastUpdate = null; -/* END: !twitch */ - -function onMessage(data){ /* BEGIN: !twitch */ - lastUpdate = new Date().getTime(); - if (latestContext){ - let now = new Date().getTime() / 1000; - let currentFrameTimestamp = now - latestContext.hlsLatencyBroadcaster; - let offset = data.timestamp - currentFrameTimestamp; - - // log event received timings - if (lastMessage && lastMessage.teams && data.teams){ - let shownTime = false; - for (let i=0; i < 12; i++){ + function getJSON(url, callback) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, true); + xhr.responseType = 'json'; + xhr.onload = function () { + let status = xhr.status; + if (status === 200) { + callback(xhr.response); + } else { + console.error(status, xhr.response); + } + }; + xhr.send(); + } + + var lastMessage = null; + var lastDelayedMessage = null; + var start = new Date().getTime() / 1000; + var lastUpdate = null; + /* END: !twitch */ + + function onMessage(data) { + /* BEGIN: !twitch */ + lastUpdate = new Date().getTime(); + if (latestContext) { + let now = new Date().getTime() / 1000; + let currentFrameTimestamp = now - latestContext.hlsLatencyBroadcaster; + let offset = data.timestamp - currentFrameTimestamp; + + // log event received timings + if (lastMessage && lastMessage.teams && data.teams) { + let shownTime = false; + for (let i = 0; i < 12; i++) { + let team = data.teams.blue; + let lastTeam = lastMessage.teams.blue; + if (i >= 6) { + team = data.teams.red; + lastTeam = lastMessage.teams.red; + } + let player = team[i % 6]; + let lastPlayer = lastTeam[i % 6]; + if (player.kills != lastPlayer.kills) { + if (!shownTime) { + console.log( + 'now=' + (now - start) + + ', frame=' + currentFrameTimestamp + + ', event=' + (data.timestamp - start) + + ', latency=' + latestContext.hlsLatencyBroadcaster + + ', offset=' + offset + ); + shownTime = true; + } + console.log('Got ' + player.name + ' kills ' + lastPlayer.kills + ' -> ' + player.kills); + } + } + } + lastMessage = data; + } + /* END: !twitch */ + + let scoreboard = document.getElementsByClassName('scoreboard')[0]; + if (data.teams) { + scoreboard.style.display = 'block'; + let players = document.getElementsByClassName('player'); + for (let i = 0; i < 12; i++) { let team = data.teams.blue; - let lastTeam = lastMessage.teams.blue; - if (i >= 6){ + if (i >= 6) { team = data.teams.red; - lastTeam = lastMessage.teams.red; } let player = team[i % 6]; - let lastPlayer = lastTeam[i % 6]; - if (player.kills != lastPlayer.kills){ - if (!shownTime){ - console.log( - 'now=' + (now - start) + - ', frame=' + currentFrameTimestamp + - ', event=' + (data.timestamp - start) + - ', latency=' + latestContext.hlsLatencyBroadcaster + - ', offset=' + offset - ); - shownTime = true; - } - console.log('Got ' + player.name + ' kills ' + lastPlayer.kills + ' -> ' + player.kills); + let element = players[i]; + + let name = element.getElementsByClassName('name')[0]; + let hero = element.getElementsByClassName('hero')[0]; + let kills = element.getElementsByClassName('kills')[0]; + let deaths = element.getElementsByClassName('deaths')[0]; + let resurrects = element.getElementsByClassName('resurrects')[0]; + + name.innerText = player.name; + hero.className = 'hero hero-' + player.current_hero; + kills.innerText = player.kills; + deaths.innerText = player.deaths; + resurrects.innerText = player.resurrects; + if (player.current_hero === 'mercy') { + resurrects.style.display = 'block'; + element.classList.add('show-resurrects'); + } else { + resurrects.style.display = 'none'; + element.classList.remove('show-resurrects'); } } + } else { + scoreboard.style.display = 'none'; } - lastMessage = data; - } - /* END: !twitch */ - let scoreboard = document.getElementsByClassName('scoreboard')[0]; - if (data.teams){ - scoreboard.style.display = 'block'; - let players = document.getElementsByClassName('player'); - for (let i=0; i<12; i++){ - let team = data.teams.blue; - if (i >= 6){ - team = data.teams.red; - } - let player = team[i % 6]; - let element = players[i]; - - let name = element.getElementsByClassName('name')[0]; - let hero = element.getElementsByClassName('hero')[0]; - let kills = element.getElementsByClassName('kills')[0]; - let deaths = element.getElementsByClassName('deaths')[0]; - let resurrects = element.getElementsByClassName('resurrects')[0]; - - name.innerText = player.name; - hero.className = 'hero hero-' + player.current_hero; - kills.innerText = player.kills; - deaths.innerText = player.deaths; - resurrects.innerText = player.resurrects; - if (player.current_hero === 'mercy'){ - resurrects.style.display = 'block'; - element.classList.add('show-resurrects'); - } else { - resurrects.style.display = 'none'; - element.classList.remove('show-resurrects'); - } - } - } else { - scoreboard.style.display = 'none'; - } + let postgame = document.getElementsByClassName('lastgame')[0]; + if (data.postgame) { + postgame.style.display = 'flex'; + postgame.className = 'lastgame lastgame-' + data.postgame.role + + ' lastgame-' + data.postgame.result; + + let thumbnail = postgame.getElementsByClassName('thumbnail')[0]; + thumbnail.style.backgroundImage = `url(./images/map_thumbnails/${data.postgame.map.replace(' ', '-')}.jpg)`; + let hero_icon_image = thumbnail.getElementsByClassName('hero-icon-image')[0]; + hero_icon_image.src = `./images/heroes/${data.postgame.hero}.png`; + + let game_result = postgame.getElementsByClassName('game-result')[0]; + let game_time = postgame.getElementsByClassName('game-time')[0]; + let sr_change = postgame.getElementsByClassName('sr-change')[0]; + let duration = postgame.getElementsByClassName('duration')[0]; + game_result.innerText = data.postgame.result.toUpperCase(); + game_time.innerText = new Date(data.postgame.timestamp * 1000) + .toLocaleString('default', { hour: 'numeric', minute: '2-digit' }); + sr_change.innerText = data.postgame.description; + duration.innerText = data.postgame.duration; + + let link = postgame.getElementsByClassName('link')[0]; + link.href = data.postgame.link; + + let stats_block = postgame.getElementsByClassName('stats')[0]; + let rows = stats_block.getElementsByClassName('row'); + let headers = stats_block.getElementsByClassName('header'); + let stats = stats_block.getElementsByClassName('stat'); + + for (var i = 0; i < 6; i++) { + if (i >= data.postgame.stats.length) { + rows[i].style.display = 'none'; + continue; + } - let postgame = document.getElementsByClassName('lastgame')[0]; - if (data.postgame){ - postgame.style.display = 'flex'; - postgame.className = 'lastgame lastgame-' + data.postgame.role - + ' lastgame-' + data.postgame.result; - - let thumbnail = postgame.getElementsByClassName('thumbnail')[0]; - thumbnail.style.backgroundImage = `url(./images/map_thumbnails/${data.postgame.map.replace(' ', '-')}.jpg)`; - let hero_icon_image = thumbnail.getElementsByClassName('hero-icon-image')[0]; - hero_icon_image.src = `./images/heroes/${data.postgame.hero}.png`; - - let game_result = postgame.getElementsByClassName('game-result')[0]; - let game_time = postgame.getElementsByClassName('game-time')[0]; - let sr_change = postgame.getElementsByClassName('sr-change')[0]; - let duration = postgame.getElementsByClassName('duration')[0]; - game_result.innerText = data.postgame.result.toUpperCase(); - game_time.innerText = new Date(data.postgame.timestamp * 1000) - .toLocaleString('default', {hour: 'numeric', minute: '2-digit'}); - sr_change.innerText = data.postgame.description; - duration.innerText = data.postgame.duration; - - let link = postgame.getElementsByClassName('link')[0]; - link.href = data.postgame.link; - - let stats_block = postgame.getElementsByClassName('stats')[0]; - let rows = stats_block.getElementsByClassName('row'); - let headers = stats_block.getElementsByClassName('header'); - let stats = stats_block.getElementsByClassName('stat'); - - for (var i = 0; i < 6; i++) { - if (i >= data.postgame.stats.length) { - rows[i].style.display = 'none'; - continue; + headers[i].innerText = data.postgame.stats[i].key; + let stat = data.postgame.stats[i].value; + stats[i].innerText = stat === null ? '?' : stat; } - - headers[i].innerText = data.postgame.stats[i].key; - let stat = data.postgame.stats[i].value; - stats[i].innerText = stat === null ? '?' : stat; + } else { + postgame.style.display = 'none'; } - } else { - postgame.style.display = 'none'; } -} -var latestContext = null; -window.onload = function() { - /* BEGIN: !twitch */ - if (window.Twitch){ - window.Twitch.ext.onError(function(error){ - console.error(error); - }); - /* END: !twitch */ - - window.Twitch.ext.onAuthorized(function(auth) { - window.setInterval(function(){ - if (!lastUpdate || (new Date().getTime()) - lastUpdate > 120 * 1000){ - // no update for the last 2min - EBS is offline - document.getElementsByClassName('scoreboard')[0].style.display = 'none'; - } - }, 15 * 1000); - }); - - window.Twitch.ext.listen('broadcast', function(target, contentType, message){ - onMessage(JSON.parse(message)); - }); - - window.Twitch.ext.onContext(function(context) { - latestContext = context; - }); - - /* BEGIN: !twitch */ - } else { - getJSON('/scoreboard.json', function(data){ - onMessage(data); - }); - window.setInterval(function(){ - getJSON('/scoreboard.json', function(data){ - onMessage(data); - }); - }, 5000); - } - /* END: !twitch */ -}; + var latestContext = null; + window.onload = function () { + updateLayout() + + /* BEGIN: !twitch */ + if (window.Twitch) { + window.Twitch.ext.onError(function (error) { + console.error(error); + }); + /* END: !twitch */ + + window.Twitch.ext.onAuthorized(function (auth) { + window.setInterval(function () { + if (!lastUpdate || (new Date().getTime()) - lastUpdate > 120 * 1000) { + // no update for the last 2min - EBS is offline + document.getElementsByClassName('scoreboard')[0].style.display = 'none'; + } + }, 15 * 1000); + }); + + window.Twitch.ext.listen('broadcast', function (target, contentType, message) { + onMessage(JSON.parse(message)); + }); + + window.Twitch.ext.onContext(function (context) { + latestContext = context; + }); + + /* BEGIN: !twitch */ + } else { + getJSON('/scoreboard.json', function (data) { + onMessage(data); + }); + window.setInterval(function () { + getJSON('/scoreboard.json', function (data) { + onMessage(data); + }); + }, 5000); + } + /* END: !twitch */ + }; +})() diff --git a/scoreboard/style.css b/scoreboard/style.css index 32ee47b..0e0b869 100644 --- a/scoreboard/style.css +++ b/scoreboard/style.css @@ -16,6 +16,15 @@ body { font-style: normal; } +.scoreboard.vertical { + opacity: 0.8; + width: 100%; + padding-left: 0.25%; + margin-top: 1.5%; + height: 15.3%; + background-color: rgba(255, 255, 255, 0%); +} + .scoreboard { opacity: 0.8; width: 38.25%; @@ -30,7 +39,13 @@ body { top: 0; left: 0; height: 50%; - width: 100%; + width: 38vw; + display: block; + float: left; +} + +.team-red { + padding-left: 24vw; } .scoreboard > :nth-child(2){ @@ -47,11 +62,12 @@ body { } .team-blue .player::before { /* Parallelogram colour. Name section starts at 65% */ - background: linear-gradient(to bottom, hsl(200, 90%, 30%, 70%) 0%,hsl(200, 90%, 30%, 70%) 65%, hsl(200, 80%, 20%, 80%) 65%,hsl(200, 80%, 20%, 80%) 100%); + background: linear-gradient(to bottom, hsl(200, 90%, 30%, 40%) 0%,hsl(200, 90%, 30%, 20%) 65%, hsl(200, 80%, 20%, 40%) 65%,hsl(200, 80%, 20%, 40%) 100%); } .team-red .player::before { /* Parallelogram colour. Name section starts at 65% */ - background: linear-gradient(to bottom, hsl(0, 100%, 40%, 70%) 0%,hsl(0, 100%, 40%, 70%) 65%, hsl(0, 100%, 30%, 80%) 65%,hsl(0, 100%, 30%, 80%) 100%); + background: linear-gradient(to bottom, hsl(0, 100%, 40%, 40%) 0%,hsl(0, 100%, 40%, 20%) 65%, hsl(0, 100%, 30%, 40%) 65%,hsl(0, 100%, 30%, 40%) 100%); + } .player { position: relative; @@ -164,12 +180,20 @@ body { top: calc(2%); } +.powered-by-container.vertical { + position: absolute; + top: 0; + left: 45vw; + background-color: rgba(22, 22, 22, 0.8); +} .powered-by-container { position: absolute; top: 0; left: 33.3vw; transform: skew(15deg) translateX(9%); background-color: #222222; + left: 45vw; + background-color: rgba(22, 22, 22, 0.8); } .powered-by { font-family: 'Roboto', sans-serif; @@ -181,7 +205,6 @@ body { padding: 0.01vw; padding-left: 0.3vw; padding-right: 0.3vw; - transform: skew(-15deg); } .powered-by .link { color: #e1af41;