<!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 class="col"> <button type="button" class="btn btn-primary btn-lg btn-block" id="button_settings"><i class="fa fa-cog"></i></button> </div> </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 modal-dialog-scrollable" 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>×</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> <div class="modal fade" id="settingsModal" tabindex="-1" role="dialog"> <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title">Settings</h5> <button type="button" class="close" data-dismiss="modal"> <span>×</span> </button> </div> <div class="modal-body"> <h6>Last RFID id:</h6> <span id="last_rfid_id"></span> <button class="btn btn-warning" id="button_add_mapping"><i class="fa fa-arrows-alt-h"></i></button> <h6>Last RFID data:</h6> <span id="last_rfid_data"></span> <h6>Actions</h6> <button type="button" class="btn btn-danger btn-lg btn-block" id="button_reset_vs1053">Reset VS1053 chip</button> <button type="button" class="btn btn-danger btn-lg btn-block" id="button_reboot">Reboot ESMP3</button> </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'); } $('#button_add_mapping').toggle(data.last_rfid.uid.length>0); $('#last_rfid_id').html(data.last_rfid.uid); $('#last_rfid_data').html(data.last_rfid.data); } 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]); tr.append($('<td>').html(data.unmapped[i].substr(1))); tr.append($('<td>').append($('<button>').addClass('button btn-warning add_mapping_button').hide().append($('<i>').addClass('fa fa-arrows-alt-h')))); $('#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))); tr.append($('<td>').append($('<button>').addClass('button btn-danger add_mapping_button').hide().append($('<i>').addClass('fa fa-arrows-alt-h')))); $('#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; case "controller": update_controller(json); break; } } } var play_on_click = true; $(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) { if (play_on_click) {ws.send("play " + $(e.target).parents('tr').data('folder')); $('#openModal').modal('hide');} }); $('#button_settings').click(function(e) { $('#settingsModal').modal('show'); }); $('#button_reset_vs1053').click(function(e) { ws.send("reset_vs1053"); $('#settingsModal').modal('hide'); }); $('#button_reboot').click(function(e) { ws.send("reboot"); $('#settingsModal').modal('hide'); }); $('#button_add_mapping').click(function(e) { $('#settingsModal').modal('hide'); $('#openModal').modal('show'); $('.add_mapping_button').show(); play_on_click = false; }); $('#openModal').on('click', '.add_mapping_button', function(e) {ws.send("add_mapping=" + $('#last_rfid_id').html() + "=" + $(e.target).parents('tr').data('folder')); $('#openModal').modal('hide'); $('.add_mapping_button').hide(); e.stopPropagation(); play_on_click=true; return false;}); }); </script> </html>