mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Implementing the tvdb provider
This commit is contained in:
parent
ecb4101924
commit
2d45d6422d
@ -35,7 +35,7 @@ namespace Kyoo.Controllers
|
|||||||
/// If this metadata provider does not support <typeparamref name="T"/>.
|
/// If this metadata provider does not support <typeparamref name="T"/>.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
/// <returns>A new <typeparamref name="T"/> containing metadata from your provider</returns>
|
/// <returns>A new <typeparamref name="T"/> containing metadata from your provider</returns>
|
||||||
[ItemNotNull]
|
[ItemCanBeNull]
|
||||||
Task<T> Get<T>([NotNull] T item)
|
Task<T> Get<T>([NotNull] T item)
|
||||||
where T : class, IResource;
|
where T : class, IResource;
|
||||||
|
|
||||||
|
157
Kyoo.TheTvdb/Convertors.cs
Normal file
157
Kyoo.TheTvdb/Convertors.cs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using Kyoo.Models;
|
||||||
|
using TvDbSharper.Dto;
|
||||||
|
|
||||||
|
namespace Kyoo.TheTvdb
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A set of extensions methods used to convert tvdb models to Kyoo models.
|
||||||
|
/// </summary>
|
||||||
|
public static class Convertors
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convert the string representation of the status in the tvdb API to a Kyoo's <see cref="Status"/> enum.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="status">The string representing the status.</param>
|
||||||
|
/// <returns>A kyoo <see cref="Status"/> value or null.</returns>
|
||||||
|
private static Status? GetStatus(string status)
|
||||||
|
{
|
||||||
|
return status switch
|
||||||
|
{
|
||||||
|
"Ended" => Status.Finished,
|
||||||
|
"Continuing" => Status.Airing,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parse a TVDB date and return a <see cref="DateTime"/> or null if the string is invalid.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="date">The date string to parse</param>
|
||||||
|
/// <returns>The parsed <see cref="DateTime"/> or null.</returns>
|
||||||
|
private static DateTime ParseDate(string date)
|
||||||
|
{
|
||||||
|
DateTime.TryParseExact(date, "yyyy-mm-dd", CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsed);
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a series search to a show.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="result">The search result</param>
|
||||||
|
/// <param name="provider">The provider representing the tvdb inside kyoo</param>
|
||||||
|
/// <returns>A show representing the given search result.</returns>
|
||||||
|
public static Show ToShow(this SeriesSearchResult result, Provider provider)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Slug = result.Slug,
|
||||||
|
Title = result.SeriesName,
|
||||||
|
Aliases = result.Aliases,
|
||||||
|
Overview = result.Overview,
|
||||||
|
Status = GetStatus(result.Status),
|
||||||
|
StartAir = ParseDate(result.FirstAired),
|
||||||
|
Poster = result.Poster != null ? $"https://www.thetvdb.com{result.Poster}" : null,
|
||||||
|
ExternalIDs = new[]
|
||||||
|
{
|
||||||
|
new MetadataID<Show>
|
||||||
|
{
|
||||||
|
DataID = result.Id.ToString(),
|
||||||
|
Link = $"https://www.thetvdb.com/series/{result.Slug}",
|
||||||
|
Second = provider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a tvdb series to a kyoo show.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="series">The series to convert</param>
|
||||||
|
/// <param name="provider">The provider representing the tvdb inside kyoo</param>
|
||||||
|
/// <returns>A show representing the given series.</returns>
|
||||||
|
public static Show ToShow(this Series series, Provider provider)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
Slug = series.Slug,
|
||||||
|
Title = series.SeriesName,
|
||||||
|
Aliases = series.Aliases,
|
||||||
|
Overview = series.Overview,
|
||||||
|
Status = GetStatus(series.Status),
|
||||||
|
StartAir = ParseDate(series.FirstAired),
|
||||||
|
Poster = series.Poster != null ? $"https://www.thetvdb.com/banners/{series.Poster}" : null,
|
||||||
|
Backdrop = series.FanArt != null ? $"https://www.thetvdb.com/banners/{series.FanArt}" : null,
|
||||||
|
Genres = series.Genre.Select(y => new Genre(y)).ToList(),
|
||||||
|
ExternalIDs = new[]
|
||||||
|
{
|
||||||
|
new MetadataID<Show>
|
||||||
|
{
|
||||||
|
DataID = series.Id.ToString(),
|
||||||
|
Link = $"https://www.thetvdb.com/series/{series.Slug}",
|
||||||
|
Second = provider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a tvdb actor to a kyoo <see cref="PeopleRole"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="actor">The actor to convert</param>
|
||||||
|
/// <param name="provider">The provider representing the tvdb inside kyoo</param>
|
||||||
|
/// <returns>A people role representing the given actor in the role they played.</returns>
|
||||||
|
public static PeopleRole ToPeopleRole(this Actor actor, Provider provider)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
People = new People
|
||||||
|
{
|
||||||
|
Slug = Utility.ToSlug(actor.Name),
|
||||||
|
Name = actor.Name,
|
||||||
|
Poster = actor.Image != null ? $"https://www.thetvdb.com/banners/{actor.Image}" : null,
|
||||||
|
ExternalIDs = new []
|
||||||
|
{
|
||||||
|
new MetadataID<People>()
|
||||||
|
{
|
||||||
|
DataID = actor.Id.ToString(),
|
||||||
|
Link = $"https://www.thetvdb.com/people/{actor.Id}",
|
||||||
|
Second = provider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Role = actor.Role
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a tvdb episode to a kyoo <see cref="Episode"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="episode">The episode to convert</param>
|
||||||
|
/// <param name="provider">The provider representing the tvdb inside kyoo</param>
|
||||||
|
/// <returns>A episode representing the given tvdb episode.</returns>
|
||||||
|
public static Episode ToEpisode(this EpisodeRecord episode, Provider provider)
|
||||||
|
{
|
||||||
|
return new()
|
||||||
|
{
|
||||||
|
SeasonNumber = episode.AiredSeason,
|
||||||
|
EpisodeNumber = episode.AiredEpisodeNumber,
|
||||||
|
AbsoluteNumber = episode.AbsoluteNumber,
|
||||||
|
Title = episode.EpisodeName,
|
||||||
|
Overview = episode.Overview,
|
||||||
|
Thumb = episode.Filename != null ? $"https://www.thetvdb.com/banners/{episode.Filename}" : null,
|
||||||
|
ExternalIDs = new[]
|
||||||
|
{
|
||||||
|
new MetadataID<Episode>
|
||||||
|
{
|
||||||
|
DataID = episode.Id.ToString(),
|
||||||
|
Link = $"https://www.thetvdb.com/series/{episode.SeriesId}/episodes/{episode.Id}",
|
||||||
|
Second = provider
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Autofac;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace Kyoo.TheTvdb
|
namespace Kyoo.TheTvdb
|
||||||
{
|
{
|
||||||
@ -33,9 +33,9 @@ namespace Kyoo.TheTvdb
|
|||||||
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
|
public void Configure(ContainerBuilder builder)
|
||||||
{
|
{
|
||||||
// services.AddProvider<ProviderTvdb>();
|
builder.RegisterProvider<ProviderTvdb>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using Kyoo.Controllers;
|
using Kyoo.Controllers;
|
||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using TvDbSharper;
|
using TvDbSharper;
|
||||||
@ -15,189 +15,97 @@ namespace Kyoo.TheTvdb
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ProviderTvdb : IMetadataProvider
|
public class ProviderTvdb : IMetadataProvider
|
||||||
{
|
{
|
||||||
public Provider Provider { get; }
|
/// <summary>
|
||||||
public Task<T> Get<T>(T item) where T : class, IResource
|
/// The internal tvdb client used to make requests.
|
||||||
|
/// </summary>
|
||||||
|
private readonly TvDbClient _client = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The API key used to authenticate with the tvdb API.
|
||||||
|
/// </summary>
|
||||||
|
private readonly string _apiKey;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public Provider Provider => new()
|
||||||
{
|
{
|
||||||
|
Slug = "the-tvdb",
|
||||||
|
Name = "TheTVDB",
|
||||||
|
LogoExtension = "png",
|
||||||
|
Logo = "https://www.thetvdb.com/images/logo.png"
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
public ProviderTvdb(string apiKey)
|
||||||
|
{
|
||||||
|
_apiKey = apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task _Authenticate()
|
||||||
|
{
|
||||||
|
if (_client.Authentication.Token == null)
|
||||||
|
return _client.Authentication.AuthenticateAsync(_apiKey);
|
||||||
|
return _client.Authentication.RefreshTokenAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<T> Get<T>(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,
|
||||||
|
_ => throw new NotSupportedException()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[ItemCanBeNull]
|
||||||
|
private async Task<Show> _GetShow([NotNull] Show show)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(show.GetID(Provider.Slug), out int id))
|
||||||
|
return (await _SearchShow(show.Title)).FirstOrDefault();
|
||||||
|
TvDbResponse<Series> series = await _client.Series.GetAsync(id);
|
||||||
|
return series.Data.ToShow(Provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ItemCanBeNull]
|
||||||
|
private async Task<Episode> _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<EpisodeRecord[]> episodes = await _client.Series.GetEpisodesAsync(id, 0, query);
|
||||||
|
return episodes.Data.FirstOrDefault()?.ToEpisode(Provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task<ICollection<T>> Search<T>(string query)
|
||||||
|
where T : class, IResource
|
||||||
|
{
|
||||||
|
await _Authenticate();
|
||||||
|
if (typeof(T) == typeof(Show))
|
||||||
|
return (await _SearchShow(query) as ICollection<T>)!;
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ICollection<T>> Search<T>(string query) where T : class, IResource
|
[ItemNotNull]
|
||||||
|
private async Task<ICollection<Show>> _SearchShow(string query)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
TvDbResponse<SeriesSearchResult[]> shows = await _client.Search.SearchSeriesByNameAsync(query);
|
||||||
|
return shows.Data.Select(x => x.ToShow(Provider)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ICollection<PeopleRole>> GetPeople(Show show)
|
/// <inheritdoc />
|
||||||
|
public async Task<ICollection<PeopleRole>> GetPeople(Show show)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
||||||
|
return null;
|
||||||
|
await _Authenticate();
|
||||||
|
TvDbResponse<Actor[]> people = await _client.Series.GetActorsAsync(id);
|
||||||
|
return people.Data.Select(x => x.ToPeopleRole(Provider)).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// public class Old
|
|
||||||
// {
|
|
||||||
// private static readonly ProviderID _provider = new()
|
|
||||||
// {
|
|
||||||
// Slug = "the-tvdb",
|
|
||||||
// Name = "TheTVDB",
|
|
||||||
// LogoExtension = "png",
|
|
||||||
// Logo = "https://www.thetvdb.com/images/logo.png"
|
|
||||||
// };
|
|
||||||
// public ProviderID Provider => _provider;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// private readonly TvDbClient _client = new();
|
|
||||||
//
|
|
||||||
// private Task Authentificate()
|
|
||||||
// {
|
|
||||||
// if (_client.Authentication.Token == null)
|
|
||||||
// return _client.Authentication.AuthenticateAsync(APIKey);
|
|
||||||
// return _client.Authentication.RefreshTokenAsync();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public Task<Collection> GetCollectionFromName(string name)
|
|
||||||
// {
|
|
||||||
// return Task.FromResult<Collection>(null);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public async Task<ICollection<Show>> SearchShows(string showName, bool isMovie)
|
|
||||||
// {
|
|
||||||
// await Authentificate();
|
|
||||||
//
|
|
||||||
// if (isMovie)
|
|
||||||
// return null; //There is no movie search API for now on TheTVDB.
|
|
||||||
// TvDbResponse<SeriesSearchResult[]> shows = await _client.Search.SearchSeriesAsync(showName, SearchParameter.Name);
|
|
||||||
// return shows.Data.Select(x => x.ToShow(Provider)).ToArray();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public async Task<Show> GetShowByID(Show show)
|
|
||||||
// {
|
|
||||||
// if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
|
||||||
// return await Task.FromResult<Show>(null);
|
|
||||||
// await Authentificate();
|
|
||||||
// TvDbResponse<Series> serie = await _client.Series.GetAsync(id);
|
|
||||||
// return serie.Data.ToShow(Provider);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public async Task<ICollection<PeopleRole>> GetPeople(Show show)
|
|
||||||
// {
|
|
||||||
// if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
|
||||||
// return null;
|
|
||||||
// await Authentificate();
|
|
||||||
// TvDbResponse<Actor[]> people = await _client.Series.GetActorsAsync(id);
|
|
||||||
// return people.Data.Select(x => x.ToPeopleRole(Provider)).ToArray();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public Task<Season> GetSeason(Show show, int seasonNumber)
|
|
||||||
// {
|
|
||||||
// return Task.FromResult<Season>(null);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public async Task<Episode> GetEpisode(Show show, int seasonNumber, int episodeNumber, int absoluteNumber)
|
|
||||||
// {
|
|
||||||
// if (!int.TryParse(show?.GetID(Provider.Name), out int id))
|
|
||||||
// return null;
|
|
||||||
// await Authentificate();
|
|
||||||
// TvDbResponse<EpisodeRecord[]> episodes = absoluteNumber != -1
|
|
||||||
// ? await _client.Series.GetEpisodesAsync(id, 0, new EpisodeQuery {AbsoluteNumber = absoluteNumber})
|
|
||||||
// : await _client.Series.GetEpisodesAsync(id, 0, new EpisodeQuery {AiredSeason = seasonNumber, AiredEpisode = episodeNumber});
|
|
||||||
// EpisodeRecord x = episodes.Data[0];
|
|
||||||
//
|
|
||||||
// if (absoluteNumber == -1)
|
|
||||||
// absoluteNumber = x.AbsoluteNumber ?? -1;
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// seasonNumber = x.AiredSeason ?? -1;
|
|
||||||
// episodeNumber = x.AiredEpisodeNumber ?? -1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return new Episode(seasonNumber,
|
|
||||||
// episodeNumber,
|
|
||||||
// absoluteNumber,
|
|
||||||
// x.EpisodeName,
|
|
||||||
// x.Overview,
|
|
||||||
// DateTime.ParseExact(x.FirstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture),
|
|
||||||
// -1,
|
|
||||||
// x.Filename != null ? "https://www.thetvdb.com/banners/" + x.Filename : null,
|
|
||||||
// new []
|
|
||||||
// {
|
|
||||||
// new MetadataID(Provider, x.Id.ToString(), $"https://www.thetvdb.com/series/{id}/episodes/{x.Id}")
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public static class Convertors
|
|
||||||
// {
|
|
||||||
// private static int? GetYear(string firstAired)
|
|
||||||
// {
|
|
||||||
// if (firstAired?.Length >= 4 && int.TryParse(firstAired.Substring(0, 4), out int year))
|
|
||||||
// return year;
|
|
||||||
// return null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private static Status? GetStatus(string status)
|
|
||||||
// {
|
|
||||||
// return status switch
|
|
||||||
// {
|
|
||||||
// "Ended" => Status.Finished,
|
|
||||||
// "Continuing" => Status.Airing,
|
|
||||||
// _ => null
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static Show ToShow(this SeriesSearchResult x, ProviderID provider)
|
|
||||||
// {
|
|
||||||
// Show ret = new(x.Slug,
|
|
||||||
// x.SeriesName,
|
|
||||||
// x.Aliases,
|
|
||||||
// null,
|
|
||||||
// x.Overview,
|
|
||||||
// null,
|
|
||||||
// null,
|
|
||||||
// GetStatus(x.Status),
|
|
||||||
// GetYear(x.FirstAired),
|
|
||||||
// null,
|
|
||||||
// new[]
|
|
||||||
// {
|
|
||||||
// new MetadataID(provider, x.Id.ToString(), $"https://www.thetvdb.com/series/{x.Slug}")
|
|
||||||
// });
|
|
||||||
// if (x.Poster != null)
|
|
||||||
// Utility.SetImage(ret, $"https://www.thetvdb.com{x.Poster}", ImageType.Poster);
|
|
||||||
// return ret;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static Show ToShow(this Series x, ProviderID provider)
|
|
||||||
// {
|
|
||||||
// return new(x.Slug,
|
|
||||||
// x.SeriesName,
|
|
||||||
// x.Aliases,
|
|
||||||
// null,
|
|
||||||
// x.Overview,
|
|
||||||
// null,
|
|
||||||
// x.Genre.Select(y => new Genre(Utility.ToSlug(y), y)),
|
|
||||||
// GetStatus(x.Status),
|
|
||||||
// GetYear(x.FirstAired),
|
|
||||||
// null,
|
|
||||||
// new[]
|
|
||||||
// {
|
|
||||||
// new MetadataID(provider, x.Id.ToString(),$"https://www.thetvdb.com/series/{x.Slug}")
|
|
||||||
// })
|
|
||||||
// {
|
|
||||||
// Poster = x.Poster != null ? $"https://www.thetvdb.com/banners/{x.Poster}" : null,
|
|
||||||
// Backdrop = x.FanArt != null ? $"https://www.thetvdb.com/banners/{x.FanArt}" : null
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// public static PeopleRole ToPeopleRole(this Actor x, ProviderID provider)
|
|
||||||
// {
|
|
||||||
// return new (Utility.ToSlug(x.Name),
|
|
||||||
// x.Name,
|
|
||||||
// x.Role,
|
|
||||||
// null,
|
|
||||||
// x.Image != null ? $"https://www.thetvdb.com/banners/{x.Image}" : null,
|
|
||||||
// new[]
|
|
||||||
// {
|
|
||||||
// new MetadataID(provider, x.Id.ToString(), $"https://www.thetvdb.com/people/{x.Id}")
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user