Skip to content

Commit

Permalink
fix: edge cases of tags editing
Browse files Browse the repository at this point in the history
  • Loading branch information
pnck committed May 7, 2024
1 parent 87325c8 commit 84ef8c1
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 15 deletions.
39 changes: 34 additions & 5 deletions src/input_ncm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ inline bool fb2k_ncm::input_ncm::g_is_our_content_type(const char *p_content_typ
/// The former is stored in the audio content, while the latter is stored in the ncm header.
/// @note
/// - See also: `ncm_file::overwrite_meta()`
inline void fb2k_ncm::input_ncm::retag(const file_info &p_info, abort_callback &p_abort) {
void fb2k_ncm::input_ncm::retag(const file_info &p_info, abort_callback &p_abort) {
DEBUG_LOG("input_ncm::retag()");
// Replay Gain
file_info_impl cur_file_info;
Expand All @@ -45,21 +45,50 @@ inline void fb2k_ncm::input_ncm::retag(const file_info &p_info, abort_callback &
// NOTE: Always do differential update, to maximally avoid appending "overwrite" key,
// which will change the "163 key xxxx" content.
auto target_json = meta_processor(p_info).dump();
if (target_json.empty()) { // fallback case: clear all fields
return this->remove_tags(p_abort);
}
this->get_info(cur_file_info, p_abort);
auto current_json = meta_processor(cur_file_info).dump();

if (current_json.contains(overwrite_key)) {
current_json.erase(overwrite_key);
auto overwrite = json_t::object();

if (ncm_file_->meta_info().contains(overwrite_key)) {
// overwrite is guaranteed to be suitable with current_meta
// because this->get_info() will call parse() and reset meta_info()
overwrite = ncm_file_->meta_info()[overwrite_key];
}

auto diff = json_t::diff(current_json, target_json);
ncm_file_->overwrite_meta(json_t::object().patch(diff), p_abort);
auto to_merge = json_t::object();
for (const auto &op : diff) {
json_t::json_pointer pt(op["path"]);
for (; !pt.parent_pointer().empty(); pt = pt.parent_pointer()) {
continue;
}
if (op["op"] == "remove") {
if (!overwrite.contains(pt.back())) {
overwrite.emplace(pt.back(), nullptr);
} else {
overwrite[pt.back()] = nullptr;
}
} else {
if (overwrite.contains(pt.back())) {
overwrite.erase(pt.back());
}
overwrite.emplace(pt.back(), target_json.at(pt)); // copy the top level
}
}

overwrite.merge_patch(to_merge);

ncm_file_->overwrite_meta(overwrite, p_abort);
}

/// @brief "Clear tags" => restore the meta field (163 key) to its original state
/// @attention ReplayGain and embedded tags in the audio content are left untouched.
/// @note ReplayGain can be wiped by retagging, since the meta diff would be empty then.
inline void fb2k_ncm::input_ncm::remove_tags(abort_callback &p_abort) {
void fb2k_ncm::input_ncm::remove_tags(abort_callback &p_abort) {
DEBUG_LOG("input_ncm::remove_tags()");
// source_info_writer_->remove_tags_fallback(p_abort);
ncm_file_->overwrite_meta(nlohmann::json(), p_abort);
Expand Down
18 changes: 15 additions & 3 deletions src/meta_process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,17 @@ void meta_processor::update_by_json(const nlohmann::json &json, bool overwriting
using refl_f_t = void(const nlohmann::json &);
auto reflection = std::unordered_map<std::string_view, std::function<refl_f_t>>{}; // UPPERCASE keys
reflection["artist"] = [&](const json_t &j) {
if (j.is_null()) {
artist.reset();
return;
}
if (!artist.has_value()) {
artist.emplace();
} else if (overwriting) {
artist.reset();
artist.emplace();
}
for (const auto &val : j.get_ref<const json_t::array_t &>()) {
if (!val.is_array()) {
continue;
}
if (val.size() != 2) {
continue;
}
Expand All @@ -121,6 +125,10 @@ void meta_processor::update_by_json(const nlohmann::json &json, bool overwriting

#define reflect_single(field, TYPE) \
[&](const json_t &j) { \
if (j.is_null()) { \
field.reset(); \
return; \
} \
try { \
update_v(field, j.get<TYPE>()); \
} catch (const json_t::type_error &) { \
Expand All @@ -133,6 +141,10 @@ void meta_processor::update_by_json(const nlohmann::json &json, bool overwriting
}
#define reflect_multi_string(field) \
[&](const json_t &j) { \
if (j.is_null()) { \
field.reset(); \
return; \
} \
if (!j.is_array()) { \
return; \
} \
Expand Down
17 changes: 11 additions & 6 deletions src/ncm_file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ bool ncm_file::save_raw_audio(const char *to_dir, abort_callback &p_abort) {
return false;
}

void ncm_file::overwrite_meta(const nlohmann::json &meta, abort_callback &p_abort) {
void ncm_file::overwrite_meta(const nlohmann::json &overwrite, abort_callback &p_abort) {
if (!meta_parsed()) {
this->parse(parse_targets::NCM_PARSE_META);
}
Expand All @@ -329,15 +329,20 @@ void ncm_file::overwrite_meta(const nlohmann::json &meta, abort_callback &p_abor
// embed overwriting meta into the source

auto meta_str_to_write = std::string("music:");
nlohmann::ordered_json live_meta = nlohmann::ordered_json::parse(meta_str_); // NOTE: use unmodified raw json string to keep stricted order
nlohmann::ordered_json live_meta =
nlohmann::ordered_json::parse(meta_str_); // NOTE: use unmodified raw json string to keep stricted order
if (live_meta.contains(overwrite_key)) {
live_meta.erase(overwrite_key); // replace the old key
}

if (meta.size()) {
live_meta[overwrite_key] = meta;
live_meta[overwrite_key].emplace(foo_input_ncm_comment_key, foo_input_ncm_comment);
}
if (auto size = overwrite.size(); size > 0)
do {
if (size == 1 && overwrite.contains(foo_input_ncm_comment_key)) {
break;
}
live_meta[overwrite_key] = overwrite;
live_meta[overwrite_key].emplace(foo_input_ncm_comment_key, foo_input_ncm_comment);
} while (false);
meta_str_to_write += live_meta.dump();

DEBUG_LOG_F("Overwriting meta (to {}): {}", this->path(), meta_str_to_write);
Expand Down
2 changes: 1 addition & 1 deletion src/ncm_file.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ namespace fb2k_ncm
}
void parse(uint16_t to_parse = 0xffff);
bool save_raw_audio(const char *to_dir, abort_callback &p_abort = fb2k::noAbort);
void overwrite_meta(const nlohmann::json &meta, abort_callback &p_abort = fb2k::noAbort);
void overwrite_meta(const nlohmann::json &overwrite, abort_callback &p_abort = fb2k::noAbort);
void reset_album_image(album_art_data_ptr image, abort_callback &p_abort = fb2k::noAbort);

private:
Expand Down

0 comments on commit 84ef8c1

Please sign in to comment.