<html> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content="Twitch Sings tools for data analysis"> <meta name="author" content="Martyn Ranyard"> <title>Twitch Sings Tools</title> <!-- Bootstrap core CSS --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet" crossorigin="anonymous"> <!-- Custom styles for this template --> <link href="/cover.css" rel="stylesheet"> <style> .bd-placeholder-img { font-size: 1.125rem; text-anchor: middle; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #insightspanel > table:nth-child(1) > thead:nth-child(1) > tr:nth-child(1) > td:nth-child(1) @media (min-width: 768px) { .bd-placeholder-img-lg { font-size: 3.5rem; } } li.match-nomatch{ background-color: #1e2122; } li.match-matchtrack{ background-color: #E9B000; } li.match-fullmatch{ background-color: #008F95; } li.match-matchtrackfuzzt{ background-color: darkgray; } li.match-fullmatchfuzzy{ background-color: darkgray; } a{ text-decoration-line: underline; } .displaySetting{ display: inline } .hiddenDisplaySetting{ display: none; } .hiddenSave { display: none; } .editSetting{ display: none; } .visibleEditSetting{ display: inline; } .visibleSave { display: inline; } th { font-weight: bold; font-style: italic; } #csvpanel td { padding: 5px; } #csvpanel th { padding: 5px; } </style> </head> <body class="text-center"> <div class="cover-container d-flex w-100 h-100 p-3 mx-auto flex-column"> <header class="masthead mb-auto"> <div class="inner"> <h3 class="masthead-brand">Twitch Sings Tools</h3> <nav class="nav nav-masthead justify-content-center"> <a class="nav-link active" href="/">Home</a> </nav> </div> </header> <main role="main" class="inner cover"> <script> function editMode() { var alldisps = document.getElementsByClassName("displaySetting"); for (item of alldisps) { item.classList.add("hiddenDisplaySetting") } for (item of alldisps) { item.classList.remove("displaySetting") } var alldisps = document.getElementsByClassName("editSetting"); for (item of alldisps) { item.classList.add("visibleEditSetting") } for (item of alldisps) { item.classList.remove("editSetting") } document.getElementById("saveButton").classList.remove("hiddenSave") document.getElementById("saveButton").classList.add("visibleSave") document.getElementById("leaveButton").classList.remove("hiddenSave") document.getElementById("leaveButton").classList.add("visibleSave") document.getElementById("yuhateme").classList.remove("hiddenSave") document.getElementById("yuhateme").classList.add("visibleSave") } </script> <h1 class="cover-heading">Twitch Sings Tools admin panel for {{.Channel}}!!!</h1> <ul class="nav nav-tabs" style="width: 100%;"> <li class="nav-item"> <a id="insights" class="nav-link active panel" href="#" onclick="tabClick(this)">Insights</a> </li> <li class="nav-item"> <a id="data" class="nav-link panel" href="#" onclick="tabClick(this)">Data</a> </li> <li class="nav-item"> <a id="csv" class="nav-link panel" href="#" onclick="tabClick(this)">CSV</a> </li> <li class="nav-item"> <a id="bot" class="nav-link panel" href="#" onclick="tabClick(this)">Bot</a> </li> </ul> <div style="width: 100%; overflow-y: scroll; display: block;" id="insightspanel" class="controlpanel"> <table> <tr><th><h2>Top 10 Songs : </h2></th><th><h2>Top 10 Singers : </h2></th></tr> <tr><td><table> <thead><tr><th>Song</th><th>Sings</th></tr></thead> {{ range .TopNSongs }} <tr><td>{{ .SongTitle }}</td><td>{{ .Sings }}</td></tr> {{ end }} </table></td><td><table> <thead><tr><th>Singer</th><th>Sings</th></tr></thead> {{ range .TopNSingers }} <tr><td>{{ .SingerName }}</td><td>{{ .Sings }}</td></tr> {{ end }} </table></td></tr> </table> </div> <div style="width: 100%; overflow-y: scroll; display: none;" id="datapanel" class="controlpanel"> <table id="dataTable"> <thead><tr><th>Published</th><th>What</th><th>Who</th><th>Last sang this song</th><th>Last dueted with performer</th></th></thead> {{ range .SongData }} <tr><td title="{{ .Date }}">{{ .NiceDate }}</td><td>{{ .SongTitle }}</td><td>{{ .OtherSinger }}</td><td title="{{ .LastSungSong }}">{{ .NiceLastSungSong }}</td><td title="{{ .LastSungSinger }}">{{ .NiceLastSungSinger }}</td></tr> {{ end }} </table> </div> <div style="width: 100%; overflow-y: scroll; display: none;" id="csvpanel" class="controlpanel"> <h3>Download your data as :</h3> <center> <table border="2"> <tr><th>CSV</th><th>TSV</th></tr> <tr><td><a href="/csv/{{.Channel}}/{{.ChannelKey}}">here</a></td><td><a href="/tsv/{{.Channel}}/{{.ChannelKey}}">here</a></td></tr> </table> </center> <h3>Excel is not very good at handling CSV format it seems...</h3> <p>It is important to "Import Data" not "Open" the csv in many cases (8 year old discussion of this behaviour here) - from that post the instructions are : </p> <blockquote>In Excel, DATA tab, in the Get External Data subsection, click "From Text" and import your CSV in the Wizard.</blockquote> <p>LibreOffice calc kinda just works...just sayin' ;-)</p> </div> <div style="width: 100%; overflow-y: scroll; display: none;" id="botpanel" class="controlpanel"> <h2>The bot isn't really ready yet... it just has the old Karaokards facility at the moment. I woudn't bother inviting it yet.</h2> {{ if .HasLeft }} <h2>Not in your channel at the moment!</h2> <p>The bot is not currently in your channel, chances are you've not ever asked it to join, you asked it to leave, or something went horribly wrong.</p> <p>You can invite the bot to your channel by clicking here : <input id="joinButton" type="submit" name="join" value="Come on in"></p> {{ else }} <form method="POST"> {{ if .Leaving }} <h2>Do you really want this bot to leave your channel?</h2> <p><input id="leaveButton" type="submit" name="reallyleave" value="Really leave twitch channel"></p> {{ else }} <h2>Note you can give your moderators the url you are on right now to control this bot. They don't have to be logged into twitch to do so.</h2> <table> <thead><tr><th>Channel Data :</th><th><input type="button" value="Edit" onclick="javascript:editMode();"></th></tr></thead> <tbody> <tr><td>Member of channel since {{.SinceTimeUTC}}</td></tr> <tr><td>Command for prompt:</td><td class="displaySetting"></tdclass>{{.Command}}</td><td class="editSetting"><input type="text" name="Command" value="{{.Command}}"></td></tr> <tr><td>Extra prompts (one per line):</td><td class="displaySetting">{{.ExtraStrings}}</td><td class="editSetting"><textarea name="ExtraStrings" >{{.ExtraStrings}}</textarea></td></tr> <tr><td> </td><td><input id="saveButton" type="submit" class="hiddenSave" name="save" value="Save changes"></td></tr> <tr id="yuhateme" class="hiddenSave"><td>Or... please don't go but...</td></tr> <tr><td><input id="leaveButton" type="submit" class="hiddenSave" name="leave" value="Leave twitch channel"></td></tr> </tbody> </table> {{ end }} {{ end }} </div> </form> <script type="text/javascript"> function tabClick(self) { var theTabs = document.querySelectorAll(".panel") for (tab of theTabs) { tab.className = "nav-link panel" } self.className = "nav-link panel active" var thePanels = document.querySelectorAll(".controlpanel") for (panel of thePanels) { panel.style.display = "none" } document.getElementById(self.id+"panel").style.display = "block" } /** * Modified and more readable version of the answer by Paul S. to sort a table with ASC and DESC order * with the <thead> and <tbody> structure easily. * * https://stackoverflow.com/a/14268260/4241030 */ var TableSorter = { makeSortable: function(table){ // Store context of this in the object var _this = this; var th = table.tHead, i; th && (th = th.rows[0]) && (th = th.cells); if (th){ i = th.length; }else{ return; // if no `<thead>` then do nothing } // Loop through every <th> inside the header while (--i >= 0) (function (i) { var dir = 1; // Append click listener to sort th[i].addEventListener('click', function () { _this._sort(table, i, (dir = 1 - dir)); }); }(i)); }, _sort: function (table, col, reverse) { var tb = table.tBodies[0], // use `<tbody>` to ignore `<thead>` and `<tfoot>` rows tr = Array.prototype.slice.call(tb.rows, 0), // put rows into array i; reverse = -((+reverse) || -1); // Sort rows tr = tr.sort(function (a, b) { // `-1 *` if want opposite order return reverse * ( // Using `.textContent.trim()` for test a.cells[col].textContent.trim().localeCompare( b.cells[col].textContent.trim() ) ); }); for(i = 0; i < tr.length; ++i){ // Append rows in new order tb.appendChild(tr[i]); } } }; window.onload = function(){ TableSorter.makeSortable(document.getElementById("dataTable")); }; </script> </main> <footer class="mastfoot mt-auto"> <div class="inner"> <p>Cover template for <a href="https://getbootstrap.com/">Bootstrap</a>, by <a href="https://twitter.com/mdo">@mdo</a>.</p> </div> </footer> </div> </body> </html> </body> </html>