diff --git a/data/www/script.js b/data/www/script.js
index 8d7f5c0..0bca97c 100644
--- a/data/www/script.js
+++ b/data/www/script.js
@@ -1,6 +1,7 @@
const GLOBAL_TIMEOUT = 10000;
let connectionOk = true;
let statusTimeout = null;
+let selectedFile = "";
function play() {
console.log("Play...");
@@ -23,9 +24,9 @@ function volume(modifier) {
.catch(handleError);
}
-function loadStatus() {
+async function loadStatus() {
console.log("Status...");
- fetch("/status", { signal: AbortSignal.timeout(GLOBAL_TIMEOUT) })
+ return fetch("/status", { signal: AbortSignal.timeout(GLOBAL_TIMEOUT) })
.then(response => response.json())
.then(handleStatus)
.catch(handleError);
@@ -49,18 +50,18 @@ function handleStatus(data) {
location.reload();
}
- let dom = "";
- data.files.available.forEach((element, index) => {
- let className = "w3-blue";
- if (index === data.files.selectedIndex) {
- className = "w3-green";
+ if (data.files.selected != selectedFile) {
+ selectedFile = data.files.selected;
+ document.querySelectorAll(".w3-green").forEach(element => {
+ element.classList.remove("w3-green");
+ element.classList.add("w3-blue");
+ });
+ const previouslySelected = document.querySelector(`[data-name='${selectedFile}']`);
+ if (previouslySelected) {
+ previouslySelected.classList.remove("w3-blue");
+ previouslySelected.classList.add("w3-green");
}
- dom += ``;
- });
- if (data.files.moreNotShown) {
- dom += ``;
}
- document.getElementById("available-files").innerHTML = dom;
document.getElementById("volume-current").innerText = data.volume.current;
document.getElementById("volume-increase").disabled = !data.volume.canIncrease;
@@ -68,6 +69,40 @@ function handleStatus(data) {
statusTimeout = setTimeout(loadStatus, GLOBAL_TIMEOUT);
}
+async function listFiles(cursor=0) {
+ console.log("List files...");
+ return fetch(`/list-files?cursor=${cursor}`, { signal: AbortSignal.timeout(GLOBAL_TIMEOUT) })
+ .then(response => response.json())
+ .then(data => {
+ let dom = "";
+ data.files.forEach(element => {
+ if (!element) {
+ // Filter out null
+ return;
+ }
+ let className = "w3-blue";
+ if (element === selectedFile) {
+ className = "w3-green";
+ }
+ dom += ``;
+ });
+ if (data.files.moreNotShown) {
+ dom += ``;
+ }
+ const availableFilesNode = document.getElementById("available-files");
+ if (cursor == 0) {
+ availableFilesNode.innerHTML = dom;
+ }
+ else {
+ availableFilesNode.innerHTML += dom;
+ }
+ if (data.next) {
+ return listFiles(data.next);
+ }
+ })
+ .catch(handleError);
+}
+
function handleError(error) {
console.error(error);
clearTimeout(statusTimeout);
@@ -78,6 +113,6 @@ function handleError(error) {
}
(() => {
- loadStatus();
+ loadStatus().then(() => listFiles());
statusTimeout = setTimeout(loadStatus, GLOBAL_TIMEOUT);
})();
diff --git a/src/main.cpp b/src/main.cpp
index 5f0a95f..1d39f86 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -83,6 +83,7 @@ void play()
void onStop(AsyncWebServerRequest *request)
{
+ Serial.println("Stop playing");
audio.stopSong();
request->send(200);
}
@@ -98,40 +99,57 @@ void onStatus(AsyncWebServerRequest *request)
Serial.println("Status");
AsyncResponseStream *response = request->beginResponseStream("application/json");
- DynamicJsonDocument root(4096);
- JsonObject files = root.createNestedObject("files");
- files["selectedIndex"] = -1;
- files["moreNotShown"] = false;
+ StaticJsonDocument<96> root;
+ root["files"]["selected"] = selectedFile.c_str();
JsonObject volume = root.createNestedObject("volume");
volume["current"] = currentVolume;
volume["canDecrease"] = currentVolume > 0;
volume["canIncrease"] = currentVolume < 21;
- JsonArray availableFiles = files.createNestedArray("available");
+ serializeJson(root, *response);
+ request->send(response);
+}
+
+void onListFiles(AsyncWebServerRequest *request)
+{
+ Serial.print("List files cursor=");
+ int cursor = 0;
+ if (request->hasParam("cursor")) {
+ String s_cursor = request->getParam("cursor")->value();
+ cursor = s_cursor.toInt();
+ }
+ Serial.println(cursor);
+
+ AsyncResponseStream *response = request->beginResponseStream("application/json");
+
+ StaticJsonDocument<512> root;
+ root["next"] = -1;
+ JsonArray files = root.createNestedArray("files");
File music = SD.open("/");
File file = music.openNextFile();
- unsigned int index = 0;
+ int index = 0;
while (file)
{
String fileName = file.name();
if (fileIsValid(fileName))
{
- availableFiles.add(fileName);
- if (fileName == selectedFile) {
- files["selectedIndex"] = index;
- }
index++;
+ if (index >= cursor)
+ files.add(fileName);
}
file.close();
if (root.overflowed())
{
- files["moreNotShown"] = true;
+ root["next"] = index;
break;
}
file = music.openNextFile();
}
+ if (root["next"] == -1) {
+ root.remove("next");
+ }
serializeJson(root, *response);
request->send(response);
@@ -316,6 +334,7 @@ void setup()
server.on("/play", HTTP_GET, onPlay);
server.on("/stop", HTTP_GET, onStop);
server.on("/status", HTTP_GET, onStatus);
+ server.on("/list-files", HTTP_GET, onListFiles);
server.on("/select-file", HTTP_POST, onSelectFile);
server.on("/change-volume", HTTP_POST, onChangeVolume);
server.on("/upload", HTTP_POST, onUpload, onUploadFile);