22 SDIndex(SDT &sd) { p_sd = &sd; };
23 void begin(
const char *startDir,
const char *extension,
24 const char *file_name_pattern,
bool setupIndex =
true) {
26 this->start_dir = startDir;
27 this->ext = extension;
28 this->file_name_pattern = file_name_pattern;
29 idx_path = filePathString(startDir,
"idx.txt");
30 idx_defpath = filePathString(startDir,
"idx-def.txt");
31 int idx_file_size = indexFileTSize();
32 LOGI(
"Index file size: %d", idx_file_size);
34 String(startDir) +
"|" + extension +
"|" + file_name_pattern;
35 String keyOld = getIndexDef();
36 if (setupIndex && (keyNew != keyOld || idx_file_size == 0)) {
37 FileT idxfile = p_sd->open(idx_path.c_str(), FILE_WRITE);
38 LOGW(
"Creating index file");
40 LOGI(
"Indexing completed");
47 void ls(
Print &p,
const char *startDir,
const char *extension,
48 const char *file_name_pattern =
"*") {
50 this->ext = extension;
51 this->file_name_pattern = file_name_pattern;
53 file_path_stack.clear();
54 file_path_str.clear();
61 LOGE(
"idx %d is negative", idx);
66 if (max_idx >= 0 && idx >= max_idx) {
67 LOGE(
"idx %d >= size %d", idx, max_idx);
72 FileT idxfile = p_sd->open(idx_path.c_str());
76 LOGE(
"Failed to open index file: %s", idx_path.c_str());
82 if (idxfile.available() == 0) {
83 LOGE(
"Index file is empty");
89 while (idxfile.available() > 0 && !found) {
90 result = idxfile.readStringUntil(
'\n');
93 char *c_str = (
char *)result.c_str();
95 int lastPos = result.length() - 1;
96 if (c_str[lastPos] == 13) {
100 LOGD(
"%d -> %s", count, c_str);
111 return found ? result.c_str() :
nullptr;
116 if (filename ==
nullptr) {
117 LOGE(
"filename is null");
121 FileT idxfile = p_sd->open(idx_path.c_str());
122 if (idxfile.available() == 0) {
123 LOGE(
"Index file is empty");
129 String searchName(filename);
131 while (idxfile.available() > 0) {
132 result = idxfile.readStringUntil(
'\n');
135 char *c_str = (
char *)result.c_str();
137 int lastPos = result.length() - 1;
138 if (lastPos >= 0 && c_str[lastPos] == 13) {
142 LOGD(
"Comparing %d: '%s' with '%s'", count, c_str, filename);
145 String currentFile(c_str);
146 if (currentFile == searchName ||
147 currentFile.endsWith(
"/" + searchName) ||
148 currentFile.endsWith(searchName)) {
149 LOGD(
"Found '%s' at index %d", filename, count);
163 LOGD(
"File '%s' not found in index", filename);
169 FileT idxfile = p_sd->open(idx_path.c_str());
172 while (idxfile.available() > 0) {
173 result = idxfile.readStringUntil(
'\n');
175 char *c_str = (
char *)result.c_str();
189 List<String> file_path_stack;
190 String file_path_str;
191 const char *start_dir;
193 const char *ext =
nullptr;
194 const char *file_name_pattern =
nullptr;
197 String filePathString(
const char *name,
const char *suffix) {
198 String result = name;
199 return result.endsWith(
"/") ? result + suffix : result +
"/" + suffix;
204 LOGD(
"listDir: %s", dirname);
205 FileT root = open(dirname);
207 LOGE(
"Open failed: %s", dirname);
211 if (!isDirectory(root)) {
212 LOGD(
"Is not directory: %s", dirname);
216 if (
StrView(dirname).startsWith(
".")) {
217 LOGD(
"Invalid file: %s", dirname);
223 FileT file = openNext(root);
225 if (isDirectory(file)) {
227 LOGD(
"name: %s", name.c_str());
229 listDir(idxfile, name.c_str());
233 LOGD(
"Adding file to index: %s", fn);
236 LOGD(
"Ignoring %s", fn);
239 file = openNext(root);
244 bool isDirectory(FileT &f) {
249 result = f.isDirectory();
251 LOGD(
"isDirectory %s: %d",
fileName(f), result);
255 FileT openNext(FileT &dir) {
259 if (!result.openNext(&dir, O_READ)) {
260 LOGD(
"No next file");
264 return dir.openNextFile();
268 void pushPath(
const char *name) {
269 LOGD(
"pushPath: %s", name);
270 LOGD(
"pushPath: %s", name);
271 String nameStr(name);
272 file_path_stack.push_back(nameStr);
278 file_path_stack.pop_back(str);
279 LOGD(
"popPath: %s", str.c_str());
285 const char *file_name =
fileName(file);
286 if (file.isDirectory()) {
287 LOGD(
"-> isValidAudioFile: '%s': %d", file_name,
false);
290 StrView strFileTName(file_name);
292 strFileTName.
matches(file_name_pattern) && !isHidden(file);
293 LOGD(
"-> isValidAudioFile: '%s': %d", file_name, result);
297 String getIndexDef() {
298 FileT idxdef = p_sd->open(idx_defpath.c_str());
299 String key1 = idxdef.readString();
303 void saveIndexDef(String keyNew) {
304 FileT idxdef = p_sd->open(idx_defpath.c_str(), FILE_WRITE);
305 idxdef.write((
const uint8_t *)keyNew.c_str(), keyNew.length());
309 size_t indexFileTSize() {
310 FileT idxfile = p_sd->open(idx_path.c_str());
311 size_t result = idxfile.size();
316 void rewind(FileT &f) {
329 static char name[MAX_FILE_LEN];
330 file.getName(name, MAX_FILE_LEN);
339 return file.name() + pos;
345#if defined(USE_SDFAT) || ESP_IDF_VERSION_MAJOR >= 4
346 LOGD(
"-> fileNamePath: %s",
fileName(file));
347 file_path_str = start_dir;
348 if (!file_path_str.endsWith(
"/")) {
349 file_path_str +=
"/";
351 for (
int j = 0; j < file_path_stack.size(); j++) {
352 file_path_str += file_path_stack[j] +
"/";
355 static char name[MAX_FILE_LEN];
356 strncpy(name,
fileName(file), MAX_FILE_LEN);
357 file_path_str += name;
358 const char *result = file_path_str.c_str();
359 LOGD(
"<- fileNamePath: %s", result);
366 bool isHidden(FileT &f) {
374 FileT open(
const char *name) {
378 if (!result.open(name)) {
379 LOGE(
"FileT open error: %s", name);
383 return p_sd->open(name,
"r");