Replaced the huge html file served at / by a simple note that the API exists. The former API demo that has been there will move to an external server running on normal linux machines.
This commit is contained in:
parent
9bdc57633b
commit
35138308ef
@ -11,7 +11,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
||||
For more information, please refer to <http://unlicense.org/>
|
||||
*/
|
||||
|
||||
String generate_api_json(bool success, String content, bool plain) {
|
||||
String send_api_json(bool success, String content, bool plain) {
|
||||
String json = "{\"success\": "; // success
|
||||
json += success ? "true" : "false";
|
||||
json += ", ";
|
||||
@ -24,13 +24,14 @@ String generate_api_json(bool success, String content, bool plain) {
|
||||
}
|
||||
json += "}";
|
||||
|
||||
api_server.send(200, "application/json", json);
|
||||
return json;
|
||||
}
|
||||
String generate_api_json(bool success) { // if you just want the basic json frame with the basic info
|
||||
return generate_api_json(success, "", true);
|
||||
String send_api_json(bool success) { // if you just want the basic json frame with the basic info
|
||||
return send_api_json(success, "", true);
|
||||
}
|
||||
String generate_api_json(bool success, String content) { // when info is to be embedded
|
||||
return generate_api_json(success, content, false);
|
||||
String send_api_json(bool success, String content) { // when info is to be embedded
|
||||
return send_api_json(success, content, false);
|
||||
}
|
||||
bool isStringConvertable2Int(String toIntStr) {
|
||||
for (int i = 0; i < toIntStr.length(); i++) { // check if a non-digit character is in the given string
|
||||
@ -39,399 +40,17 @@ bool isStringConvertable2Int(String toIntStr) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ----------------------
|
||||
---- API FUNCTIONS ----
|
||||
-----------------------*/
|
||||
|
||||
/*
|
||||
void api_root() {
|
||||
Serial.println(F("[HTTP] [Config] 200 - '/'"));
|
||||
|
||||
String html = "<!doctype html>";
|
||||
html += "<html><head>";
|
||||
html += "<meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'>";
|
||||
html += "<title>Web UI | " + version + "</title>";
|
||||
html += "<link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css' rel='stylesheet' integrity='sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN' crossorigin='anonymous'>";
|
||||
html += "<style>#playbackMuteButton:hover { background-color: #00000000; }</style>";
|
||||
html += "</head><body data-bs-theme='dark'>";
|
||||
html += "<div class='text-center container-sm' style='padding: 4em 0em'>";
|
||||
|
||||
html += "<p>Welcome to</p>";
|
||||
html += "<h1 id='title_frname'>" + configuration.getString(PREFERENCES_KEY_FRIENDLY_NAME, "NetSpeaker") + "</h1>";
|
||||
html += "<p style='font-size: .875em; color: var(--bs-code-color); padding-top: .5rem'>" + version + "</p>";
|
||||
|
||||
html += "<hr style='margin: 3em 0em;'>";
|
||||
|
||||
// informations accordion
|
||||
html += "<div class='accordion text-start' id='accordion-info'>";
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-info-playback' aria-expanded='true' aria-controls='accordion-info-playback'>";
|
||||
html += " Playback information";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-info-playback' class='accordion-collapse collapse' data-bs-parent='#accordion-info'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <table class='table table-striped'><tbody><tr>";
|
||||
html += " <td>Playing</td>";
|
||||
html += " <td class='text-end'>";
|
||||
html += audioPlaying ? "yes" : "no";
|
||||
html += " </td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Volume</td>";
|
||||
html += " <td class='text-end'>" + String(currentVolume) + "/" + String(maxVolume) + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Muted</td>";
|
||||
html += " <td class='text-end'>";
|
||||
html += muted ? "yes" : "no";
|
||||
html += " </td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Equalizer Low</td>";
|
||||
html += " <td class='text-end'>" + String(eqLow) + "dB</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Equalizer Mid</td>";
|
||||
html += " <td class='text-end'>" + String(eqMid) + "dB</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Equalizer High</td>";
|
||||
html += " <td class='text-end'>" + String(eqHigh) + "dB</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Balance (range -16 | +16)</td>";
|
||||
html += " <td class='text-end'>" + String(balanceLevel) + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Path to playlist</td>";
|
||||
html += " <td class='text-end'>" + currentPlaylist + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Index in playlist (starting from 0)</td>";
|
||||
html += " <td class='text-end'>" + String(currentPlaylistPosition) + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource path</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.resourcePath + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource type</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.type + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource title</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.title + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource album</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.album + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource artist</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.artist + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource track number</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.track + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource year</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.year + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource genre</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.genre + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Resource language (for TTS)</td>";
|
||||
html += " <td class='text-end'>" + pbInfo.tts_language + "</td>";
|
||||
html += " </tr></tbody></table>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-info-general' aria-expanded='true' aria-controls='accordion-info-general'>";
|
||||
html += " General information";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-info-general' class='accordion-collapse collapse' data-bs-parent='#accordion-info'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <table class='table table-striped'><tbody><tr>";
|
||||
html += " <td>Version</td>";
|
||||
html += " <td class='text-end'>" + version + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Friendly name</td>";
|
||||
html += " <td class='text-end'>" + configuration.getString(PREFERENCES_KEY_FRIENDLY_NAME, "<not_given>") + "</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Save & Restore state</td>";
|
||||
html += " <td class='text-end'>";
|
||||
html += configuration.getBool(PREFERENCES_KEY_RESTORE_OLD_STATE, false) ? "yes" : "no";
|
||||
html += " </td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Save & Restore playing state (default no)</td>";
|
||||
html += " <td class='text-end'>";
|
||||
html += configuration.getBool(PREFERENCES_KEY_RESTORE_PLAYING, false) ? "yes" : "no";
|
||||
html += " </td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>WiFi SSID</td>";
|
||||
html += " <td class='text-end'>" + configuration.getString(PREFERENCES_KEY_WIFI_SSID, "") + "</td>";
|
||||
html += " </tr></tbody></table>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += "</div>";
|
||||
|
||||
html += "<hr style='margin: 3em 0em;'>";
|
||||
|
||||
// ------------------------------
|
||||
// -- API FUNCTIONS ACCODRION --
|
||||
// ------------------------------
|
||||
html += "<div class='accordion text-start' id='accordion'>";
|
||||
// PLAYBACK Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-playback' aria-expanded='true' aria-controls='accordion-collapse-playback'>";
|
||||
html += " Playback";
|
||||
html += " <span class='badge text-bg-success'>/api/v1/playback/</span>";
|
||||
html += " <span class='badge text-bg-info'>/api/v1/volume/</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-playback' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <table class='table table-striped'><tbody><tr>";
|
||||
html += " <td>Playing</td>";
|
||||
html += " <td class='text-end' id='playbackTable_audioPlayingValue'>";
|
||||
html += audioPlaying ? "yes" : "no";
|
||||
html += " </td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Volume</td>";
|
||||
html += " <td class='text-end' id='playbackTable_volumeValue'>" + String(currentVolume) + "/" + String(maxVolume) + "%</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Muted</td>";
|
||||
html += " <td class='text-end' id='playbackTable_mutedValue'>";
|
||||
html += muted ? "yes" : "no";
|
||||
html += " </td>";
|
||||
html += " </tr></tbody></table>";
|
||||
html += " <hr><div class='btn-group' role='group' aria-label='Basic playback option (play, pause, next, previous)'>";
|
||||
html += " <button type='button' class='btn btn-secondary' onclick=\"http = new XMLHttpRequest();http.open('GET', '/api/v1/playback/previous');http.send();\">";
|
||||
html += " <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-rewind-circle' viewBox='0 0 16 16'>";
|
||||
html += " <path d='M7.729 5.055a.5.5 0 0 0-.52.038l-3.5 2.5a.5.5 0 0 0 0 .814l3.5 2.5A.5.5 0 0 0 8 10.5V8.614l3.21 2.293A.5.5 0 0 0 12 10.5v-5a.5.5 0 0 0-.79-.407L8 7.386V5.5a.5.5 0 0 0-.271-.445'/>";
|
||||
html += " <path d='M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8'/>";
|
||||
html += " </svg>";
|
||||
html += " </button>";
|
||||
html += " <button type='button' class='btn btn-success' onclick=\"http = new XMLHttpRequest();http.open('GET', '/api/v1/playback/play');http.send();document.getElementById('playbackTable_audioPlayingValue').innerHTML = 'yes';\">";
|
||||
html += " <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-play-circle' viewBox='0 0 16 16'>";
|
||||
html += " <path d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16'></path>";
|
||||
html += " <path d='M6.271 5.055a.5.5 0 0 1 .52.038l3.5 2.5a.5.5 0 0 1 0 .814l-3.5 2.5A.5.5 0 0 1 6 10.5v-5a.5.5 0 0 1 .271-.445'></path>";
|
||||
html += " </svg>";
|
||||
html += " </button>";
|
||||
html += " <button type='button' class='btn btn-success' onclick=\"http = new XMLHttpRequest();http.open('GET', '/api/v1/playback/pause');http.send();document.getElementById('playbackTable_audioPlayingValue').innerHTML = 'no';\">";
|
||||
html += " <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-pause-circle' viewBox='0 0 16 16'>";
|
||||
html += " <path d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16'/>";
|
||||
html += " <path d='M5 6.25a1.25 1.25 0 1 1 2.5 0v3.5a1.25 1.25 0 1 1-2.5 0zm3.5 0a1.25 1.25 0 1 1 2.5 0v3.5a1.25 1.25 0 1 1-2.5 0z'/>";
|
||||
html += " </svg>";
|
||||
html += " </button>";
|
||||
html += " <button type='button' class='btn btn-secondary' onclick=\"http = new XMLHttpRequest();http.open('GET', '/api/v1/playback/next');http.send();\">";
|
||||
html += " <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-skip-forward-circle' viewBox='0 0 16 16'>";
|
||||
html += " <path d='M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16'/>";
|
||||
html += " <path d='M4.271 5.055a.5.5 0 0 1 .52.038L7.5 7.028V5.5a.5.5 0 0 1 .79-.407L11 7.028V5.5a.5.5 0 0 1 1 0v5a.5.5 0 0 1-1 0V8.972l-2.71 1.935a.5.5 0 0 1-.79-.407V8.972l-2.71 1.935A.5.5 0 0 1 4 10.5v-5a.5.5 0 0 1 .271-.445'/>";
|
||||
html += " </svg>";
|
||||
html += " </button>";
|
||||
html += " </div>";
|
||||
html += " <br><hr><br><label for='volumeRange' class='form-label'>Volume</label>";
|
||||
html += " <input type='range' class='form-range' value='" + String(currentVolume) + "' min='0' max='" + String(maxVolume) + "' id='volumeRange' onchange='value = document.getElementById(\"volumeRange\").value; http = new XMLHttpRequest();http.open(\"GET\", \"/api/v1/volume/\" + value);http.send();document.getElementById(\"playbackTable_volumeValue\").innerHTML = value + \"/" + String(maxVolume) + "%\"'>";
|
||||
html += " <button type='button' id='playbackMuteButton' onclick=";
|
||||
html += " \"http = new XMLHttpRequest();";
|
||||
html += " http.open('GET', '/api/v1/volume/toggle_mute');";
|
||||
html += " http.send(); button = document.getElementById('playbackMuteButton');";
|
||||
html += " button.classList.contains('btn-outline-danger') ? button.className = 'btn btn-danger' : button.className = 'btn btn-outline-danger';";
|
||||
html += " mutedValueHTML = document.getElementById('playbackTable_mutedValue');";
|
||||
html += " button.classList.contains('btn-outline-danger') ? mutedValueHTML.innerHTML = 'no' : mutedValueHTML.innerHTML = 'yes'\" class='btn ";
|
||||
html += muted ? "btn-danger'>" : "btn-outline-danger'>";
|
||||
html += " <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-volume-mute' viewBox='0 0 16 16'>";
|
||||
html += " <path d='M6.717 3.55A.5.5 0 0 1 7 4v8a.5.5 0 0 1-.812.39L3.825 10.5H1.5A.5.5 0 0 1 1 10V6a.5.5 0 0 1 .5-.5h2.325l2.363-1.89a.5.5 0 0 1 .529-.06zM6 5.04 4.312 6.39A.5.5 0 0 1 4 6.5H2v3h2a.5.5 0 0 1 .312.11L6 10.96zm7.854.606a.5.5 0 0 1 0 .708L12.207 8l1.647 1.646a.5.5 0 0 1-.708.708L11.5 8.707l-1.646 1.647a.5.5 0 0 1-.708-.708L10.793 8 9.146 6.354a.5.5 0 1 1 .708-.708L11.5 7.293l1.646-1.647a.5.5 0 0 1 .708 0z'></path>";
|
||||
html += " </svg> Mute/Unmute</button>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// PLAYLIST Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-playlist' aria-expanded='true' aria-controls='accordion-collapse-playlist'>";
|
||||
html += " Playlist";
|
||||
html += " <span class='badge text-bg-success'>/api/v1/playlist/</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-playlist' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
// play playlist (select playlist) api demo
|
||||
html += " <p>Demo for playing a specific playlist on the SD card over the API.</p>";
|
||||
html += " <div class='input-group mb-3'>";
|
||||
html += " <input type='text' class='form-control' placeholder='Playlist path (must start with a /)' aria-label='Playlist path (must start with a /)' aria-describedby='playlist_playBtn' id='playlist_playPathInput'>";
|
||||
html += " <button class='btn btn-success' type='button' id='playlist_playBtn' onclick=";
|
||||
html += " \"playlistPath = document.getElementById('playlist_playPathInput').value;";
|
||||
html += " http = new XMLHttpRequest();http.open('GET', '/api/v1/playlist/play?playlist_path='+playlistPath);http.send();\">";
|
||||
html += " Change</button>";
|
||||
html += " </div>";
|
||||
html += " <hr>";
|
||||
// create playlist api demo
|
||||
html += " <p>Demo for creating a new playlist containing all the contents of the given folder (on the SD card).</p>";
|
||||
html += " <p>The new playlist will be located in the given folder and is named <code>.directory.m3u</code>. This can't be changed.</p>";
|
||||
html += " <p>Creating fully personalized playlist or even uploading one will be subject of further development (see also the Roadmap of the NetSpeaker project!).</p>";
|
||||
html += " <div class='input-group mb-3'>";
|
||||
html += " <input type='text' class='form-control' placeholder='Folder path (must start with and end without a /)' aria-label='Folder path (must start with a /)' aria-describedby='playlist_createBtn' id='playlist_createPathInput'>";
|
||||
html += " <button class='btn btn-success' type='button' id='playlist_createBtn' onclick=";
|
||||
html += " \"folderPath = document.getElementById('playlist_createPathInput').value;";
|
||||
html += " http = new XMLHttpRequest();http.open('GET', '/api/v1/playlist/create?folder_path='+folderPath);http.send();\">";
|
||||
html += " Change</button>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// BALANCE Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-balance' aria-expanded='true' aria-controls='accordion-collapse-balance'>";
|
||||
html += " Balance";
|
||||
html += " <span class='badge text-bg-info'>/api/v1/balance/</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-balance' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <p>The Audio library used maps -16 to most right and 16 to most left. Don't be confused by the appearently wrong direction the slider moves the balance to right and left.</p>";
|
||||
html += " <table class='table table-striped'><tbody><tr>";
|
||||
html += " <td>Balance (range -16 | +16)</td>";
|
||||
html += " <td class='text-end' id='balanceChangeTable_balanceValue'>" + String(balanceLevel) + "</td>";
|
||||
html += " </tr></tbody></table>";
|
||||
html += " <br><hr><label for='balanceRange' class='form-label'>Balance (-16 to 16)</label>";
|
||||
html += " <input type='range' class='form-range' value='" + String(balanceLevel+16) + "' min='0' max='32' id='balanceRange' onchange='value = document.getElementById(\"balanceRange\").value; http = new XMLHttpRequest();http.open(\"GET\", \"/api/v1/balance/\" + value);http.send(); document.getElementById(\"balanceChangeTable_balanceValue\").innerHTML = value-16;'>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// EQUALIZER Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-eq' aria-expanded='true' aria-controls='accordion-collapse-eq'>";
|
||||
html += " Equalizer";
|
||||
html += " <span class='badge text-bg-info'>/api/v1/eq/</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-eq' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <table class='table table-striped'><tbody><tr>";
|
||||
html += " <td>Equalizer Low (-40dB to 6dB)</td>";
|
||||
html += " <td class='text-end' id='eqChangeTable_eqLowValue'>" + String(eqLow) + "dB</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Equalizer Mid (-40dB to 6dB)</td>";
|
||||
html += " <td class='text-end' id='eqChangeTable_eqMidValue'>" + String(eqMid) + "dB</td>";
|
||||
html += " </tr><tr>";
|
||||
html += " <td>Equalizer High (-40dB to 6dB)</td>";
|
||||
html += " <td class='text-end' id='eqChangeTable_eqHighValue'>" + String(eqHigh) + "dB</td>";
|
||||
html += " </tr></tbody></table>";
|
||||
html += " <br><hr><label for='eqLowRange' class='form-label'>Equalizer for lows (-40dB to 6dB)</label>";
|
||||
html += " <input type='range' class='form-range' value='" + String(eqLow+40) + "' min='0' max='46' id='eqLowRange' onchange='value = document.getElementById(\"eqLowRange\").value; http = new XMLHttpRequest();http.open(\"GET\", \"/api/v1/eq/low/\" + value);http.send(); document.getElementById(\"eqChangeTable_eqLowValue\").innerHTML = value-40 + \"dB\";'>";
|
||||
html += " <br><hr><br><label for='eqMidRange' class='form-label'>Equalizer for mids (-40dB to 6dB)</label>";
|
||||
html += " <input type='range' class='form-range' value='" + String(eqMid+40) + "' min='0' max='46' id='eqMidRange' onchange='value = document.getElementById(\"eqMidRange\").value; http = new XMLHttpRequest();http.open(\"GET\", \"/api/v1/eq/mid/\" + value);http.send(); document.getElementById(\"eqChangeTable_eqMidValue\").innerHTML = value-40 + \"dB\";'>";
|
||||
html += " <br><hr><br><label for='eqHighRange' class='form-label'>Equalizer for highs (-40dB to 6dB)</label>";
|
||||
html += " <input type='range' class='form-range' value='" + String(eqHigh+40) + "' min='0' max='46' id='eqHighRange' onchange='value = document.getElementById(\"eqHighRange\").value; http = new XMLHttpRequest();http.open(\"GET\", \"/api/v1/eq/high/\" + value);http.send(); document.getElementById(\"eqChangeTable_eqHighValue\").innerHTML = value-40 + \"dB\";'>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// FRIENDLY NAME Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-frname' aria-expanded='true' aria-controls='accordion-collapse-frname'>";
|
||||
html += " Friendly name";
|
||||
html += " <span class='badge text-bg-warning'>/api/v1/system/name</span>"; // explicitly no trailing / as there are the two endpoints /name and /name/change
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-frname' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <div class='input-group mb-3'>";
|
||||
html += " <span class='input-group-text' id='frnameChange_oldName'>" + configuration.getString(PREFERENCES_KEY_FRIENDLY_NAME) + "</span>";
|
||||
html += " <span class='input-group-text'> -> </span>";
|
||||
html += " <input type='text' class='form-control' placeholder='New friendly name' aria-label='New friendly name' aria-describedby='frnameChange_BTN_submitName' id='frnameChange_newNameInput'>";
|
||||
html += " <button class='btn btn-success' type='button' id='frnameChange_BTN_submitName' onclick=";
|
||||
html += " \"newNameInput = document.getElementById('frnameChange_newNameInput'); if(newNameInput.value != ''){ http = new XMLHttpRequest();http.open('GET', '/api/v1/system/name/change?friendly_name='+newNameInput.value);http.send();document.getElementById('frnameChange_oldName').innerHTML=newNameInput.value;document.getElementById('title_frname').innerHTML=newNameInput.value;newNameInput.value=''; }\">";
|
||||
html += " Change</button>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// WiFi CONFIGURATION Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-wifi' aria-expanded='true' aria-controls='accordion-collapse-wifi'>";
|
||||
html += " WiFi configuration";
|
||||
html += " <span class='badge text-bg-warning'>/api/v1/system/wifi/</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-wifi' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <p>Demo for changing the wifi SSID and PSK (= Pre-Shared Key; well-known as 'Password' or 'Key'). There's no need to give both - if you just wanna change the password - do it!</p>";
|
||||
html += " <p>After doing this, you have to go down to the restart collapsible. There, restart the NetSpeaker and it should connect to the configured WiFi.</p>";
|
||||
html += " <p>If anything is wrong (either SSID or PSK wrong/typo, or the wifi's not available), the NetSpeaker opens an HotSpot with the SSID <code>" + apSSID + "</code> and the PSK <code>" + apPSK + "</code>! </p>";
|
||||
html += " <div class='input-group mb-3'>";
|
||||
html += " <span class='input-group-text'>SSID</span>";
|
||||
html += " <input type='text' class='form-control' placeholder='Type in a new SSID here (optional)' aria-label='Type in a new SSID here (optional)' aria-describedby='wifiChange_submitBtn' id='wifiChange_ssidInput'>";
|
||||
html += " <span class='input-group-text'>PSK</span>";
|
||||
html += " <input type='password' class='form-control' placeholder='Type in a new PSK here (optional)' aria-label='Type in a new PSK here (optional)' aria-describedby='wifiChange_submitBtn' id='wifiChange_pskInput'>";
|
||||
html += " <button class='btn btn-success' type='button' id='wifiChange_submitBtn' onclick=";
|
||||
html += " \"newSSID = document.getElementById('wifiChange_ssidInput').value;";
|
||||
html += " newPSK = document.getElementById('wifiChange_pskInput').value;";
|
||||
html += " http = new XMLHttpRequest();http.open('GET', '/api/v1/system/wifi/change?ssid='+newSSID+'&psk='+newPSK);http.send();\">";
|
||||
html += " Change</button>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// SAVE AND RESTORE Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-restore' aria-expanded='true' aria-controls='accordion-collapse-restore'>";
|
||||
html += " Save & Restore";
|
||||
html += " <span class='badge text-bg-warning'>/api/v1/system/restore_state/</span>";
|
||||
html += " <span class='badge text-bg-warning'>/api/v1/system/restore_playing/</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-restore' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <p>Restoring the old/last state can be toggeled on or off over the API. Doing so can have many reasons, one could be that you wanted to build a device always playing some startup sound, or so.</p>";
|
||||
html += " <div class='form-check form-switch'>";
|
||||
html += " <input onclick=\"this.value ? console.log('Toggeled on') : console.log('Toggeled off');\" class='form-check-input' type='checkbox' role='switch' id='restoreStateSwitch' " + configuration.getBool(PREFERENCES_KEY_RESTORE_OLD_STATE, true) ? "checked" : String() + " >";
|
||||
html += " <label class='form-check-label' for='restoreStateSwitch'>Restore last saved state</label>";
|
||||
html += " </div>";
|
||||
html += " <div class='form-check form-switch'>";
|
||||
html += " <input onclick=\"this.value ? console.log('Toggeled on') : console.log('Toggeled off');\" class='form-check-input' type='checkbox' role='switch' id='restorePlayingSwitch' " + configuration.getBool(PREFERENCES_KEY_RESTORE_PLAYING, true) ? "checked" : String() + " >";
|
||||
html += " <label class='form-check-label' for='restorePlayingSwitch'>Also restore last playing state</label>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
// RESTART Collapsible
|
||||
html += " <div class='accordion-item'>";
|
||||
html += " <h2 class='accordion-header'>";
|
||||
html += " <button class='accordion-button collapsed' type='button' data-bs-toggle='collapse' data-bs-target='#accordion-collapse-restart' aria-expanded='true' aria-controls='accordion-collapse-restart'>";
|
||||
html += " Restart";
|
||||
html += " <span class='badge text-bg-danger'>/api/v1/system/restart</span>";
|
||||
html += " </button>";
|
||||
html += " </h2>";
|
||||
html += " <div id='accordion-collapse-restart' class='accordion-collapse collapse' data-bs-parent='#accordion'>";
|
||||
html += " <div class='accordion-body'>";
|
||||
html += " <button type='button' class='btn btn-danger' onclick=\"function wait(ms){var start = new Date().getTime();var end=start;while(end<start+ms){end = new Date().getTime();}}http = new XMLHttpRequest();http.open('GET', '/api/v1/system/restart');http.send();wait(3000);window.location.reload();\">";
|
||||
html += " <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-bootstrap-reboot' viewBox='0 0 16 16'>";
|
||||
html += " <path d='M1.161 8a6.84 6.84 0 1 0 6.842-6.84.58.58 0 1 1 0-1.16 8 8 0 1 1-6.556 3.412l-.663-.577a.58.58 0 0 1 .227-.997l2.52-.69a.58.58 0 0 1 .728.633l-.332 2.592a.58.58 0 0 1-.956.364l-.643-.56A6.812 6.812 0 0 0 1.16 8z'></path>";
|
||||
html += " <path d='M6.641 11.671V8.843h1.57l1.498 2.828h1.314L9.377 8.665c.897-.3 1.427-1.106 1.427-2.1 0-1.37-.943-2.246-2.456-2.246H5.5v7.352zm0-3.75V5.277h1.57c.881 0 1.416.499 1.416 1.32 0 .84-.504 1.324-1.386 1.324h-1.6z'></path>";
|
||||
html += " </svg> Restart";
|
||||
html += " </button>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
html += " </div>";
|
||||
|
||||
html += "</div></div>";
|
||||
html += "<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js' integrity='sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL' crossorigin='anonymous'></script>";
|
||||
html += "</body></html>";
|
||||
|
||||
api_server.send(200, "text/html", html);
|
||||
}
|
||||
*/
|
||||
void api_v1_playback_toggle() {
|
||||
Serial.println("[HTTP] [API] 200 - '/api/v1/playback/toggle'");
|
||||
|
||||
audioPlaying = !audioPlaying;
|
||||
Serial.printf("[INFO] Playback has switched: %s\n", audioPlaying ? "Playing" : "Paused");
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true));
|
||||
send_api_json(true);
|
||||
}
|
||||
|
||||
void api_v1_playback_play() {
|
||||
@ -440,7 +59,7 @@ void api_v1_playback_play() {
|
||||
audioPlaying = true;
|
||||
Serial.printf("[INFO] Playback has switched: Playing\n");
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true));
|
||||
send_api_json(true);
|
||||
}
|
||||
|
||||
void api_v1_playback_pause() {
|
||||
@ -449,7 +68,7 @@ void api_v1_playback_pause() {
|
||||
audioPlaying = false;
|
||||
Serial.printf("[INFO] Playback has switched: Paused\n");
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true));
|
||||
send_api_json(true);
|
||||
}
|
||||
|
||||
void api_v1_playback_next() {
|
||||
@ -459,7 +78,7 @@ void api_v1_playback_next() {
|
||||
String content = "\"resource_playlist_index\": ";
|
||||
content += String(currentPlaylistPosition);
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, content));
|
||||
send_api_json(true, content);
|
||||
}
|
||||
|
||||
void api_v1_playback_previous() {
|
||||
@ -469,7 +88,7 @@ void api_v1_playback_previous() {
|
||||
String content = "\"resource_playlist_index\": ";
|
||||
content += String(currentPlaylistPosition);
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, content));
|
||||
send_api_json(true, content);
|
||||
}
|
||||
|
||||
void api_v1_playback_byindex() {
|
||||
@ -481,7 +100,7 @@ void api_v1_playback_byindex() {
|
||||
for (int i = 0; i < option.length(); i++) {
|
||||
if (isDigit((char)option[i])) toIntStr += option[i];
|
||||
else {
|
||||
api_server.send(200, "application/json", generate_api_json(false));
|
||||
send_api_json(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -491,12 +110,12 @@ void api_v1_playback_byindex() {
|
||||
currentPlaylistPosition = index - 1;
|
||||
nextAudio(); // the clean way of playing the next resource
|
||||
} else {
|
||||
api_server.send(200, "application/json", generate_api_json(false));
|
||||
send_api_json(false);
|
||||
}
|
||||
|
||||
String content = "\"resource_playlist_index\": ";
|
||||
content += String(currentPlaylistPosition);
|
||||
api_server.send(200, "application/json", generate_api_json(true, content));
|
||||
send_api_json(true, content);
|
||||
}
|
||||
|
||||
void api_v1_volume() {
|
||||
@ -519,7 +138,7 @@ void api_v1_volume() {
|
||||
} else if (option == "get") {
|
||||
// just here that no 'success: false' is sent
|
||||
} else if (option == "get_max") {
|
||||
api_server.send(200, "application/json", generate_api_json(success, "\"volume_max\": " + String(maxVolume)));
|
||||
send_api_json(success, "\"volume_max\": " + String(maxVolume));
|
||||
} else {
|
||||
String toIntStr;
|
||||
int volumeLevel;
|
||||
@ -539,7 +158,7 @@ void api_v1_volume() {
|
||||
content += String(currentVolume);
|
||||
content += ", \"muted\": ";
|
||||
content += muted ? "true" : "false";
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_balance() {
|
||||
@ -570,7 +189,7 @@ void api_v1_balance() {
|
||||
|
||||
String content = "\"balance\": "; // prepare the http response
|
||||
content += String(balanceLevel);
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_eq_get() {
|
||||
@ -583,7 +202,7 @@ void api_v1_eq_get() {
|
||||
content += ", \"equalizer_high\": "; // prepare the http response
|
||||
content += String(eqHigh);
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, content)); // generate json and send it
|
||||
send_api_json(true, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_eq_reset() {
|
||||
@ -603,7 +222,7 @@ void api_v1_eq_reset() {
|
||||
content += ", \"equalizer_high\": "; // prepare the http response
|
||||
content += String(eqHigh);
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, content)); // generate json and send it
|
||||
send_api_json(true, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_eq_low() {
|
||||
@ -629,7 +248,7 @@ void api_v1_eq_low() {
|
||||
|
||||
String content = "\"equalizer_low\": "; // prepare the http response
|
||||
content += String(eqLow);
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
void api_v1_eq_mid() {
|
||||
String option = api_server.pathArg(0);
|
||||
@ -654,7 +273,7 @@ void api_v1_eq_mid() {
|
||||
|
||||
String content = "\"equalizer_mid\": "; // prepare the http response
|
||||
content += String(eqMid);
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
void api_v1_eq_high() {
|
||||
String option = api_server.pathArg(0);
|
||||
@ -679,7 +298,7 @@ void api_v1_eq_high() {
|
||||
|
||||
String content = "\"equalizer_high\": "; // prepare the http response
|
||||
content += String(eqHigh);
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_playback_info() {
|
||||
@ -696,7 +315,7 @@ void api_v1_playback_info() {
|
||||
content += "\"resource_playlist_path\": \"" + currentPlaylist + "\", "; // playlist path
|
||||
content += "\"resource_playlist_index\": " + String(currentPlaylistPosition); // playlist index (starting from 0)
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, content));
|
||||
send_api_json(true, content);
|
||||
}
|
||||
|
||||
void api_v1_playlist_get() {
|
||||
@ -724,7 +343,7 @@ void api_v1_playlist_get() {
|
||||
}
|
||||
content += "}";
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, content));
|
||||
send_api_json(true, content);
|
||||
}
|
||||
|
||||
void api_v1_playlist_create() {
|
||||
@ -743,9 +362,9 @@ void api_v1_playlist_create() {
|
||||
if (code) { // if creating the playlist was successful
|
||||
String playlistPath = folderPath + "/" + directoryPlaylistName + playlistExtension;
|
||||
String content = "\"playlist_path\": \"" + playlistPath + "\"";
|
||||
api_server.send(200, "application/json", generate_api_json(true, content));
|
||||
send_api_json(true, content);
|
||||
} else {
|
||||
api_server.send(200, "application/json", generate_api_json(false));
|
||||
send_api_json(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,12 +381,12 @@ void api_v1_playlist_play() {
|
||||
}
|
||||
|
||||
if (getURLFromPlaylist(playlistPath, 0) == "") { // get the first item from the playlist to check whether the pl is empty or nonexistent
|
||||
api_server.send(200, "application/json", generate_api_json(false)); // send no success info
|
||||
send_api_json(false); // send no success info
|
||||
} else {
|
||||
currentPlaylist = playlistPath;
|
||||
currentPlaylistPosition = -1;
|
||||
nextAudio();
|
||||
api_server.send(200, "application/json", generate_api_json(true)); // just return the success info
|
||||
send_api_json(true); // just return the success info
|
||||
}
|
||||
}
|
||||
|
||||
@ -785,7 +404,7 @@ void api_v1_system_restart() {
|
||||
void api_v1_system_friendlyname_get() {
|
||||
Serial.println("[HTTP] [API] 200 - '/api/v1/system/name'");
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, "\"friendly_name\": \"" + configuration.getString(PREFERENCES_KEY_FRIENDLY_NAME) + "\""));
|
||||
send_api_json(true, "\"friendly_name\": \"" + configuration.getString(PREFERENCES_KEY_FRIENDLY_NAME) + "\"");
|
||||
}
|
||||
|
||||
void api_v1_system_friendlyname_change() {
|
||||
@ -804,14 +423,14 @@ void api_v1_system_friendlyname_change() {
|
||||
}
|
||||
// define what to do if nothing really changed (or no argument was given)
|
||||
if (newFriendlyName == currentFriendlyName || !arg_given) {
|
||||
api_server.send(200, "application/json", generate_api_json(false, "\"friendly_name\": \"" + currentFriendlyName + "\"")); // return with no success ("false")
|
||||
send_api_json(false, "\"friendly_name\": \"" + currentFriendlyName + "\""); // return with no success ("false")
|
||||
return;
|
||||
}
|
||||
|
||||
configuration.putString(PREFERENCES_KEY_FRIENDLY_NAME, newFriendlyName);
|
||||
Serial.printf("[INFO] Changed friendly name from \"%s\" to \"%s\".\n", currentFriendlyName.c_str(), newFriendlyName.c_str());
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, "\"friendly_name\": \"" + newFriendlyName + "\""));
|
||||
send_api_json(true, "\"friendly_name\": \"" + newFriendlyName + "\"");
|
||||
}
|
||||
|
||||
void api_v1_system_restore_state() {
|
||||
@ -833,7 +452,7 @@ void api_v1_system_restore_state() {
|
||||
|
||||
String content = "\"restore_state\": "; // prepare the http response
|
||||
content += configuration.getBool(PREFERENCES_KEY_RESTORE_OLD_STATE, false) ? "true" : "false";
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_system_restore_playing() {
|
||||
@ -855,19 +474,19 @@ void api_v1_system_restore_playing() {
|
||||
|
||||
String content = "\"restore_playing\": "; // prepare the http response
|
||||
content += configuration.getBool(PREFERENCES_KEY_RESTORE_PLAYING, false) ? "true" : "false";
|
||||
api_server.send(200, "application/json", generate_api_json(success, content)); // generate json and send it
|
||||
send_api_json(success, content); // generate json and send it
|
||||
}
|
||||
|
||||
void api_v1_system_version() {
|
||||
Serial.printf("[HTTP] [API] 200 - '/api/v1/system/version'\n");
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, "\"version\": \"" + version + "\", " + "\"version_tag\": \"" + version_tag + "\""));
|
||||
send_api_json(true, "\"version\": \"" + version + "\", " + "\"version_tag\": \"" + version_tag + "\"");
|
||||
}
|
||||
|
||||
void api_v1_system_wifi_getssid() {
|
||||
Serial.println("[HTTP] [API] 200 - '/api/v1/system/wifi/get_ssid'");
|
||||
|
||||
api_server.send(200, "application/json", generate_api_json(true, "\"wifi_ssid\": \"" + configuration.getString(PREFERENCES_KEY_WIFI_SSID) + "\""));
|
||||
send_api_json(true, "\"wifi_ssid\": \"" + configuration.getString(PREFERENCES_KEY_WIFI_SSID) + "\"");
|
||||
}
|
||||
|
||||
void api_v1_system_wifi_change() {
|
||||
@ -897,20 +516,24 @@ void api_v1_system_wifi_change() {
|
||||
} else if (ssid == "" && psk != "") { // just the psk is given
|
||||
configuration.putString(PREFERENCES_KEY_WIFI_PSK, psk);
|
||||
} else { // none of ssid or psk is given
|
||||
api_server.send(200, "application/json", generate_api_json(false));
|
||||
send_api_json(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("[INFO] Changed wifi credentials (SSID: '%s' | PSK: '%s')\n", ssid.c_str(), psk.c_str());
|
||||
api_server.send(200, "application/json", generate_api_json(true, "\"ssid\": \"" + ssid + "\", \"psk\": \"" + psk + "\""));
|
||||
send_api_json(true, "\"ssid\": \"" + ssid + "\", \"psk\": \"" + psk + "\"");
|
||||
}
|
||||
|
||||
void setupWeb() {
|
||||
//api_server.on("/", api_root);
|
||||
api_server.on("/", []() {
|
||||
Serial.println("[HTTP] [API] 404: Not Found");
|
||||
char message[] = "{\"message\": 404, \"message\": \"Welcome to your NetSpeaker's API! More info can be found at https://git.privacynerd.de/NetSpeaker/NetSpeaker\"}";
|
||||
api_server.send(404, "application/json", message);
|
||||
}); // on /
|
||||
api_server.onNotFound([]() {
|
||||
Serial.println("[HTTP] [API] 404: Not Found");
|
||||
api_server.send(404, "application/json", "{\"code\": 404, \"message\": \"Resource not found.\"}");
|
||||
});
|
||||
}); // on NotFound (the fallback if nothing else configured for the requested URL)
|
||||
api_server.on("/api/v1/playback/toggle", api_v1_playback_toggle);
|
||||
api_server.on("/api/v1/playback/play", api_v1_playback_play);
|
||||
api_server.on("/api/v1/playback/pause", api_v1_playback_pause);
|
||||
|
Loading…
x
Reference in New Issue
Block a user