<!doctype html>
<html>
<head>
    <meta charset='utf-8'>
    <meta name='viewport' content='width=device-width,initial-scale=1'>
    <title>NetSpeaker Demo (on [IP here])</title>
    <link href='https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css' rel='stylesheet'
          integrity='sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN' crossorigin='anonymous'>
    <style>#playbackMuteButton:hover { background-color: #00000000; }</style>
</head>
<body data-bs-theme='dark'>
<div class='text-center container-sm placeholder-glow' style='padding: 4em 0em'>

    <p>Welcome to</p>
    <h1 id='updatedLabel_FRNAME_title'><span class="placeholder col-3"></span></h1>
    <p id="title_onIP"><span class="placeholder col-1"></span></p>
    <p style='font-size: .875em; color: var(--bs-code-color); padding-top: .5rem' id="updatedLabel_VERSION_title"><span
            class="placeholder col-2"></span></p>

    <hr style='margin: 3em 0em;'>

    <!-----------------------------
    ---- INFORMATIONS ACCORDION ---
    ------------------------------>
    <div class='accordion text-start' id='accordion-info'>
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Playback information
                </button>
            </h2>
            <div id='accordion-info-playback' class='accordion-collapse collapse' data-bs-parent='#accordion-info'>
                <div class='accordion-body'>
                    <table class='table table-striped'>
                        <tbody>
                        <tr>
                            <td>Playing</td>
                            <td class='text-end' id="updatedLabel_PLAYING_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Volume</td>
                            <td class='text-end' id="updatedLabel_VOLUME_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Muted</td>
                            <td class='text-end' id="updatedLabel_MUTED_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Equalizer Low</td>
                            <td class='text-end' id="updatedLabel_EQLOW_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Equalizer Mid</td>
                            <td class='text-end' id="updatedLabel_EQMID_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Equalizer High</td>
                            <td class='text-end' id="updatedLabel_EQHIGH_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Balance (range -16 | +16)</td>
                            <td class='text-end' id="updatedLabel_BALANCE_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Path to playlist</td>
                            <td class='text-end' id="updatedLabel_RS_PLPATH_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Index in playlist (starting from 0)</td>
                            <td class='text-end' id="updatedLabel_RS_PLIDX_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource path</td>
                            <td class='text-end' id="updatedLabel_RS_PATH_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource type</td>
                            <td class='text-end' id="updatedLabel_RS_TYPE_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource title</td>
                            <td class='text-end' id="updatedLabel_RS_TITLE_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource album</td>
                            <td class='text-end' id="updatedLabel_RS_ALBUM_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource artist</td>
                            <td class='text-end' id="updatedLabel_RS_ARTIST_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource track number</td>
                            <td class='text-end' id="updatedLabel_RS_TRACKNR_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource year</td>
                            <td class='text-end' id="updatedLabel_RS_YEAR_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource genre</td>
                            <td class='text-end' id="updatedLabel_RS_GENRE_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource copyright</td>
                            <td class='text-end' id="updatedLabel_RS_COPYRIGHT_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Resource language (for TTS)</td>
                            <td class='text-end' id="updatedLabel_RS_LANGUAGE_table_top"><span class="placeholder col-12"></span></td>
                        </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    General information
                </button>
            </h2>
            <div id='accordion-info-general' class='accordion-collapse collapse' data-bs-parent='#accordion-info'>
                <div class='accordion-body'>
                    <table class='table table-striped'>
                        <tbody>
                        <tr>
                            <td>Version</td>
                            <td class='text-end' id="updatedLabel_VERSION_table"><span class="placeholder col-4"></span></td>
                        </tr>
                        <tr>
                            <td>Friendly name</td>
                            <td class='text-end' id="updatedLabel_FRNAME_table"><span class="placeholder col-4"></span></td>
                        </tr>
                        <tr>
                            <td>Save & Restore state</td>
                            <td class='text-end' id="updatedLabel_RESTORESTATE_table"><span class="placeholder col-4"></span></td>
                        </tr>
                        <tr>
                            <td>Save & Restore playing state (default no)</td>
                            <td class='text-end' id="updatedLabel_RESTOREPLAYING_table"><span class="placeholder col-4"></span></td>
                        </tr>
                        <tr>
                            <td>WiFi SSID</td>
                            <td class='text-end' id="updatedLabel_WIFISSID_table"><span class="placeholder col-4"></span></td>
                        </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>

    <hr style='margin: 3em 0em;'>


    <!---------------------------------->
    <!---- API FUNCTIONS ACCODRION  ---->
    <!---------------------------------->
    <div class='accordion text-start' id='accordion'>

        <!-- PLAYBACK Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Playback
                    &nbsp;<span class='badge text-bg-success'>/api/v1/playback/</span>
                    &nbsp;<span class='badge text-bg-info'>/api/v1/volume/</span>
                </button>
            </h2>
            <div id='accordion-collapse-playback' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <table class='table table-striped'>
                        <tbody>
                        <tr>
                            <td>Playing</td>
                            <td class='text-end' id='updatedLabel_PLAYING_table_bottom'><span class="placeholder col-4"></span></td>
                        </tr>
                        <tr>
                            <td>Volume</td>
                            <td class='text-end' id='updatedLabel_VOLUME_table_bottom'><span class="placeholder col-4"></span></td>
                        </tr>
                        <tr>
                            <td>Muted</td>
                            <td class='text-end' id='updatedLabel_MUTED_table_bottom'><span class="placeholder col-4"></span></td>
                        </tr>
                        </tbody>
                    </table>
                    <hr>
                    <div class='btn-group' role='group' aria-label='Basic playback option (play, pause, next, previous)'>
                        <button type='button' class='btn btn-secondary' onclick="http
                                = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/playback/previous');http.send();updateStrings();">
                            <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-rewind-circle'
                                 viewBox='0 0 16 16'>
                                <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'/>
                                <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'/>
                            </svg>
                        </button>
                        <button type='button' class='btn btn-success' onclick="http
                                = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/playback/play');http.send();updateStrings();">
                            <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-play-circle'
                                 viewBox='0 0 16 16'>
                                <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>
                                <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>
                            </svg>
                        </button>
                        <button type='button' class='btn btn-success' onclick="http
                                = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/playback/pause');http.send();updateStrings();">
                            <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-pause-circle'
                                 viewBox='0 0 16 16'>
                                <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 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'/>
                            </svg>
                        </button>
                        <button type='button' class='btn btn-secondary'
                                onclick="http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/playback/next');http.send();updateStrings();">
                            <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'>
                                <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 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'/>
                            </svg>
                        </button>
                    </div>
                    <br>
                    <hr>
                    <br><label for='volumeRange' class='form-label'>Volume</label>
                    <input type='range' class='form-range' value='0' min='0' max='0'
                           id='updatedLabel_VOLUME_range_bottom'
                           onchange="http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/volume/' + this.value);http.send();updateStrings();">
                    <button type='button' id='playbackMuteButton' onclick=
                            "http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/volume/toggle_mute');http.send();updateStrings();"
                            class='btn btn-danger'>
                        <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-volume-mute'
                             viewBox='0 0 16 16'>
                            <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>
                        </svg>
                        Mute/Unmute
                    </button>
                </div>
            </div>
        </div>

        <!--PLAYLIST Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Playlist
                    &nbsp;<span class='badge text-bg-success'>/api/v1/playlist/</span>
                </button>
            </h2>
            <div id='accordion-collapse-playlist' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <!--play playlist (select playlist) api demo -->
                    <p>Demo for playing a specific playlist on the SD card over the API.</p>
                    <div class='input-group mb-3'>
                        <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'>
                        <button class='btn btn-success' type='button' id='playlist_playBtn' onclick=
                                "playlistPath = document.getElementById('playlist_playPathInput').value;
                                http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/playlist/play?playlist_path='+playlistPath);http.send();
                                updateStrings();">
                            Change
                        </button>
                    </div>
                    <hr>
                    <!-- Create playlist api demo -->
                    <p>Demo for creating a new playlist containing all the contents of the given folder (on the SD card).</p>
                    <p>The new playlist will be located in the given folder and is named <code>.directory.m3u</code>. This can't be changed.
                    </p>
                    <p>Creating fully personalized playlist or even uploading one will be subject of further development (see also the
                        Roadmap of the NetSpeaker project!).</p>
                    <div class='input-group mb-3'>
                        <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'>
                        <button class='btn btn-success' type='button' id='playlist_createBtn' onclick=
                                "folderPath = document.getElementById('playlist_createPathInput').value;
                                http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/playlist/create?folder_path='+folderPath);http.send();
                                updateStrings();">
                            Change
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <!--BALANCE Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Balance
                    &nbsp;<span class='badge text-bg-info'>/api/v1/balance/</span>
                </button>
            </h2>
            <div id='accordion-collapse-balance' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <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>
                    <table class='table table-striped'>
                        <tbody>
                        <tr>
                            <td>Balance (range -16 | +16)</td>
                            <td class='text-end' id='updatedLabel_BALANCE_table_bottom'><span class="placeholder col-12"></span></td>
                        </tr>
                        </tbody>
                    </table>
                    <br>
                    <hr>
                    <label for='balanceRange' class='form-label'>Balance (-16 to 16)</label>
                    <input type='range' class='form-range' value='16' min='0' max='32' id='updatedLabel_BALANCE_range_bottom'
                           onchange="http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/balance/' + this.value);http.send();updateStrings();">
                </div>
            </div>
        </div>

        <!-- EQUALIZER Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Equalizer
                    &nbsp;<span class='badge text-bg-info'>/api/v1/eq/</span>
                </button>
            </h2>
            <div id='accordion-collapse-eq' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <table class='table table-striped'>
                        <tbody>
                        <tr>
                            <td>Equalizer Low (-40dB to 6dB)</td>
                            <td class='text-end' id='updatedLabel_EQLOW_table_bottom'><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Equalizer Mid (-40dB to 6dB)</td>
                            <td class='text-end' id='updatedLabel_EQMID_table_bottom'><span class="placeholder col-12"></span></td>
                        </tr>
                        <tr>
                            <td>Equalizer High (-40dB to 6dB)</td>
                            <td class='text-end' id='updatedLabel_EQHIGH_table_bottom'><span class="placeholder col-12"></span></td>
                        </tr>
                        </tbody>
                    </table>
                    <br>
                    <hr>
                    <label for='eqLowRange' class='form-label'>Equalizer for lows (-40dB to 6dB)</label>
                    <input type='range' class='form-range' value='" + String(eqLow+40) + "' min='0' max='46' id='updatedLabel_EQLOW_range_bottom'
                           onchange="http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/eq/low/' + this.value);http.send();updateStrings();">
                    <br>
                    <hr>
                    <br><label for='eqMidRange' class='form-label'>Equalizer for mids (-40dB to 6dB)</label>
                    <input type='range' class='form-range' value='" + String(eqMid+40) + "' min='0' max='46' id='updatedLabel_EQMID_range_bottom'
                           onchange="http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/eq/mid/' + this.value);http.send();updateStrings();">
                    <br>
                    <hr>
                    <br><label for='eqHighRange' class='form-label'>Equalizer for highs (-40dB to 6dB)</label>
                    <input type='range' class='form-range' value='" + String(eqHigh+40) + "' min='0' max='46' id='updatedLabel_EQHIGH_range_bottom'
                           onchange="http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/eq/high/' + this.value);http.send();updateStrings();">
                </div>
            </div>
        </div>

        <!-- FRIENDLY NAME Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Friendly name
                    &nbsp;<span class='badge text-bg-warning'>/api/v1/system/name</span>
                    <!--explicitly no trailing / as there are the two endpoints /name and /name/change -->
                </button>
            </h2>
            <div id='accordion-collapse-frname' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <div class='input-group mb-3'>
                        <span class='input-group-text' id='updatedLabel_FRNAME_oldinputtext'>...</span>
                        <span class='input-group-text'> -> </span>
                        <input type='text' class='form-control' placeholder='New friendly name' aria-label='New friendly name'
                               aria-describedby='frnameChange_BTN_submitName' id='frnameChange_newNameInput'>
                        <button class='btn btn-success' type='button' id='frnameChange_BTN_submitName' onclick="
                        newName=document.getElementById('frnameChange_newNameInput').value;oldName=document.getElementById('updatedLabel_FRNAME_oldinputtext').innerHTML;
                        if(oldName != newName) {
                            http = new XMLHttpRequest();http.open('GET', 'http://' + document.cookie + '/api/v1/system/name/change?friendly_name=' + newName);http.send();
                            updateStrings();
                        }">
                            Change
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <!-- WiFi CONFIGURATION Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    WiFi configuration
                    &nbsp;<span class='badge text-bg-warning'>/api/v1/system/wifi/</span>
                </button>
            </h2>
            <div id='accordion-collapse-wifi' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <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>
                    <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>
                    <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></code> and the PSK <code></code>! </p>
                    <div class='input-group mb-3'>
                        <span class='input-group-text'>SSID</span>
                        <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'>
                        <span class='input-group-text'>PSK</span>
                        <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'>
                        <button class='btn btn-success' type='button' id='wifiChange_submitBtn' onclick=
                                "newSSID
                                = document.getElementById('wifiChange_ssidInput').value;
                                newPSK = document.getElementById('wifiChange_pskInput').value;
                                http = new XMLHttpRequest();http.open('GET',
                                '/api/v1/system/wifi/change?ssid='+newSSID+'&psk='+newPSK);http.send();">
                            Change
                        </button>
                    </div>
                </div>
            </div>
        </div>

        <!-- SAVE AND RESTORE Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Save & Restore
                    &nbsp;<span class='badge text-bg-warning'>/api/v1/system/restore_state/</span>
                    &nbsp;<span class='badge text-bg-warning'>/api/v1/system/restore_playing/</span>
                </button>
            </h2>
            <div id='accordion-collapse-restore' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <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>
                    <div class='form-check form-switch'>
                        <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() + " >
                        <label class='form-check-label' for='restoreStateSwitch'>Restore last saved state</label>
                    </div>
                    <div class='form-check form-switch'>
                        <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() + " >
                        <label class='form-check-label' for='restorePlayingSwitch'>Also restore last playing state</label>
                    </div>
                </div>
            </div>
        </div>

        <!-- RESTART Collapsible -->
        <div class='accordion-item'>
            <h2 class='accordion-header'>
                <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'>
                    Restart
                    &nbsp;<span class='badge text-bg-danger'>/api/v1/system/restart</span>
                </button>
            </h2>
            <div id='accordion-collapse-restart' class='accordion-collapse collapse' data-bs-parent='#accordion'>
                <div class='accordion-body'>
                    <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();">
                        <svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-bootstrap-reboot'
                             viewBox='0 0 16 16'>
                            <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>
                            <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>
                        </svg>
                        Restart
                    </button>
                </div>
            </div>
        </div>
    </div>


    <!-- Modal -->
    <div class="modal fade" id="selectIPAddressModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1"
         aria-labelledby="selectIPAddressModalLabel" aria-hidden="true">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h1 class="modal-title fs-5" id="selectIPAddressModalLabel">NetSpeaker configuration</h1>
                </div>
                <div class="text-start modal-body">
                    <p>Please give the IP adress of you NetSpeaker here, so that this site can access its API.</p>
                    <div class="mb-3">
                        <div class="input-group">
                            <span class="input-group-text">http://</span>
                            <input type="text" class="form-control" id="ipAdressInput">
                        </div>
                    </div>
                    <div id="configWorkingAlertPlaceholder"></div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-primary" id="ipAdressModalApplyBtn">Apply & Test</button>
                    <button type="button" class="btn btn-success" id="ipAdressModalOkBtn">Ok</button>
                </div>
            </div>
        </div>
    </div>
</div>
<script src='https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js'
        integrity='sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL' crossorigin='anonymous'></script>
<script type="text/javascript">
    function isValidIP(ipaddress) {
        if (/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/.test(ipaddress)) {
            return true;
        }
        return false;
    }
    function appendAlert(alertPlaceholder, message, type) {
      const wrapper = document.createElement('div')
      wrapper.innerHTML = [
        `<div class="alert alert-${type} alert-dismissible" role="alert">`,
        `   <div>${message}</div>`,
        '   <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>',
        '</div>'
      ].join('')

      alertPlaceholder.append(wrapper)
    }

    versionLabel1 = document.getElementById('updatedLabel_VERSION_title');
    versionLabel2 = document.getElementById('updatedLabel_VERSION_table');
    frnameLabel1 = document.getElementById('updatedLabel_FRNAME_title');
    frnameLabel2 = document.getElementById('updatedLabel_FRNAME_table');
    frnameLabel3 = document.getElementById('updatedLabel_FRNAME_oldinputtext');
    restoreStateLabel1 = document.getElementById('updatedLabel_RESTORESTATE_table')
    restorePlayingStateLabel1 = document.getElementById('updatedLabel_RESTOREPLAYING_table')
    wifiLabel1 = document.getElementById('updatedLabel_WIFISSID_table');
    const playingLabel1 = document.getElementById("updatedLabel_PLAYING_table_top");
    const playingLabel2 = document.getElementById("updatedLabel_PLAYING_table_bottom");
    const rs_plpathLabel1 = document.getElementById("updatedLabel_RS_PLPATH_table_top");
    const rs_plidxLabel1 = document.getElementById("updatedLabel_RS_PLIDX_table_top");
    const rs_pathLabel1 = document.getElementById("updatedLabel_RS_PATH_table_top");
    const rs_typeLabel1 = document.getElementById("updatedLabel_RS_TYPE_table_top");
    const rs_titleLabel1 = document.getElementById("updatedLabel_RS_TITLE_table_top");
    const rs_albumLabel1 = document.getElementById("updatedLabel_RS_ALBUM_table_top");
    const rs_artistLabel1 = document.getElementById("updatedLabel_RS_ARTIST_table_top");
    const rs_tracknrLabel1 = document.getElementById("updatedLabel_RS_TRACKNR_table_top");
    const rs_yearLabel1 = document.getElementById("updatedLabel_RS_YEAR_table_top");
    const rs_genreLabel1 = document.getElementById("updatedLabel_RS_GENRE_table_top");
    const rs_copyrightLabel1 = document.getElementById("updatedLabel_RS_COPYRIGHT_table_top");
    const rs_languageLabel1 = document.getElementById("updatedLabel_RS_LANGUAGE_table_top");
    volumeLabel1 = document.getElementById('updatedLabel_VOLUME_table_top');
    volumeLabel2 = document.getElementById('updatedLabel_VOLUME_table_bottom');
    volumeRange1 = document.getElementById('updatedLabel_VOLUME_range_bottom');
    mutedLabel1 = document.getElementById('updatedLabel_MUTED_table_top');
    mutedLabel2 = document.getElementById('updatedLabel_MUTED_table_bottom');
    eqLowLabel1 = document.getElementById('updatedLabel_EQLOW_table_top');
    eqLowLabel2 = document.getElementById('updatedLabel_EQLOW_table_bottom');
    eqLowRange1 = document.getElementById('updatedLabel_EQLOW_range_bottom');
    eqMidLabel1 = document.getElementById('updatedLabel_EQMID_table_top');
    eqMidLabel2 = document.getElementById('updatedLabel_EQMID_table_bottom');
    eqMidRange1 = document.getElementById('updatedLabel_EQMID_range_bottom');
    eqHighLabel1 = document.getElementById('updatedLabel_EQHIGH_table_top');
    eqHighLabel2 = document.getElementById('updatedLabel_EQHIGH_table_bottom');
    eqHighRange1 = document.getElementById('updatedLabel_EQHIGH_range_bottom');
    balanceLabel1 = document.getElementById('updatedLabel_BALANCE_table_top');
    balanceLabel2 = document.getElementById('updatedLabel_BALANCE_table_bottom');
    balanceRange1 = document.getElementById('updatedLabel_BALANCE_range_bottom');


    function updateStrings() {
        apiBase =                        "http://" + document.cookie;
        versionApiEndpoint =             "/api/v1/system/version";
        frnameApiEndpoint =              "/api/v1/system/name";
        restoreStateApiEndpoint =        "/api/v1/system/restore_state/get";
        restorePlayingStateApiEndpoint = "/api/v1/system/restore_playing/get";
        wifiApiEndpoint =                "/api/v1/system/wifi/get_ssid";
        playbackInfoApiEndpoint =        "/api/v1/playback/info";
        volumeApiEndpoint =              "/api/v1/volume/get";
        eqApiEndpoint =                  "/api/v1/eq/get";
        balanceApiEndpoint =             "/api/v1/balance/get";

        /* Version string parser */
        var versionRequest = new XMLHttpRequest();
        versionRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var versionString = JSON.parse(this.responseText).version;
                versionLabel1.innerHTML = versionString;
                versionLabel2.innerHTML = versionString;
            }
        }
        versionRequest.open("GET", apiBase + versionApiEndpoint, true);
        versionRequest.send();


        /* friendly name parser */
        var frnameRequest = new XMLHttpRequest();
        frnameRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var frnameString = JSON.parse(this.responseText).friendly_name;
                frnameLabel1.innerHTML = frnameString;
                frnameLabel2.innerHTML = frnameString;
                frnameLabel3.innerHTML = frnameString;
            }
        }
        frnameRequest.open("GET", apiBase + frnameApiEndpoint, true);
        frnameRequest.send();


        /* Save & Restore parser */
        var restoreStateRequest = new XMLHttpRequest();
        restoreStateRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var restoreStateString = JSON.parse(this.responseText).restore_state;
                restoreStateLabel1.innerHTML = restoreStateString ? "yes" : "no";
            }
        }
        restoreStateRequest.open("GET", apiBase + restoreStateApiEndpoint, true);
        restoreStateRequest.send();
        
        var restorePlayingRequest = new XMLHttpRequest();
        restorePlayingRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var restorePlayingString = JSON.parse(this.responseText).restore_playing;
                restorePlayingStateLabel1.innerHTML = restorePlayingString ? "yes" : "no";
            }
        }
        restorePlayingRequest.open("GET", apiBase + restorePlayingStateApiEndpoint, true);
        restorePlayingRequest.send();


        /* WiFi SSID parser */
        var wifiRequest = new XMLHttpRequest();
        wifiRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var wifiSsidString = JSON.parse(this.responseText).wifi_ssid;
                wifiLabel1.innerHTML = wifiSsidString;
            }
        }
        wifiRequest.open("GET", apiBase + wifiApiEndpoint, true);
        wifiRequest.send();

        /* Playback info parser */
        var playbackInfoRequest = new XMLHttpRequest();
        playbackInfoRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var playbackInfoResponse = JSON.parse(this.responseText);

                playingLabel1.innerHTML = playbackInfoResponse.state == "playing" ? "yes" : "no";
                playingLabel2.innerHTML = playbackInfoResponse.state == "playing" ? "yes" : "no";
                rs_plpathLabel1.innerHTML = playbackInfoResponse.resource_playlist_path;
                rs_plidxLabel1.innerHTML = playbackInfoResponse.resource_playlist_index;
                rs_pathLabel1.innerHTML = playbackInfoResponse.resource_path;
                rs_typeLabel1.innerHTML = playbackInfoResponse.resource_type;
                rs_titleLabel1.innerHTML = playbackInfoResponse.resource_title;
                rs_albumLabel1.innerHTML = playbackInfoResponse.resource_album;
                rs_artistLabel1.innerHTML = playbackInfoResponse.resource_artist;
                rs_tracknrLabel1.innerHTML = playbackInfoResponse.resource_track;
                rs_yearLabel1.innerHTML = playbackInfoResponse.resource_year;
                rs_genreLabel1.innerHTML = playbackInfoResponse.resource_genre;
                rs_copyrightLabel1.innerHTML = playbackInfoResponse.resource_copyright;
                rs_languageLabel1.innerHTML = playbackInfoResponse.resource_tts_language;
            }
        }
        playbackInfoRequest.open("GET", apiBase + playbackInfoApiEndpoint, true);
        playbackInfoRequest.send();


        /* Volume+Muted parser */
        var volumeRequest = new XMLHttpRequest();
        volumeRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var volumeValue = JSON.parse(this.responseText).volume;
                var maxVolumeValue = JSON.parse(this.responseText).volume_max;
                var mutedValue = JSON.parse(this.responseText).muted;
                volumeLabel1.innerHTML = volumeValue + "/" + maxVolumeValue;
                volumeLabel2.innerHTML = volumeValue + "/" + maxVolumeValue;
                mutedLabel1.innerHTML = mutedValue ? "yes" : "no";
                mutedLabel2.innerHTML = mutedValue ? "yes" : "no";
                volumeRange1.max = maxVolumeValue;
                volumeRange1.value = volumeValue;
            }
        }
        volumeRequest.open("GET", apiBase + volumeApiEndpoint, true);
        volumeRequest.send();


        /* Equalizer parser */
        var eqRequest = new XMLHttpRequest();
        eqRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var eqLowValue = JSON.parse(this.responseText).equalizer_low;
                var eqMidValue = JSON.parse(this.responseText).equalizer_mid;
                var eqHighValue = JSON.parse(this.responseText).equalizer_high;
                eqLowLabel1.innerHTML = eqLowValue + "dB";
                eqLowLabel2.innerHTML = eqLowValue + "dB";
                eqLowRange1.value = eqLowValue + 40;
                eqMidLabel1.innerHTML = eqMidValue + "dB";
                eqMidLabel2.innerHTML = eqMidValue + "dB";
                eqMidRange1.value = eqMidValue + 40;
                eqHighLabel1.innerHTML = eqHighValue + "dB";
                eqHighLabel2.innerHTML = eqHighValue + "dB";
                eqHighRange1.value = eqHighValue + 40;
            }
        }
        eqRequest.open("GET", apiBase + eqApiEndpoint, true);
        eqRequest.send();


        /* Balance parser */
        var balanceRequest = new XMLHttpRequest();
        balanceRequest.onreadystatechange = function() {
            if (this.readyState == 4 && this.status == 200) {
                var balanceValue = JSON.parse(this.responseText).balance;
                balanceLabel1.innerHTML = balanceValue;
                balanceLabel2.innerHTML = balanceValue;
                balanceRange1.value = balanceValue + 16;  // as the slider goes from 0 to 32 (as the API accepts it)
            }
        }
        balanceRequest.open("GET", apiBase + balanceApiEndpoint, true);
        balanceRequest.send();

    }

    function setupSite() {
        document.title = "NetSpeaker Demo (on " + document.cookie + ")";
        document.getElementById("title_onIP").innerHTML = "on " + document.cookie;
        setTimeout(updateStrings, 1000);  // to make user see the epic placeholder glow effect of the bootstrap library
        setInterval(updateStrings, 10000);
    }
    window.onload = function(e) {
        if (document.cookie == "" || !isValidIP(document.cookie)) {
            var selectIPModal = new bootstrap.Modal(document.getElementById('selectIPAddressModal'), {});
            selectIPModal.show();

            const alertPlaceholder = document.getElementById('configWorkingAlertPlaceholder');

            function configButtonEventListener(hideModalOnSuccess) {
                var ipAddressEntered = document.getElementById('ipAdressInput').value;
                if(isValidIP(ipAddressEntered)) {
                    var request = new XMLHttpRequest();
                    request.onreadystatechange = function() {
                        if (this.readyState == 4 && this.status == 200) {
                            appendAlert(alertPlaceholder, 'Working Configuration!', 'success');
                            document.cookie = ipAddressEntered;
                            setupSite()
                            setTimeout(function(){
                                if(hideModalOnSuccess) selectIPModal.hide();
                            }, 500);
                        } else if (this.readyState != 4) {
                            // just do nothing, wait!
                        } else {
                            appendAlert(alertPlaceholder, 'Configuration not working', 'danger');
                        }
                    };
                    request.open("GET", "http://" + ipAddressEntered + "/api/v1/system/version", true);
                    request.send()
                } else {
                    appendAlert(alertPlaceholder, 'Configuration not working', 'danger');
                }
            }

            const ipAdressModalApplyBtn = document.getElementById('ipAdressModalApplyBtn');
            ipAdressModalApplyBtn.addEventListener('click', () => { configButtonEventListener(false); });

            const ipAdressModalOkBtn = document.getElementById('ipAdressModalOkBtn');
            ipAdressModalOkBtn.addEventListener('click', () => { configButtonEventListener(true); });

        } else if (isValidIP(document.cookie)) setupSite();
    }  // end of onload function
</script>
</body>
</html>


<!-- An uncomplete list of XML IDs used in this piece of HTML:
updatedLabel_PLAYING_table_top
updatedLabel_PLAYING_table_bottom

updatedLabel_VOLUME_table_top
updatedLabel_VOLUME_table_bottom

updatedLabel_MUTED_table_top
updatedLabel_MUTED_table_bottom

updatedLabel_BALANCE_table_top
updatedLabel_BALANCE_table_bottom

updatedLabel_EQLOW_table_top
updatedLabel_EQLOW_table_bottom
updatedLabel_EQMID_table_top
updatedLabel_EQMID_table_bottom
updatedLabel_EQHIGH_table_top
updatedLabel_EQHIGH_table_bottom

updatedLabel_RS_PLPATH_table_top
updatedLabel_RS_PLIDX_table_top
updatedLabel_RS_PATH_table_top
updatedLabel_RS_TYPE_table_top
updatedLabel_RS_TITLE_table_top
updatedLabel_RS_ALBUM_table_top
updatedLabel_RS_ARTIST_table_top
updatedLabel_RS_TRACKNR_table_top
updatedLabel_RS_YEAR_table_top
updatedLabel_RS_GENRE_table_top
updatedLabel_RS_COPYRIGHT_table_top
updatedLabel_RS_LANGUAGE_table_top
-->