Browse Source

add song album_artist metadata (#673)

pull/674/head
Jason Dove 4 years ago committed by GitHub
parent
commit
ea339a1622
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      CHANGELOG.md
  2. 1
      ErsatzTV.Core/Domain/Metadata/SongMetadata.cs
  3. 6
      ErsatzTV.Core/Metadata/LocalMetadataProvider.cs
  4. 13
      ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs
  5. 1
      ErsatzTV.Core/Metadata/MetadataFormatTag.cs
  6. 4
      ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs
  7. 2
      ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs
  8. 3886
      ErsatzTV.Infrastructure/Migrations/20220305002016_Add_SongMetadataAlbumArtist.Designer.cs
  9. 25
      ErsatzTV.Infrastructure/Migrations/20220305002016_Add_SongMetadataAlbumArtist.cs
  10. 3886
      ErsatzTV.Infrastructure/Migrations/20220305002236_Reset_SongMetadataAlbumArtist.Designer.cs
  11. 31
      ErsatzTV.Infrastructure/Migrations/20220305002236_Reset_SongMetadataAlbumArtist.cs
  12. 3
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs
  13. 6
      ErsatzTV.Infrastructure/Search/SearchIndex.cs
  14. 3
      docs/user-guide/search.md

2
CHANGELOG.md

@ -13,10 +13,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -13,10 +13,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- Add automated error reporting via Bugsnag
- This can be disabled by editing the `appsettings.json` file or by setting the `Bugsnag:Enable` environment variable to `false`
- Add `album_artist` to song metadata and to search index
### Changed
- Framerate normalization will never normalize framerate below 24fps
- Instead, content with a lower framerate will be normalized up to 24fps
- `Shuffle In Order` will group songs by album artist instead of by track artist
## [0.4.2-alpha] - 2022-02-26
### Fixed

1
ErsatzTV.Core/Domain/Metadata/SongMetadata.cs

@ -4,6 +4,7 @@ public class SongMetadata : Metadata @@ -4,6 +4,7 @@ public class SongMetadata : Metadata
{
public string Album { get; set; }
public string Artist { get; set; }
public string AlbumArtist { get; set; }
public string Date { get; set; }
public string Track { get; set; }
public int SongId { get; set; }

6
ErsatzTV.Core/Metadata/LocalMetadataProvider.cs

@ -232,6 +232,11 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -232,6 +232,11 @@ public class LocalMetadataProvider : ILocalMetadataProvider
result.Artist = artist;
}
if (tags.TryGetValue(MetadataFormatTag.AlbumArtist, out string albumArtist))
{
result.AlbumArtist = albumArtist;
}
if (tags.TryGetValue(MetadataFormatTag.Date, out string date))
{
result.Date = date;
@ -766,6 +771,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -766,6 +771,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
{
existing.Title = metadata.Title;
existing.Artist = metadata.Artist;
existing.AlbumArtist = metadata.AlbumArtist;
existing.Album = metadata.Album;
existing.Date = metadata.Date;
existing.Track = metadata.Track;

13
ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs

@ -88,9 +88,20 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -88,9 +88,20 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
result.Add(MetadataFormatTag.Album, ffprobe.format.tags.album);
}
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.albumArtist))
{
result.Add(MetadataFormatTag.AlbumArtist, ffprobe.format.tags.albumArtist);
}
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.artist))
{
result.Add(MetadataFormatTag.Artist, ffprobe.format.tags.artist);
// if no album artist is present, use the track artist
if (!result.ContainsKey(MetadataFormatTag.AlbumArtist))
{
result.Add(MetadataFormatTag.AlbumArtist, ffprobe.format.tags.artist);
}
}
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.date))
@ -366,6 +377,8 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -366,6 +377,8 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
public record FFprobeFormatTags(
string title,
string artist,
[property: JsonProperty(PropertyName = "album artist")]
string albumArtist,
string album,
string track,
string genre,

1
ErsatzTV.Core/Metadata/MetadataFormatTag.cs

@ -4,6 +4,7 @@ public static class MetadataFormatTag @@ -4,6 +4,7 @@ public static class MetadataFormatTag
{
public static readonly string Album = "album";
public static readonly string Artist = "artist";
public static readonly string AlbumArtist = "albumartist";
public static readonly string Date = "date";
public static readonly string Genre = "genre";
public static readonly string Title = "title";

4
ErsatzTV.Infrastructure/Data/Repositories/MediaCollectionRepository.cs

@ -312,7 +312,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -312,7 +312,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
var allArtists = items.OfType<Song>()
.SelectMany(s => s.SongMetadata)
.Map(sm => sm.Artist)
.Map(sm => sm.AlbumArtist)
.Distinct()
.ToList();
@ -324,7 +324,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository @@ -324,7 +324,7 @@ public class MediaCollectionRepository : IMediaCollectionRepository
var songArtistCollections = new Dictionary<int, List<MediaItem>>();
foreach (Song song in items.OfType<Song>())
{
int key = allArtists.IndexOf(song.SongMetadata.HeadOrNone().Match(sm => sm.Artist, string.Empty));
int key = allArtists.IndexOf(song.SongMetadata.HeadOrNone().Match(sm => sm.AlbumArtist, string.Empty));
List<MediaItem> list = songArtistCollections.ContainsKey(key)
? songArtistCollections[key]

2
ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs

@ -24,7 +24,7 @@ public class MetadataRepository : IMetadataRepository @@ -24,7 +24,7 @@ public class MetadataRepository : IMetadataRepository
public async Task<bool> Update(Metadata metadata)
{
await using TvContext dbContext = _dbContextFactory.CreateDbContext();
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
dbContext.Entry(metadata).State = EntityState.Modified;
return await dbContext.SaveChangesAsync() > 0;
}

3886
ErsatzTV.Infrastructure/Migrations/20220305002016_Add_SongMetadataAlbumArtist.Designer.cs generated

File diff suppressed because it is too large Load Diff

25
ErsatzTV.Infrastructure/Migrations/20220305002016_Add_SongMetadataAlbumArtist.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_SongMetadataAlbumArtist : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "AlbumArtist",
table: "SongMetadata",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AlbumArtist",
table: "SongMetadata");
}
}
}

3886
ErsatzTV.Infrastructure/Migrations/20220305002236_Reset_SongMetadataAlbumArtist.Designer.cs generated

File diff suppressed because it is too large Load Diff

31
ErsatzTV.Infrastructure/Migrations/20220305002236_Reset_SongMetadataAlbumArtist.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Reset_SongMetadataAlbumArtist : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(
@"UPDATE LibraryPath SET LastScan = '0001-01-01 00:00:00' WHERE Id IN
(SELECT LP.Id FROM LibraryPath LP INNER JOIN Library L on L.Id = LP.LibraryId WHERE MediaKind = 5)");
migrationBuilder.Sql(
@"UPDATE Library SET LastScan = '0001-01-01 00:00:00' WHERE MediaKind = 5");
migrationBuilder.Sql(
@"UPDATE SongMetadata SET DateUpdated = '0001-01-01 00:00:00'");
migrationBuilder.Sql(
@"UPDATE LibraryFolder SET Etag = NULL WHERE Id IN
(SELECT LF.Id FROM LibraryFolder LF INNER JOIN LibraryPath LP on LF.LibraryPathId = LP.Id INNER JOIN Library L on LP.LibraryId = L.Id WHERE MediaKind = 5)");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

3
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -1672,6 +1672,9 @@ namespace ErsatzTV.Infrastructure.Migrations @@ -1672,6 +1672,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<string>("Album")
.HasColumnType("TEXT");
b.Property<string>("AlbumArtist")
.HasColumnType("TEXT");
b.Property<string>("Artist")
.HasColumnType("TEXT");

6
ErsatzTV.Infrastructure/Search/SearchIndex.cs

@ -52,6 +52,7 @@ public sealed class SearchIndex : ISearchIndex @@ -52,6 +52,7 @@ public sealed class SearchIndex : ISearchIndex
private const string MinutesField = "minutes";
private const string ArtistField = "artist";
private const string StateField = "state";
private const string AlbumArtistField = "album_artist";
public const string MovieType = "movie";
public const string ShowType = "show";
@ -894,6 +895,11 @@ public sealed class SearchIndex : ISearchIndex @@ -894,6 +895,11 @@ public sealed class SearchIndex : ISearchIndex
doc.Add(new TextField(ArtistField, metadata.Artist, Field.Store.NO));
}
if (!string.IsNullOrWhiteSpace(metadata.AlbumArtist))
{
doc.Add(new TextField(AlbumArtistField, metadata.AlbumArtist, Field.Store.NO));
}
foreach (Tag tag in metadata.Tags)
{
doc.Add(new TextField(TagField, tag.Name, Field.Store.NO));

3
docs/user-guide/search.md

@ -103,7 +103,8 @@ The following fields are available for searching songs: @@ -103,7 +103,8 @@ The following fields are available for searching songs:
- `title`: The song title, or the filename of the song (without extension)
- `album`: The song album
- `artist`: The song artist
- `artist`: The song/track artist
- `album_artist`: The album artist
- `genre`: The song genre
- `tag`: All of the song's parent folders
- `minutes`: the rounded-up whole number duration of the song in minutes

Loading…
Cancel
Save