summaryrefslogtreecommitdiff
path: root/src/database
diff options
context:
space:
mode:
Diffstat (limited to 'src/database')
-rw-r--r--src/database/database.cpp104
-rw-r--r--src/database/include/database.hpp24
-rw-r--r--src/database/include/records.hpp2
-rw-r--r--src/database/include/tag_parser.hpp18
-rw-r--r--src/database/include/track.hpp43
-rw-r--r--src/database/records.cpp4
-rw-r--r--src/database/tag_parser.cpp50
-rw-r--r--src/database/track.cpp6
8 files changed, 129 insertions, 122 deletions
diff --git a/src/database/database.cpp b/src/database/database.cpp
index fd0e50c1..1ecd72e0 100644
--- a/src/database/database.cpp
+++ b/src/database/database.cpp
@@ -144,7 +144,7 @@ auto Database::Update() -> std::future<void> {
OwningSlice prefix = EncodeDataPrefix();
it->Seek(prefix.slice);
while (it->Valid() && it->key().starts_with(prefix.slice)) {
- std::optional<TrackData> track = ParseDataValue(it->value());
+ std::shared_ptr<TrackData> track = ParseDataValue(it->value());
if (!track) {
// The value was malformed. Drop this record.
ESP_LOGW(kTag, "dropping malformed metadata");
@@ -159,9 +159,9 @@ auto Database::Update() -> std::future<void> {
continue;
}
- TrackTags tags{};
- if (!tag_parser_.ReadAndParseTags(track->filepath(), &tags) ||
- tags.encoding() == Container::kUnsupported) {
+ std::shared_ptr<TrackTags> tags =
+ tag_parser_.ReadAndParseTags(track->filepath());
+ if (!tags || tags->encoding() == Container::kUnsupported) {
// We couldn't read the tags for this track. Either they were
// malformed, or perhaps the file is missing. Either way, tombstone
// this record.
@@ -174,7 +174,7 @@ auto Database::Update() -> std::future<void> {
// At this point, we know that the track still exists in its original
// location. All that's left to do is update any metadata about it.
- uint64_t new_hash = tags.Hash();
+ uint64_t new_hash = tags->Hash();
if (new_hash != track->tags_hash()) {
// This track's tags have changed. Since the filepath is exactly the
// same, we assume this is a legitimate correction. Update the
@@ -185,7 +185,9 @@ auto Database::Update() -> std::future<void> {
dbPutHash(new_hash, track->id());
}
- dbCreateIndexesForTrack({*track, tags});
+ Track t{track, tags};
+
+ dbCreateIndexesForTrack(t);
it->Next();
}
@@ -197,15 +199,14 @@ auto Database::Update() -> std::future<void> {
.stage = event::UpdateProgress::Stage::kScanningForNewTracks,
});
file_gatherer_.FindFiles("", [&](const std::pmr::string& path) {
- TrackTags tags;
- if (!tag_parser_.ReadAndParseTags(path, &tags) ||
- tags.encoding() == Container::kUnsupported) {
+ std::shared_ptr<TrackTags> tags = tag_parser_.ReadAndParseTags(path);
+ if (!tags || tags->encoding() == Container::kUnsupported) {
// No parseable tags; skip this fiile.
return;
}
// Check for any existing record with the same hash.
- uint64_t hash = tags.Hash();
+ uint64_t hash = tags->Hash();
OwningSlice key = EncodeHashKey(hash);
std::optional<TrackId> existing_hash;
std::string raw_entry;
@@ -219,33 +220,36 @@ auto Database::Update() -> std::future<void> {
TrackId id = dbMintNewTrackId();
ESP_LOGI(kTag, "recording new 0x%lx", id);
- TrackData data(id, path, hash);
- dbPutTrackData(data);
+ auto data = std::make_shared<TrackData>(id, path, hash);
+ dbPutTrackData(*data);
dbPutHash(hash, id);
- dbCreateIndexesForTrack({data, tags});
+ auto t = std::make_shared<Track>(data, tags);
+ dbCreateIndexesForTrack(*t);
return;
}
- std::optional<TrackData> existing_data = dbGetTrackData(*existing_hash);
+ std::shared_ptr<TrackData> existing_data = dbGetTrackData(*existing_hash);
if (!existing_data) {
// We found a hash that matches, but there's no data record? Weird.
- TrackData new_data(*existing_hash, path, hash);
- dbPutTrackData(new_data);
- dbCreateIndexesForTrack({*existing_data, tags});
+ auto new_data = std::make_shared<TrackData>(*existing_hash, path, hash);
+ dbPutTrackData(*new_data);
+ auto t = std::make_shared<Track>(new_data, tags);
+ dbCreateIndexesForTrack(*t);
return;
}
if (existing_data->is_tombstoned()) {
ESP_LOGI(kTag, "exhuming track %lu", existing_data->id());
dbPutTrackData(existing_data->Exhume(path));
- dbCreateIndexesForTrack({*existing_data, tags});
+ auto t = std::make_shared<Track>(existing_data, tags);
+ dbCreateIndexesForTrack(*t);
} else if (existing_data->filepath() != path) {
ESP_LOGW(kTag, "tag hash collision for %s and %s",
existing_data->filepath().c_str(), path.c_str());
ESP_LOGI(kTag, "hash components: %s, %s, %s",
- tags.at(Tag::kTitle).value_or("no title").c_str(),
- tags.at(Tag::kArtist).value_or("no artist").c_str(),
- tags.at(Tag::kAlbum).value_or("no album").c_str());
+ tags->at(Tag::kTitle).value_or("no title").c_str(),
+ tags->at(Tag::kArtist).value_or("no artist").c_str(),
+ tags->at(Tag::kAlbum).value_or("no album").c_str());
}
});
events::Ui().Dispatch(event::UpdateFinished{});
@@ -264,26 +268,27 @@ auto Database::GetTrackPath(TrackId id)
});
}
-auto Database::GetTrack(TrackId id) -> std::future<std::optional<Track>> {
- return worker_task_->Dispatch<std::optional<Track>>(
- [=, this]() -> std::optional<Track> {
- std::optional<TrackData> data = dbGetTrackData(id);
+auto Database::GetTrack(TrackId id) -> std::future<std::shared_ptr<Track>> {
+ return worker_task_->Dispatch<std::shared_ptr<Track>>(
+ [=, this]() -> std::shared_ptr<Track> {
+ std::shared_ptr<TrackData> data = dbGetTrackData(id);
if (!data || data->is_tombstoned()) {
return {};
}
- TrackTags tags;
- if (!tag_parser_.ReadAndParseTags(data->filepath(), &tags)) {
+ std::shared_ptr<TrackTags> tags =
+ tag_parser_.ReadAndParseTags(data->filepath());
+ if (!tags) {
return {};
}
- return Track(*data, tags);
+ return std::make_shared<Track>(data, tags);
});
}
auto Database::GetBulkTracks(std::vector<TrackId> ids)
- -> std::future<std::vector<std::optional<Track>>> {
- return worker_task_->Dispatch<std::vector<std::optional<Track>>>(
- [=, this]() -> std::vector<std::optional<Track>> {
- std::map<TrackId, Track> id_to_track{};
+ -> std::future<std::vector<std::shared_ptr<Track>>> {
+ return worker_task_->Dispatch<std::vector<std::shared_ptr<Track>>>(
+ [=, this]() -> std::vector<std::shared_ptr<Track>> {
+ std::map<TrackId, std::shared_ptr<Track>> id_to_track{};
// Sort the list of ids so that we can retrieve them all in a single
// iteration through the database, without re-seeking.
@@ -299,16 +304,16 @@ auto Database::GetBulkTracks(std::vector<TrackId> ids)
// This id wasn't found at all. Skip it.
continue;
}
- std::optional<Track> track =
+ std::shared_ptr<Track> track =
ParseRecord<Track>(it->key(), it->value());
if (track) {
- id_to_track.insert({id, *track});
+ id_to_track.insert({id, track});
}
}
// We've fetched all of the ids in the request, so now just put them
// back into the order they were asked for in.
- std::vector<std::optional<Track>> results;
+ std::vector<std::shared_ptr<Track>> results;
for (const TrackId& id : ids) {
if (id_to_track.contains(id)) {
results.push_back(id_to_track.at(id));
@@ -426,7 +431,7 @@ auto Database::dbPutTrackData(const TrackData& s) -> void {
}
}
-auto Database::dbGetTrackData(TrackId id) -> std::optional<TrackData> {
+auto Database::dbGetTrackData(TrackId id) -> std::shared_ptr<TrackData> {
OwningSlice key = EncodeDataKey(id);
std::string raw_val;
if (!db_->Get(leveldb::ReadOptions(), key.slice, &raw_val).ok()) {
@@ -454,7 +459,7 @@ auto Database::dbGetHash(const uint64_t& hash) -> std::optional<TrackId> {
return ParseHashValue(raw_val);
}
-auto Database::dbCreateIndexesForTrack(Track track) -> void {
+auto Database::dbCreateIndexesForTrack(const Track& track) -> void {
for (const IndexInfo& index : GetIndexes()) {
leveldb::WriteBatch writes;
if (Index(index, track, &writes)) {
@@ -481,7 +486,7 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
// Grab results.
std::optional<std::pmr::string> first_key;
- std::vector<T> records;
+ std::vector<std::shared_ptr<T>> records;
while (records.size() < c.page_size && it->Valid()) {
if (!it->key().starts_with({c.prefix.data(), c.prefix.size()})) {
break;
@@ -489,9 +494,9 @@ auto Database::dbGetPage(const Continuation<T>& c) -> Result<T>* {
if (!first_key) {
first_key = it->key().ToString();
}
- std::optional<T> parsed = ParseRecord<T>(it->key(), it->value());
+ std::shared_ptr<T> parsed = ParseRecord<T>(it->key(), it->value());
if (parsed) {
- records.push_back(*parsed);
+ records.push_back(parsed);
}
if (c.forward) {
it->Next();
@@ -577,7 +582,7 @@ template auto Database::dbGetPage<std::pmr::string>(
template <>
auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
const leveldb::Slice& val)
- -> std::optional<IndexRecord> {
+ -> std::shared_ptr<IndexRecord> {
std::optional<IndexKey> data = ParseIndexKey(key);
if (!data) {
return {};
@@ -588,28 +593,29 @@ auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
title = val.ToString();
}
- return IndexRecord(*data, title, data->track);
+ return std::make_shared<IndexRecord>(*data, title, data->track);
}
template <>
auto Database::ParseRecord<Track>(const leveldb::Slice& key,
const leveldb::Slice& val)
- -> std::optional<Track> {
- std::optional<TrackData> data = ParseDataValue(val);
+ -> std::shared_ptr<Track> {
+ std::shared_ptr<TrackData> data = ParseDataValue(val);
if (!data || data->is_tombstoned()) {
return {};
}
- TrackTags tags;
- if (!tag_parser_.ReadAndParseTags(data->filepath(), &tags)) {
+ std::shared_ptr<TrackTags> tags =
+ tag_parser_.ReadAndParseTags(data->filepath());
+ if (!tags) {
return {};
}
- return Track(*data, tags);
+ return std::make_shared<Track>(data, tags);
}
template <>
auto Database::ParseRecord<std::pmr::string>(const leveldb::Slice& key,
const leveldb::Slice& val)
- -> std::optional<std::pmr::string> {
+ -> std::shared_ptr<std::pmr::string> {
std::ostringstream stream;
stream << "key: ";
if (key.size() < 3 || key.data()[1] != '\0') {
@@ -634,7 +640,7 @@ auto Database::ParseRecord<std::pmr::string>(const leveldb::Slice& key,
}
}
std::pmr::string res{stream.str(), &memory::kSpiRamResource};
- return res;
+ return std::make_shared<std::pmr::string>(res);
}
IndexRecord::IndexRecord(const IndexKey& key,
diff --git a/src/database/include/database.hpp b/src/database/include/database.hpp
index 98540f41..6ad8d318 100644
--- a/src/database/include/database.hpp
+++ b/src/database/include/database.hpp
@@ -48,12 +48,14 @@ struct Continuation {
template <typename T>
class Result {
public:
- auto values() const -> const std::vector<T>& { return values_; }
+ auto values() const -> const std::vector<std::shared_ptr<T>>& {
+ return values_;
+ }
auto next_page() -> std::optional<Continuation<T>>& { return next_page_; }
auto prev_page() -> std::optional<Continuation<T>>& { return prev_page_; }
- Result(const std::vector<T>&& values,
+ Result(const std::vector<std::shared_ptr<T>>&& values,
std::optional<Continuation<T>> next,
std::optional<Continuation<T>> prev)
: values_(values), next_page_(next), prev_page_(prev) {}
@@ -62,7 +64,7 @@ class Result {
Result& operator=(const Result&) = delete;
private:
- std::vector<T> values_;
+ std::vector<std::shared_ptr<T>> values_;
std::optional<Continuation<T>> next_page_;
std::optional<Continuation<T>> prev_page_;
};
@@ -102,14 +104,14 @@ class Database {
auto GetTrackPath(TrackId id) -> std::future<std::optional<std::pmr::string>>;
- auto GetTrack(TrackId id) -> std::future<std::optional<Track>>;
+ auto GetTrack(TrackId id) -> std::future<std::shared_ptr<Track>>;
/*
* Fetches data for multiple tracks more efficiently than multiple calls to
* GetTrack.
*/
auto GetBulkTracks(std::vector<TrackId> id)
- -> std::future<std::vector<std::optional<Track>>>;
+ -> std::future<std::vector<std::shared_ptr<Track>>>;
auto GetIndexes() -> std::vector<IndexInfo>;
auto GetTracksByIndex(const IndexInfo& index, std::size_t page_size)
@@ -145,30 +147,30 @@ class Database {
auto dbEntomb(TrackId track, uint64_t hash) -> void;
auto dbPutTrackData(const TrackData& s) -> void;
- auto dbGetTrackData(TrackId id) -> std::optional<TrackData>;
+ auto dbGetTrackData(TrackId id) -> std::shared_ptr<TrackData>;
auto dbPutHash(const uint64_t& hash, TrackId i) -> void;
auto dbGetHash(const uint64_t& hash) -> std::optional<TrackId>;
- auto dbCreateIndexesForTrack(Track track) -> void;
+ auto dbCreateIndexesForTrack(const Track& track) -> void;
template <typename T>
auto dbGetPage(const Continuation<T>& c) -> Result<T>*;
template <typename T>
auto ParseRecord(const leveldb::Slice& key, const leveldb::Slice& val)
- -> std::optional<T>;
+ -> std::shared_ptr<T>;
};
template <>
auto Database::ParseRecord<IndexRecord>(const leveldb::Slice& key,
const leveldb::Slice& val)
- -> std::optional<IndexRecord>;
+ -> std::shared_ptr<IndexRecord>;
template <>
auto Database::ParseRecord<Track>(const leveldb::Slice& key,
const leveldb::Slice& val)
- -> std::optional<Track>;
+ -> std::shared_ptr<Track>;
template <>
auto Database::ParseRecord<std::pmr::string>(const leveldb::Slice& key,
const leveldb::Slice& val)
- -> std::optional<std::pmr::string>;
+ -> std::shared_ptr<std::pmr::string>;
} // namespace database
diff --git a/src/database/include/records.hpp b/src/database/include/records.hpp
index b144dece..e7d7738c 100644
--- a/src/database/include/records.hpp
+++ b/src/database/include/records.hpp
@@ -53,7 +53,7 @@ auto EncodeDataValue(const TrackData& track) -> OwningSlice;
* Parses bytes previously encoded via EncodeDataValue back into a TrackData.
* May return nullopt if parsing fails.
*/
-auto ParseDataValue(const leveldb::Slice& slice) -> std::optional<TrackData>;
+auto ParseDataValue(const leveldb::Slice& slice) -> std::shared_ptr<TrackData>;
/* Encodes a hash key for the specified hash. */
auto EncodeHashKey(const uint64_t& hash) -> OwningSlice;
diff --git a/src/database/include/tag_parser.hpp b/src/database/include/tag_parser.hpp
index d77967d8..04817c59 100644
--- a/src/database/include/tag_parser.hpp
+++ b/src/database/include/tag_parser.hpp
@@ -16,21 +16,21 @@ namespace database {
class ITagParser {
public:
virtual ~ITagParser() {}
- virtual auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
- -> bool = 0;
+ virtual auto ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> = 0;
};
class GenericTagParser : public ITagParser {
public:
- auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
- -> bool override;
+ auto ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> override;
};
class TagParserImpl : public ITagParser {
public:
TagParserImpl();
- auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
- -> bool override;
+ auto ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> override;
private:
std::map<std::pmr::string, std::unique_ptr<ITagParser>> extension_to_parser_;
@@ -41,7 +41,7 @@ class TagParserImpl : public ITagParser {
* cache should be slightly larger than any page sizes in the UI.
*/
std::mutex cache_mutex_;
- util::LruCache<16, std::pmr::string, TrackTags> cache_;
+ util::LruCache<16, std::pmr::string, std::shared_ptr<TrackTags>> cache_;
// We could also consider keeping caches of artist name -> std::pmr::string
// and similar. This hasn't been done yet, as this isn't a common workload in
@@ -50,8 +50,8 @@ class TagParserImpl : public ITagParser {
class OpusTagParser : public ITagParser {
public:
- auto ReadAndParseTags(const std::pmr::string& path, TrackTags* out)
- -> bool override;
+ auto ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> override;
};
} // namespace database
diff --git a/src/database/include/track.hpp b/src/database/include/track.hpp
index 1c11ddea..3c7b20fa 100644
--- a/src/database/include/track.hpp
+++ b/src/database/include/track.hpp
@@ -61,12 +61,17 @@ enum class Tag {
*/
class TrackTags {
public:
- auto encoding() const -> Container { return encoding_; };
- auto encoding(Container e) -> void { encoding_ = e; };
-
TrackTags()
: encoding_(Container::kUnsupported), tags_(&memory::kSpiRamResource) {}
+ TrackTags(const TrackTags& other) = delete;
+ TrackTags& operator=(TrackTags& other) = delete;
+
+ bool operator==(const TrackTags&) const = default;
+
+ auto encoding() const -> Container { return encoding_; };
+ auto encoding(Container e) -> void { encoding_ = e; };
+
std::optional<int> channels;
std::optional<int> sample_rate;
std::optional<int> bits_per_sample;
@@ -85,10 +90,6 @@ class TrackTags {
*/
auto Hash() const -> uint64_t;
- bool operator==(const TrackTags&) const = default;
- TrackTags& operator=(const TrackTags&) = default;
- TrackTags(const TrackTags&) = default;
-
private:
Container encoding_;
std::pmr::unordered_map<Tag, std::pmr::string> tags_;
@@ -139,6 +140,11 @@ class TrackData {
play_count_(play_count),
is_tombstoned_(is_tombstoned) {}
+ TrackData(TrackData&& other) = delete;
+ TrackData& operator=(TrackData& other) = delete;
+
+ bool operator==(const TrackData&) const = default;
+
auto id() const -> TrackId { return id_; }
auto filepath() const -> std::pmr::string { return filepath_; }
auto play_count() const -> uint32_t { return play_count_; }
@@ -158,8 +164,6 @@ class TrackData {
* new location.
*/
auto Exhume(const std::pmr::string& new_path) const -> TrackData;
-
- bool operator==(const TrackData&) const = default;
};
/*
@@ -172,23 +176,22 @@ class TrackData {
*/
class Track {
public:
- Track(const TrackData& data, const TrackTags& tags)
+ Track(std::shared_ptr<TrackData>& data, std::shared_ptr<TrackTags> tags)
: data_(data), tags_(tags) {}
- Track(const Track& other) = default;
- auto data() const -> const TrackData& { return data_; }
- auto tags() const -> const TrackTags& { return tags_; }
-
- auto TitleOrFilename() const -> std::pmr::string;
+ Track(Track& other) = delete;
+ Track& operator=(Track& other) = delete;
bool operator==(const Track&) const = default;
- Track operator=(const Track& other) const { return Track(other); }
+
+ auto data() const -> const TrackData& { return *data_; }
+ auto tags() const -> const TrackTags& { return *tags_; }
+
+ auto TitleOrFilename() const -> std::pmr::string;
private:
- const TrackData data_;
- const TrackTags tags_;
+ std::shared_ptr<TrackData> data_;
+ std::shared_ptr<TrackTags> tags_;
};
-void swap(Track& first, Track& second);
-
} // namespace database
diff --git a/src/database/records.cpp b/src/database/records.cpp
index f493500c..103b3547 100644
--- a/src/database/records.cpp
+++ b/src/database/records.cpp
@@ -149,7 +149,7 @@ auto EncodeDataValue(const TrackData& track) -> OwningSlice {
return OwningSlice(as_str);
}
-auto ParseDataValue(const leveldb::Slice& slice) -> std::optional<TrackData> {
+auto ParseDataValue(const leveldb::Slice& slice) -> std::shared_ptr<TrackData> {
CborParser parser;
CborValue container;
CborError err;
@@ -211,7 +211,7 @@ auto ParseDataValue(const leveldb::Slice& slice) -> std::optional<TrackData> {
return {};
}
- return TrackData(id, path, hash, play_count, is_tombstoned);
+ return std::make_shared<TrackData>(id, path, hash, play_count, is_tombstoned);
}
/* 'H/ 0xBEEF' */
diff --git a/src/database/tag_parser.cpp b/src/database/tag_parser.cpp
index 8912690b..fe71089d 100644
--- a/src/database/tag_parser.cpp
+++ b/src/database/tag_parser.cpp
@@ -130,14 +130,13 @@ TagParserImpl::TagParserImpl() {
extension_to_parser_["opus"] = std::make_unique<OpusTagParser>();
}
-auto TagParserImpl::ReadAndParseTags(const std::pmr::string& path,
- TrackTags* out) -> bool {
+auto TagParserImpl::ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> {
{
std::lock_guard<std::mutex> lock{cache_mutex_};
- std::optional<TrackTags> cached = cache_.Get(path);
+ std::optional<std::shared_ptr<TrackTags>> cached = cache_.Get(path);
if (cached) {
- *out = *cached;
- return true;
+ return *cached;
}
}
@@ -152,41 +151,43 @@ auto TagParserImpl::ReadAndParseTags(const std::pmr::string& path,
}
}
- if (!parser->ReadAndParseTags(path, out)) {
- return false;
+ std::shared_ptr<TrackTags> tags = parser->ReadAndParseTags(path);
+ if (!tags) {
+ return {};
}
// There wasn't a track number found in the track's tags. Try to synthesize
// one from the filename, which will sometimes have a track number at the
// start.
- if (!out->at(Tag::kAlbumTrack)) {
+ if (!tags->at(Tag::kAlbumTrack)) {
auto slash_pos = path.find_last_of("/");
if (slash_pos != std::pmr::string::npos && path.size() - slash_pos > 1) {
- out->set(Tag::kAlbumTrack, path.substr(slash_pos + 1));
+ tags->set(Tag::kAlbumTrack, path.substr(slash_pos + 1));
}
}
// Normalise track numbers; they're usually treated as strings, but we would
// like to sort them lexicographically.
- out->set(Tag::kAlbumTrack,
- convert_track_number(out->at(Tag::kAlbumTrack).value_or("0")));
+ tags->set(Tag::kAlbumTrack,
+ convert_track_number(tags->at(Tag::kAlbumTrack).value_or("0")));
{
std::lock_guard<std::mutex> lock{cache_mutex_};
- cache_.Put(path, *out);
+ cache_.Put(path, tags);
}
- return true;
+ return tags;
}
-auto GenericTagParser::ReadAndParseTags(const std::pmr::string& path,
- TrackTags* out) -> bool {
+auto GenericTagParser::ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> {
libtags::Aux aux;
- aux.tags = out;
+ auto out = std::make_shared<TrackTags>();
+ aux.tags = out.get();
if (f_stat(path.c_str(), &aux.info) != FR_OK ||
f_open(&aux.file, path.c_str(), FA_READ) != FR_OK) {
ESP_LOGW(kTag, "failed to open file %s", path.c_str());
- return false;
+ return {};
}
// Fine to have this on the stack; this is only called on tasks with large
// stacks anyway, due to all the string handling.
@@ -205,7 +206,7 @@ auto GenericTagParser::ReadAndParseTags(const std::pmr::string& path,
if (res != 0) {
// Parsing failed.
ESP_LOGE(kTag, "tag parsing for %s failed, reason %d", path.c_str(), res);
- return false;
+ return {};
}
switch (ctx.format) {
@@ -240,25 +241,26 @@ auto GenericTagParser::ReadAndParseTags(const std::pmr::string& path,
if (ctx.duration > 0) {
out->duration = ctx.duration;
}
- return true;
+ return out;
}
-auto OpusTagParser::ReadAndParseTags(const std::pmr::string& path,
- TrackTags* out) -> bool {
+auto OpusTagParser::ReadAndParseTags(const std::pmr::string& path)
+ -> std::shared_ptr<TrackTags> {
std::pmr::string vfs_path = "/sdcard" + path;
int err;
OggOpusFile* f = op_test_file(vfs_path.c_str(), &err);
if (f == NULL) {
ESP_LOGE(kTag, "opusfile tag parsing failed: %d", err);
- return false;
+ return {};
}
const OpusTags* tags = op_tags(f, -1);
if (tags == NULL) {
ESP_LOGE(kTag, "no tags in opusfile");
op_free(f);
- return false;
+ return {};
}
+ auto out = std::make_shared<TrackTags>();
out->encoding(Container::kOpus);
for (const auto& pair : kVorbisIdToTag) {
const char* tag = opus_tags_query(tags, pair.first, 0);
@@ -268,7 +270,7 @@ auto OpusTagParser::ReadAndParseTags(const std::pmr::string& path,
}
op_free(f);
- return true;
+ return out;
}
} // namespace database
diff --git a/src/database/track.cpp b/src/database/track.cpp
index a3c7dc99..f48bb8ed 100644
--- a/src/database/track.cpp
+++ b/src/database/track.cpp
@@ -64,12 +64,6 @@ auto TrackData::Exhume(const std::pmr::string& new_path) const -> TrackData {
return TrackData(id_, new_path, tags_hash_, play_count_, false);
}
-void swap(Track& first, Track& second) {
- Track temp = first;
- first = second;
- second = temp;
-}
-
auto Track::TitleOrFilename() const -> std::pmr::string {
auto title = tags().at(Tag::kTitle);
if (title) {