fixed some crashes, html..
This commit is contained in:
parent
571a1c5c39
commit
a1d486dd2d
|
|
@ -119,7 +119,10 @@ void DirectoryNode::buildDirectoryTree(const char *currentPath)
|
||||||
}
|
}
|
||||||
else if (String(entry.name()).endsWith(".mp3")||String(entry.name()).endsWith(".MP3"))
|
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());
|
ids.push_back(getNextId());
|
||||||
}
|
}
|
||||||
entry.close();
|
entry.close();
|
||||||
|
|
@ -182,75 +185,97 @@ void DirectoryNode::advanceToFirstMP3InThisNode()
|
||||||
|
|
||||||
DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id)
|
DirectoryNode *DirectoryNode::advanceToMP3(const uint16_t id)
|
||||||
{
|
{
|
||||||
|
// First check MP3 files in this directory
|
||||||
|
|
||||||
for (size_t i = 0; i < ids.size(); i++)
|
for (size_t i = 0; i < ids.size(); i++)
|
||||||
|
{
|
||||||
|
if (id == ids[i])
|
||||||
{
|
{
|
||||||
if (id == ids[i])
|
// Found the current MP3 file
|
||||||
{
|
currentPlaying = &mp3Files[i];
|
||||||
// Found the current MP3 file
|
currentPlayingId = id;
|
||||||
currentPlaying = &mp3Files[i];
|
return this;
|
||||||
currentPlayingId = id;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively search subdirectories
|
||||||
for (auto subdir : subdirectories)
|
for (auto subdir : subdirectories)
|
||||||
{
|
{
|
||||||
|
// Check if the ID matches a subdirectory ID
|
||||||
if (subdir->getId() == id)
|
if (subdir->getId() == id)
|
||||||
{
|
{
|
||||||
subdir->advanceToFirstMP3InThisNode();
|
subdir->advanceToFirstMP3InThisNode();
|
||||||
return subdir;
|
return subdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have each subdirectory advance its song
|
// Recursively search in subdirectory
|
||||||
for (size_t i = 0; i < subdir->ids.size(); i++)
|
DirectoryNode* result = subdir->advanceToMP3(id);
|
||||||
|
if (result != nullptr && result->getCurrentPlaying() != nullptr)
|
||||||
{
|
{
|
||||||
if (id == subdir->ids[i])
|
return result;
|
||||||
{
|
|
||||||
// Found the current MP3 file
|
|
||||||
subdir->currentPlaying = &subdir->mp3Files[i];
|
|
||||||
subdir->currentPlayingId = id;
|
|
||||||
return subdir;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we get here, there were no MP3 files or subdirectories left to check
|
// If we get here, no song with this ID was found
|
||||||
currentPlaying = nullptr;
|
Serial.println("advanceToMP3: No song found for ID: " + String(id));
|
||||||
Serial.println("no more nodes found");
|
return nullptr;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectoryNode *DirectoryNode::advanceToMP3(const String *currentGlobal)
|
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)
|
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();
|
subdir->advanceToFirstMP3InThisNode();
|
||||||
return subdir;
|
return subdir;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Have each subdirectory advance its song
|
// Recursively search in subdirectory
|
||||||
for (size_t i = 0; i < subdir->mp3Files.size(); i++)
|
DirectoryNode* result = subdir->advanceToMP3(currentGlobal);
|
||||||
|
if (result != nullptr && result->getCurrentPlaying() != nullptr)
|
||||||
{
|
{
|
||||||
if (*currentGlobal == subdir->mp3Files[i])
|
return result;
|
||||||
{
|
|
||||||
// Found the current MP3 file
|
|
||||||
if (i < subdir->mp3Files.size() - 1)
|
|
||||||
{
|
|
||||||
subdir->setCurrentPlaying(&subdir->mp3Files[i]);
|
|
||||||
return subdir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we get here, there were no MP3 files or subdirectories left to check
|
// If we get here, no matching song was found
|
||||||
currentPlaying = nullptr;
|
Serial.println("advanceToMP3: No song found for: " + *currentGlobal);
|
||||||
Serial.println("no more nodes found");
|
return nullptr;
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -466,16 +491,7 @@ String DirectoryNode::getCurrentPlayingFilePath() const
|
||||||
{
|
{
|
||||||
if (currentPlaying != nullptr)
|
if (currentPlaying != nullptr)
|
||||||
{
|
{
|
||||||
String filePath = name;
|
return *currentPlaying;
|
||||||
if (!filePath.startsWith("/")) {
|
|
||||||
filePath = "/"+filePath;
|
|
||||||
}
|
|
||||||
if (!filePath.endsWith("/"))
|
|
||||||
{
|
|
||||||
filePath += "/";
|
|
||||||
}
|
|
||||||
filePath += *currentPlaying;
|
|
||||||
return filePath;
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
126
src/main.cpp
126
src/main.cpp
|
|
@ -302,26 +302,43 @@ void playSongById(uint16_t id, uint32_t continueSeconds = 0)
|
||||||
{
|
{
|
||||||
currentNode = rootNode.advanceToMP3(id);
|
currentNode = rootNode.advanceToMP3(id);
|
||||||
|
|
||||||
if (currentNode==nullptr) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String mp3File = currentNode->getCurrentPlayingFilePath();
|
String mp3File = currentNode->getCurrentPlayingFilePath();
|
||||||
Serial.print("playing by id: ");
|
if (mp3File.length() == 0) {
|
||||||
Serial.print(id);Serial.print(" ");Serial.println(continueSeconds);
|
|
||||||
|
|
||||||
Serial.println(mp3File.c_str());
|
|
||||||
deactivateRFID();
|
|
||||||
activateSD();
|
|
||||||
|
|
||||||
if (currentNode != nullptr && currentNode->getCurrentPlaying()==nullptr) {
|
|
||||||
currentNode = nullptr;
|
currentNode = nullptr;
|
||||||
Serial.println("no node by id found, exiting playSongById");
|
Serial.println("Empty file path for ID: " + String(id));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playFile(mp3File.c_str());
|
Serial.print("Playing by ID: ");
|
||||||
if (continueSeconds!=0) {
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (continueSeconds != 0) {
|
||||||
audio.setAudioPlayPosition(continueSeconds);
|
audio.setAudioPlayPosition(continueSeconds);
|
||||||
}
|
}
|
||||||
activateRFID();
|
activateRFID();
|
||||||
|
|
@ -330,12 +347,45 @@ void playSongById(uint16_t id, uint32_t continueSeconds = 0)
|
||||||
|
|
||||||
void playSongByName(String song)
|
void playSongByName(String song)
|
||||||
{
|
{
|
||||||
|
if (song.length() == 0) {
|
||||||
|
Serial.println("Empty song name provided");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
currentNode = rootNode.advanceToMP3(&song);
|
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();
|
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();
|
deactivateRFID();
|
||||||
activateSD();
|
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)
|
void playSongByPath(String path)
|
||||||
|
|
@ -345,13 +395,23 @@ void playSongByPath(String path)
|
||||||
|
|
||||||
void playSongByRFID(String id)
|
void playSongByRFID(String id)
|
||||||
{
|
{
|
||||||
auto songit = rfid_map.find(id);
|
if (id.length() == 0) {
|
||||||
if (songit==rfid_map.end()) {
|
Serial.println("Empty RFID ID provided");
|
||||||
Serial.println("song for uid not found.");
|
|
||||||
return;
|
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);
|
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);
|
File file = SD.open(filename);
|
||||||
|
|
||||||
|
|
@ -530,6 +590,7 @@ std::map<String, String> readDataFromFile(const char *filename) {
|
||||||
// Extract key and value
|
// Extract key and value
|
||||||
String key = line.substring(0, separatorIndex).c_str();
|
String key = line.substring(0, separatorIndex).c_str();
|
||||||
String value = line.substring(separatorIndex + 1).c_str();
|
String value = line.substring(separatorIndex + 1).c_str();
|
||||||
|
Serial.println("found rfid mapping for "+value);
|
||||||
// Add key-value pair to the map
|
// Add key-value pair to the map
|
||||||
rfid_map[key] = value;
|
rfid_map[key] = value;
|
||||||
}
|
}
|
||||||
|
|
@ -549,6 +610,29 @@ String processor(const String &var)
|
||||||
{
|
{
|
||||||
return rootNode.getDirectoryStructureHTML();
|
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 += "&";
|
||||||
|
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
|
return String(); // Return empty string instead of creating new String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -747,7 +831,7 @@ void setup()
|
||||||
rootNode.buildDirectoryTree("/");
|
rootNode.buildDirectoryTree("/");
|
||||||
rootNode.printDirectoryTree();
|
rootNode.printDirectoryTree();
|
||||||
|
|
||||||
readDataFromFile(mapping_file.c_str());
|
readDataFromFile(getSysDir(mapping_file));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,7 @@
|
||||||
<body>
|
<body>
|
||||||
<h1>🎵 HannaBox 🎵</h1>
|
<h1>🎵 HannaBox 🎵</h1>
|
||||||
<span id="state"></span><br/><br/>
|
<span id="state"></span><br/><br/>
|
||||||
<span id="voltage"></span><br/>
|
|
||||||
<span id="uid"></span><br/>
|
|
||||||
<span id="heap"></span><br/>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button class="prev-button" onclick="simpleGetCall('previous');"></button>
|
<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;">
|
<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>
|
<h3>Upload File</h3>
|
||||||
<form id="uploadForm" class="form" method="POST" action="/upload" enctype="multipart/form-data">
|
<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"/>
|
<input type="file" name="data" id="uploadFile" accept=".mp3,.wav,.flac,.m4a,.ogg"/>
|
||||||
|
|
@ -56,11 +56,13 @@
|
||||||
<div class="progress-bar">
|
<div class="progress-bar">
|
||||||
<div class="progress-fill" id="progressFill"></div>
|
<div class="progress-fill" id="progressFill"></div>
|
||||||
</div>
|
</div>
|
||||||
<span id="progressText">0%</span>
|
<span id="progressText">0</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<h3>Edit RFID Mapping</h3>
|
<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">
|
<form id="editMappingForm" class="form">
|
||||||
<label for="rfid">RFID:</label>
|
<label for="rfid">RFID:</label>
|
||||||
<input type="text" id="rfid" name="rfid" required><br>
|
<input type="text" id="rfid" name="rfid" required><br>
|
||||||
|
|
@ -77,8 +79,9 @@
|
||||||
<input type="text" id="moveTo" placeholder="/newname.mp3"/>
|
<input type="text" id="moveTo" placeholder="/newname.mp3"/>
|
||||||
<button type="button" class="action-btn" onclick="moveFile()">Move/Rename</button>
|
<button type="button" class="action-btn" onclick="moveFile()">Move/Rename</button>
|
||||||
</form>
|
</form>
|
||||||
<form class="form">
|
|
||||||
<h3>Delete File</h3>
|
<h3>Delete File</h3>
|
||||||
|
<form class="form">
|
||||||
<label for="deleteFileName">Filename:</label>
|
<label for="deleteFileName">Filename:</label>
|
||||||
<input type="text" id="deleteFileName" placeholder="/song.mp3"/>
|
<input type="text" id="deleteFileName" placeholder="/song.mp3"/>
|
||||||
<button type="button" class="action-btn" onclick="deleteFileOnServer()">Delete</button>
|
<button type="button" class="action-btn" onclick="deleteFileOnServer()">Delete</button>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue