1
8
Fork
You've already forked nup
0

Support a recording appearing in multiple albums #32

Open
opened 2022年02月09日 16:23:33 +01:00 by derat · 3 comments
derat commented 2022年02月09日 16:23:33 +01:00 (Migrated from github.com)
Copy link

Sometimes a single recording of a song ends up on multiple albums, e.g. https://musicbrainz.org/recording/8cc47fd7-eec3-4e2e-bcce-eba2fd37d891 and https://musicbrainz.org/recording/0ca150e4-f806-446c-b360-1f0c0077d847 (MusicBrainz lists separate recordings there, but I think they're actually the same). Artists also often release songs first as singles on Bandcamp and then re-release them in albums that contain other previously-unreleased songs.

Right now, I deal with this by merging one song into the other and deleting the MP3 and Datastore entity of the former song. I don't care much about the wasted space from storing a second MP3 of the recording, but I don't want to have two entities with separate play histories and potentially-different ratings and tags.

It'd be nice to be able to insert a placeholder song in this case so that the album with the deleted copy can still be played as intended. I haven't thought much about how this would work. Should I create a separate entity type for placeholder songs (how would queries work)? Or should I add an e.g. CanonicalSongID field to the Song struct and update clients to use it instead of SongID when reporting plays or updating ratings and tags? That feels hard too: clients would need to load the canonical song to display the placeholder's ratings or tags unless I tried to duplicate user data.

One other issue is that duplicate songs usually have different volume levels, so the AlbumGain field will be incorrect for one of the albums. (TrackGain often seems to be slightly different too.)

Sometimes a single recording of a song ends up on multiple albums, e.g. https://musicbrainz.org/recording/8cc47fd7-eec3-4e2e-bcce-eba2fd37d891 and https://musicbrainz.org/recording/0ca150e4-f806-446c-b360-1f0c0077d847 (MusicBrainz lists separate recordings there, but I think they're actually the same). Artists also often release songs first as singles on Bandcamp and then re-release them in albums that contain other previously-unreleased songs. Right now, I deal with this by merging one song into the other and deleting the MP3 and Datastore entity of the former song. I don't care much about the wasted space from storing a second MP3 of the recording, but I don't want to have two entities with separate play histories and potentially-different ratings and tags. It'd be nice to be able to insert a placeholder song in this case so that the album with the deleted copy can still be played as intended. I haven't thought much about how this would work. Should I create a separate entity type for placeholder songs (how would queries work)? Or should I add an e.g. `CanonicalSongID` field to the `Song` struct and update clients to use it instead of `SongID` when reporting plays or updating ratings and tags? That feels hard too: clients would need to load the canonical song to display the placeholder's ratings or tags unless I tried to duplicate user data. One other issue is that duplicate songs usually have different volume levels, so the `AlbumGain` field will be incorrect for one of the albums. (`TrackGain` often seems to be slightly different too.)
derat commented 2022年02月09日 17:30:40 +01:00 (Migrated from github.com)
Copy link

Yeah, I'm not sure how this would work. User data would need to be maintained across all versions of a song so that queries based on ratings, tags, or plays would still work. It might also be weird to get multiple copies of the same song when e.g. shuffling by artist.

All versions of a song would need to share these fields:

  • SHA1
  • Filename
  • Length
  • TrackGain
  • AlbumGain (as mentioned above, this will be wrong for non-canonical versions)
  • PeakAmp
  • Rating
  • Plays
  • Tags

Each version would have its own values for these fields:

  • CoverFilename
  • Artist
  • Title
  • Album
  • AlbumArtist
  • AlbumID
  • Track
  • Disc

And then there are a bunch of generated fields like ArtistLower, Keywords, RatingAtLeast*, etc. that would end up in one group or the other depending on how they're derived.

Yeah, I'm not sure how this would work. User data would need to be maintained across all versions of a song so that queries based on ratings, tags, or plays would still work. It might also be weird to get multiple copies of the same song when e.g. shuffling by artist. All versions of a song would need to share these fields: * SHA1 * Filename * Length * TrackGain * AlbumGain (as mentioned above, this will be wrong for non-canonical versions) * PeakAmp * Rating * Plays * Tags Each version would have its own values for these fields: * CoverFilename * Artist * Title * Album * AlbumArtist * AlbumID * Track * Disc And then there are a bunch of generated fields like `ArtistLower`, `Keywords`, `RatingAtLeast*`, etc. that would end up in one group or the other depending on how they're derived.
derat commented 2022年02月09日 17:57:22 +01:00 (Migrated from github.com)
Copy link

Another (gross?) hack might be to make the unique fields/properties optionally hold multiple values. This might make queries just work (I'm not at all sure about that), but it'd probably make marshaling and unmarshaling to and from Datastore and JSON complicated.

This probably isn't worth the effort.

Another (gross?) hack might be to make the unique fields/properties optionally hold multiple values. This might make queries just work (I'm not at all sure about that), but it'd probably make marshaling and unmarshaling to and from Datastore and JSON complicated. This probably isn't worth the effort.

Just to move some TODOs out of the code, maybe this could be done using the metadata override stuff in cmd/nup/client/files/override.go. If I went this route, it'd probably make sense to add field(s) to the MetadataOverride struct for referencing another song's SHA1, filename, or song ID. There would probably need to be some way to override the base song's AlbumGain field too.

scanForUpdatedSongs in cmd/nup/update/scan.go would also need to be updated to scan all of cfg.MetadataDir for new or updated metadata files while also avoiding duplicate updates in the case where both the song file and the corresponding override file have been updated.

Just to move some TODOs out of the code, maybe this could be done using the metadata override stuff in cmd/nup/client/files/override.go. If I went this route, it'd probably make sense to add field(s) to the `MetadataOverride` struct for referencing another song's SHA1, filename, or song ID. There would probably need to be some way to override the base song's `AlbumGain` field too. `scanForUpdatedSongs` in cmd/nup/update/scan.go would also need to be updated to scan all of `cfg.MetadataDir` for new or updated metadata files while also avoiding duplicate updates in the case where both the song file and the corresponding override file have been updated.
Sign in to join this conversation.
No Branch/Tag specified
main
headless
picture
datastore
No results found.
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
derat/nup#32
Reference in a new issue
derat/nup
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?