Browse Source

music video nfo multiple artists (#780)

* support multiple artist entries in music video nfo metadata

* clean up other video and song etags
pull/782/head
Jason Dove 4 years ago committed by GitHub
parent
commit
8ba6374165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 2
      ErsatzTV.Core.Tests/Metadata/Nfo/MusicVideoNfoReaderTests.cs
  3. 7
      ErsatzTV.Core/Domain/Metadata/MusicVideoArtist.cs
  4. 1
      ErsatzTV.Core/Domain/Metadata/MusicVideoMetadata.cs
  5. 3
      ErsatzTV.Core/Interfaces/Repositories/ILibraryRepository.cs
  6. 2
      ErsatzTV.Core/Interfaces/Repositories/IMusicVideoRepository.cs
  7. 1
      ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs
  8. 23
      ErsatzTV.Core/Metadata/LocalMetadataProvider.cs
  9. 11
      ErsatzTV.Core/Metadata/MusicVideoFolderScanner.cs
  10. 2
      ErsatzTV.Core/Metadata/Nfo/MusicVideoNfo.cs
  11. 3
      ErsatzTV.Core/Metadata/Nfo/MusicVideoNfoReader.cs
  12. 11
      ErsatzTV.Core/Metadata/OtherVideoFolderScanner.cs
  13. 11
      ErsatzTV.Core/Metadata/SongFolderScanner.cs
  14. 4
      ErsatzTV.Infrastructure/Data/Configurations/Metadata/MusicVideoMetadataConfiguration.cs
  15. 29
      ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs
  16. 8
      ErsatzTV.Infrastructure/Data/Repositories/MetadataRepository.cs
  17. 19
      ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs
  18. 4
      ErsatzTV.Infrastructure/Data/Repositories/SearchRepository.cs
  19. 4239
      ErsatzTV.Infrastructure/Migrations/20220502133555_Add_MusicVideoArtists.Designer.cs
  20. 43
      ErsatzTV.Infrastructure/Migrations/20220502133555_Add_MusicVideoArtists.cs
  21. 4239
      ErsatzTV.Infrastructure/Migrations/20220502171259_Reset_MusicVideoLibraries.Designer.cs
  22. 34
      ErsatzTV.Infrastructure/Migrations/20220502171259_Reset_MusicVideoLibraries.cs
  23. 4239
      ErsatzTV.Infrastructure/Migrations/20220502172236_Reset_OtherVideosSongsFolderEtags.Designer.cs
  24. 23
      ErsatzTV.Infrastructure/Migrations/20220502172236_Reset_OtherVideosSongsFolderEtags.cs
  25. 29
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs
  26. 14
      ErsatzTV.Infrastructure/Search/SearchIndex.cs

1
CHANGELOG.md

@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Use `Sort Title` from Movie NFO metadata if available - Use `Sort Title` from Movie NFO metadata if available
- Support multiple `Artist` entries in music video NFO metadata
## [0.5.3-beta] - 2022-04-29 ## [0.5.3-beta] - 2022-04-29
### Fixed ### Fixed

2
ErsatzTV.Core.Tests/Metadata/Nfo/MusicVideoNfoReaderTests.cs

@ -113,7 +113,7 @@ https://www.themoviedb.org/movie/11-star-wars"));
foreach (MusicVideoNfo nfo in result.RightToSeq()) foreach (MusicVideoNfo nfo in result.RightToSeq())
{ {
nfo.Artist.Should().Be("ABBA"); nfo.Artists.Should().BeEquivalentTo(new List<string> { "ABBA" });
nfo.Title.Should().Be("Dancing Queen"); nfo.Title.Should().Be("Dancing Queen");
nfo.Album.Should().Be("Arrival"); nfo.Album.Should().Be("Arrival");
nfo.Plot.Should().Be( nfo.Plot.Should().Be(

7
ErsatzTV.Core/Domain/Metadata/MusicVideoArtist.cs

@ -0,0 +1,7 @@
namespace ErsatzTV.Core.Domain;
public class MusicVideoArtist
{
public int Id { get; set; }
public string Name { get; set; }
}

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

@ -6,4 +6,5 @@ public class MusicVideoMetadata : Metadata
public string Plot { get; set; } public string Plot { get; set; }
public int MusicVideoId { get; set; } public int MusicVideoId { get; set; }
public MusicVideo MusicVideo { get; set; } public MusicVideo MusicVideo { get; set; }
public List<MusicVideoArtist> Artists { get; set; }
} }

3
ErsatzTV.Core/Interfaces/Repositories/ILibraryRepository.cs

@ -11,10 +11,7 @@ public interface ILibraryRepository
Task<Unit> UpdateLastScan(Library library); Task<Unit> UpdateLastScan(Library library);
Task<Unit> UpdateLastScan(LibraryPath libraryPath); Task<Unit> UpdateLastScan(LibraryPath libraryPath);
Task<List<LibraryPath>> GetLocalPaths(int libraryId); Task<List<LibraryPath>> GetLocalPaths(int libraryId);
Task<Option<LibraryPath>> GetPath(int libraryPathId);
Task<int> CountMediaItemsByPath(int libraryPathId); Task<int> CountMediaItemsByPath(int libraryPathId);
Task<List<int>> GetMediaIdsByLocalPath(int libraryPathId);
Task DeleteLocalPath(int libraryPathId);
Task<Unit> SetEtag(LibraryPath libraryPath, Option<LibraryFolder> knownFolder, string path, string etag); Task<Unit> SetEtag(LibraryPath libraryPath, Option<LibraryFolder> knownFolder, string path, string etag);
Task<Unit> CleanEtagsForLibraryPath(LibraryPath libraryPath); Task<Unit> CleanEtagsForLibraryPath(LibraryPath libraryPath);
} }

2
ErsatzTV.Core/Interfaces/Repositories/IMusicVideoRepository.cs

@ -12,9 +12,11 @@ public interface IMusicVideoRepository
Task<IEnumerable<string>> FindMusicVideoPaths(LibraryPath libraryPath); Task<IEnumerable<string>> FindMusicVideoPaths(LibraryPath libraryPath);
Task<List<int>> DeleteByPath(LibraryPath libraryPath, string path); Task<List<int>> DeleteByPath(LibraryPath libraryPath, string path);
Task<bool> AddArtist(MusicVideoMetadata metadata, MusicVideoArtist artist);
Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre); Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre);
Task<bool> AddTag(MusicVideoMetadata metadata, Tag tag); Task<bool> AddTag(MusicVideoMetadata metadata, Tag tag);
Task<bool> AddStudio(MusicVideoMetadata metadata, Studio studio); Task<bool> AddStudio(MusicVideoMetadata metadata, Studio studio);
Task<bool> RemoveArtist(MusicVideoArtist artist);
Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids); Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids);
Task<IEnumerable<string>> FindOrphanPaths(LibraryPath libraryPath); Task<IEnumerable<string>> FindOrphanPaths(LibraryPath libraryPath);
Task<int> GetMusicVideoCount(int artistId); Task<int> GetMusicVideoCount(int artistId);

1
ErsatzTV.Core/Metadata/FallbackMetadataProvider.cs

@ -230,6 +230,7 @@ public class FallbackMetadataProvider : IFallbackMetadataProvider
metadata.Title = match.Success metadata.Title = match.Success
? match.Groups[2].Value.Trim() ? match.Groups[2].Value.Trim()
: Path.GetFileNameWithoutExtension(fileName); : Path.GetFileNameWithoutExtension(fileName);
metadata.Artists = new List<MusicVideoArtist>();
metadata.Genres = new List<Genre>(); metadata.Genres = new List<Genre>();
metadata.Tags = new List<Tag>(); metadata.Tags = new List<Tag>();
metadata.Studios = new List<Studio>(); metadata.Studios = new List<Studio>();

23
ErsatzTV.Core/Metadata/LocalMetadataProvider.cs

@ -193,6 +193,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
Plot = nfo.Plot, Plot = nfo.Plot,
Year = GetYear(nfo.Year, string.Empty), Year = GetYear(nfo.Year, string.Empty),
ReleaseDate = GetAired(nfo.Year, string.Empty), ReleaseDate = GetAired(nfo.Year, string.Empty),
Artists = nfo.Artists.Map(a => new MusicVideoArtist { Name = a }).ToList(),
Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(), Genres = nfo.Genres.Map(g => new Genre { Name = g }).ToList(),
Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(), Tags = nfo.Tags.Map(t => new Tag { Name = t }).ToList(),
Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList() Studios = nfo.Studios.Map(s => new Studio { Name = s }).ToList()
@ -727,6 +728,28 @@ public class LocalMetadataProvider : ILocalMetadataProvider
_musicVideoRepository.AddStudio, _musicVideoRepository.AddStudio,
(_, _) => Task.FromResult(false)); (_, _) => Task.FromResult(false));
foreach (MusicVideoArtist artist in existing.Artists
.Filter(g => metadata.Artists.All(g2 => g2.Name != g.Name))
.ToList())
{
existing.Artists.Remove(artist);
if (await _musicVideoRepository.RemoveArtist(artist))
{
updated = true;
}
}
foreach (MusicVideoArtist artist in metadata.Artists
.Filter(g => existing.Artists.All(g2 => g2.Name != g.Name))
.ToList())
{
existing.Artists.Add(artist);
if (await _musicVideoRepository.AddArtist(existing, artist))
{
updated = true;
}
}
return await _metadataRepository.Update(existing) || updated; return await _metadataRepository.Update(existing) || updated;
} }

11
ErsatzTV.Core/Metadata/MusicVideoFolderScanner.cs

@ -307,6 +307,8 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
continue; continue;
} }
var hasErrors = false;
foreach (string file in allFiles.OrderBy(identity)) foreach (string file in allFiles.OrderBy(identity))
{ {
// TODO: figure out how to rebuild playouts // TODO: figure out how to rebuild playouts
@ -321,6 +323,7 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
foreach (BaseError error in maybeMusicVideo.LeftToSeq()) foreach (BaseError error in maybeMusicVideo.LeftToSeq())
{ {
_logger.LogWarning("Error processing music video at {Path}: {Error}", file, error.Value); _logger.LogWarning("Error processing music video at {Path}: {Error}", file, error.Value);
hasErrors = true;
} }
foreach (MediaItemScanResult<MusicVideo> result in maybeMusicVideo.RightToSeq()) foreach (MediaItemScanResult<MusicVideo> result in maybeMusicVideo.RightToSeq())
@ -329,10 +332,14 @@ public class MusicVideoFolderScanner : LocalFolderScanner, IMusicVideoFolderScan
{ {
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id }); await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
} }
await _libraryRepository.SetEtag(libraryPath, knownFolder, musicVideoFolder, etag);
} }
} }
// only do this once per folder and only if all files processed successfully
if (!hasErrors)
{
await _libraryRepository.SetEtag(libraryPath, knownFolder, musicVideoFolder, etag);
}
} }
return Unit.Default; return Unit.Default;

2
ErsatzTV.Core/Metadata/Nfo/MusicVideoNfo.cs

@ -6,7 +6,7 @@ namespace ErsatzTV.Core.Metadata.Nfo;
public class MusicVideoNfo public class MusicVideoNfo
{ {
[XmlElement("artist")] [XmlElement("artist")]
public string Artist { get; set; } public List<string> Artists { get; set; }
[XmlElement("title")] [XmlElement("title")]
public string Title { get; set; } public string Title { get; set; }

3
ErsatzTV.Core/Metadata/Nfo/MusicVideoNfoReader.cs

@ -30,6 +30,7 @@ public class MusicVideoNfoReader : NfoReader<MusicVideoNfo>, IMusicVideoNfoReade
case "musicvideo": case "musicvideo":
nfo = new MusicVideoNfo nfo = new MusicVideoNfo
{ {
Artists = new List<string>(),
Genres = new List<string>(), Genres = new List<string>(),
Tags = new List<string>(), Tags = new List<string>(),
Studios = new List<string>() Studios = new List<string>()
@ -39,7 +40,7 @@ public class MusicVideoNfoReader : NfoReader<MusicVideoNfo>, IMusicVideoNfoReade
await ReadStringContent( await ReadStringContent(
reader, reader,
nfo, nfo,
(musicVideo, artist) => musicVideo.Artist = artist); (musicVideo, artist) => musicVideo.Artists.Add(artist));
break; break;
case "title": case "title":
await ReadStringContent(reader, nfo, (musicVideo, title) => musicVideo.Title = title); await ReadStringContent(reader, nfo, (musicVideo, title) => musicVideo.Title = title);

11
ErsatzTV.Core/Metadata/OtherVideoFolderScanner.cs

@ -136,6 +136,8 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
"UPDATE: Etag has changed for folder {Folder}", "UPDATE: Etag has changed for folder {Folder}",
otherVideoFolder); otherVideoFolder);
var hasErrors = false;
foreach (string file in allFiles.OrderBy(identity)) foreach (string file in allFiles.OrderBy(identity))
{ {
Either<BaseError, MediaItemScanResult<OtherVideo>> maybeVideo = await _otherVideoRepository Either<BaseError, MediaItemScanResult<OtherVideo>> maybeVideo = await _otherVideoRepository
@ -148,6 +150,7 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
foreach (BaseError error in maybeVideo.LeftToSeq()) foreach (BaseError error in maybeVideo.LeftToSeq())
{ {
_logger.LogWarning("Error processing other video at {Path}: {Error}", file, error.Value); _logger.LogWarning("Error processing other video at {Path}: {Error}", file, error.Value);
hasErrors = true;
} }
foreach (MediaItemScanResult<OtherVideo> result in maybeVideo.RightToSeq()) foreach (MediaItemScanResult<OtherVideo> result in maybeVideo.RightToSeq())
@ -156,10 +159,14 @@ public class OtherVideoFolderScanner : LocalFolderScanner, IOtherVideoFolderScan
{ {
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id }); await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
} }
await _libraryRepository.SetEtag(libraryPath, knownFolder, otherVideoFolder, etag);
} }
} }
// only do this once per folder and only if all files processed successfully
if (!hasErrors)
{
await _libraryRepository.SetEtag(libraryPath, knownFolder, otherVideoFolder, etag);
}
} }
foreach (string path in await _otherVideoRepository.FindOtherVideoPaths(libraryPath)) foreach (string path in await _otherVideoRepository.FindOtherVideoPaths(libraryPath))

11
ErsatzTV.Core/Metadata/SongFolderScanner.cs

@ -134,6 +134,8 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
"UPDATE: Etag has changed for folder {Folder}", "UPDATE: Etag has changed for folder {Folder}",
songFolder); songFolder);
var hasErrors = false;
foreach (string file in allFiles.OrderBy(identity)) foreach (string file in allFiles.OrderBy(identity))
{ {
Either<BaseError, MediaItemScanResult<Song>> maybeSong = await _songRepository Either<BaseError, MediaItemScanResult<Song>> maybeSong = await _songRepository
@ -146,6 +148,7 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
foreach (BaseError error in maybeSong.LeftToSeq()) foreach (BaseError error in maybeSong.LeftToSeq())
{ {
_logger.LogWarning("Error processing song at {Path}: {Error}", file, error.Value); _logger.LogWarning("Error processing song at {Path}: {Error}", file, error.Value);
hasErrors = true;
} }
foreach (MediaItemScanResult<Song> result in maybeSong.RightToSeq()) foreach (MediaItemScanResult<Song> result in maybeSong.RightToSeq())
@ -154,10 +157,14 @@ public class SongFolderScanner : LocalFolderScanner, ISongFolderScanner
{ {
await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id }); await _searchIndex.RebuildItems(_searchRepository, new List<int> { result.Item.Id });
} }
await _libraryRepository.SetEtag(libraryPath, knownFolder, songFolder, etag);
} }
} }
// only do this once per folder and only if all files processed successfully
if (!hasErrors)
{
await _libraryRepository.SetEtag(libraryPath, knownFolder, songFolder, etag);
}
} }
foreach (string path in await _songRepository.FindSongPaths(libraryPath)) foreach (string path in await _songRepository.FindSongPaths(libraryPath))

4
ErsatzTV.Infrastructure/Data/Configurations/Metadata/MusicVideoMetadataConfiguration.cs

@ -29,5 +29,9 @@ public class MusicVideoMetadataConfiguration : IEntityTypeConfiguration<MusicVid
builder.HasMany(mvm => mvm.Subtitles) builder.HasMany(mvm => mvm.Subtitles)
.WithOne() .WithOne()
.OnDelete(DeleteBehavior.Cascade); .OnDelete(DeleteBehavior.Cascade);
builder.HasMany(mvm => mvm.Artists)
.WithOne()
.OnDelete(DeleteBehavior.Cascade);
} }
} }

29
ErsatzTV.Infrastructure/Data/Repositories/LibraryRepository.cs

@ -82,15 +82,6 @@ public class LibraryRepository : ILibraryRepository
.Match(l => l.Paths, () => new List<LibraryPath>()); .Match(l => l.Paths, () => new List<LibraryPath>());
} }
public async Task<Option<LibraryPath>> GetPath(int libraryPathId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.LibraryPaths
.OrderBy(lp => lp.Id)
.SingleOrDefaultAsync(lp => lp.Id == libraryPathId)
.Map(Optional);
}
public async Task<int> CountMediaItemsByPath(int libraryPathId) public async Task<int> CountMediaItemsByPath(int libraryPathId)
{ {
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
@ -99,26 +90,6 @@ public class LibraryRepository : ILibraryRepository
new { LibraryPathId = libraryPathId }); new { LibraryPathId = libraryPathId });
} }
public async Task<List<int>> GetMediaIdsByLocalPath(int libraryPathId)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.QueryAsync<int>(
@"SELECT Id FROM MediaItem WHERE LibraryPathId = @LibraryPathId",
new { LibraryPathId = libraryPathId })
.Map(result => result.ToList());
}
public async Task DeleteLocalPath(int libraryPathId)
{
await using TvContext context = await _dbContextFactory.CreateDbContextAsync();
LibraryPath libraryPath = await context.LibraryPaths.FindAsync(libraryPathId);
if (libraryPath != null)
{
context.LibraryPaths.Remove(libraryPath);
await context.SaveChangesAsync();
}
}
public async Task<Unit> SetEtag( public async Task<Unit> SetEtag(
LibraryPath libraryPath, LibraryPath libraryPath,
Option<LibraryFolder> knownFolder, Option<LibraryFolder> knownFolder,

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

@ -102,6 +102,14 @@ public class MetadataRepository : IMetadataRepository
} }
} }
if (metadata is MusicVideoMetadata musicVideoMetadata)
{
foreach (MusicVideoArtist artist in Optional(musicVideoMetadata.Artists).Flatten())
{
dbContext.Entry(artist).State = EntityState.Added;
}
}
return await dbContext.SaveChangesAsync() > 0; return await dbContext.SaveChangesAsync() > 0;
} }

19
ErsatzTV.Infrastructure/Data/Repositories/MusicVideoRepository.cs

@ -26,6 +26,8 @@ public class MusicVideoRepository : IMusicVideoRepository
.Include(mv => mv.MusicVideoMetadata) .Include(mv => mv.MusicVideoMetadata)
.ThenInclude(mvm => mvm.Artwork) .ThenInclude(mvm => mvm.Artwork)
.Include(mv => mv.MusicVideoMetadata) .Include(mv => mv.MusicVideoMetadata)
.ThenInclude(mvm => mvm.Artists)
.Include(mv => mv.MusicVideoMetadata)
.ThenInclude(mvm => mvm.Genres) .ThenInclude(mvm => mvm.Genres)
.Include(mv => mv.MusicVideoMetadata) .Include(mv => mv.MusicVideoMetadata)
.ThenInclude(mvm => mvm.Tags) .ThenInclude(mvm => mvm.Tags)
@ -100,6 +102,14 @@ public class MusicVideoRepository : IMusicVideoRepository
return ids; return ids;
} }
public async Task<bool> AddArtist(MusicVideoMetadata metadata, MusicVideoArtist artist)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"INSERT INTO MusicVideoArtist (Name, MusicVideoMetadataId) VALUES (@Name, @MetadataId)",
new { artist.Name, MetadataId = metadata.Id }).Map(result => result > 0);
}
public async Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre) public async Task<bool> AddGenre(MusicVideoMetadata metadata, Genre genre)
{ {
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
@ -124,6 +134,15 @@ public class MusicVideoRepository : IMusicVideoRepository
new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0); new { studio.Name, MetadataId = metadata.Id }).Map(result => result > 0);
} }
public async Task<bool> RemoveArtist(MusicVideoArtist artist)
{
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();
return await dbContext.Connection.ExecuteAsync(
"DELETE FROM MusicVideoArtist WHERE Id = @Id",
new { artist.Id })
.Map(result => result > 0);
}
public async Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids) public async Task<List<MusicVideoMetadata>> GetMusicVideosForCards(List<int> ids)
{ {
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(); await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync();

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

@ -73,6 +73,8 @@ public class SearchRepository : ISearchRepository
.Include(mi => (mi as MusicVideo).Artist) .Include(mi => (mi as MusicVideo).Artist)
.ThenInclude(mm => mm.ArtistMetadata) .ThenInclude(mm => mm.ArtistMetadata)
.Include(mi => (mi as MusicVideo).MusicVideoMetadata) .Include(mi => (mi as MusicVideo).MusicVideoMetadata)
.ThenInclude(mm => mm.Artists)
.Include(mi => (mi as MusicVideo).MusicVideoMetadata)
.ThenInclude(mm => mm.Genres) .ThenInclude(mm => mm.Genres)
.Include(mi => (mi as MusicVideo).MusicVideoMetadata) .Include(mi => (mi as MusicVideo).MusicVideoMetadata)
.ThenInclude(mm => mm.Tags) .ThenInclude(mm => mm.Tags)
@ -206,6 +208,8 @@ public class SearchRepository : ISearchRepository
.Include(mi => (mi as MusicVideo).Artist) .Include(mi => (mi as MusicVideo).Artist)
.ThenInclude(mm => mm.ArtistMetadata) .ThenInclude(mm => mm.ArtistMetadata)
.Include(mi => (mi as MusicVideo).MusicVideoMetadata) .Include(mi => (mi as MusicVideo).MusicVideoMetadata)
.ThenInclude(mm => mm.Artists)
.Include(mi => (mi as MusicVideo).MusicVideoMetadata)
.ThenInclude(mm => mm.Genres) .ThenInclude(mm => mm.Genres)
.Include(mi => (mi as MusicVideo).MusicVideoMetadata) .Include(mi => (mi as MusicVideo).MusicVideoMetadata)
.ThenInclude(mm => mm.Tags) .ThenInclude(mm => mm.Tags)

4239
ErsatzTV.Infrastructure/Migrations/20220502133555_Add_MusicVideoArtists.Designer.cs generated

File diff suppressed because it is too large Load Diff

43
ErsatzTV.Infrastructure/Migrations/20220502133555_Add_MusicVideoArtists.cs

@ -0,0 +1,43 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_MusicVideoArtists : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "MusicVideoArtist",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
Name = table.Column<string>(type: "TEXT", nullable: true),
MusicVideoMetadataId = table.Column<int>(type: "INTEGER", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_MusicVideoArtist", x => x.Id);
table.ForeignKey(
name: "FK_MusicVideoArtist_MusicVideoMetadata_MusicVideoMetadataId",
column: x => x.MusicVideoMetadataId,
principalTable: "MusicVideoMetadata",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_MusicVideoArtist_MusicVideoMetadataId",
table: "MusicVideoArtist",
column: "MusicVideoMetadataId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "MusicVideoArtist");
}
}
}

4239
ErsatzTV.Infrastructure/Migrations/20220502171259_Reset_MusicVideoLibraries.Designer.cs generated

File diff suppressed because it is too large Load Diff

34
ErsatzTV.Infrastructure/Migrations/20220502171259_Reset_MusicVideoLibraries.cs

@ -0,0 +1,34 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Reset_MusicVideoLibraries : 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 = 3)");
migrationBuilder.Sql(
@"UPDATE Library SET LastScan = '0001-01-01 00:00:00' WHERE MediaKind = 3");
migrationBuilder.Sql(
@"UPDATE MusicVideoMetadata SET DateUpdated = '0001-01-01 00:00:00'");
migrationBuilder.Sql(
@"DELETE FROM LibraryFolder WHERE Id IN
(SELECT LF.Id FROM LibraryFolder LF
INNER JOIN LibraryPath LP on LP.Id = LF.LibraryPathId
INNER JOIN Library L on L.Id = LP.LibraryId
WHERE L.MediaKind = 3)");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

4239
ErsatzTV.Infrastructure/Migrations/20220502172236_Reset_OtherVideosSongsFolderEtags.Designer.cs generated

File diff suppressed because it is too large Load Diff

23
ErsatzTV.Infrastructure/Migrations/20220502172236_Reset_OtherVideosSongsFolderEtags.cs

@ -0,0 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Reset_OtherVideosSongsFolderEtags : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(
@"DELETE FROM LibraryFolder WHERE Id IN
(SELECT LF.Id FROM LibraryFolder LF
INNER JOIN LibraryPath LP on LP.Id = LF.LibraryPathId
INNER JOIN Library L on L.Id = LP.LibraryId
WHERE L.MediaKind IN (4, 5))");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

29
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -1225,6 +1225,25 @@ namespace ErsatzTV.Infrastructure.Migrations
b.ToTable("MultiCollectionSmartItem"); b.ToTable("MultiCollectionSmartItem");
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoArtist", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("MusicVideoMetadataId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("MusicVideoMetadataId");
b.ToTable("MusicVideoArtist");
});
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b =>
{ {
b.Property<int>("Id") b.Property<int>("Id")
@ -3056,6 +3075,14 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Navigation("SmartCollection"); b.Navigation("SmartCollection");
}); });
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoArtist", b =>
{
b.HasOne("ErsatzTV.Core.Domain.MusicVideoMetadata", null)
.WithMany("Artists")
.HasForeignKey("MusicVideoMetadataId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b => modelBuilder.Entity("ErsatzTV.Core.Domain.MusicVideoMetadata", b =>
{ {
b.HasOne("ErsatzTV.Core.Domain.MusicVideo", "MusicVideo") b.HasOne("ErsatzTV.Core.Domain.MusicVideo", "MusicVideo")
@ -4006,6 +4033,8 @@ namespace ErsatzTV.Infrastructure.Migrations
{ {
b.Navigation("Actors"); b.Navigation("Actors");
b.Navigation("Artists");
b.Navigation("Artwork"); b.Navigation("Artwork");
b.Navigation("Genres"); b.Navigation("Genres");

14
ErsatzTV.Infrastructure/Search/SearchIndex.cs

@ -751,14 +751,26 @@ public sealed class SearchIndex : ISearchIndex
doc.Add(new TextField(StudioField, studio.Name, Field.Store.NO)); doc.Add(new TextField(StudioField, studio.Name, Field.Store.NO));
} }
var artists = new System.Collections.Generic.HashSet<string>();
if (musicVideo.Artist != null) if (musicVideo.Artist != null)
{ {
foreach (ArtistMetadata artistMetadata in musicVideo.Artist.ArtistMetadata) foreach (ArtistMetadata artistMetadata in musicVideo.Artist.ArtistMetadata)
{ {
doc.Add(new TextField(ArtistField, artistMetadata.Title, Field.Store.NO)); artists.Add(artistMetadata.Title);
} }
} }
foreach (MusicVideoArtist artist in metadata.Artists)
{
artists.Add(artist.Name);
}
foreach (string artist in artists)
{
doc.Add(new TextField(ArtistField, artist, Field.Store.NO));
}
_writer.UpdateDocument(new Term(IdField, musicVideo.Id.ToString()), doc); _writer.UpdateDocument(new Term(IdField, musicVideo.Id.ToString()), doc);
} }
catch (Exception ex) catch (Exception ex)

Loading…
Cancel
Save