mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-24 02:02:36 -04:00
Creating the provider manager
This commit is contained in:
parent
9d37426764
commit
3d79d41a60
@ -5,8 +5,8 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
public interface ICrawler
|
||||
{
|
||||
Task Start(bool watch);
|
||||
void Start();
|
||||
|
||||
Task StopAsync();
|
||||
void Cancel();
|
||||
}
|
||||
}
|
||||
|
@ -63,9 +63,9 @@ namespace Kyoo.Controllers
|
||||
long GetOrCreateGenre(Genre genre);
|
||||
long GetOrCreateStudio(Studio studio);
|
||||
|
||||
void RegisterShowPeople(long showID, List<People> actors);
|
||||
void RegisterShowPeople(long showID, IEnumerable<People> actors);
|
||||
void AddShowToCollection(long showID, long collectionID);
|
||||
void RegisterInLibrary(long showID, string libraryPath);
|
||||
void RegisterInLibrary(long showID, Library library);
|
||||
|
||||
void RemoveEpisode(Episode episode);
|
||||
void ClearSubtitles(long episodeID);
|
||||
|
@ -6,18 +6,18 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
public interface IMetadataProvider
|
||||
{
|
||||
public string Name { get; }
|
||||
|
||||
//For the collection
|
||||
Task<Collection> GetCollectionFromName(string name);
|
||||
|
||||
//For the show
|
||||
Task<Show> GetShowByID(string id);
|
||||
Task<Show> GetShowFromName(string showName, string showPath);
|
||||
Task<Show> GetImages(Show show);
|
||||
Task<List<People>> GetPeople(string id);
|
||||
Task<IEnumerable<People>> GetPeople(string id);
|
||||
|
||||
//For the seasons
|
||||
Task<Season> GetSeason(string showName, long seasonNumber);
|
||||
Task<string> GetSeasonImage(string showName, long seasonNumber);
|
||||
|
||||
//For the episodes
|
||||
Task<Episode> GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath);
|
||||
|
15
Kyoo.Common/Controllers/IProviderManager.cs
Normal file
15
Kyoo.Common/Controllers/IProviderManager.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Models;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public interface IProviderManager
|
||||
{
|
||||
Task<Collection> GetCollectionFromName(string name, Library library);
|
||||
Task<Show> GetShowFromName(string showName, string showPath, Library library);
|
||||
Task<Season> GetSeason(string showName, long seasonNumber, Library library);
|
||||
Task<Episode> GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library);
|
||||
Task<IEnumerable<People>> GetPeople(string showExternalIDs, Library library);
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ namespace Kyoo.Controllers.ThumbnailsManager
|
||||
public interface IThumbnailsManager
|
||||
{
|
||||
Task<Show> Validate(Show show);
|
||||
Task<List<People>> Validate(List<People> actors);
|
||||
Task<IEnumerable<People>> Validate(IEnumerable<People> actors);
|
||||
Task<Episode> Validate(Episode episode);
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,76 @@
|
||||
using Kyoo.Controllers;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Utility;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class Collection
|
||||
public class Collection : IMergable<Collection>
|
||||
|
||||
{
|
||||
[JsonIgnore] public long id;
|
||||
public string Slug;
|
||||
public string Name;
|
||||
public string Poster;
|
||||
public string Overview;
|
||||
[JsonIgnore] public string ImgPrimary;
|
||||
public IEnumerable<Show> Shows;
|
||||
[JsonIgnore] public long id = -1;
|
||||
public string Slug;
|
||||
public string Name;
|
||||
public string Poster;
|
||||
public string Overview;
|
||||
[JsonIgnore] public string ImgPrimary;
|
||||
public IEnumerable<Show> Shows;
|
||||
|
||||
public Collection() { }
|
||||
public Collection()
|
||||
{
|
||||
}
|
||||
|
||||
public Collection(long id, string slug, string name, string overview, string imgPrimary)
|
||||
{
|
||||
this.id = id;
|
||||
Slug = slug;
|
||||
Name = name;
|
||||
Overview = overview;
|
||||
ImgPrimary = imgPrimary;
|
||||
}
|
||||
public Collection(long id, string slug, string name, string overview, string imgPrimary)
|
||||
{
|
||||
this.id = id;
|
||||
Slug = slug;
|
||||
Name = name;
|
||||
Overview = overview;
|
||||
ImgPrimary = imgPrimary;
|
||||
}
|
||||
|
||||
public static Collection FromReader(System.Data.SQLite.SQLiteDataReader reader)
|
||||
{
|
||||
Collection col = new Collection((long)reader["id"],
|
||||
reader["slug"] as string,
|
||||
reader["name"] as string,
|
||||
reader["overview"] as string,
|
||||
reader["imgPrimary"] as string);
|
||||
col.Poster = "poster/" + col.Slug;
|
||||
return col;
|
||||
}
|
||||
public static Collection FromReader(System.Data.SQLite.SQLiteDataReader reader)
|
||||
{
|
||||
Collection col = new Collection((long) reader["id"],
|
||||
reader["slug"] as string,
|
||||
reader["name"] as string,
|
||||
reader["overview"] as string,
|
||||
reader["imgPrimary"] as string);
|
||||
col.Poster = "poster/" + col.Slug;
|
||||
return col;
|
||||
}
|
||||
|
||||
public Show AsShow()
|
||||
{
|
||||
return new Show(-1, Slug, Name, null, null, Overview, null, null, null, null, null, null);
|
||||
}
|
||||
public Show AsShow()
|
||||
{
|
||||
return new Show(-1, Slug, Name, null, null, Overview, null, null, null, null, null, null);
|
||||
}
|
||||
|
||||
public Collection SetShows(ILibraryManager libraryManager)
|
||||
{
|
||||
Shows = libraryManager.GetShowsInCollection(id);
|
||||
return this;
|
||||
}
|
||||
public Collection SetShows(ILibraryManager libraryManager)
|
||||
{
|
||||
Shows = libraryManager.GetShowsInCollection(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Collection Merge(Collection collection)
|
||||
{
|
||||
if (id == -1)
|
||||
id = collection.id;
|
||||
if (Slug == null)
|
||||
Slug = collection.Slug;
|
||||
if (Name == null)
|
||||
Name = collection.Name;
|
||||
if (Poster == null)
|
||||
Poster = collection.Poster;
|
||||
if (Overview == null)
|
||||
Overview = collection.Overview;
|
||||
if (ImgPrimary == null)
|
||||
ImgPrimary = collection.ImgPrimary;
|
||||
if (Shows == null)
|
||||
Shows = collection.Shows;
|
||||
else
|
||||
Shows = Shows.Concat(collection.Shows);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using Kyoo.Utility;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class Episode
|
||||
public class Episode : IMergable<Episode>
|
||||
{
|
||||
[JsonIgnore] public long id;
|
||||
[JsonIgnore] public long ShowID;
|
||||
@ -97,5 +98,35 @@ namespace Kyoo.Models
|
||||
{
|
||||
return showSlug + "-s" + seasonNumber + "e" + episodeNumber;
|
||||
}
|
||||
|
||||
public Episode Merge(Episode other)
|
||||
{
|
||||
if (id == -1)
|
||||
id = other.id;
|
||||
if (ShowID == -1)
|
||||
ShowID = other.ShowID;
|
||||
if (SeasonID == -1)
|
||||
SeasonID = other.SeasonID;
|
||||
if (seasonNumber == -1)
|
||||
seasonNumber = other.seasonNumber;
|
||||
if (episodeNumber == -1)
|
||||
episodeNumber = other.episodeNumber;
|
||||
if (absoluteNumber == -1)
|
||||
absoluteNumber = other.absoluteNumber;
|
||||
if (Path == null)
|
||||
Path = other.Path;
|
||||
if (Title == null)
|
||||
Title = other.Title;
|
||||
if (Overview == null)
|
||||
Overview = other.Overview;
|
||||
if (ReleaseDate == null)
|
||||
ReleaseDate = other.ReleaseDate;
|
||||
if (Runtime == -1)
|
||||
Runtime = other.Runtime;
|
||||
if (ImgPrimary == null)
|
||||
ImgPrimary = other.ImgPrimary;
|
||||
ExternalIDs += '|' + other.ExternalIDs;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,14 +7,16 @@ namespace Kyoo.Models
|
||||
[JsonIgnore] public readonly long id;
|
||||
public string Slug;
|
||||
public string Name;
|
||||
public string Path;
|
||||
public string[] Paths;
|
||||
public string[] Providers;
|
||||
|
||||
public Library(long id, string slug, string name, string path)
|
||||
public Library(long id, string slug, string name, string[] paths, string[] providers)
|
||||
{
|
||||
this.id = id;
|
||||
Slug = slug;
|
||||
Name = name;
|
||||
Path = path;
|
||||
Paths = paths;
|
||||
Providers = providers;
|
||||
}
|
||||
|
||||
public static Library FromReader(System.Data.SQLite.SQLiteDataReader reader)
|
||||
@ -22,7 +24,8 @@ namespace Kyoo.Models
|
||||
return new Library((long)reader["id"],
|
||||
reader["slug"] as string,
|
||||
reader["name"] as string,
|
||||
reader["path"] as string);
|
||||
(reader["path"] as string)?.Split('|'),
|
||||
(reader["providers"] as string)?.Split('|'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
using Newtonsoft.Json;
|
||||
using Kyoo.Utility;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class People
|
||||
public class People : IMergable<People>
|
||||
{
|
||||
[JsonIgnore] public long id;
|
||||
public string slug;
|
||||
@ -52,5 +53,23 @@ namespace Kyoo.Models
|
||||
reader["imgPrimary"] as string,
|
||||
reader["externalIDs"] as string);
|
||||
}
|
||||
|
||||
public People Merge(People other)
|
||||
{
|
||||
if (id == -1)
|
||||
id = other.id;
|
||||
if (slug == null)
|
||||
slug = other.slug;
|
||||
if (Name == null)
|
||||
Name = other.Name;
|
||||
if (Role == null)
|
||||
Role = other.Role;
|
||||
if (Type == null)
|
||||
Type = other.Type;
|
||||
if (imgPrimary == null)
|
||||
imgPrimary = other.imgPrimary;
|
||||
externalIDs += '|' + other.externalIDs;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using Kyoo.Utility;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class Season
|
||||
public class Season : IMergable<Season>
|
||||
{
|
||||
[JsonIgnore] public readonly long id;
|
||||
[JsonIgnore] public long ShowID;
|
||||
@ -40,5 +42,23 @@ namespace Kyoo.Models
|
||||
reader["imgPrimary"] as string,
|
||||
reader["externalIDs"] as string);
|
||||
}
|
||||
|
||||
public Season Merge(Season other)
|
||||
{
|
||||
if (ShowID == -1)
|
||||
ShowID = other.ShowID;
|
||||
if (seasonNumber == -1)
|
||||
seasonNumber = other.seasonNumber;
|
||||
if (Title == null)
|
||||
Title = other.Title;
|
||||
if (Overview == null)
|
||||
Overview = other.Overview;
|
||||
if (year == null)
|
||||
year = other.year;
|
||||
if (ImgPrimary == null)
|
||||
ImgPrimary = other.ImgPrimary;
|
||||
ExternalIDs += '|' + other.ExternalIDs;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
using Kyoo.Controllers;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Utility;
|
||||
|
||||
namespace Kyoo.Models
|
||||
{
|
||||
public class Show
|
||||
public class Show : IMergable<Show>
|
||||
{
|
||||
[JsonIgnore] public long id = -1;
|
||||
|
||||
@ -111,7 +113,7 @@ namespace Kyoo.Models
|
||||
return new Show((long)reader["id"],
|
||||
reader["slug"] as string,
|
||||
reader["title"] as string,
|
||||
(reader["aliases"] as string)?.Split('|') ?? null,
|
||||
(reader["aliases"] as string)?.Split('|'),
|
||||
reader["path"] as string,
|
||||
reader["overview"] as string,
|
||||
reader["trailerUrl"] as string,
|
||||
@ -161,6 +163,46 @@ namespace Kyoo.Models
|
||||
seasons = manager.GetSeasons(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Show Merge(Show other)
|
||||
{
|
||||
if (id == -1)
|
||||
id = other.id;
|
||||
if (Slug == null)
|
||||
Slug = other.Slug;
|
||||
if (Title == null)
|
||||
Title = other.Title;
|
||||
if (Aliases == null)
|
||||
Aliases = other.Aliases;
|
||||
else
|
||||
Aliases = Aliases.Concat(other.Aliases);
|
||||
if (Genres == null)
|
||||
Genres = other.Genres;
|
||||
else
|
||||
Genres = Genres.Concat(other.Genres);
|
||||
if (Path == null)
|
||||
Path = other.Path;
|
||||
if (Overview == null)
|
||||
Overview = other.Overview;
|
||||
if (TrailerUrl == null)
|
||||
TrailerUrl = other.TrailerUrl;
|
||||
if (Status == null)
|
||||
Status = other.Status;
|
||||
if (StartYear == null)
|
||||
StartYear = other.StartYear;
|
||||
if (EndYear == null)
|
||||
EndYear = other.EndYear;
|
||||
if (ImgPrimary == null)
|
||||
ImgPrimary = other.ImgPrimary;
|
||||
if (ImgThumb == null)
|
||||
ImgThumb = other.ImgThumb;
|
||||
if (ImgLogo == null)
|
||||
ImgLogo = other.ImgLogo;
|
||||
if (ImgBackdrop == null)
|
||||
ImgBackdrop = other.ImgBackdrop;
|
||||
ExternalIDs += '|' + other.ExternalIDs;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Status { Finished, Airing }
|
||||
|
9
Kyoo.Common/Utility/IMergable.cs
Normal file
9
Kyoo.Common/Utility/IMergable.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Kyoo.Utility
|
||||
{
|
||||
public interface IMergable<T>
|
||||
{
|
||||
public T Merge(T other);
|
||||
}
|
||||
}
|
@ -14,16 +14,15 @@ namespace Kyoo.Controllers
|
||||
{
|
||||
public class Crawler : ICrawler
|
||||
{
|
||||
private static ICrawler runningCrawler;
|
||||
private bool isScanning;
|
||||
private bool isRunning;
|
||||
private readonly CancellationTokenSource cancellation;
|
||||
|
||||
private readonly ILibraryManager libraryManager;
|
||||
private readonly IMetadataProvider metadataProvider;
|
||||
private readonly IProviderManager metadataProvider;
|
||||
private readonly ITranscoder transcoder;
|
||||
private readonly IConfiguration config;
|
||||
|
||||
public Crawler(ILibraryManager libraryManager, IMetadataProvider metadataProvider, ITranscoder transcoder, IConfiguration configuration)
|
||||
public Crawler(ILibraryManager libraryManager, IProviderManager metadataProvider, ITranscoder transcoder, IConfiguration configuration)
|
||||
{
|
||||
this.libraryManager = libraryManager;
|
||||
this.metadataProvider = metadataProvider;
|
||||
@ -32,30 +31,27 @@ namespace Kyoo.Controllers
|
||||
cancellation = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
public async Task Start(bool watch)
|
||||
public void Start()
|
||||
{
|
||||
if (runningCrawler == null)
|
||||
{
|
||||
runningCrawler = this;
|
||||
await StartAsync(watch, cancellation.Token);
|
||||
}
|
||||
else if (runningCrawler is Crawler crawler)
|
||||
{
|
||||
if (!crawler.isScanning)
|
||||
{
|
||||
await crawler.StopAsync();
|
||||
runningCrawler = this;
|
||||
await StartAsync(watch, cancellation.Token);
|
||||
}
|
||||
}
|
||||
if (isRunning)
|
||||
return;
|
||||
isRunning = true;
|
||||
StartAsync(cancellation.Token);
|
||||
}
|
||||
|
||||
private Task StartAsync(bool watch, CancellationToken cancellationToken)
|
||||
public void Cancel()
|
||||
{
|
||||
if (!isRunning)
|
||||
return;
|
||||
isRunning = false;
|
||||
cancellation.Cancel();
|
||||
}
|
||||
|
||||
private async void StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
IEnumerable<Episode> episodes = libraryManager.GetAllEpisodes();
|
||||
IEnumerable<string> libraryPaths = libraryManager.GetLibrariesPath();
|
||||
IEnumerable<Library> libraries = libraryManager.GetLibraries();
|
||||
|
||||
isScanning = true;
|
||||
Debug.WriteLine("&Crawler started");
|
||||
foreach (Episode episode in episodes)
|
||||
{
|
||||
@ -63,106 +59,46 @@ namespace Kyoo.Controllers
|
||||
libraryManager.RemoveEpisode(episode);
|
||||
}
|
||||
|
||||
foreach (string path in libraryPaths)
|
||||
{
|
||||
Scan(path, cancellationToken);
|
||||
foreach (Library library in libraries)
|
||||
await Scan(library, cancellationToken);
|
||||
|
||||
if(watch)
|
||||
Watch(path, cancellationToken);
|
||||
}
|
||||
|
||||
isScanning = false;
|
||||
if (watch)
|
||||
while (!cancellationToken.IsCancellationRequested);
|
||||
isRunning = false;
|
||||
Debug.WriteLine("&Crawler stopped");
|
||||
runningCrawler = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
private async void Scan(string folderPath, CancellationToken cancellationToken)
|
||||
private async Task Scan(Library library, CancellationToken cancellationToken)
|
||||
{
|
||||
string[] files = Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories);
|
||||
IEnumerable<string> files = new List<string>();
|
||||
|
||||
files = library.Paths.Aggregate(files, (current, path) =>
|
||||
current.Concat(Directory.GetFiles(path, "*", SearchOption.AllDirectories)));
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
if (IsVideo(file))
|
||||
{
|
||||
Debug.WriteLine("&Registering episode at: " + file);
|
||||
await ExtractEpisodeData(file, folderPath);
|
||||
}
|
||||
if (!IsVideo(file))
|
||||
continue;
|
||||
await RegisterFile(file, library);
|
||||
}
|
||||
}
|
||||
|
||||
private void Watch(string folderPath, CancellationToken cancellationToken)
|
||||
private async Task RegisterFile(string path, Library library)
|
||||
{
|
||||
Debug.WriteLine("Folder watching not implemented yet.");
|
||||
//Debug.WriteLine("&Watching " + folderPath + " for changes");
|
||||
//using (FileSystemWatcher watcher = new FileSystemWatcher())
|
||||
//{
|
||||
// watcher.Path = folderPath;
|
||||
// watcher.IncludeSubdirectories = true;
|
||||
// watcher.NotifyFilter = NotifyFilters.LastAccess
|
||||
// | NotifyFilters.LastWrite
|
||||
// | NotifyFilters.FileName
|
||||
// | NotifyFilters.Size
|
||||
// | NotifyFilters.DirectoryName;
|
||||
|
||||
// watcher.Created += FileCreated;
|
||||
// watcher.Changed += FileChanged;
|
||||
// watcher.Renamed += FileRenamed;
|
||||
// watcher.Deleted += FileDeleted;
|
||||
|
||||
|
||||
// watcher.EnableRaisingEvents = true;
|
||||
|
||||
// while (!cancellationToken.IsCancellationRequested);
|
||||
//}
|
||||
}
|
||||
|
||||
//private void FileCreated(object sender, FileSystemEventArgs e)
|
||||
//{
|
||||
// Debug.WriteLine("&File Created at " + e.FullPath);
|
||||
// if (IsVideo(e.FullPath))
|
||||
// {
|
||||
// Debug.WriteLine("&Created file is a video");
|
||||
// _ = TryRegisterEpisode(e.FullPath);
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void FileChanged(object sender, FileSystemEventArgs e)
|
||||
//{
|
||||
// Debug.WriteLine("&File Changed at " + e.FullPath);
|
||||
//}
|
||||
|
||||
//private void FileRenamed(object sender, RenamedEventArgs e)
|
||||
//{
|
||||
// Debug.WriteLine("&File Renamed at " + e.FullPath);
|
||||
//}
|
||||
|
||||
//private void FileDeleted(object sender, FileSystemEventArgs e)
|
||||
//{
|
||||
// Debug.WriteLine("&File Deleted at " + e.FullPath);
|
||||
//}
|
||||
|
||||
private async Task ExtractEpisodeData(string episodePath, string libraryPath)
|
||||
{
|
||||
if (!libraryManager.IsEpisodeRegistered(episodePath))
|
||||
if (!libraryManager.IsEpisodeRegistered(path))
|
||||
{
|
||||
string relativePath = episodePath.Substring(libraryPath.Length);
|
||||
string relativePath = path.Substring(library.Paths.Length);
|
||||
string patern = config.GetValue<string>("regex");
|
||||
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
|
||||
Match match = regex.Match(relativePath);
|
||||
|
||||
string showPath = Path.GetDirectoryName(episodePath);
|
||||
string showPath = Path.GetDirectoryName(path);
|
||||
string collectionName = match.Groups["Collection"]?.Value;
|
||||
string showName = match.Groups["ShowTitle"].Value;
|
||||
bool seasonSuccess = long.TryParse(match.Groups["Season"].Value, out long seasonNumber);
|
||||
bool episodeSucess = long.TryParse(match.Groups["Episode"].Value, out long episodeNumber);
|
||||
long absoluteNumber = -1;
|
||||
|
||||
Debug.WriteLine("&Registering episode at: " + path);
|
||||
if (!seasonSuccess || !episodeSucess)
|
||||
{
|
||||
//Considering that the episode is using absolute path.
|
||||
@ -182,37 +118,37 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
Show show = await RegisterOrGetShow(collectionName, showName, showPath, libraryPath);
|
||||
Show show = await RegisterOrGetShow(collectionName, showName, showPath, library);
|
||||
if (show != null)
|
||||
await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, episodePath);
|
||||
await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, path, library);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Show> RegisterOrGetShow(string collectionName, string showTitle, string showPath, string libraryPath)
|
||||
private async Task<Show> RegisterOrGetShow(string collectionName, string showTitle, string showPath, Library library)
|
||||
{
|
||||
string showProviderIDs;
|
||||
|
||||
if (!libraryManager.IsShowRegistered(showPath, out long showID))
|
||||
{
|
||||
Show show = await metadataProvider.GetShowFromName(showTitle, showPath);
|
||||
Show show = await metadataProvider.GetShowFromName(showTitle, showPath, library);
|
||||
showProviderIDs = show.ExternalIDs;
|
||||
showID = libraryManager.RegisterShow(show);
|
||||
|
||||
if (showID == -1)
|
||||
return null;
|
||||
|
||||
libraryManager.RegisterInLibrary(showID, libraryPath);
|
||||
libraryManager.RegisterInLibrary(showID, library);
|
||||
if (!string.IsNullOrEmpty(collectionName))
|
||||
{
|
||||
if (!libraryManager.IsCollectionRegistered(Slugifier.ToSlug(collectionName), out long collectionID))
|
||||
{
|
||||
Collection collection = await metadataProvider.GetCollectionFromName(collectionName);
|
||||
Collection collection = await metadataProvider.GetCollectionFromName(collectionName, library);
|
||||
collectionID = libraryManager.RegisterCollection(collection);
|
||||
}
|
||||
libraryManager.AddShowToCollection(showID, collectionID);
|
||||
}
|
||||
|
||||
List<People> actors = await metadataProvider.GetPeople(show.ExternalIDs);
|
||||
IEnumerable<People> actors = await metadataProvider.GetPeople(show.ExternalIDs, library);
|
||||
libraryManager.RegisterShowPeople(showID, actors);
|
||||
}
|
||||
else
|
||||
@ -221,27 +157,27 @@ namespace Kyoo.Controllers
|
||||
return new Show { id = showID, ExternalIDs = showProviderIDs, Title = showTitle };
|
||||
}
|
||||
|
||||
private async Task RegisterEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath)
|
||||
private async Task RegisterEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library)
|
||||
{
|
||||
long seasonID = -1;
|
||||
if (seasonNumber != -1)
|
||||
{
|
||||
if (!libraryManager.IsSeasonRegistered(show.id, seasonNumber, out seasonID))
|
||||
{
|
||||
Season season = await metadataProvider.GetSeason(show.Title, seasonNumber);
|
||||
Season season = await metadataProvider.GetSeason(show.Title, seasonNumber, library);
|
||||
season.ShowID = show.id;
|
||||
seasonID = libraryManager.RegisterSeason(season);
|
||||
}
|
||||
}
|
||||
|
||||
Episode episode = await metadataProvider.GetEpisode(show.ExternalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath);
|
||||
Episode episode = await metadataProvider.GetEpisode(show.ExternalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath, library);
|
||||
episode.ShowID = show.id;
|
||||
|
||||
if (seasonID == -1)
|
||||
{
|
||||
if (!libraryManager.IsSeasonRegistered(show.id, episode.seasonNumber, out seasonID))
|
||||
{
|
||||
Season season = await metadataProvider.GetSeason(show.Title, episode.seasonNumber);
|
||||
Season season = await metadataProvider.GetSeason(show.Title, episode.seasonNumber, library);
|
||||
season.ShowID = show.id;
|
||||
seasonID = libraryManager.RegisterSeason(season);
|
||||
}
|
||||
@ -263,18 +199,15 @@ namespace Kyoo.Controllers
|
||||
libraryManager.RegisterTrack(track);
|
||||
}
|
||||
|
||||
if (episode.Path.EndsWith(".mkv"))
|
||||
if (episode.Path.EndsWith(".mkv") && CountExtractedSubtitles(episode) != subcount)
|
||||
{
|
||||
if (CountExtractedSubtitles(episode) != subcount)
|
||||
Track[] subtitles = await transcoder.ExtractSubtitles(episode.Path);
|
||||
if (subtitles != null)
|
||||
{
|
||||
Track[] subtitles = await transcoder.ExtractSubtitles(episode.Path);
|
||||
if (subtitles != null)
|
||||
foreach (Track track in subtitles)
|
||||
{
|
||||
foreach (Track track in subtitles)
|
||||
{
|
||||
track.episodeID = episode.id;
|
||||
libraryManager.RegisterTrack(track);
|
||||
}
|
||||
track.episodeID = episode.id;
|
||||
libraryManager.RegisterTrack(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ namespace Kyoo.Controllers
|
||||
sqlConnection = new SQLiteConnection($"Data Source={databasePath};Version=3");
|
||||
sqlConnection.Open();
|
||||
|
||||
string createStatement = @"CREATE TABLE shows(
|
||||
const string createStatement = @"CREATE TABLE shows(
|
||||
id INTEGER PRIMARY KEY UNIQUE,
|
||||
slug TEXT UNIQUE,
|
||||
title TEXT,
|
||||
@ -92,7 +92,8 @@ namespace Kyoo.Controllers
|
||||
id INTEGER PRIMARY KEY UNIQUE,
|
||||
slug TEXT UNIQUE,
|
||||
name TEXT,
|
||||
path TEXT
|
||||
path TEXT,
|
||||
providers TEXT
|
||||
);
|
||||
CREATE TABLE librariesLinks(
|
||||
libraryID INTEGER,
|
||||
@ -209,10 +210,11 @@ namespace Kyoo.Controllers
|
||||
|
||||
public string GetShowExternalIDs(long showID)
|
||||
{
|
||||
string query = string.Format("SELECT * FROM shows WHERE id = {0};", showID);
|
||||
|
||||
string query = "SELECT * FROM shows WHERE id = $showID;";
|
||||
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$showID", showID);
|
||||
SQLiteDataReader reader = cmd.ExecuteReader();
|
||||
|
||||
if (reader.Read())
|
||||
@ -949,13 +951,14 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterInLibrary(long showID, string libraryPath)
|
||||
public void RegisterInLibrary(long showID, Library library)
|
||||
{
|
||||
string query = "INSERT INTO librariesLinks (libraryID, showID) SELECT id, $showID FROM libraries WHERE libraries.path = $libraryPath;";
|
||||
string query =
|
||||
"INSERT INTO librariesLinks (libraryID, showID) SELECT id, $showID FROM libraries WHERE libraries.id = $libraryID;";
|
||||
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$libraryPath", libraryPath);
|
||||
cmd.Parameters.AddWithValue("$libraryID", library.id);
|
||||
cmd.Parameters.AddWithValue("$showID", showID);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
@ -1102,21 +1105,21 @@ namespace Kyoo.Controllers
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterShowPeople(long showID, List<People> people)
|
||||
public void RegisterShowPeople(long showID, IEnumerable<People> people)
|
||||
{
|
||||
if (people == null)
|
||||
return;
|
||||
|
||||
string linkQuery = "INSERT INTO peopleLinks (peopleID, showID, role, type) VALUES($peopleID, $showID, $role, $type);";
|
||||
|
||||
for (int i = 0; i < people.Count; i++)
|
||||
foreach (People peop in people)
|
||||
{
|
||||
using (SQLiteCommand cmd = new SQLiteCommand(linkQuery, sqlConnection))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("$peopleID", GetOrCreatePeople(people[i]));
|
||||
cmd.Parameters.AddWithValue("$peopleID", GetOrCreatePeople(peop));
|
||||
cmd.Parameters.AddWithValue("$showID", showID);
|
||||
cmd.Parameters.AddWithValue("$role", people[i].Role);
|
||||
cmd.Parameters.AddWithValue("$type", people[i].Type);
|
||||
cmd.Parameters.AddWithValue("$role", peop.Role);
|
||||
cmd.Parameters.AddWithValue("$type", peop.Type);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
@ -1,124 +1,87 @@
|
||||
using Kyoo.Models;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System;
|
||||
using System;
|
||||
using Kyoo.Models;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Controllers.ThumbnailsManager;
|
||||
using Kyoo.Utility;
|
||||
|
||||
namespace Kyoo.Controllers
|
||||
{
|
||||
public class ProviderManager : IMetadataProvider
|
||||
public class ProviderManager : IProviderManager
|
||||
{
|
||||
private readonly IEnumerable<IMetadataProvider> providers;
|
||||
private readonly IThumbnailsManager thumbnailsManager;
|
||||
private readonly IConfiguration config;
|
||||
|
||||
public ProviderManager(IThumbnailsManager thumbnailsManager, IPluginManager pluginManager, IConfiguration config)
|
||||
public ProviderManager(IThumbnailsManager thumbnailsManager, IPluginManager pluginManager)
|
||||
{
|
||||
this.thumbnailsManager = thumbnailsManager;
|
||||
this.config = config;
|
||||
providers = pluginManager.GetPlugins<IMetadataProvider>();
|
||||
}
|
||||
|
||||
public Show Merge(IEnumerable<Show> shows)
|
||||
public async Task<T> GetMetadata<T>(Func<IMetadataProvider, Task<T>> providerCall, Library library, string what) where T : IMergable<T>, new()
|
||||
{
|
||||
return shows.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Season Merge(IEnumerable<Season> seasons)
|
||||
{
|
||||
return seasons.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Episode Merge(IEnumerable<Episode> episodes)
|
||||
{
|
||||
return episodes.FirstOrDefault(); //Should do something if the return is null;
|
||||
}
|
||||
|
||||
//For all the following methods, it should use all providers and merge the data.
|
||||
|
||||
public Task<Collection> GetCollectionFromName(string name)
|
||||
{
|
||||
return providers[0].GetCollectionFromName(name);
|
||||
}
|
||||
|
||||
public Task<Show> GetImages(Show show)
|
||||
{
|
||||
return providers[0].GetImages(show);
|
||||
}
|
||||
|
||||
public async Task<Season> GetSeason(string showName, int seasonNumber)
|
||||
{
|
||||
List<Season> datas = new List<Season>();
|
||||
for (int i = 0; i < providers.Count; i++)
|
||||
T ret = new T();
|
||||
|
||||
foreach (IMetadataProvider provider in providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name)))
|
||||
{
|
||||
datas.Add(await providers[i].GetSeason(showName, seasonNumber));
|
||||
try
|
||||
{
|
||||
if (library.Providers.Contains(provider.Name))
|
||||
ret = ret.Merge(await providerCall(provider));
|
||||
} catch (Exception ex) {
|
||||
Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. (Excepetion: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return Merge(datas);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public async Task<Show> GetShowByID(string id)
|
||||
|
||||
public async Task<IEnumerable<T>> GetMetadata<T>(Func<IMetadataProvider, Task<IEnumerable<T>>> providerCall, Library library, string what)
|
||||
{
|
||||
List<Show> datas = new List<Show>();
|
||||
for (int i = 0; i < providers.Count; i++)
|
||||
List<T> ret = new List<T>();
|
||||
|
||||
foreach (IMetadataProvider provider in providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name)))
|
||||
{
|
||||
datas.Add(await providers[i].GetShowByID(id));
|
||||
try
|
||||
{
|
||||
if (library.Providers.Contains(provider.Name))
|
||||
ret.AddRange(await providerCall(provider));
|
||||
} catch (Exception ex) {
|
||||
Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. (Excepetion: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
return Merge(datas);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public async Task<Collection> GetCollectionFromName(string name, Library library)
|
||||
{
|
||||
return await GetMetadata(provider => provider.GetCollectionFromName(name), library, $"the collection {name}");
|
||||
}
|
||||
|
||||
public async Task<Show> GetShowFromName(string showName, string showPath)
|
||||
public async Task<Show> GetShowFromName(string showName, string showPath, Library library)
|
||||
{
|
||||
List<Show> datas = new List<Show>();
|
||||
for (int i = 0; i < providers.Count; i++)
|
||||
{
|
||||
datas.Add(await providers[i].GetShowFromName(showName, showPath));
|
||||
}
|
||||
|
||||
Show show = Merge(datas);
|
||||
return await thumbnailsManager.Validate(show);
|
||||
Show show = await GetMetadata(provider => provider.GetShowFromName(showName, showPath), library, $"the show {showName}");
|
||||
await thumbnailsManager.Validate(show);
|
||||
return show;
|
||||
}
|
||||
|
||||
public async Task<Season> GetSeason(string showName, long seasonNumber)
|
||||
public async Task<Season> GetSeason(string showName, long seasonNumber, Library library)
|
||||
{
|
||||
List<Season> datas = new List<Season>();
|
||||
for (int i = 0; i < providers.Count; i++)
|
||||
{
|
||||
datas.Add(await providers[i].GetSeason(showName, seasonNumber));
|
||||
}
|
||||
|
||||
return Merge(datas);
|
||||
return await GetMetadata(provider => provider.GetSeason(showName, seasonNumber), library, $"the season ${seasonNumber} of {showName}");
|
||||
}
|
||||
|
||||
public Task<string> GetSeasonImage(string showName, long seasonNumber)
|
||||
public async Task<Episode> GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library)
|
||||
{
|
||||
//Should select the best provider for this show.
|
||||
|
||||
return providers[0].GetSeasonImage(showName, seasonNumber);
|
||||
Episode episode = await GetMetadata(provider => provider.GetEpisode(externalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath), library, $"the episode at {episodePath}");
|
||||
await thumbnailsManager.Validate(episode);
|
||||
return episode;
|
||||
}
|
||||
|
||||
public async Task<Episode> GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath)
|
||||
public async Task<IEnumerable<People>> GetPeople(string showExternalIDs, Library library)
|
||||
{
|
||||
List<Episode> datas = new List<Episode>();
|
||||
for (int i = 0; i < providers.Count; i++)
|
||||
{
|
||||
datas.Add(await providers[i].GetEpisode(externalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath));
|
||||
}
|
||||
|
||||
Episode episode = Merge(datas);
|
||||
episode.Path = episodePath;
|
||||
return await thumbnailsManager.Validate(episode);
|
||||
}
|
||||
|
||||
public async Task<List<People>> GetPeople(string id)
|
||||
{
|
||||
List<People> actors = await providers[0].GetPeople(id);
|
||||
return await thumbnailsManager.Validate(actors);
|
||||
IEnumerable<People> people = await GetMetadata(provider => provider.GetPeople(showExternalIDs), library, $"unknown data");
|
||||
people = await thumbnailsManager.Validate(people);
|
||||
return people;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,20 +67,20 @@ namespace Kyoo.Controllers.ThumbnailsManager
|
||||
return show;
|
||||
}
|
||||
|
||||
public async Task<List<People>> Validate(List<People> people)
|
||||
public async Task<IEnumerable<People>> Validate(IEnumerable<People> people)
|
||||
{
|
||||
for (int i = 0; i < people?.Count; i++)
|
||||
foreach (People peop in people)
|
||||
{
|
||||
string root = config.GetValue<string>("peoplePath");
|
||||
Directory.CreateDirectory(root);
|
||||
|
||||
string localThumb = root + "/" + people[i].slug + ".jpg";
|
||||
if (people[i].imgPrimary != null && !File.Exists(localThumb))
|
||||
string localThumb = root + "/" + peop.slug + ".jpg";
|
||||
if (peop.imgPrimary != null && !File.Exists(localThumb))
|
||||
{
|
||||
try
|
||||
{
|
||||
using WebClient client = new WebClient();
|
||||
await client.DownloadFileTaskAsync(new Uri(people[i].imgPrimary), localThumb);
|
||||
await client.DownloadFileTaskAsync(new Uri(peop.imgPrimary), localThumb);
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
|
@ -18,10 +18,10 @@ namespace Kyoo.Controllers
|
||||
this.crawler = crawler;
|
||||
}
|
||||
|
||||
[HttpGet("scan/{watch}")]
|
||||
public IActionResult ScanLibrary(bool watch)
|
||||
[HttpGet("scan")]
|
||||
public IActionResult ScanLibrary()
|
||||
{
|
||||
crawler.Start(watch);
|
||||
crawler.Start();
|
||||
return Ok("Scanning");
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ namespace Kyoo
|
||||
services.AddSingleton<ITranscoder, Transcoder>();
|
||||
services.AddSingleton<ICrawler, Crawler>();
|
||||
services.AddSingleton<IThumbnailsManager, ThumbnailsManager>();
|
||||
services.AddSingleton<IMetadataProvider, ProviderManager>();
|
||||
services.AddSingleton<IProviderManager, ProviderManager>();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
|
Loading…
x
Reference in New Issue
Block a user