using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models;
using Kyoo.Abstractions.Models.Attributes;
using Kyoo.Abstractions.Models.Exceptions;
namespace Kyoo.Core.Tasks
{
///
/// A task to register a new episode
///
[TaskMetadata("register", "Register episode", "Register a new episode")]
public class RegisterEpisode : ITask
{
///
/// An identifier to extract metadata from paths.
///
private readonly IIdentifier _identifier;
///
/// The library manager used to register the episode.
///
private readonly ILibraryManager _libraryManager;
///
/// A metadata provider to retrieve the metadata of the new episode (and related items if they do not exist).
///
private readonly AProviderComposite _metadataProvider;
///
/// The thumbnail manager used to download images.
///
private readonly IThumbnailsManager _thumbnailsManager;
///
/// The transcoder used to extract subtitles and metadata.
///
private readonly ITranscoder _transcoder;
///
/// Create a new task.
///
///
/// An identifier to extract metadata from paths.
///
///
/// The library manager used to register the episode.
///
///
/// A metadata provider to retrieve the metadata of the new episode (and related items if they do not exist).
///
///
/// The thumbnail manager used to download images.
///
///
/// The transcoder used to extract subtitles and metadata.
///
public RegisterEpisode(IIdentifier identifier,
ILibraryManager libraryManager,
AProviderComposite metadataProvider,
IThumbnailsManager thumbnailsManager,
ITranscoder transcoder)
{
_identifier = identifier;
_libraryManager = libraryManager;
_metadataProvider = metadataProvider;
_thumbnailsManager = thumbnailsManager;
_transcoder = transcoder;
}
///
public TaskParameters GetParameters()
{
return new()
{
TaskParameter.CreateRequired("path", "The path of the episode file"),
TaskParameter.CreateRequired("library", "The library in witch the episode is")
};
}
///
public async Task Run(TaskParameters arguments, IProgress progress, CancellationToken cancellationToken)
{
string path = arguments["path"].As();
Library library = arguments["library"].As();
progress.Report(0);
if (library != null)
{
if (library.Providers == null)
await _libraryManager.Load(library, x => x.Providers);
_metadataProvider.UseProviders(library.Providers);
}
try
{
(Collection collection, Show show, Season season, Episode episode) = await _identifier.Identify(path);
progress.Report(15);
collection = await _RegisterAndFill(collection);
progress.Report(20);
Show registeredShow = await _RegisterAndFill(show);
if (registeredShow.Path != show.Path)
{
if (show.StartAir.HasValue)
{
show.Slug += $"-{show.StartAir.Value.Year}";
show = await _libraryManager.Create(show);
}
else
{
throw new TaskFailedException($"Duplicated show found ({show.Slug}) " +
$"at {registeredShow.Path} and {show.Path}");
}
}
else
show = registeredShow;
progress.Report(50);
if (season != null)
season.Show = show;
season = await _RegisterAndFill(season);
progress.Report(60);
episode.Show = show;
episode.Season = season;
if (!show.IsMovie)
episode = await _metadataProvider.Get(episode);
progress.Report(70);
episode.Tracks = (await _transcoder.ExtractInfos(episode, false))
.Where(x => x.Type != StreamType.Attachment)
.ToArray();
await _thumbnailsManager.DownloadImages(episode);
progress.Report(90);
await _libraryManager.Create(episode);
progress.Report(95);
await _libraryManager.AddShowLink(show, library, collection);
progress.Report(100);
}
catch (IdentificationFailedException ex)
{
throw new TaskFailedException(ex);
}
catch (DuplicatedItemException ex)
{
throw new TaskFailedException(ex);
}
}
///
/// Retrieve the equivalent item if it already exists in the database,
/// if it does not, fill metadata using the metadata provider, download images and register the item to the
/// database.
///
/// The item to retrieve or fill and register
/// The type of the item
/// The existing or filled item.
private async Task _RegisterAndFill(T item)
where T : class, IResource, IThumbnails, IMetadata
{
if (item == null || string.IsNullOrEmpty(item.Slug))
return null;
T existing = await _libraryManager.GetOrDefault(item.Slug);
if (existing != null)
{
await _libraryManager.Load(existing, x => x.ExternalIDs);
return existing;
}
item = await _metadataProvider.Get(item);
await _thumbnailsManager.DownloadImages(item);
switch (item)
{
case Show show when show.People != null:
foreach (PeopleRole role in show.People)
await _thumbnailsManager.DownloadImages(role.People);
break;
case Season season:
season.Title ??= $"Season {season.SeasonNumber}";
break;
}
return await _libraryManager.CreateIfNotExists(item);
}
}
}