Browse Source

add `metadata_kind` to search index (#790)

* more nfo cleanup

* add metadata_kind to search index
pull/791/head
Jason Dove 4 years ago committed by GitHub
parent
commit
ab10f0ed81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      CHANGELOG.md
  2. 4
      ErsatzTV.Core/Metadata/Nfo/ArtistNfoReader.cs
  3. 4
      ErsatzTV.Core/Metadata/Nfo/EpisodeNfoReader.cs
  4. 4
      ErsatzTV.Core/Metadata/Nfo/MovieNfoReader.cs
  5. 4
      ErsatzTV.Core/Metadata/Nfo/MusicVideoNfoReader.cs
  6. 4
      ErsatzTV.Core/Metadata/Nfo/OtherVideoNfoReader.cs
  7. 4
      ErsatzTV.Core/Metadata/Nfo/TvShowNfoReader.cs
  8. 24
      ErsatzTV.Infrastructure/Search/SearchIndex.cs

4
CHANGELOG.md

@ -7,6 +7,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
- Reduce memory use due to library scan operations - Reduce memory use due to library scan operations
### Added
- Add `metadata_kind` field to search index to allow searching for items with a particular metdata source
- Valid metadata kinds are `fallback`, `sidecar` (NFO), `external` (from a media server) and `embedded` (songs)
### Changed ### Changed
- Replace invalid (control) characters in NFO metadata with replacement character `<EFBFBD>` before parsing - Replace invalid (control) characters in NFO metadata with replacement character `<EFBFBD>` before parsing
- Store partial (incomplete) NFO metadata results when invalid XML is encountered - Store partial (incomplete) NFO metadata results when invalid XML is encountered

4
ErsatzTV.Core/Metadata/Nfo/ArtistNfoReader.cs

@ -95,9 +95,7 @@ public class ArtistNfoReader : NfoReader<ArtistNfo>, IArtistNfoReader
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());
} }
catch (XmlException ex) when (ex.Message.Contains( catch (XmlException)
"invalid character",
StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.LogWarning("Invalid XML detected; returning incomplete metadata"); _logger.LogWarning("Invalid XML detected; returning incomplete metadata");
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());

4
ErsatzTV.Core/Metadata/Nfo/EpisodeNfoReader.cs

@ -114,9 +114,7 @@ public class EpisodeNfoReader : NfoReader<TvShowEpisodeNfo>, IEpisodeNfoReader
return result; return result;
} }
catch (XmlException ex) when (ex.Message.Contains( catch (XmlException)
"invalid character",
StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.LogWarning("Invalid XML detected; returning incomplete metadata"); _logger.LogWarning("Invalid XML detected; returning incomplete metadata");
return result; return result;

4
ErsatzTV.Core/Metadata/Nfo/MovieNfoReader.cs

@ -126,9 +126,7 @@ public class MovieNfoReader : NfoReader<MovieNfo>, IMovieNfoReader
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());
} }
catch (XmlException ex) when (ex.Message.Contains( catch (XmlException)
"invalid character",
StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.LogWarning("Invalid XML detected; returning incomplete metadata"); _logger.LogWarning("Invalid XML detected; returning incomplete metadata");
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());

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

@ -108,9 +108,7 @@ public class MusicVideoNfoReader : NfoReader<MusicVideoNfo>, IMusicVideoNfoReade
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());
} }
catch (XmlException ex) when (ex.Message.Contains( catch (XmlException)
"invalid character",
StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.LogWarning("Invalid XML detected; returning incomplete metadata"); _logger.LogWarning("Invalid XML detected; returning incomplete metadata");
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());

4
ErsatzTV.Core/Metadata/Nfo/OtherVideoNfoReader.cs

@ -126,9 +126,7 @@ public class OtherVideoNfoReader : NfoReader<OtherVideoNfo>, IOtherVideoNfoReade
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());
} }
catch (XmlException ex) when (ex.Message.Contains( catch (XmlException)
"invalid character",
StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.LogWarning("Invalid XML detected; returning incomplete metadata"); _logger.LogWarning("Invalid XML detected; returning incomplete metadata");
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());

4
ErsatzTV.Core/Metadata/Nfo/TvShowNfoReader.cs

@ -112,9 +112,7 @@ public class TvShowNfoReader : NfoReader<TvShowNfo>, ITvShowNfoReader
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());
} }
catch (XmlException ex) when (ex.Message.Contains( catch (XmlException)
"invalid character",
StringComparison.InvariantCultureIgnoreCase))
{ {
_logger.LogWarning("Invalid XML detected; returning incomplete metadata"); _logger.LogWarning("Invalid XML detected; returning incomplete metadata");
return Optional(nfo).ToEither((BaseError)new FailedToReadNfo()); return Optional(nfo).ToEither((BaseError)new FailedToReadNfo());

24
ErsatzTV.Infrastructure/Search/SearchIndex.cs

@ -54,6 +54,7 @@ public sealed class SearchIndex : ISearchIndex
private const string ShowTitleField = "show_title"; private const string ShowTitleField = "show_title";
private const string ShowGenreField = "show_genre"; private const string ShowGenreField = "show_genre";
private const string ShowTagField = "show_tag"; private const string ShowTagField = "show_tag";
private const string MetadataKindField = "metadata_kind";
internal const string MinutesField = "minutes"; internal const string MinutesField = "minutes";
internal const string HeightField = "height"; internal const string HeightField = "height";
@ -87,7 +88,7 @@ public sealed class SearchIndex : ISearchIndex
_initialized = false; _initialized = false;
} }
public int Version => 24; public int Version => 25;
public async Task<bool> Initialize( public async Task<bool> Initialize(
ILocalFileSystem localFileSystem, ILocalFileSystem localFileSystem,
@ -363,7 +364,8 @@ public sealed class SearchIndex : ISearchIndex
new StringField(LibraryIdField, movie.LibraryPath.Library.Id.ToString(), Field.Store.NO), new StringField(LibraryIdField, movie.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO), new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES), new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new StringField(StateField, movie.State.ToString(), Field.Store.NO) new StringField(StateField, movie.State.ToString(), Field.Store.NO),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
await AddLanguages(searchRepository, doc, movie.MediaVersions); await AddLanguages(searchRepository, doc, movie.MediaVersions);
@ -500,7 +502,8 @@ public sealed class SearchIndex : ISearchIndex
new StringField(LibraryIdField, show.LibraryPath.Library.Id.ToString(), Field.Store.NO), new StringField(LibraryIdField, show.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO), new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES), new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new StringField(StateField, show.State.ToString(), Field.Store.NO) new StringField(StateField, show.State.ToString(), Field.Store.NO),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
List<string> languages = await searchRepository.GetLanguagesForShow(show); List<string> languages = await searchRepository.GetLanguagesForShow(show);
@ -670,7 +673,8 @@ public sealed class SearchIndex : ISearchIndex
new TextField(LibraryNameField, artist.LibraryPath.Library.Name, Field.Store.NO), new TextField(LibraryNameField, artist.LibraryPath.Library.Name, Field.Store.NO),
new StringField(LibraryIdField, artist.LibraryPath.Library.Id.ToString(), Field.Store.NO), new StringField(LibraryIdField, artist.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO), new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES) new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
List<string> languages = await searchRepository.GetLanguagesForArtist(artist); List<string> languages = await searchRepository.GetLanguagesForArtist(artist);
@ -722,7 +726,8 @@ public sealed class SearchIndex : ISearchIndex
new StringField(LibraryIdField, musicVideo.LibraryPath.Library.Id.ToString(), Field.Store.NO), new StringField(LibraryIdField, musicVideo.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO), new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES), new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new StringField(StateField, musicVideo.State.ToString(), Field.Store.NO) new StringField(StateField, musicVideo.State.ToString(), Field.Store.NO),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
await AddLanguages(searchRepository, doc, musicVideo.MediaVersions); await AddLanguages(searchRepository, doc, musicVideo.MediaVersions);
@ -818,7 +823,8 @@ public sealed class SearchIndex : ISearchIndex
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES), new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new StringField(StateField, episode.State.ToString(), Field.Store.NO), new StringField(StateField, episode.State.ToString(), Field.Store.NO),
new Int32Field(SeasonNumberField, episode.Season?.SeasonNumber ?? 0, Field.Store.NO), new Int32Field(SeasonNumberField, episode.Season?.SeasonNumber ?? 0, Field.Store.NO),
new Int32Field(EpisodeNumberField, metadata.EpisodeNumber, Field.Store.NO) new Int32Field(EpisodeNumberField, metadata.EpisodeNumber, Field.Store.NO),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
// add some show fields to help filter episodes within a particular show // add some show fields to help filter episodes within a particular show
@ -938,7 +944,8 @@ public sealed class SearchIndex : ISearchIndex
new StringField(LibraryIdField, otherVideo.LibraryPath.Library.Id.ToString(), Field.Store.NO), new StringField(LibraryIdField, otherVideo.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO), new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES), new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new StringField(StateField, otherVideo.State.ToString(), Field.Store.NO) new StringField(StateField, otherVideo.State.ToString(), Field.Store.NO),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
await AddLanguages(searchRepository, doc, otherVideo.MediaVersions); await AddLanguages(searchRepository, doc, otherVideo.MediaVersions);
@ -1036,7 +1043,8 @@ public sealed class SearchIndex : ISearchIndex
new StringField(LibraryIdField, song.LibraryPath.Library.Id.ToString(), Field.Store.NO), new StringField(LibraryIdField, song.LibraryPath.Library.Id.ToString(), Field.Store.NO),
new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO), new StringField(TitleAndYearField, GetTitleAndYear(metadata), Field.Store.NO),
new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES), new StringField(JumpLetterField, GetJumpLetter(metadata), Field.Store.YES),
new StringField(StateField, song.State.ToString(), Field.Store.NO) new StringField(StateField, song.State.ToString(), Field.Store.NO),
new TextField(MetadataKindField, metadata.MetadataKind.ToString(), Field.Store.NO)
}; };
await AddLanguages(searchRepository, doc, song.MediaVersions); await AddLanguages(searchRepository, doc, song.MediaVersions);

Loading…
Cancel
Save