Massive changes. Added a quite nice webinterface with live data using WebSockets. Removed the FTP server (wasn't that useful anyways). JSON creating using ArduinoJson instead of String concatenation. Ans, and, and.

This commit is contained in:
2019-11-16 23:03:13 +01:00
parent 0cddfaf0d9
commit 7c3eb2f605
22 changed files with 625 additions and 2809 deletions

236
include/index.html Normal file
View File

@ -0,0 +1,236 @@
const char* html = R"V0G0N(<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>ESMP3</title>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://kit.fontawesome.com/272149490a.js" crossorigin="anonymous"></script>
</head>
<body>
<div class="container bg-dark text-light">
<div class="row">
<div class="col-sm-1">
<h1 id="play_state_icon"><i class="fa fa-stop"></i></h1>
</div>
<div class="col-sm-11">
<h2><i class="fa fa-compact-disc"></i> <span id="album"></span></h2>
<h2><i class="fa fa-scroll"></i> <span id="track"></span></h2>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="col">
<input type="range" class="custom-range" id="position_slider" disabled>
</div>
</div>
<div class="row">
<div class="col-sm-6">
</div>
<div class="col-sm-1">
<h3><i class="fa fa-volume-down"></i></h3>
</div>
<div class="col-sm-4">
<input type="range" class="custom-range" id="volume_slider">
</div>
<div class="col-sm-1">
<h3><i class="fa fa-volume-up"></i></h3>
</div>
</div>
<div class="row">
<div class="col">
<button type="button" class="btn btn-primary btn-lg btn-block" id="button_track_prev"><i class="fa fa-step-backward"></i></button>
</div>
<div class="col">
<button type="button" class="btn btn-primary btn-lg btn-block" id="button_stop"><i class="fa fa-stop"></i></button>
</div>
<div class="col">
<button type="button" class="btn btn-primary btn-lg btn-block" id="button_play"><i class="fa fa-play"></i></button>
</div>
<div class="col">
<button type="button" class="btn btn-primary btn-lg btn-block" id="button_track_next"><i class="fa fa-step-forward"></i></button>
</div>
<div class="col">
<button type="button" class="btn btn-primary btn-lg btn-block" id="button_lock"><i class="fa fa-lock-open"></i></button>
</div>
<div class="col">
<button type="button" class="btn btn-primary btn-lg btn-block" id="button_open"><i class="fa fa-eject"></i></button>
</div>
</div>
<div class="container">
<table class="table table-hover table-sm" id="track_list_table">
<thead class="thead-light">
<tr>
<th>Nr.</th>
<th>Status</th>
<th>Track</th>
</tr>
</thead>
<tbody class="" id="track_list">
</tbody>
</table>
</div>
<div class="modal fade" id="openModal" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Album öffnen</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div id="albums_without_id_area">
<h6>Albums without RFID card</h6>
<table class="table table-hover table-sm">
<tbody id="albums_without_id">
</tbody>
</table>
</div>
<h6>Albums with RFID</h6>
<table class="table table-hover table-sm">
<tbody id="albums_with_id">
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</body>
<script>
update_player = function(data) {
$('#play_state_icon i').removeClass('fa-stop', 'fa-play').addClass(data.playing ? 'fa-play' : 'fa-stop');
if (data.playing) {
$('#button_play').removeClass('btn-primary').addClass('btn-secondary', 'btn-disabled');
$('#button_stop').removeClass('btn-secondary', 'btn-disabled').addClass('btn-primary');
} else if (data.playlist) {
$('#button_play').removeClass('btn-secondary', 'btn-disabled').addClass('btn-primary');
$('#button_stop').removeClass('btn-primary').addClass('btn-secondary', 'btn-disabled');
} else {
$('#button_play').removeClass('btn-primary').addClass('btn-secondary', 'btn-disabled');
$('#button_stop').removeClass('btn-primary').addClass('btn-secondary', 'btn-disabled');
}
$('#volume_slider').attr('min', data.volume.min).attr('max', data.volume.max).val(data.volume.current);
if (data.playlist) update_playlist(data.playlist);
}
update_playlist = function(data) {
$('#track_list tr').remove();
for (var i=0; i<data.files.length; i++) {
tr = $('<tr>').data('track', i);
tr.append($('<td>').html(i + 1));
tr.append($('<td>').html(data.current_track==i ? '<i class="fa fa-play"></i>' : ''));
tr.append($('<td>').html(data.files[i].substr(data.files[i].lastIndexOf('/')+1)));
$('#track_list').append(tr);
}
if (data.has_track_next) {
$('#button_track_next').removeClass('btn-secondary', 'btn-disabled').addClass('btn-primary');
} else {
$('#button_track_next').removeClass('btn-primary').addClass('btn-secondary', 'btn-disabled');
}
if (data.has_track_prev) {
$('#button_track_prev').removeClass('btn-secondary', 'btn-disabled').addClass('btn-primary');
} else {
$('#button_track_prev').removeClass('btn-primary').addClass('btn-secondary', 'btn-disabled');
}
var file = data.files[data.current_track];
if (file) {
file = file.substr(1);
$('#album').html(file.substr(0, file.indexOf('/')));
file = file.substr(file.indexOf('/')+1);
$('#track').html(file.substr(0, file.lastIndexOf('.')));
}
}
update_controller = function(data) {
if (data.lock_state == "locked") {
$('#button_lock').removeClass('btn-primary', 'btn-warning').addClass('btn-danger');
$('#button_lock i').removeClass('fa-lock-open').addClass('fa-lock');
} else if (data.lock_state == "locking") {
$('#button_lock').removeClass('btn-primary', 'btn-danger').addClass('btn-warning');
$('#button_lock i').removeClass('fa-lock-open').addClass('fa-lock');
} else {
$('#button_lock').removeClass('btn-danger', 'btn-warning').addClass('btn-primary');
$('#button_lock i').removeClass('fa-lock').addClass('fa-lock-open');
}
}
update_playlist_manager = function(data) {
if (data.unmapped.length > 0) {
$('#albums_without_id_area').show();
$('#albums_without_id tr').remove();
data.unmapped = data.unmapped.sort();
for (var i=0; i<data.unmapped.length; i++) {
var tr = $('<tr>').attr('data-folder', data.unmapped[i]).append($('<td>').html(data.unmapped[i].substr(1)));
$('#albums_without_id').append(tr);
}
} else {
$('#albums_without_id_area').hide();
}
var folders = Object.keys(data.folders).sort();
for (var i in folders) {
var folder = folders[i];
var tr = $('<tr>').attr('data-folder', folder);
tr.append($('<td>').html(folder.substr(1)));
$('#albums_with_id').append(tr);
}
}
update_position = function(data) {
$('#position_slider').attr('max', data.file_size).val(data.position);
}
process_ws_message = function(event) {
var data = event.data.split("\n");;
for (var i=0; i<data.length; i++) {
var json = JSON.parse(data[i]);
console.log(json);
switch(json["_type"]) {
case "position": update_position(json); break;
case "player": update_player(json); break;
case "playlist_manager": update_playlist_manager(json); break;
}
}
}
$(function() {
ws = new WebSocket("ws://" + location.host + "/ws");
ws.onmessage = process_ws_message;
$('#volume_slider').change(function(e) { ws.send("volume=" + e.target.value); });
$('#button_play').click(function(e) { ws.send("play"); });
$('#button_stop').click(function(e) { ws.send("stop"); });
$('#button_track_next').click(function(e) { ws.send("track_next"); });
$('#button_track_prev').click(function(e) { ws.send("track_prev"); });
$('#button_open').click(function(e) { $('#openModal').modal('show'); });
$('#track_list').on('click', 'tr', function(e) { ws.send("track=" + $(e.target).parent().data('track')); });
$('#albums_without_id, #albums_with_id').on('click', 'tr', function(e) { ws.send("play " + $(e.target).parent().data('folder')); $('#openModal').modal('hide'); });
});
</script>
</html>
)V0G0N";