Working with the provider for TheTvDB.

This commit is contained in:
Zoe Roux 2019-08-05 04:00:31 +02:00
parent 054a2718b7
commit 880434186e
9 changed files with 229 additions and 19 deletions

3
.gitignore vendored
View File

@ -337,4 +337,5 @@ ASALocalRun/
.localhistory/ .localhistory/
# BeatPulse healthcheck temp database # BeatPulse healthcheck temp database
healthchecksdb healthchecksdb
/Kyoo/TheTVDB-Credentials.json

View File

@ -40,7 +40,7 @@ namespace Kyoo.InternalAPI
return null; return null;
} }
public void Scan(string folderPath) public async void Scan(string folderPath)
{ {
string[] files = Directory.GetFiles(folderPath); string[] files = Directory.GetFiles(folderPath);
@ -50,7 +50,7 @@ namespace Kyoo.InternalAPI
{ {
Debug.WriteLine("&Should insert this: " + file); Debug.WriteLine("&Should insert this: " + file);
string patern = @".*\\(?<ShowTitle>.+?) S(?<Season>\d+)E(?<Episode>\d+)"; string patern = config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase); Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
Match match = regex.Match(file); Match match = regex.Match(file);
@ -63,7 +63,10 @@ namespace Kyoo.InternalAPI
if(!libraryManager.IsShowRegistered(ShowPath)) if(!libraryManager.IsShowRegistered(ShowPath))
{ {
Show show = metadataProvider.GetShowFromName(ShowTitle); Show show = await metadataProvider.GetShowFromName(ShowTitle);
Debug.WriteLine("&Show Name: " + show.Title + " Overview: " + show.Overview);
//long showID = libraryManager.RegisterShow(show);
} }
} }
} }

View File

@ -27,7 +27,7 @@ namespace Kyoo.InternalAPI
string createStatement = @"CREATE TABLE shows( string createStatement = @"CREATE TABLE shows(
id INTEGER PRIMARY KEY UNIQUE, id INTEGER PRIMARY KEY UNIQUE,
uri TEXT UNIQUE, slug TEXT UNIQUE,
title TEXT, title TEXT,
aliases TEXT, aliases TEXT,
path TEXT, path TEXT,
@ -94,7 +94,7 @@ namespace Kyoo.InternalAPI
CREATE TABLE libraries( CREATE TABLE libraries(
id INTEGER PRIMARY KEY UNIQUE, id INTEGER PRIMARY KEY UNIQUE,
uri TEXT UNIQUE, slug TEXT UNIQUE,
name TEXT name TEXT
); );
CREATE TABLE librariesLinks( CREATE TABLE librariesLinks(
@ -106,7 +106,7 @@ namespace Kyoo.InternalAPI
CREATE TABLE studios( CREATE TABLE studios(
id INTEGER PRIMARY KEY UNIQUE, id INTEGER PRIMARY KEY UNIQUE,
uri TEXT UNIQUE, slug TEXT UNIQUE,
name TEXT name TEXT
); );
CREATE TABLE studiosLinks( CREATE TABLE studiosLinks(
@ -118,7 +118,7 @@ namespace Kyoo.InternalAPI
CREATE TABLE people( CREATE TABLE people(
id INTEGER PRIMARY KEY UNIQUE, id INTEGER PRIMARY KEY UNIQUE,
uri TEXT UNIQUE, slug TEXT UNIQUE,
name TEXT, name TEXT,
imgPrimary TEXT, imgPrimary TEXT,
externalIDs TEXT externalIDs TEXT
@ -134,7 +134,7 @@ namespace Kyoo.InternalAPI
CREATE TABLE genres( CREATE TABLE genres(
id INTEGER PRIMARY KEY UNIQUE, id INTEGER PRIMARY KEY UNIQUE,
uri TEXT UNIQUE, slug TEXT UNIQUE,
name TEXT name TEXT
); );
CREATE TABLE genresLinks( CREATE TABLE genresLinks(

View File

@ -1,9 +1,12 @@
using Kyoo.Models; using Kyoo.Models;
using System.Threading.Tasks;
namespace Kyoo.InternalAPI namespace Kyoo.InternalAPI
{ {
public interface IMetadataProvider public interface IMetadataProvider
{ {
Show GetShowFromName(string showName); Task<Show> GetShowFromID(string externalIDs);
Task<Show> GetShowFromName(string showName);
} }
} }

View File

@ -1,12 +1,164 @@
using Kyoo.Models; using Kyoo.Models;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
namespace Kyoo.InternalAPI.MetadataProvider namespace Kyoo.InternalAPI.MetadataProvider
{ {
public class ProviderTheTvDB : IMetadataProvider public class ProviderTheTvDB : ProviderHelper, IMetadataProvider
{ {
public Show GetShowFromName(string showName) public override string Provider => "TvDB";
private struct DataTvDB
{ {
throw new System.NotImplementedException(); public string seriesName;
public string overview;
public string slug;
public string network;
public string status;
public int id;
public string firstAired;
public string banner;
public string[] aliases;
}
async Task<string> Authentificate()
{
WebRequest request = WebRequest.Create("https://api.thetvdb.com/login");
request.Method = "POST";
request.Timeout = 12000;
request.ContentType = "application/json";
string json = "{ \"apikey\": \"IM2OXA8UHUIU0GH6\" }";
byte[] bytes = Encoding.ASCII.GetBytes(json);
request.ContentLength = bytes.Length;
using (Stream stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
}
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
if(response.StatusCode == HttpStatusCode.OK)
{
Stream stream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
string content = await reader.ReadToEndAsync();
stream.Close();
response.Close();
var obj = new { Token = "" };
return JsonConvert.DeserializeAnonymousType(content, obj).Token;
}
}
else
Debug.WriteLine("&Couldn't authentificate in TheTvDB API.\nError status: " + response.StatusCode + " Message: " + response.StatusDescription);
return null;
}
public async Task<Show> GetShowFromName(string showName)
{
string token = await Authentificate();
Debug.WriteLine("&Sucess, token = " + token);
if (token != null)
{
WebRequest request = WebRequest.Create("https://api.thetvdb.com/search/series?name=" + HttpUtility.HtmlEncode(showName));
request.Method = "GET";
request.Timeout = 12000;
request.ContentType = "application/json";
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream stream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
string content = await reader.ReadToEndAsync();
stream.Close();
response.Close();
var model = new { data = new DataTvDB[0] };
DataTvDB data = JsonConvert.DeserializeAnonymousType(content, model).data[0];
long? startYear = null;
if (!long.TryParse(data.firstAired?.Substring(4), out long year))
startYear = year;
Show show = new Show(-1, ToSlug(showName), data.seriesName, data.aliases?.ToList(), data.overview, null, startYear, null, null, null, null, null, null, string.Format("{0}={1}|", Provider, data.id));
return await GetShowFromID(show.ExternalIDs) ?? show;
}
}
else
{
Debug.WriteLine("&TheTvDB Provider couldn't work for this show: " + showName + ".\nError Code: " + response.StatusCode + " Message: " + response.StatusDescription);
response.Close();
}
}
return new Show() { Slug = ToSlug(showName), Title = showName };
}
public async Task<Show> GetShowFromID(string externalIDs)
{
string id = GetId(externalIDs);
if (id == null)
return null;
string token = await Authentificate();
if (token == null)
return null;
WebRequest request = WebRequest.Create("https://api.thetvdb.com/search/series/" + id);
request.Method = "GET";
request.Timeout = 12000;
request.ContentType = "application/json";
request.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + token);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream stream = response.GetResponseStream();
using (StreamReader reader = new StreamReader(stream))
{
string content = await reader.ReadToEndAsync();
stream.Close();
response.Close();
var model = new { data = new DataTvDB[0] };
DataTvDB data = JsonConvert.DeserializeAnonymousType(content, model).data[0];
long? startYear = null;
if (!long.TryParse(data.firstAired?.Substring(4), out long year))
startYear = year;
Show show = new Show(-1, ToSlug(showName), data.seriesName, data.aliases?.ToList(), data.overview, null, startYear, null, null, null, null, null, null, string.Format("TvDB={0}|", data.id));
return await GetShowFromID(show.ExternalIDs) ?? show;
}
}
else
{
Debug.WriteLine("&TheTvDB Provider couldn't work for the show with the id: " + id + ".\nError Code: " + response.StatusCode + " Message: " + response.StatusDescription);
response.Close();
return null;
}
} }
} }
} }

View File

@ -0,0 +1,48 @@
using System.Text;
using System.Text.RegularExpressions;
namespace Kyoo.InternalAPI.MetadataProvider
{
public abstract class ProviderHelper
{
public abstract string Provider { get; }
public string GetId(string externalIDs)
{
if (externalIDs.Contains(Provider))
{
int startIndex = externalIDs.IndexOf(Provider) + Provider.Length;
return externalIDs.Substring(startIndex, externalIDs.IndexOf('|', startIndex) - startIndex);
}
else
return null;
}
public string ToSlug(string showTitle)
{
if (showTitle == null)
return null;
//First to lower case
showTitle = showTitle.ToLowerInvariant();
//Remove all accents
//var bytes = Encoding.GetEncoding("Cyrillic").GetBytes(showTitle);
//showTitle = Encoding.ASCII.GetString(bytes);
//Replace spaces
showTitle = Regex.Replace(showTitle, @"\s", "-", RegexOptions.Compiled);
//Remove invalid chars
showTitle = Regex.Replace(showTitle, @"[^\w\s\p{Pd}]", "", RegexOptions.Compiled);
//Trim dashes from end
showTitle = showTitle.Trim('-', '_');
//Replace double occurences of - or \_
showTitle = Regex.Replace(showTitle, @"([-_]){2,}", "$1", RegexOptions.Compiled);
return showTitle;
}
}
}

View File

@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" /> <PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.1.1" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.1.1" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" /> <PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="System.Data.SQLite" Version="1.0.111" /> <PackageReference Include="System.Data.SQLite" Version="1.0.111" />
</ItemGroup> </ItemGroup>

View File

@ -5,9 +5,9 @@ namespace Kyoo.Models
{ {
public class Show public class Show
{ {
public readonly long id; public readonly long id = -1;
public string Uri; public string Slug;
public string Title; public string Title;
public List<string> Aliases; public List<string> Aliases;
public string Overview; public string Overview;
@ -24,11 +24,12 @@ namespace Kyoo.Models
public string ExternalIDs; public string ExternalIDs;
public Show() { }
public Show(long id, string uri, string title, List<string> aliases, string overview, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgBanner, string imgLogo, string imgBackdrop, string externalIDs) public Show(long id, string slug, string title, List<string> aliases, string overview, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgBanner, string imgLogo, string imgBackdrop, string externalIDs)
{ {
this.id = id; this.id = id;
Uri = uri; Slug = slug;
Title = title; Title = title;
Aliases = aliases; Aliases = aliases;
Overview = overview; Overview = overview;
@ -46,7 +47,7 @@ namespace Kyoo.Models
public static Show FromReader(System.Data.SQLite.SQLiteDataReader reader) public static Show FromReader(System.Data.SQLite.SQLiteDataReader reader)
{ {
return new Show((long)reader["id"], return new Show((long)reader["id"],
reader["uri"] as string, reader["slug"] as string,
reader["title"] as string, reader["title"] as string,
(reader["aliases"] as string)?.Split('|').ToList() ?? null, (reader["aliases"] as string)?.Split('|').ToList() ?? null,
reader["overview"] as string, reader["overview"] as string,

View File

@ -2,5 +2,6 @@
"databasePath": "C://Projects/database.db", "databasePath": "C://Projects/database.db",
"libraryPaths": [ "libraryPaths": [
"D:\\Videos" "D:\\Videos"
] ],
"regex": ".*\\\\(?<ShowTitle>.+?) S(?<Season>\\d+)E(?<Episode>\\d+)"
} }