@ -1,28 +1,35 @@
@@ -1,28 +1,35 @@
using System ;
using System.IO ;
using System.Text.RegularExpressions ;
using System.Threading.Tasks ;
using System.Xml.Serialization ;
using ErsatzTV.Core.Domain ;
using ErsatzTV.Core.Interfaces.Metadata ;
using ErsatzTV.Core.Interfaces.Repositories ;
using LanguageExt ;
using Microsoft.Extensions.Logging ;
using static LanguageExt . Prelude ;
namespace ErsatzTV.Core.Metadata
{
public class LocalMetadataProvider : ILocalMetadataProvider
{
private static readonly XmlSerializer MovieSerializer = new ( typeof ( MovieNfo ) ) ;
private static readonly XmlSerializer TvShowSerializer = new ( typeof ( TvShowEpisodeNfo ) ) ;
private readonly ILogger < LocalMetadataProvider > _l ogger ;
private readonly IMediaItemRepository _ mediaItemRepository ;
public LocalMetadataProvider ( IMediaItemRepository mediaItemRepository ) = >
public LocalMetadataProvider ( IMediaItemRepository mediaItemRepository , ILogger < LocalMetadataProvider > logger )
{
_ mediaItemRepository = mediaItemRepository ;
_l ogger = logger ;
}
public async Task RefreshMetadata ( MediaItem mediaItem )
{
Option < MediaMetadata > maybeMetadata = await LoadMetadata ( mediaItem ) ;
MediaMetadata metadata =
maybeMetadata . IfNone ( ( ) = > FallbackMetadataProvider . GetFallbackMetadata ( mediaItem . Path ) ) ;
maybeMetadata . IfNone ( ( ) = > FallbackMetadataProvider . GetFallbackMetadata ( mediaItem ) ) ;
await ApplyMetadataUpdate ( mediaItem , metadata ) ;
}
@ -50,54 +57,72 @@ namespace ErsatzTV.Core.Metadata
@@ -50,54 +57,72 @@ namespace ErsatzTV.Core.Metadata
string nfoFileName = Path . ChangeExtension ( mediaItem . Path , "nfo" ) ;
if ( nfoFileName = = null | | ! File . Exists ( nfoFileName ) )
{
_l ogger . LogDebug ( "NFO file does not exist at {Path}" , nfoFileName ) ;
return None ;
}
if ( ! ( mediaItem . Source is LocalMediaSource localMediaSource ) )
{
_l ogger . LogDebug ( "Media source {Name} is not a local media source" , mediaItem . Source . Name ) ;
return None ;
}
var tvShowSerializer = new XmlSerializer ( typeof ( TvShowEpisodeNfo ) ) ;
var movieSerializer = new XmlSerializer ( typeof ( MovieNfo ) ) ;
TryAsync < object > tvShowAttempt = TryAsync (
async ( ) = >
{
await using FileStream fileStream = File . Open ( nfoFileName , FileMode . Open ) ;
return tvShowSerializer . Deserialize ( fileStream ) ;
} ) ;
TryAsync < object > movieAttempt = TryAsync (
async ( ) = >
{
await using FileStream fileStream = File . Open ( nfoFileName , FileMode . Open ) ;
return movieSerializer . Deserialize ( fileStream ) ;
} ) ;
return await choice ( tvShowAttempt , movieAttempt ) . Match < object , Option < MediaMetadata > > (
result = >
{
switch ( result )
return localMediaSource . MediaType switch
{
MediaType . Movie = > await LoadMovieMetadata ( nfoFileName ) ,
MediaType . TvShow = > await LoadTvShowMetadata ( nfoFileName ) ,
_ = > None
} ;
}
private async Task < Option < MediaMetadata > > LoadTvShowMetadata ( string nfoFileName )
{
try
{
await using FileStream fileStream = File . Open ( nfoFileName , FileMode . Open , FileAccess . Read ) ;
Option < TvShowEpisodeNfo > maybeNfo = TvShowSerializer . Deserialize ( fileStream ) as TvShowEpisodeNfo ;
return maybeNfo . Match < Option < MediaMetadata > > (
nfo = > new MediaMetadata
{
case TvShowEpisodeNfo nfo :
return new MediaMetadata
{
MediaType = MediaType . TvShow ,
Title = nfo . ShowTitle ,
Subtitle = nfo . Title ,
Description = nfo . Outline ,
EpisodeNumber = nfo . Episode ,
SeasonNumber = nfo . Season ,
Aired = GetAired ( nfo . Aired )
} ;
case MovieNfo nfo :
return new MediaMetadata
{
MediaType = MediaType . Movie ,
Title = nfo . Title ,
Description = nfo . Outline ,
ContentRating = nfo . ContentRating ,
Aired = GetAired ( nfo . Premiered )
} ;
default :
return None ;
}
} ,
None ) ;
MediaType = MediaType . TvShow ,
Title = nfo . ShowTitle ,
Subtitle = nfo . Title ,
Description = nfo . Outline ,
EpisodeNumber = nfo . Episode ,
SeasonNumber = nfo . Season ,
Aired = GetAired ( nfo . Aired )
} ,
None ) ;
}
catch ( Exception ex )
{
_l ogger . LogDebug ( ex , "Failed to read TV nfo metadata from {Path}" , nfoFileName ) ;
return None ;
}
}
private async Task < Option < MediaMetadata > > LoadMovieMetadata ( string nfoFileName )
{
try
{
await using FileStream fileStream = File . Open ( nfoFileName , FileMode . Open , FileAccess . Read ) ;
Option < MovieNfo > maybeNfo = MovieSerializer . Deserialize ( fileStream ) as MovieNfo ;
return maybeNfo . Match < Option < MediaMetadata > > (
nfo = > new MediaMetadata
{
MediaType = MediaType . Movie ,
Title = nfo . Title ,
Description = nfo . Outline ,
ContentRating = nfo . ContentRating ,
Aired = GetAired ( nfo . Premiered )
} ,
None ) ;
}
catch ( Exception ex )
{
_l ogger . LogDebug ( ex , "Failed to read Movie nfo metadata from {Path}" , nfoFileName ) ;
return None ;
}
}
private static DateTime ? GetAired ( string aired )