using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Kyoo.Authentication.Models;
using Kyoo.Controllers;
using Kyoo.Models;
using Microsoft.Extensions.Options;
using TvDbSharper;
using TvDbSharper.Dto;
namespace Kyoo.TheTvdb
{
///
/// A metadata provider for The TVDB.
///
public class ProviderTvdb : IMetadataProvider
{
///
/// The internal tvdb client used to make requests.
///
private readonly ITvDbClient _client;
///
/// The API key used to authenticate with the tvdb API.
///
private readonly IOptions _apiKey;
///
public Provider Provider => new()
{
Slug = "the-tvdb",
Name = "TheTVDB",
LogoExtension = "png",
Logo = "https://www.thetvdb.com/images/logo.png"
};
///
/// Create a new using a tvdb client and an api key.
///
/// The tvdb client to use
/// The api key
public ProviderTvdb(ITvDbClient client, IOptions apiKey)
{
_client = client;
_apiKey = apiKey;
}
///
/// Authenticate and refresh the token of the tvdb client.
///
private Task _Authenticate()
{
if (_client.Authentication.Token == null)
return _client.Authentication.AuthenticateAsync(_apiKey.Value.ApiKey);
return _client.Authentication.RefreshTokenAsync();
}
///
public async Task Get(T item)
where T : class, IResource
{
await _Authenticate();
return item switch
{
Show show => await _GetShow(show) as T,
Episode episode => await _GetEpisode(episode) as T,
_ => null
};
}
///
/// Retrieve metadata about a show.
///
/// The base show to retrieve metadata for.
/// A new show filled with metadata from the tvdb.
[ItemCanBeNull]
private async Task _GetShow([NotNull] Show show)
{
if (!int.TryParse(show.GetID(Provider.Slug), out int id))
{
Show found = (await _SearchShow(show.Title)).FirstOrDefault();
if (found == null)
return null;
return await Get(found);
}
TvDbResponse series = await _client.Series.GetAsync(id);
Show ret = series.Data.ToShow(Provider);
TvDbResponse people = await _client.Series.GetActorsAsync(id);
ret.People = people.Data.Select(x => x.ToPeopleRole(Provider)).ToArray();
return ret;
}
///
/// Retrieve metadata about an episode.
///
/// The base episode to retrieve metadata for.
/// A new episode filled with metadata from the tvdb.
[ItemCanBeNull]
private async Task _GetEpisode([NotNull] Episode episode)
{
if (!int.TryParse(episode.Show?.GetID(Provider.Slug), out int id))
return null;
EpisodeQuery query = episode.AbsoluteNumber != null
? new EpisodeQuery {AbsoluteNumber = episode.AbsoluteNumber}
: new EpisodeQuery {AiredSeason = episode.SeasonNumber, AiredEpisode = episode.EpisodeNumber};
TvDbResponse episodes = await _client.Series.GetEpisodesAsync(id, 0, query);
return episodes.Data.FirstOrDefault()?.ToEpisode(Provider);
}
///
public async Task> Search(string query)
where T : class, IResource
{
await _Authenticate();
if (typeof(T) == typeof(Show))
return (await _SearchShow(query) as ICollection)!;
return ArraySegment.Empty;
}
///
/// Search for shows in the tvdb.
///
/// The query to ask the tvdb about.
/// A list of shows that could be found on the tvdb.
[ItemNotNull]
private async Task> _SearchShow(string query)
{
try
{
TvDbResponse shows = await _client.Search.SearchSeriesByNameAsync(query);
return shows.Data.Select(x => x.ToShow(Provider)).ToArray();
}
catch (TvDbServerException)
{
return ArraySegment.Empty;
}
}
}
}