fixed some crashes, html..

This commit is contained in:
Stefan Ostermann 2025-07-28 14:15:11 +02:00
parent 571a1c5c39
commit a1d486dd2d
3 changed files with 181 additions and 78 deletions

View File

@ -119,7 +119,10 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
}
else if (String(entry.name()).endsWith(".mp3")||String(entry.name()).endsWith(".MP3"))
{
mp3Files.push_back(entry.name());
String fullPath = String(currentPath);
if (!fullPath.endsWith("/")) fullPath += "/";
fullPath += entry.name();
mp3Files.push_back(fullPath);
ids.push_back(getNextId());
}
entry.close();
@ -182,8 +185,7 @@ void DirectoryNode::advanceToFirstMP3InThisNode()
DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id)
{
// First check MP3 files in this directory
for (size_t i = 0; i < ids.size(); i++)
{
if (id == ids[i])
@ -195,62 +197,85 @@ DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id)
}
}
// Recursively search subdirectories
for (auto subdir : subdirectories)
{
// Check if the ID matches a subdirectory ID
if (subdir->getId() == id)
{
subdir->advanceToFirstMP3InThisNode();
return subdir;
}
// Have each subdirectory advance its song
for (size_t i = 0; i < subdir->ids.size(); i++)
// Recursively search in subdirectory
DirectoryNode* result = subdir->advanceToMP3(id);
if (result != nullptr && result->getCurrentPlaying() != nullptr)
{
if (id == subdir->ids[i])
{
// Found the current MP3 file
subdir->currentPlaying = &subdir->mp3Files[i];
subdir->currentPlayingId = id;
return subdir;
}
return result;
}
}
// If we get here, there were no MP3 files or subdirectories left to check
currentPlaying = nullptr;
Serial.println("no more nodes found");
return this;
// If we get here, no song with this ID was found
Serial.println("advanceToMP3: No song found for ID: " + String(id));
return nullptr;
}
DirectoryNode *DirectoryNode::advanceToMP3(const String *currentGlobal)
{
if (currentGlobal == nullptr) {
Serial.println("advanceToMP3: currentGlobal is null");
return nullptr;
}
// Check if the input is an absolute path (starts with '/') or just a filename
bool isAbsolutePath = currentGlobal->startsWith("/");
// First, check MP3 files in this directory
for (size_t i = 0; i < mp3Files.size(); i++)
{
if (isAbsolutePath) {
// For absolute paths, do exact match
if (*currentGlobal == mp3Files[i])
{
setCurrentPlaying(&mp3Files[i]);
return this;
}
} else {
// For filenames, extract filename from full path and compare
String filename = mp3Files[i];
int lastSlash = filename.lastIndexOf('/');
if (lastSlash != -1) {
filename = filename.substring(lastSlash + 1);
}
if (*currentGlobal == filename)
{
setCurrentPlaying(&mp3Files[i]);
return this;
}
}
}
// Recursively search subdirectories
for (auto subdir : subdirectories)
{
if (subdir->getName() == *currentGlobal)
// Check if the string matches a directory name (only for non-absolute paths)
if (!isAbsolutePath && subdir->getName() == *currentGlobal)
{
subdir->advanceToFirstMP3InThisNode();
return subdir;
}
// Have each subdirectory advance its song
for (size_t i = 0; i < subdir->mp3Files.size(); i++)
// Recursively search in subdirectory
DirectoryNode* result = subdir->advanceToMP3(currentGlobal);
if (result != nullptr && result->getCurrentPlaying() != nullptr)
{
if (*currentGlobal == subdir->mp3Files[i])
{
// Found the current MP3 file
if (i < subdir->mp3Files.size() - 1)
{
subdir->setCurrentPlaying(&subdir->mp3Files[i]);
return subdir;
}
}
return result;
}
}
// If we get here, there were no MP3 files or subdirectories left to check
currentPlaying = nullptr;
Serial.println("no more nodes found");
return this;
// If we get here, no matching song was found
Serial.println("advanceToMP3: No song found for: " + *currentGlobal);
return nullptr;
}
/**
@ -466,16 +491,7 @@ String DirectoryNode::getCurrentPlayingFilePath() const
{
if (currentPlaying != nullptr)
{
String filePath = name;
if (!filePath.startsWith("/")) {
filePath = "/"+filePath;
}
if (!filePath.endsWith("/"))
{
filePath += "/";
}
filePath += *currentPlaying;
return filePath;
return *currentPlaying;
}
return "";
}

View File

@ -303,24 +303,41 @@ void playSongById(uint16_t id, uint32_t continueSeconds = 0)
currentNode = rootNode.advanceToMP3(id);
if (currentNode == nullptr) {
Serial.println("No node found for ID: " + String(id));
return;
}
// Check if the current playing song is valid
if (currentNode->getCurrentPlaying() == nullptr) {
currentNode = nullptr;
Serial.println("No song found for ID: " + String(id));
return;
}
String mp3File = currentNode->getCurrentPlayingFilePath();
Serial.print("playing by id: ");
Serial.print(id);Serial.print(" ");Serial.println(continueSeconds);
Serial.println(mp3File.c_str());
deactivateRFID();
activateSD();
if (currentNode != nullptr && currentNode->getCurrentPlaying()==nullptr) {
if (mp3File.length() == 0) {
currentNode = nullptr;
Serial.println("no node by id found, exiting playSongById");
Serial.println("Empty file path for ID: " + String(id));
return;
}
Serial.print("Playing by ID: ");
Serial.print(id);
Serial.print(" ");
Serial.println(continueSeconds);
Serial.println(mp3File.c_str());
deactivateRFID();
activateSD();
if (!playFile(mp3File.c_str())) {
Serial.println("Failed to play file: " + mp3File);
currentNode = nullptr;
activateRFID();
deactivateSD();
return;
}
playFile(mp3File.c_str());
if (continueSeconds != 0) {
audio.setAudioPlayPosition(continueSeconds);
}
@ -330,12 +347,45 @@ void playSongById(uint16_t id, uint32_t continueSeconds = 0)
void playSongByName(String song)
{
if (song.length() == 0) {
Serial.println("Empty song name provided");
return;
}
currentNode = rootNode.advanceToMP3(&song);
if (currentNode == nullptr) {
Serial.println("No node found for song: " + song);
return;
}
// Check if the current playing song is valid
if (currentNode->getCurrentPlaying() == nullptr) {
currentNode = nullptr;
Serial.println("No song found for name: " + song);
return;
}
String mp3File = currentNode->getCurrentPlayingFilePath();
Serial.println(mp3File.c_str());
if (mp3File.length() == 0) {
currentNode = nullptr;
Serial.println("Empty file path for song: " + song);
return;
}
Serial.println("Playing song: " + mp3File);
deactivateRFID();
activateSD();
playFile(mp3File.c_str());
if (!playFile(mp3File.c_str())) {
Serial.println("Failed to play file: " + mp3File);
currentNode = nullptr;
activateRFID();
deactivateSD();
return;
}
activateRFID();
deactivateSD();
}
void playSongByPath(String path)
@ -345,13 +395,23 @@ void playSongByPath(String path)
void playSongByRFID(String id)
{
auto songit = rfid_map.find(id);
if (songit==rfid_map.end()) {
Serial.println("song for uid not found.");
if (id.length() == 0) {
Serial.println("Empty RFID ID provided");
return;
}
Serial.println("searching for ");
Serial.println(songit->second);
auto songit = rfid_map.find(id);
if (songit == rfid_map.end()) {
Serial.println("Song for UID not found: " + id);
return;
}
if (songit->second.length() == 0) {
Serial.println("Empty song name mapped to RFID: " + id);
return;
}
Serial.println("Searching for song: " + songit->second);
playSongByName(songit->second);
}
@ -517,7 +577,7 @@ void editMapping(AsyncWebServerRequest *request) {
}
}
std::map<String, String> readDataFromFile(const char *filename) {
std::map<String, String> readDataFromFile(String filename) {
File file = SD.open(filename);
@ -530,6 +590,7 @@ std::map<String, String> readDataFromFile(const char *filename) {
// Extract key and value
String key = line.substring(0, separatorIndex).c_str();
String value = line.substring(separatorIndex + 1).c_str();
Serial.println("found rfid mapping for "+value);
// Add key-value pair to the map
rfid_map[key] = value;
}
@ -549,6 +610,29 @@ String processor(const String &var)
{
return rootNode.getDirectoryStructureHTML();
}
if (var == "MAPPING") {
auto htmlEscape = [](const String& s) -> String {
String out;
for (size_t i = 0; i < s.length(); ++i) {
char c = s[i];
if (c == '&') out += "&amp;";
else if (c == '<') out += "";
else if (c == '>') out += "";
else if (c == '"') out += "";
else if (c == '\'') out += "";
else out += c;
}
return out;
};
String html = "<table style='width:100%;border-collapse:collapse;'><tr><th style='border:1px solid #ccc;padding:4px;'>RFID</th><th style='border:1px solid #ccc;padding:4px;'>Song</th></tr>";
for (const auto& pair : rfid_map) {
html += "<tr><td style='border:1px solid #ccc;padding:4px;'>" + htmlEscape(pair.first) + "</td><td style='border:1px solid #ccc;padding:4px;'>" + htmlEscape(pair.second) + "</td></tr>";
}
html += "</table>";
return html;
}
return String(); // Return empty string instead of creating new String
}
@ -747,7 +831,7 @@ void setup()
rootNode.buildDirectoryTree("/");
rootNode.printDirectoryTree();
readDataFromFile(mapping_file.c_str());
readDataFromFile(getSysDir(mapping_file));

View File

@ -8,9 +8,7 @@
<body>
<h1>🎵 HannaBox 🎵</h1>
<span id="state"></span><br/><br/>
<span id="voltage"></span><br/>
<span id="uid"></span><br/>
<span id="heap"></span><br/>
<div>
<button class="prev-button" onclick="simpleGetCall('previous');"></button>
@ -42,11 +40,13 @@
<button id="toggleFileManagerButton" class="action-btn" onclick="toggleFileManager()">Toggle File Manager</button>
<button id="toggleFileManagerButton" class="action-btn" onclick="toggleFileManager()">Toggle Manager</button>
<div id="fileManager" style="display:none; margin-top:20px;">
<h2>File Manager</h2>
<h2>Manager</h2>
<span id="voltage"></span><br/>
<span id="uid"></span><br/>
<span id="heap"></span><br/>
<h3>Upload File</h3>
<form id="uploadForm" class="form" method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="data" id="uploadFile" accept=".mp3,.wav,.flac,.m4a,.ogg"/>
@ -56,11 +56,13 @@
<div class="progress-bar">
<div class="progress-fill" id="progressFill"></div>
</div>
<span id="progressText">0%</span>
<span id="progressText">0</span>
</div>
</form>
<h3>Edit RFID Mapping</h3>
Hint: Use a folder or filename, not the absolute file path!
<div class="form">%MAPPING%</div>
<form id="editMappingForm" class="form">
<label for="rfid">RFID:</label>
<input type="text" id="rfid" name="rfid" required><br>
@ -77,8 +79,9 @@
<input type="text" id="moveTo" placeholder="/newname.mp3"/>
<button type="button" class="action-btn" onclick="moveFile()">Move/Rename</button>
</form>
<form class="form">
<h3>Delete File</h3>
<form class="form">
<label for="deleteFileName">Filename:</label>
<input type="text" id="deleteFileName" placeholder="/song.mp3"/>
<button type="button" class="action-btn" onclick="deleteFileOnServer()">Delete</button>