Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WiP] Track metadata import/export #2336

Closed
wants to merge 10 commits into from
Closed

[WiP] Track metadata import/export #2336

wants to merge 10 commits into from

Conversation

uklotzde
Copy link
Contributor

@uklotzde uklotzde commented Oct 29, 2019

Please ignore, out of date. Needs to be rebased on a set of library design changes with various fixes. I'm currently no longer able to maintain all my pending fixes and have put all new development tasks on hold.

This PR introduces a simpler, more robust, and better maintainable mapping or synchronization between track metadata that is both stored in the database and in file tags. The code is still complicated, but it's a step in the right direction. It is also another prerequisite for #2282.

We currently only store a subset of properties in the database. Adding support for new fields in the future is non-trivial as we need to incrementally import the missing properties from file tags and must avoid to overwrite any existing file tags when exporting metadata.

The default value for newly added database fields is supposed to be NULL (= missing). A special case from the past is total tracks that has been initialized with "//". Those properties must be replaced with the corresponding file tags step by step whenever a track is loaded.

When enabling __EXTRA_METADATA__ track objects will also be populated with all properties that are available as file tags but are not (yet) stored in the database. The values stored in the database take precedence over imported file tags.

Reorganization

  • Remove special case handling of certain properties from TagLib code
  • Remove special case handling of certain properties from TrackInfo/AlbumInfo/TrackMetadata
  • Move tag migration code for total tracks from TrackDAO into TrackRecord
  • Move all code for merging imported file tags into TrackRecord

Import

SoundSourceProxy::updateTrackFromSource() Import and merge file tags when loading track objects. This will also populate all missing fields that are not (yet) stored in the database.

Export

Track::exportMetadata() Import and merge file tags again before exporting metadata. Tags are only written if differences are detected to avoid modifying the corresponding file if not needed.

@uklotzde uklotzde added this to the 2.3.0 milestone Oct 29, 2019
@uklotzde
Copy link
Contributor Author

uklotzde commented Nov 5, 2019

Finally, after many unrelated changed in DlgTagFetcher the MSVC 2017 build seems to be successful (although it timed out). I have absolutely no idea why it only failed for this particular branch but succeeded on other branches like #2282 that include the exact same code!?!?

@Holzhaus
Copy link
Member

Holzhaus commented Nov 5, 2019

Windows works in mysterious ways.

@uklotzde uklotzde changed the title Track metadata import/export [WiP] Track metadata import/export Nov 10, 2019
@uklotzde
Copy link
Contributor Author

Rebased on #2344 to avoid merge conflicts.

Copy link
Member

@daschuer daschuer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.
Is there. Something that especially requires a manual test.

void Library::saveEvictedTrack(Track* pTrack) noexcept {
// It can produce dangerous signal loops if the track is still
// sending signals while being saved!
// See: https://bugs.launchpad.net/mixxx/+bug/1365708
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can this be removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The disconnecting code is part of GlobalTrackCache::saveEvictedTrack(). I have amended it with a more appropriate description regarding objects-under-destruction.

I don't experience any issues while saving intermediate modifications in the internal and external collections. Otherwise this would be a design or programming error that needs to be fixed.

SoundSourceProxy::exportTrackMetadataBeforeSaving(pTrack);
break;
case TrackMetadataExportMode::Deferred:
pTrack->markForMetadataExport();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to set the flag unconditionally?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. If the metadata is saved intermediately for keeping the databases up-to-date we must remember to save the file tags when the track objects goes out of scope. This is required even if the dirty flag is not set again, because no further changes happened after modifications have been saved to the database.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will add a comment.

// discard a users's custom choice! We are using a whitelisting
// filter here that explicitly checks all valid preconditions
// when it is permissible to update/replace existing cover art.
if (((coverInfoOld.source == CoverInfo::UNKNOWN) || (coverInfoOld.source == CoverInfo::GUESSED)) &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we invert the logic, we have only USER_SELECTED? I think this would be better to read.
Or a switch case with cases for all values and a debug assert in the default case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think switching from a white list to a black list is a fair compromise to reduce the overall complexity:

if (coverInfoOld.source == CoverInfo::USER_SELECTED
        &&  coverInfoOld.type == CoverInfo::FILE) {
   ...skip re-import
} else {
   ...replace cover art
}

@@ -33,9 +33,6 @@ class AlbumInfo final {
AlbumInfo& operator=(AlbumInfo&&) = default;
AlbumInfo& operator=(const AlbumInfo&) = default;

// TODO(XXX): Remove after all new fields have been added to the library
void resetUnsupportedValues();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand the original code and the change. Can you give a hint?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original implementation relied on null values as a marker. Fields with null values were not exported to prevent overwriting valid file tags with empty, missing fields.

@@ -25,6 +25,12 @@ class Bpm final {

// Adjusts floating-point values to match their string representation
// in file tags to account for rounding errors.
// NOTE(2019-02-19, uklotzde): The pre-normalization cannot prevent
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a to-do?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is a fact resulting from the ID3v2 format.

@uklotzde
Copy link
Contributor Author

Thanks for taking a look, Daniel. Unfortunately I have to rebase this work on a library redesign that fixes a crash on shutdown and insufficient synchronization of external track collections caused by inapproiate dependencies. I'm only able to maintain a single branch of changes.

@Be-ing
Copy link
Contributor

Be-ing commented Nov 11, 2019

Maybe it would be easier to maintain one Aoide prerequisites branch than maintain several interdependent branches?

@uklotzde
Copy link
Contributor Author

That's what I plan to prepare. But it becomes harder and harder to maintain and without any commitment from the team I feel unable to continue.

@uklotzde uklotzde closed this Nov 11, 2019
@daschuer
Copy link
Member

Does the "Close and comment" button strikes in?

@uklotzde uklotzde deleted the metadata_import_export branch November 12, 2019 06:29
@uklotzde
Copy link
Contributor Author

No. This has intentionally been closed. I'm trying to get rid of maintenance burden.

@daschuer
Copy link
Member

That's s pity. You spend a significant time to work on this PR and I have spend significant time to review the PR. IMHO it is a good way forward to split you work into small PRs.

I can imagine that rebasing is a lot of risky work, because it creates many untested intermediate commits that likely all conflicting.

So why not just merge you development branch?

@uklotzde
Copy link
Contributor Author

I've tried to split off some smaller PRs, but that just got not reviewed. I cannot keep track of multiple concurrent changes with conflicts due to our legacy architecture.

@uklotzde
Copy link
Contributor Author

I have preserved the changes of your review by modifying or commenting the code accordingly. But without a clear commitment for progress I'm not able to continue.

@daschuer
Copy link
Member

What kind of commitment you are looking for?

@Holzhaus
Copy link
Member

Can you restore the branch? I'd review it ASAP ;-)

@Holzhaus Holzhaus added this to Done in 2.3 release Mar 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
No open projects
2.3 release
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

4 participants