#include "DirectoryNode.h" DirectoryNode::DirectoryNode(const String &nodeName) : name(nodeName), currentPlaying(nullptr) {} DirectoryNode::~DirectoryNode() { for (DirectoryNode *childNode : subdirectories) { delete childNode; } } const String &DirectoryNode::getName() const { return name; } const std::vector &DirectoryNode::getSubdirectories() const { return subdirectories; } const std::vector &DirectoryNode::getMP3Files() const { return mp3Files; } void DirectoryNode::setCurrentPlaying(const String *mp3File) { currentPlaying = mp3File; } const String *DirectoryNode::getCurrentPlaying() const { return currentPlaying; } void DirectoryNode::addSubdirectory(DirectoryNode *subdirectory) { subdirectories.push_back(subdirectory); } void DirectoryNode::addMP3File(const String &mp3File) { mp3Files.push_back(mp3File); } void DirectoryNode::setSecondsPlayed(const uint32_t seconds) { secondsPlayed = seconds; } uint32_t DirectoryNode::getSecondsPlayed() { return secondsPlayed; } void DirectoryNode::buildDirectoryTree(const char *currentPath) { File rootDir = SD.open(currentPath); while (true) { File entry = rootDir.openNextFile(); if (!entry) { break; } if (entry.isDirectory() && strcmp(entry.name(),sys_dir.c_str())) { DirectoryNode *newNode = new DirectoryNode(entry.name()); subdirectories.push_back(newNode); newNode->buildDirectoryTree((String(currentPath) + entry.name()).c_str()); } else if (String(entry.name()).endsWith(".mp3")) { mp3Files.push_back(entry.name()); } entry.close(); } rootDir.close(); } void DirectoryNode::printDirectoryTree(int level) const { for (int i = 0; i < level; i++) { Serial.print(" "); } Serial.println(name); for (const String &mp3File : mp3Files) { for (int i = 0; i <= level; i++) { Serial.print(" "); } Serial.println(mp3File); } for (DirectoryNode *childNode : subdirectories) { childNode->printDirectoryTree(level + 1); } } DirectoryNode *DirectoryNode::findFirstDirectoryWithMP3s() { if (!mp3Files.empty()) { // Found a directory with MP3 files return this; } for (DirectoryNode *subdirectory : subdirectories) { DirectoryNode *result = subdirectory->findFirstDirectoryWithMP3s(); if (result != nullptr) { // Found a directory with MP3 files in the subdirectories return result; } } // No directory with MP3 files found return nullptr; } void DirectoryNode::advanceToFirstMP3InThisNode() { if (mp3Files.size()>0) { currentPlaying = &mp3Files[0]; } } DirectoryNode* DirectoryNode::advanceToMP3(const String* currentGlobal) { for (auto subdir : subdirectories) { if (subdir->getName()==*currentGlobal) { subdir->advanceToFirstMP3InThisNode(); return subdir; } // Have each subdirectory advance its song for (size_t i = 0; i < subdir->mp3Files.size(); i++) { if (*currentGlobal == subdir->mp3Files[i]) { // Found the current MP3 file if (i < subdir->mp3Files.size() - 1) { subdir->currentPlaying = &subdir->mp3Files[i]; return subdir; } } } } // If we get here, there were no MP3 files or subdirectories left to check currentPlaying = nullptr; Serial.println("no more nodes found"); return this; } DirectoryNode* DirectoryNode::advanceToNextMP3(const String* currentGlobal) { bool useFirst = false; Serial.println(currentGlobal->c_str()); if (currentGlobal != nullptr) { for (size_t i = 0; i < mp3Files.size(); i++) { if (*currentGlobal == mp3Files[i]) { // Found the current playing MP3 file if (i < mp3Files.size() - 1) { // Advance to the next MP3 file in the same directory currentPlaying = &mp3Files[i + 1]; return this; } useFirst = true; // Reached the end of the MP3 files in the directory break; } } } // We are either not playing, or we've exhausted all the MP3 files in this directory. // Therefore, we need to recursively look in our subdirectories. for (auto subdir : subdirectories) { Serial.println("searching next node"); if (useFirst && subdir->mp3Files.size()>0) { subdir->currentPlaying = &subdir->mp3Files[0]; return subdir; } // Have each subdirectory advance its song for (size_t i = 0; i < subdir->mp3Files.size(); i++) { if (*currentGlobal == subdir->mp3Files[i]) { // Found the current playing MP3 file if (i < subdir->mp3Files.size() - 1) { // Advance to the next MP3 file in the same directory subdir->currentPlaying = &subdir->mp3Files[i + 1]; return subdir; } else { useFirst = true; } // Reached the end of the MP3 files in the directory break; } } } // If we get here, there were no MP3 files or subdirectories left to check currentPlaying = nullptr; Serial.println("no more nodes found"); return this; } String DirectoryNode::getDirectoryStructureHTML() const { String html; html.reserve(1024); // Reserve memory for better performance if (name=="/") { html += "\n"; } return html; } void DirectoryNode::appendIndentation(String &html, int level) const { for (int i = 0; i < level; i++) { html += " "; } } String DirectoryNode::getCurrentPlayingFilePath() const { if (currentPlaying != nullptr) { String filePath = "/" + name; if (!filePath.endsWith("/")) { filePath += "/"; } filePath += *currentPlaying; return filePath; } return ""; }