diff options
| author | jacqueline <me@jacqueline.id.au> | 2023-04-28 13:26:47 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2023-04-28 13:26:47 +1000 |
| commit | bdadc159c7538e88eab5efcfeb2ecf971a510c60 (patch) | |
| tree | 5ed6b06fb6f913bdb97b6439451f4a587bda3203 /src | |
| parent | cd520b9360f0d0d4ab7582d2cbf2aa96060a0500 (diff) | |
| download | tangara-fw-bdadc159c7538e88eab5efcfeb2ecf971a510c60.tar.gz | |
Add libtags for extracting info from files
Diffstat (limited to 'src')
| -rw-r--r-- | src/database/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/database/include/tag_processor.hpp | 2 | ||||
| -rw-r--r-- | src/database/tag_processor.cpp | 94 |
3 files changed, 94 insertions, 4 deletions
diff --git a/src/database/CMakeLists.txt b/src/database/CMakeLists.txt index 0bc6f6b9..47f8fe31 100644 --- a/src/database/CMakeLists.txt +++ b/src/database/CMakeLists.txt @@ -1,7 +1,7 @@ idf_component_register( SRCS "env_esp.cpp" "database.cpp" "tag_processor.cpp" "db_task.cpp" INCLUDE_DIRS "include" - REQUIRES "result" "span" "esp_psram" "fatfs") + REQUIRES "result" "span" "esp_psram" "fatfs" "libtags") target_compile_options(${COMPONENT_LIB} PRIVATE ${EXTRA_WARNINGS}) diff --git a/src/database/include/tag_processor.hpp b/src/database/include/tag_processor.hpp index fb2201db..eda88225 100644 --- a/src/database/include/tag_processor.hpp +++ b/src/database/include/tag_processor.hpp @@ -6,6 +6,8 @@ namespace database { struct FileInfo { bool is_playable; + std::string artist; + std::string album; std::string title; }; diff --git a/src/database/tag_processor.cpp b/src/database/tag_processor.cpp index 16dbf160..5752d61b 100644 --- a/src/database/tag_processor.cpp +++ b/src/database/tag_processor.cpp @@ -1,14 +1,102 @@ #include "tag_processor.hpp" +#include <ff.h> +#include <tags.h> +#include <esp_log.h> + namespace database { +namespace libtags { + +struct Aux { + FIL file; + FILINFO info; + std::string artist; + std::string album; + std::string title; +}; + +static int read(Tagctx *ctx, void *buf, int cnt) { + Aux *aux = reinterpret_cast<Aux*>(ctx->aux); + UINT bytes_read; + if (f_read(&aux->file, buf, cnt, &bytes_read) != FR_OK) { + return -1; + } + return bytes_read; +} + +static int seek(Tagctx *ctx, int offset, int whence) { + Aux *aux = reinterpret_cast<Aux*>(ctx->aux); + FRESULT res; + if (whence == 0) { + // Seek from the start of the file. This is f_lseek's behaviour. + res = f_lseek(&aux->file, offset); + } else if (whence == 1) { + // Seek from current offset. + res = f_lseek(&aux->file, aux->file.fptr + offset); + } else if (whence == 2) { + // Seek from the end of the file + res = f_lseek(&aux->file, aux->info.fsize + offset); + } else { + return -1; + } + return res; +} + +static void +tag(Tagctx *ctx, int t, const char *k, const char *v, int offset, int size, Tagread f) { + Aux *aux = reinterpret_cast<Aux*>(ctx->aux); + if (t == Ttitle) { + aux->title = v; + } else if (t == Tartist) { + aux->artist = v; + } else if (t == Talbum) { + aux->album = v; + } +} + +static void +toc(Tagctx *ctx, int ms, int offset) {} + +} // namespace libtags + +static const std::size_t kBufSize = 1024; +static const char* kTag = "TAGS"; + auto GetInfo(const std::string& path, FileInfo* out) -> bool { - // TODO(jacqueline): bring in taglib for this - if (path.ends_with(".mp3")) { + libtags::Aux aux; + if (f_stat(path.c_str(), &aux.info) != FR_OK || f_open(&aux.file, path.c_str(), FA_READ) != FR_OK) { + ESP_LOGI(kTag, "failed to open file"); + return false; + } + // Fine to have this on the stack; this is only called on the leveldb task. + char buf[kBufSize]; + Tagctx ctx; + ctx.read = libtags::read; + ctx.seek = libtags::seek; + ctx.tag = libtags::tag; + ctx.toc = libtags::toc; + ctx.aux = &aux; + ctx.buf = buf; + ctx.bufsz = kBufSize; + int res = tagsget(&ctx); + f_close(&aux.file); + + if (res != 0) { + ESP_LOGI(kTag, "failed to parse tags"); + return false; + } + + if (ctx.format == Fmp3) { + ESP_LOGI(kTag, "file is mp3"); + ESP_LOGI(kTag, "artist: %s", aux.artist.c_str()); + ESP_LOGI(kTag, "album: %s", aux.album.c_str()); + ESP_LOGI(kTag, "title: %s", aux.title.c_str()); out->is_playable = true; - out->title = path.substr(0, path.size() - 4); + out->title = aux.title; return true; } + return false; } |
