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; } } } }