527 lines
29 KiB
HTML
527 lines
29 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
|
<title>syng 2.0.0</title>
|
|
<link rel="stylesheet" href="css/foundation.min.css"/>
|
|
<link rel="stylesheet" href="css/app.css"/>
|
|
<link rel="stylesheet" href="css/font-awesome.css"/>
|
|
<script src="jquery-3.2.1.min.js"></script>
|
|
<script src="jquery.serialize-object.min.js"></script>
|
|
<script src="js/vendor/foundation.js"></script>
|
|
<script src="js/vendor/rivets.bundled.min.js"></script>
|
|
<script src="https://cdn.socket.io/4.5.3/socket.io.min.js"></script>
|
|
</head>
|
|
<body>
|
|
<div class="page">
|
|
<div class="row" id="main-content">
|
|
<div class="hide-for-large">
|
|
<div class="splitter">
|
|
<div class="comp-column">
|
|
<div data-tabs class="tabs" id="main-tab">
|
|
<div class="tabs-title is-active"><a href="#simplesearch"><i class="fa fa-search fa-3x"></i></a></div>
|
|
<div class="tabs-title"><a href="#queue-list" id="queue-tab"><i class="fa fa-list fa-3x"></i></a></div>
|
|
<div class="tabs-title"><a href="#recent-list"><i class="fa fa-history fa-3x"></i></a></div>
|
|
</div>
|
|
<div class="tabs-container" data-tabs-content="main-tab">
|
|
<div class="tabs-panel is-active" id="simplesearch">
|
|
<div class="vsplit">
|
|
|
|
|
|
<form id="simple-search-form" class="form">
|
|
<div class="input-group">
|
|
<input id="search-query" class="input-group-field" type="search" placeholder="Search term or YouTube link (https://www.youtube.com/watch?v=...)" name="q" />
|
|
<div class="input-group-button">
|
|
<button class="button" type="submit"><i class="fa fa-search"></i></button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<div id="search-results" class="results">
|
|
<ul class="vertical menu" >
|
|
<li rv-each-result="results.items">
|
|
<div class="row">
|
|
<div class="columns small-10">
|
|
<span class="artist">{ result.artist }</span>
|
|
<span class="title">{ result.title }</span>
|
|
<span class="album">{ result.album }</span>
|
|
</div>
|
|
<div class="columns small-2">
|
|
<button class="button alert fright" rv-if="result.type | eq 'youtube'" rv-on-click="results.openNewTab">
|
|
<i class="fa fa-play"></i>
|
|
</button>
|
|
<button class="button fright" rv-on-click="results.addToQueue">
|
|
<i class="fa fa-plus"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs-panel" id="queue-list">
|
|
<div class="vsplit">
|
|
<div id="queue-list-wrapper" class="results">
|
|
<ul id="queue" class="vertical menu">
|
|
<li rv-if="queue.current" id="current">
|
|
{% if admin == True -%}
|
|
<div class="row">
|
|
<div class="columns small-9">
|
|
{%- endif %}
|
|
<div class="row">
|
|
<span class="artist">{ queue.current.artist }</span>
|
|
<span class="title">{ queue.current.title }</span>
|
|
<span class="album">{ queue.current.album }</span>
|
|
</div>
|
|
<div class="row">
|
|
<span class="singer">{ queue.current.performer }</span>
|
|
</div>
|
|
{% if admin == True -%}
|
|
</div>
|
|
<div class="columns small-3">
|
|
<div class="button-group">
|
|
<button class="button alert fright" rv-on-click="queue.abort"><i class="fa fa-step-forward"></i></button>
|
|
<button class="button alert fright" rv-on-click="queue.kill"><i class="fa fa-times"></i></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{%- endif %}
|
|
|
|
</li>
|
|
<li rv-each-entry="queue.queue">
|
|
{% if admin == True -%}
|
|
<div class="row">
|
|
<div class="columns small-9">
|
|
{%- endif %}
|
|
<div class="row">
|
|
<span class="artist">{ entry.artist }</span>
|
|
<span class="title">{ entry.title }</span>
|
|
<span class="album">{ entry.album }</span>
|
|
</div>
|
|
<div class="row">
|
|
<span class="singer">{ entry.performer }</span>
|
|
<span class="eta">{ entry.etamin }</span>
|
|
</div>
|
|
{% if admin == True -%}
|
|
</div>
|
|
<div class="columns small-3">
|
|
<button class="button alert fright" rv-on-click="queue.deleteFromQueue"><i class="fa fa-minus"></i></button>
|
|
</div>
|
|
</div>
|
|
{%- endif %}
|
|
</li>
|
|
{% if admin == True %}
|
|
<li>
|
|
<div class="row">
|
|
<div class="columns small-12">
|
|
<a class="button" download="queue.json" rv-href="queue.data">Save</a>
|
|
<label for="small-bulk-upload" class="button bulk-upload-label">Bulk Append</label>
|
|
<input type="file" id="small-bulk-upload" rv-on-change="queue.bulk_append" class="show-for-sr">
|
|
</div>
|
|
</div>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tabs-panel" id="recent-list">
|
|
<div class="vsplit">
|
|
<div id="recent-list-wrapper" class="results">
|
|
<ol id="last10" class="vertical menu">
|
|
<li rv-each-entry="queue.last10">
|
|
<div class="row">
|
|
<span class="artist">{ entry.artist }</span>
|
|
<span class="title">{ entry.title }</span>
|
|
<span class="album">{ entry.album }</span>
|
|
</div>
|
|
<div class="row">
|
|
<span class="singer">{ entry.performer }</span>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="show-for-large">
|
|
<div class="splitter">
|
|
<div class="comp-column" id="left-side">
|
|
<div class="header">Search</div>
|
|
<div id="large-simplesearch">
|
|
<div class="vsplit">
|
|
<form id="large-simple-search-form" class="form">
|
|
<div class="input-group">
|
|
<input id="large-search-query" class="input-group-field" type="search" placeholder="Search term or YouTube link (https://www.youtube.com/watch?v=...)" name="q" />
|
|
<div class="input-group-button">
|
|
<button class="button" type="submit"><i class="fa fa-search"></i></button>
|
|
</div>
|
|
<div class="input-group-button" style="padding-left: 0.25em">
|
|
<button class="button" type="button" data-open="settings-large"><i class="fa fa-sliders"></i></button>
|
|
<div class="reveal" id="settings-large" data-reveal>
|
|
<div class="grid-x">
|
|
<div class="cell small-4 medium-2">
|
|
<div class="switch">
|
|
<input class="switch-input" name="append-karaoke" id="large-append-karaoke" type="checkbox" checked="checked"> <label class="switch-paddle" for="large-append-karaoke"></label>
|
|
</div>
|
|
</div>
|
|
<div class="cell small-8 medium-4">
|
|
<label class="text-left middle" for="large-append-karaoke">Add "Karaoke" to Search</label>
|
|
</div>
|
|
<div class="cell small-4 medium-2">
|
|
<div class="switch">
|
|
<input class="switch-input" name="youtube" id="large-youtube" type="checkbox" checked="checked"> <label class="switch-paddle" for="large-youtube"></label>
|
|
</div>
|
|
</div>
|
|
<div class="cell small-8 medium-4">
|
|
<label class="text-left middle" for="large-youtube">Search YouTube</label>
|
|
</div>
|
|
|
|
<!-- {%- for channel in channels %} -->
|
|
<!-- <div class="cell small-4 medium-2"> -->
|
|
<!-- <div class="switch"> -->
|
|
<!-- <input class="switch-input" name="{{channel}}" id="large-channel-{{loop.index}}" type="checkbox" checked="checked"> <label class="switch-paddle" for="large-channel-{{loop.index}}"></label> -->
|
|
<!-- </div> -->
|
|
<!-- </div> -->
|
|
<!-- <div class="cell small-8 medium-4"> -->
|
|
<!-- <label class="text-left middle" for="large-channel-{{loop.index}}">Search {{ channel }}</label> -->
|
|
<!-- </div> -->
|
|
<!-- {%- endfor %} -->
|
|
|
|
<button class="close-button" data-close aria-label="Close modal" type="button">
|
|
<span aria-hidden="true">×</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<div id="large-search-results" class="results">
|
|
<ul class="vertical menu">
|
|
<li rv-each-result="results.items">
|
|
<div class="row">
|
|
<div class="columns small-10">
|
|
<span class="artist">{ result.artist }</span>
|
|
<span class="title">{ result.title }</span>
|
|
<span class="album">{ result.album }</span>
|
|
</div>
|
|
<div class="columns small-2">
|
|
<button class="button alert fright" rv-if="result.source | eq 'youtube'" rv-on-click="results.openNewTab">
|
|
<i class="fa fa-play"></i>
|
|
</button>
|
|
<button class="button fright" rv-on-click="results.addToQueue">
|
|
<i class="fa fa-plus"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="comp-column" id="middle">
|
|
<div class="header">Queue</div>
|
|
<div id="large-queue-list">
|
|
<div class="vsplit">
|
|
<div id="large-queue-list-wrapper" class="results">
|
|
<ul id="large-queue" class="vertical menu">
|
|
<li rv-if="queue.current" id="large-current">
|
|
{% if admin == True -%}
|
|
<div class="row">
|
|
<div class="columns small-9">
|
|
{%- endif %}
|
|
<div class="row">
|
|
<span class="artist">{ queue.current.artist }</span>
|
|
<span class="title">{ queue.current.title }</span>
|
|
<span class="album">{ queue.current.album }</span>
|
|
</div>
|
|
<div class="row">
|
|
<span class="singer">{ queue.current.performer }</span>
|
|
</div>
|
|
{% if admin == True -%}
|
|
</div>
|
|
<div class="columns small-3">
|
|
<div class="button-group">
|
|
<button class="button alert fright" rv-on-click="queue.kill">
|
|
<i class="fa fa-times"></i>
|
|
</button>
|
|
<button class="button alert fright" rv-on-click="queue.abort">
|
|
<i class="fa fa-step-forward"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{%- endif %}
|
|
|
|
</li>
|
|
<li {% if admin == True %} draggable="true" {% endif %} rv-each-entry="queue.queue">
|
|
{% if admin == True -%}
|
|
<div class="row">
|
|
<div class="columns small-9">
|
|
{%- endif %}
|
|
<div class="row">
|
|
<span class="artist">{ entry.artist }</span>
|
|
<span class="title">{ entry.title }</span>
|
|
<span class="album">{ entry.album }</span>
|
|
</div>
|
|
<div class="row">
|
|
<span class="singer">{ entry.performer }</span>
|
|
<span class="eta">{ entry.etamin }</span>
|
|
</div>
|
|
{% if admin == True -%}
|
|
</div>
|
|
<div class="columns small-3">
|
|
<div class="button-group">
|
|
<button class="button alert fright" rv-on-click="queue.moveup">
|
|
<i class="fa fa-arrow-circle-up"></i>
|
|
</button>
|
|
<button class="button alert fright" rv-on-click="queue.deleteFromQueue">
|
|
<i class="fa fa-minus"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{%- endif %}
|
|
</li>
|
|
{% if admin == True %}
|
|
<li>
|
|
<div class="row">
|
|
<div class="columns small-6">
|
|
<a class="button" download="queue.json" rv-href="queue.data">Save</a>
|
|
<label for="large-bulk-upload" class="button bulk-upload-label">Bulk Append</label>
|
|
<input type="file" id="large-bulk-upload" rv-on-change="queue.bulk_append" class="show-for-sr">
|
|
</div>
|
|
</div>
|
|
</li>
|
|
{% endif %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="comp-column" id="right-side">
|
|
<div class="header">Recent</div>
|
|
<div id="large-recent-list">
|
|
<div class="vsplit">
|
|
<div id="large-recent-list-wrapper" class="results">
|
|
<ol id="large-last10" class="vertical menu">
|
|
<li rv-each-entry="queue.last10">
|
|
<div class="row">
|
|
<span class="artist">{ entry.artist }</span>
|
|
<span class="title">{ entry.title }</span>
|
|
<span class="album">{ entry.album }</span>
|
|
</div>
|
|
<div class="row">
|
|
<span class="singer">{ entry.performer }</span>
|
|
</div>
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
<script>
|
|
const socket = io();
|
|
|
|
function ytselect(event) {
|
|
console.log(event.target.value);
|
|
var ytwarning = document.getElementsById("ytwarning");
|
|
if(event.target.value === "no_channel") {
|
|
ytwarning.style.display = "list-item";
|
|
}
|
|
ytwarning.style.display = "none";
|
|
}
|
|
|
|
function getQuery() {
|
|
var query = {};
|
|
$('input').each(function() {
|
|
if(this.type == "checkbox") {
|
|
query[this.name] = this.checked;
|
|
} else {
|
|
if(this.disabled == false) {
|
|
query[this.name] = this.value;
|
|
}
|
|
}
|
|
});
|
|
return query;
|
|
}
|
|
|
|
$(document).foundation();
|
|
results = {
|
|
items : [],
|
|
openNewTab : function(event, item) {
|
|
event.preventDefault();
|
|
window.open(item.result.id, '_blank');
|
|
},
|
|
addToQueue : function(event, item) {
|
|
event.preventDefault();
|
|
var singer = prompt("Performer:");
|
|
if(singer !== null) {
|
|
// $.post('queue', JSON.stringify({'id': item.result.id, 'singer': singer, 'type': item.result.type, 'location': item.result.location}), addQueueCallback, 'json');
|
|
socket.emit("append", {"performer": singer, "source": item.result.source, "id": item.result.id});
|
|
}
|
|
}
|
|
};
|
|
|
|
queue = {
|
|
current: null,
|
|
last10: [],
|
|
queue: [],
|
|
moveup: function (event, item) {
|
|
event.preventDefault();
|
|
if (item.index === 0) {
|
|
alert("You cannot switch places with the currently playing song.");
|
|
} else {
|
|
$.ajax({
|
|
method: 'patch',
|
|
url: 'queue',
|
|
data: JSON.stringify({'action': 'move', 'param': {'src': item.index, 'dst': item.index - 1}}),
|
|
success: updateHandler,
|
|
dataType: 'json'
|
|
})
|
|
}
|
|
},
|
|
deleteFromQueue: function (event, item) {
|
|
event.preventDefault();
|
|
$.ajax({
|
|
method: 'patch',
|
|
url: 'queue',
|
|
data: JSON.stringify({'action': 'delete', 'param': {'index': item.index} }),
|
|
success: updateHandler,
|
|
dataType: 'json'
|
|
});
|
|
},
|
|
bulk_append: function (event) {
|
|
var file = event.target.files[0];
|
|
var reader = new FileReader();
|
|
reader.onload = (function(theFile) {
|
|
return function(e) {
|
|
new_queue = JSON.parse(e.target.result);
|
|
$.post('queue', JSON.stringify(new_queue.queue), addQueueCallback, 'json');
|
|
}
|
|
})(file);
|
|
reader.readAsText(file);
|
|
},
|
|
data: "",
|
|
kill: function(event) {
|
|
event.preventDefault();
|
|
areyousure = confirm("This will kill the players process. Did you try skipping the song?");
|
|
if(areyousure === true) {
|
|
$.ajax({
|
|
method: 'patch',
|
|
url: 'queue',
|
|
data: JSON.stringify({'action': 'kill'}),
|
|
success: updateHandler,
|
|
dataType: 'json'
|
|
});
|
|
}
|
|
},
|
|
abort: function(event) {
|
|
event.preventDefault();
|
|
$.ajax({
|
|
method: 'patch',
|
|
url: 'queue',
|
|
data: JSON.stringify({'action': 'skip'}),
|
|
success: updateHandler,
|
|
dataType: 'json'
|
|
});
|
|
}
|
|
};
|
|
|
|
rivets.formatters.eq = function(value, arg) {
|
|
return value === arg;
|
|
};
|
|
|
|
if(Foundation.MediaQuery.atLeast("large")) {
|
|
$('#large-search-query').focus();
|
|
$('#search-query').get(0).disabled = true;
|
|
$('#large-search-query').get(0).disabled = false;
|
|
rivets.bind(document.getElementById("large-search-results"), {results: results});
|
|
rivets.bind(document.getElementById("large-queue"), {queue: queue});
|
|
rivets.bind(document.getElementById("large-last10"), {queue: queue});
|
|
} else {
|
|
$('#search-query').focus();
|
|
$('#large-search-query').get(0).disabled = true;
|
|
$('#search-query').get(0).disabled = false;
|
|
rivets.bind(document.getElementById("search-results"), {results: results});
|
|
rivets.bind(document.getElementById("queue"), {queue: queue});
|
|
rivets.bind(document.getElementById("last10"), {queue: queue});
|
|
}
|
|
|
|
function addQueueCallback(data) {
|
|
$("#queue-tab").click();
|
|
updateHandler(data)
|
|
}
|
|
|
|
function updateHandler(data) {
|
|
queue.queue = data['queue'];
|
|
queue.current = data['current'];
|
|
queue.last10 = data['last10'];
|
|
queue.data = "data:application/json," + (JSON.stringify({
|
|
'queue': [queue.current].concat(queue.queue)
|
|
}))
|
|
}
|
|
|
|
$("#large-simple-search-form, #simple-search-form").on("submit", function (event) {
|
|
event.preventDefault();
|
|
if ($(this).serializeObject().q.startsWith("https://www.youtube.com/")) {
|
|
results.addToQueue(event, {result: {id: $(this).serializeObject().q, type: "youtube"}});
|
|
} else {
|
|
results.items = [{title: "Loading...", artist: "Loading...", album: "Loading...", type:"temp"}];
|
|
query = {"query": $("#large-search-query").val()}
|
|
socket.emit("search", query);
|
|
}
|
|
});
|
|
|
|
$(window).on('changed.zf.mediaquery', function() {
|
|
if(Foundation.MediaQuery.atLeast("large")) {
|
|
$('#large-search-query').focus();
|
|
$('#search-query').get(0).disabled = true;
|
|
$('#large-search-query').get(0).disabled = false;
|
|
rivets.bind(document.getElementById("large-search-results"), {results: results});
|
|
rivets.bind(document.getElementById("large-queue"), {queue: queue});
|
|
rivets.bind(document.getElementById("large-last10"), {queue: queue});
|
|
} else {
|
|
$('#search-query').focus();
|
|
$('#large-search-query').get(0).disabled = true;
|
|
$('#search-query').get(0).disabled = false;
|
|
rivets.bind(document.getElementById("search-results"), {results: results});
|
|
rivets.bind(document.getElementById("queue"), {queue: queue});
|
|
rivets.bind(document.getElementById("last10"), {queue: queue});
|
|
}
|
|
});
|
|
|
|
socket.on("connect", () => {
|
|
socket.emit("register-web", {"room": "ABCD"})
|
|
})
|
|
|
|
socket.on("state", (data) => {
|
|
data['queue'] = data.slice(1);
|
|
data['current'] = data[0];
|
|
data['last10'] = [];
|
|
updateHandler(data);
|
|
});
|
|
|
|
socket.on("search-results", (data) => {
|
|
results.items = data;
|
|
});
|
|
|
|
|
|
|
|
/* $.get("queue", updateHandler);
|
|
setInterval(function() {
|
|
$.get("queue", updateHandler)
|
|
}, 2000); */
|
|
</script>
|
|
</html>
|