Finishing to rework the manager to use EF and reworking the crawler to use the new API

This commit is contained in:
Zoe Roux 2020-02-08 01:40:26 +01:00
parent a2a494d907
commit b2471c99ae
15 changed files with 179 additions and 552 deletions

View File

@ -54,16 +54,12 @@ namespace Kyoo.Controllers
long RegisterShow(Show show);
long RegisterSeason(Season season);
long RegisterEpisode(Episode episode);
void RegisterTrack(Track track);
long RegisterTrack(Track track);
void RegisterShowLinks(Library library, Collection collection, Show show);
long GetOrCreateGenre(Genre genre);
long GetOrCreateStudio(Studio studio);
void RegisterShowPeople(long showID, IEnumerable<People> actors);
void AddShowToCollection(long showID, long collectionID);
void RegisterInLibrary(long showID, Library library);
void RemoveEpisode(Episode episode);
void RemoveShow(long showID);
void RemoveSeason(long seasonID);
void RemoveEpisode(long episodeID);
void ClearSubtitles(long episodeID);
}
}

View File

@ -16,7 +16,6 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.112" />
</ItemGroup>
</Project>

View File

@ -1,5 +1,4 @@
using Kyoo.Controllers;
using Newtonsoft.Json;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
@ -7,7 +6,7 @@ namespace Kyoo.Models
{
public class Collection : IMergable<Collection>
{
[JsonIgnore] public long ID { get; set; } = -1;
[JsonIgnore] public long ID { get; set; }
public string Slug { get; set; }
public string Name { get; set; }
public string Poster { get; set; }
@ -17,40 +16,22 @@ namespace Kyoo.Models
public Collection() { }
public Collection(long id, string slug, string name, string overview, string imgPrimary)
public Collection(string slug, string name, string overview, string imgPrimary)
{
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 Show AsShow()
{
return new Show(-1, Slug, Name, null, null, Overview, null, null, null, null, null, null)
return new Show(Slug, Name, null, null, Overview, null, null, null, null, null, null)
{
IsCollection = true
};
}
public Collection SetShows(ILibraryManager libraryManager)
{
Shows = libraryManager.GetShowsInCollection(ID);
return this;
}
public Collection Merge(Collection collection)
{
if (collection == null)

View File

@ -1,5 +1,6 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Kyoo.Models
{
@ -7,9 +8,9 @@ namespace Kyoo.Models
{
[JsonIgnore] public long ID { get; set; }
[JsonIgnore] public long ShowID { get; set; }
public virtual Show Show { get; set; }
[JsonIgnore] public virtual Show Show { get; set; }
[JsonIgnore] public long SeasonID { get; set; }
public virtual Season Season { get; set; }
[JsonIgnore] public virtual Season Season { get; set; }
public long SeasonNumber { get; set; }
public long EpisodeNumber { get; set; }
@ -24,6 +25,8 @@ namespace Kyoo.Models
[JsonIgnore] public string ImgPrimary { get; set; }
public string ExternalIDs { get; set; }
public IEnumerable<Track> Tracks { get; set; }
public string ShowTitle; //Used in the API response only
public string Link; //Used in the API response only
public string Thumb; //Used in the API response only
@ -31,20 +34,14 @@ namespace Kyoo.Models
public Episode()
{
ID = -1;
ShowID = -1;
SeasonID = -1;
SeasonNumber = -1;
SeasonNumber = -1;
EpisodeNumber = -1;
AbsoluteNumber = -1;
}
public Episode(long seasonNumber, long episodeNumber, long absoluteNumber, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
{
ID = -1;
ShowID = -1;
SeasonID = -1;
SeasonNumber = seasonNumber;
SeasonNumber = seasonNumber;
EpisodeNumber = episodeNumber;
AbsoluteNumber = absoluteNumber;
Title = title;
@ -55,9 +52,8 @@ namespace Kyoo.Models
ExternalIDs = externalIDs;
}
public Episode(long id, long showID, long seasonID, long seasonNumber, long episodeNumber, long absoluteNumber, string path, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
public Episode(long showID, long seasonID, long seasonNumber, long episodeNumber, long absoluteNumber, string path, string title, string overview, DateTime? releaseDate, long runtime, string imgPrimary, string externalIDs)
{
ID = id;
ShowID = showID;
SeasonID = seasonID;
SeasonNumber = seasonNumber;
@ -72,37 +68,6 @@ namespace Kyoo.Models
ExternalIDs = externalIDs;
}
public static Episode FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Episode((long)reader["id"],
(long)reader["showID"],
(long)reader["seasonID"],
(long)reader["seasonNumber"],
(long)reader["episodeNumber"],
(long)reader["absoluteNumber"],
reader["path"] as string,
reader["title"] as string,
reader["overview"] as string,
reader["releaseDate"] as DateTime?,
(long)reader["runtime"],
reader["imgPrimary"] as string,
reader["externalIDs"] as string);
}
public Episode SetThumb(string showSlug)
{
Link = GetSlug(showSlug, SeasonNumber, EpisodeNumber);
Thumb = "thumb/" + Link;
return this;
}
public Episode SetShowTitle(string showTite)
{
ShowTitle = showTite;
return this;
}
public static string GetSlug(string showSlug, long seasonNumber, long episodeNumber)
{
return showSlug + "-s" + seasonNumber + "e" + episodeNumber;

View File

@ -20,12 +20,5 @@ namespace Kyoo.Models
Slug = slug;
Name = name;
}
public static Genre FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Genre((long)reader["id"],
reader["slug"] as string,
reader["name"] as string);
}
}
}

View File

@ -1,11 +1,10 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json;
namespace Kyoo.Models
{
public class Library
{
[JsonIgnore] public long Id { get; set; }
[JsonIgnore] public long ID { get; set; }
public string Slug { get; set; }
public string Name { get; set; }
public string[] Paths { get; set; }
@ -13,22 +12,12 @@ namespace Kyoo.Models
public Library() { }
public Library(long id, string slug, string name, string[] paths, string[] providers)
public Library(string slug, string name, string[] paths, string[] providers)
{
Id = id;
Slug = slug;
Name = name;
Paths = paths;
Providers = providers;
}
public static Library FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Library((long)reader["id"],
reader["slug"] as string,
reader["name"] as string,
(reader["path"] as string)?.Split('|'),
(reader["providers"] as string)?.Split('|'));
}
}
}

View File

@ -1,12 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Kyoo.Models
{
public class People : IMergable<People>
{
[JsonIgnore] public long ID { get; set; } = -1;
[JsonIgnore] public long ID { get; set; }
public string Slug { get; set; }
public string Name { get; set; }
public string Role;
@ -18,18 +17,16 @@ namespace Kyoo.Models
public People() {}
public People(long id, string slug, string name, string imgPrimary, string externalIDs)
public People(string slug, string name, string imgPrimary, string externalIDs)
{
ID = id;
Slug = slug;
Name = name;
ImgPrimary = imgPrimary;
ExternalIDs = externalIDs;
}
public People(long id, string slug, string name, string role, string type, string imgPrimary, string externalIDs)
public People(string slug, string name, string role, string type, string imgPrimary, string externalIDs)
{
ID = id;
Slug = slug;
Name = name;
Role = role;
@ -45,6 +42,19 @@ namespace Kyoo.Models
return this;
}
public PeopleLink ToLink(Show show)
{
return new PeopleLink
{
People = this,
PeopleID = ID,
Role = Role,
Type = Type,
Show = show,
ShowID = show.ID
};
}
public People Merge(People other)
{
if (other == null)

View File

@ -1,13 +1,12 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using Newtonsoft.Json;
namespace Kyoo.Models
{
public class Season : IMergable<Season>
{
[JsonIgnore] public long ID { get; set; } = -1;
[JsonIgnore] public long ShowID { get; set; } = -1;
[JsonIgnore] public long ID { get; set; }
[JsonIgnore] public long ShowID { get; set; }
public long SeasonNumber { get; set; } = -1;
public string Title { get; set; }
@ -17,14 +16,13 @@ namespace Kyoo.Models
[JsonIgnore] public string ImgPrimary { get; set; }
public string ExternalIDs { get; set; }
public virtual Show Show { get; set; }
public virtual IEnumerable<Episode> Episodes { get; set; }
[JsonIgnore] public virtual Show Show { get; set; }
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
public Season() { }
public Season(long id, long showID, long seasonNumber, string title, string overview, long? year, string imgPrimary, string externalIDs)
public Season(long showID, long seasonNumber, string title, string overview, long? year, string imgPrimary, string externalIDs)
{
ID = id;
ShowID = showID;
SeasonNumber = seasonNumber;
Title = title;
@ -34,18 +32,6 @@ namespace Kyoo.Models
ExternalIDs = externalIDs;
}
public static Season FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Season((long)reader["id"],
(long)reader["showID"],
(long)reader["seasonNumber"],
reader["title"] as string,
reader["overview"] as string,
reader["year"] as long?,
reader["imgPrimary"] as string,
reader["externalIDs"] as string);
}
public Season Merge(Season other)
{
if (other == null)

View File

@ -1,5 +1,4 @@
using System;
using Kyoo.Controllers;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
@ -32,9 +31,9 @@ namespace Kyoo.Models
public IEnumerable<Genre> Genres;
public virtual Studio Studio { get; set; }
public virtual IEnumerable<PeopleLink> People { get; set; }
public virtual IEnumerable<Season> Seasons { get; set; }
public virtual IEnumerable<Episode> Episodes { get; set; }
[JsonIgnore] public virtual IEnumerable<PeopleLink> People { get; set; }
[JsonIgnore] public virtual IEnumerable<Season> Seasons { get; set; }
[JsonIgnore] public virtual IEnumerable<Episode> Episodes { get; set; }
public string GetAliases()
@ -50,9 +49,8 @@ namespace Kyoo.Models
public Show() { }
public Show(long id, string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, IEnumerable<Genre> genres, Status? status, long? startYear, long? endYear, string externalIDs)
public Show(string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, IEnumerable<Genre> genres, Status? status, long? startYear, long? endYear, string externalIDs)
{
ID = id;
Slug = slug;
Title = title;
Aliases = aliases.ToArray();
@ -67,9 +65,8 @@ namespace Kyoo.Models
IsCollection = false;
}
public Show(long id, string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgLogo, string imgBackdrop, string externalIDs)
public Show(string slug, string title, IEnumerable<string> aliases, string path, string overview, string trailerUrl, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgLogo, string imgBackdrop, string externalIDs)
{
ID = id;
Slug = slug;
Title = title;
Aliases = aliases.ToArray();
@ -86,41 +83,7 @@ namespace Kyoo.Models
ExternalIDs = externalIDs;
IsCollection = false;
}
public static Show FromQueryReader(System.Data.SQLite.SQLiteDataReader reader, bool containsAliases = false)
{
Show show = new Show()
{
Slug = reader["slug"] as string,
Title = reader["title"] as string,
StartYear = reader["startYear"] as long?,
EndYear = reader["endYear"] as long?,
IsCollection = reader["'0'"] as string == "1"
};
if (containsAliases)
show.Aliases = (reader["aliases"] as string)?.Split('|');
return show;
}
public static Show FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Show((long)reader["id"],
reader["slug"] as string,
reader["title"] as string,
(reader["aliases"] as string)?.Split('|'),
reader["path"] as string,
reader["overview"] as string,
reader["trailerUrl"] as string,
reader["status"] as Status?,
reader["startYear"] as long?,
reader["endYear"] as long?,
reader["imgPrimary"] as string,
reader["imgThumb"] as string,
reader["imgLogo"] as string,
reader["imgBackdrop"] as string,
reader["externalIDs"] as string);
}
public string GetID(string provider)
{
if (ExternalIDs?.Contains(provider) != true)
@ -130,44 +93,7 @@ namespace Kyoo.Models
return ExternalIDs.Substring(startIndex);
return ExternalIDs.Substring(startIndex, ExternalIDs.IndexOf('|', startIndex) - startIndex);
}
public Show Set(string slug, string path)
{
Slug = slug;
Path = path;
return this;
}
public Show SetGenres(ILibraryManager manager)
{
Genres = manager.GetGenreForShow(ID);
return this;
}
public Show SetStudio(ILibraryManager manager)
{
Studio = manager.GetStudio(ID);
return this;
}
public Show SetDirectors(ILibraryManager manager)
{
//Directors = manager.GetDirectors(ID);
return this;
}
public Show SetPeople(ILibraryManager manager)
{
//People = manager.GetPeople(ID);
return this;
}
public Show SetSeasons(ILibraryManager manager)
{
Seasons = manager.GetSeasons(ID);
return this;
}
public Show Merge(Show other)
{
if (other == null)

View File

@ -4,7 +4,7 @@ namespace Kyoo.Models
{
public class Studio
{
[JsonIgnore] public long ID { get; set; } = -1;
[JsonIgnore] public long ID { get; set; }
public string Slug { get; set; }
public string Name { get; set; }
@ -15,21 +15,7 @@ namespace Kyoo.Models
Slug = slug;
Name = name;
}
public Studio(long id, string slug, string name)
{
ID = id;
Slug = slug;
Name = name;
}
public static Studio FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Studio((long)reader["id"],
reader["slug"] as string,
reader["name"] as string);
}
public static Studio Default()
{
return new Studio("unknow", "Unknow Studio");

View File

@ -88,18 +88,6 @@ namespace Kyoo.Models
IsExternal = false;
}
public static Track FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Track((StreamType)Enum.ToObject(typeof(StreamType), reader["streamType"]),
reader["title"] as string,
reader["language"] as string,
reader["isDefault"] as bool? ?? false,
reader["isForced"] as bool? ?? false,
reader["codec"] as string,
reader["isExternal"] as bool? ?? false,
reader["path"] as string);
}
public Track SetLink(string episodeSlug)
{
if (Type == StreamType.Subtitle)

View File

@ -13,50 +13,50 @@ namespace Kyoo.Controllers
{
public class Crawler : ICrawler
{
private bool isRunning;
private readonly CancellationTokenSource cancellation;
private bool _isRunning;
private readonly CancellationTokenSource _cancellation;
private readonly ILibraryManager libraryManager;
private readonly IProviderManager metadataProvider;
private readonly ITranscoder transcoder;
private readonly IConfiguration config;
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _metadataProvider;
private readonly ITranscoder _transcoder;
private readonly IConfiguration _config;
public Crawler(ILibraryManager libraryManager, IProviderManager metadataProvider, ITranscoder transcoder, IConfiguration configuration)
{
this.libraryManager = libraryManager;
this.metadataProvider = metadataProvider;
this.transcoder = transcoder;
config = configuration;
cancellation = new CancellationTokenSource();
_libraryManager = libraryManager;
_metadataProvider = metadataProvider;
_transcoder = transcoder;
_config = configuration;
_cancellation = new CancellationTokenSource();
}
public void Start()
{
if (isRunning)
if (_isRunning)
return;
isRunning = true;
StartAsync(cancellation.Token);
_isRunning = true;
StartAsync(_cancellation.Token);
}
public void Cancel()
{
if (!isRunning)
if (!_isRunning)
return;
isRunning = false;
cancellation.Cancel();
_isRunning = false;
_cancellation.Cancel();
}
private async void StartAsync(CancellationToken cancellationToken)
{
try
{
IEnumerable<Episode> episodes = libraryManager.GetAllEpisodes();
IEnumerable<Library> libraries = libraryManager.GetLibraries();
IEnumerable<Episode> episodes = _libraryManager.GetAllEpisodes();
IEnumerable<Library> libraries = _libraryManager.GetLibraries();
foreach (Episode episode in episodes)
{
if (!File.Exists(episode.Path))
libraryManager.RemoveEpisode(episode);
_libraryManager.RemoveEpisode(episode.ID);
}
foreach (Library library in libraries)
@ -66,7 +66,7 @@ namespace Kyoo.Controllers
{
Console.Error.WriteLine($"Unknown exception thrown durring libraries scan.\nException: {ex.Message}");
}
isRunning = false;
_isRunning = false;
Console.WriteLine("Scan finished!");
}
@ -79,7 +79,7 @@ namespace Kyoo.Controllers
{
if (cancellationToken.IsCancellationRequested)
return;
if (!IsVideo(file))
if (!IsVideo(file) || _libraryManager.IsEpisodeRegistered(file, out long _))
continue;
string relativePath = file.Substring(path.Length);
await RegisterFile(file, relativePath, library);
@ -89,136 +89,96 @@ namespace Kyoo.Controllers
private async Task RegisterFile(string path, string relativePath, Library library)
{
if (!libraryManager.IsEpisodeRegistered(path, out long _))
string patern = _config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
Match match = regex.Match(relativePath);
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;
Console.WriteLine("Registering episode at: " + path);
if (!seasonSuccess || !episodeSucess)
{
string patern = config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
Match match = regex.Match(relativePath);
//Considering that the episode is using absolute path.
seasonNumber = -1;
episodeNumber = -1;
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;
regex = new Regex(_config.GetValue<string>("absoluteRegex"));
match = regex.Match(relativePath);
Console.WriteLine("Registering episode at: " + path);
if (!seasonSuccess || !episodeSucess)
showName = match.Groups["ShowTitle"].Value;
bool absoluteSucess = long.TryParse(match.Groups["AbsoluteNumber"].Value, out absoluteNumber);
if (!absoluteSucess)
{
//Considering that the episode is using absolute path.
seasonNumber = -1;
episodeNumber = -1;
regex = new Regex(config.GetValue<string>("absoluteRegex"));
match = regex.Match(relativePath);
showName = match.Groups["ShowTitle"].Value;
bool absoluteSucess = long.TryParse(match.Groups["AbsoluteNumber"].Value, out absoluteNumber);
if (!absoluteSucess)
{
Console.Error.WriteLine("Couldn't find basic data for the episode (regexs didn't match) " + relativePath);
return;
}
Console.Error.WriteLine("Couldn't find basic data for the episode (regexs didn't match) " + relativePath);
return;
}
Show show = await RegisterOrGetShow(collectionName, showName, showPath, library);
if (show != null)
await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, path, library);
else
Console.Error.WriteLine($"Coudld not get informations about the show {showName}.");
}
Collection collection = await GetCollection(collectionName, library);
Show show = await GetShow(showName, showPath, library);
Season season = await GetSeason(show, seasonNumber, library);
Episode episode = await GetEpisode(show, season, episodeNumber, absoluteNumber, path, library);
_libraryManager.RegisterEpisode(episode);
_libraryManager.RegisterShowLinks(library, collection, show);
}
private async Task<Show> RegisterOrGetShow(string collectionName, string showTitle, string showPath, Library library)
private async Task<Collection> GetCollection(string collectionName, Library library)
{
string showProviderIDs;
if (!libraryManager.IsShowRegistered(showPath, out long showID))
{
Show show = await metadataProvider.GetShowFromName(showTitle, showPath, library);
showProviderIDs = show.ExternalIDs;
showID = libraryManager.RegisterShow(show);
if (showID == -1)
return null;
libraryManager.RegisterInLibrary(showID, library);
if (!string.IsNullOrEmpty(collectionName))
{
if (!libraryManager.IsCollectionRegistered(Utility.ToSlug(collectionName), out long collectionID))
{
Collection collection = await metadataProvider.GetCollectionFromName(collectionName, library);
collectionID = libraryManager.RegisterCollection(collection);
}
libraryManager.AddShowToCollection(showID, collectionID);
}
IEnumerable<People> actors = await metadataProvider.GetPeople(show, library);
libraryManager.RegisterShowPeople(showID, actors);
}
else
showProviderIDs = libraryManager.GetShowExternalIDs(showID);
return new Show { ID = showID, ExternalIDs = showProviderIDs, Title = showTitle };
}
private async Task<long> RegisterSeason(Show show, long seasonNumber, Library library)
{
if (libraryManager.IsSeasonRegistered(show.ID, seasonNumber, out long seasonID))
return seasonID;
Season season = await metadataProvider.GetSeason(show, seasonNumber, library);
seasonID = libraryManager.RegisterSeason(season);
return seasonID;
if (string.IsNullOrEmpty(collectionName))
return await Task.FromResult<Collection>(null);
if (_libraryManager.IsCollectionRegistered(Utility.ToSlug(collectionName), out long collectionID))
return new Collection {ID = collectionID};
return await _metadataProvider.GetCollectionFromName(collectionName, library);
}
private async Task RegisterEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library)
private async Task<Show> GetShow(string showTitle, string showPath, Library library)
{
long seasonID = -1;
if (seasonNumber != -1)
seasonID = await RegisterSeason(show, seasonNumber, library);
Episode episode = await metadataProvider.GetEpisode(show, episodePath, seasonNumber, episodeNumber, absoluteNumber, library);
if (seasonID == -1)
seasonID = await RegisterSeason(show, seasonNumber, library);
episode.SeasonID = seasonID;
episode.ID = libraryManager.RegisterEpisode(episode);
Track[] tracks = await transcoder.GetTrackInfo(episode.Path);
int subcount = 0;
foreach (Track track in tracks)
{
if (track.Type == StreamType.Subtitle)
{
subcount++;
continue;
}
track.EpisodeID = episode.ID;
libraryManager.RegisterTrack(track);
}
if (episode.Path.EndsWith(".mkv") && CountExtractedSubtitles(episode) != subcount)
{
Track[] subtitles = await transcoder.ExtractSubtitles(episode.Path);
if (subtitles != null)
{
foreach (Track track in subtitles)
{
track.EpisodeID = episode.ID;
libraryManager.RegisterTrack(track);
}
}
}
if (_libraryManager.IsShowRegistered(showPath, out long showID))
return new Show { ID = showID, Title = showTitle, ExternalIDs = _libraryManager.GetShowExternalIDs(showID) };
Show show = await _metadataProvider.GetShowFromName(showTitle, showPath, library);
show.People = from people in await _metadataProvider.GetPeople(show, library) select people.ToLink(show);
return show;
}
private int CountExtractedSubtitles(Episode episode)
private async Task<Season> GetSeason(Show show, long seasonNumber, Library library)
{
if (_libraryManager.IsSeasonRegistered(show.ID, seasonNumber, out long seasonID))
return await Task.FromResult(new Season {ID = seasonID, ShowID = show.ID, Show = show});
Season season = await _metadataProvider.GetSeason(show, seasonNumber, library);
season.Show = show;
season.ShowID = show.ID;
return season;
}
private async Task<Episode> GetEpisode(Show show, Season season, long episodeNumber, long absoluteNumber, string episodePath, Library library)
{
Episode episode = await _metadataProvider.GetEpisode(show, episodePath, season.SeasonNumber, episodeNumber, absoluteNumber, library);
episode.ShowID = show.ID;
episode.Show = show;
episode.SeasonID = season.ID;
episode.Season = season;
IEnumerable<Track> tracks = await _transcoder.GetTrackInfo(episode.Path);
List<Track> epTracks = tracks.Where(x => x.Type != StreamType.Subtitle).Concat(GetExtractedSubtitles(episode)).ToList();
if (epTracks.Count(x => !x.IsExternal) < tracks.Count())
epTracks.AddRange(await _transcoder.ExtractSubtitles(episode.Path));
episode.Tracks = epTracks;
return episode;
}
private static IEnumerable<Track> GetExtractedSubtitles(Episode episode)
{
string path = Path.Combine(Path.GetDirectoryName(episode.Path), "Subtitles");
int subcount = 0;
List<Track> tracks = new List<Track>();
if (!Directory.Exists(path))
return 0;
return tracks;
foreach (string sub in Directory.EnumerateFiles(path, "", SearchOption.AllDirectories))
{
string episodeLink = Path.GetFileNameWithoutExtension(episode.Path);
@ -236,10 +196,9 @@ namespace Kyoo.Controllers
track.Codec = "subrip";
else
track.Codec = null;
libraryManager.RegisterTrack(track);
subcount++;
tracks.Add(track);
}
return subcount;
return tracks;
}
private static readonly string[] VideoExtensions = { ".webm", ".mkv", ".flv", ".vob", ".ogg", ".ogv", ".avi", ".mts", ".m2ts", ".ts", ".mov", ".qt", ".asf", ".mp4", ".m4p", ".m4v", ".mpg", ".mp2", ".mpeg", ".mpe", ".mpv", ".m2v", ".3gp", ".3g2" };
@ -252,7 +211,7 @@ namespace Kyoo.Controllers
public Task StopAsync()
{
cancellation.Cancel();
_cancellation.Cancel();
return null;
}
}

View File

@ -1,8 +1,6 @@
using Kyoo.Models;
using Kyoo.Models.Watch;
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Linq;
namespace Kyoo.Controllers
@ -10,7 +8,6 @@ namespace Kyoo.Controllers
public class LibraryManager : ILibraryManager
{
private readonly DatabaseContext _database;
private readonly SQLiteConnection sqlConnection;
public LibraryManager(DatabaseContext database)
@ -63,9 +60,8 @@ namespace Kyoo.Controllers
public IEnumerable<Show> GetShows()
{
return (from show in _database.Shows join link in _database.CollectionLinks on show equals link.Show into gj
from l in gj.DefaultIfEmpty()
where l.CollectionID == null select l.Show).AsEnumerable().Union(
return (from show in _database.Shows from l in _database.CollectionLinks.DefaultIfEmpty()
where l.CollectionID == null select show).AsEnumerable().Union(
from collection in _database.Collections select collection.AsShow()).OrderBy(x => x.Title);
}
@ -303,43 +299,9 @@ namespace Kyoo.Controllers
#region Write Into The Database
public long RegisterCollection(Collection collection)
{
// string query = "INSERT INTO collections (slug, name, overview, imgPrimary) VALUES($slug, $name, $overview, $imgPrimary);";
//
// using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
// {
// try
// {
// cmd.Parameters.AddWithValue("$slug", collection.Slug);
// cmd.Parameters.AddWithValue("$name", collection.Name);
// cmd.Parameters.AddWithValue("$overview", collection.Overview);
// cmd.Parameters.AddWithValue("$imgPrimary", collection.ImgPrimary);
// cmd.ExecuteNonQuery();
//
// cmd.CommandText = "SELECT LAST_INSERT_ROWID()";
// return (long)cmd.ExecuteScalar();
// }
// catch
// {
// Console.Error.WriteLine("SQL error while trying to create a collection. Collection probably already registered.");
// cmd.CommandText = "SELECT * FROM collections WHERE slug = $slug";
// cmd.Parameters.AddWithValue("$slug", collection.Slug);
// return (long)cmd.ExecuteScalar();
// }
// }
return -1;
}
public void RegisterInLibrary(long showID, Library library)
{
// 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("$libraryID", library.Id);
// cmd.Parameters.AddWithValue("$showID", showID);
// cmd.ExecuteNonQuery();
// }
_database.Collections.Add(collection);
_database.SaveChanges();
return collection.ID;
}
public long RegisterShow(Show show)
@ -351,167 +313,54 @@ namespace Kyoo.Controllers
public long RegisterSeason(Season season)
{
string query = "INSERT INTO seasons (showID, seasonNumber, title, overview, year, imgPrimary, externalIDs) VALUES($showID, $seasonNumber, $title, $overview, $year, $imgPrimary, $externalIDs);";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
try
{
cmd.Parameters.AddWithValue("$showID", season.ShowID);
cmd.Parameters.AddWithValue("$seasonNumber", season.SeasonNumber);
cmd.Parameters.AddWithValue("$title", season.Title);
cmd.Parameters.AddWithValue("$overview", season.Overview);
cmd.Parameters.AddWithValue("$year", season.Year);
cmd.Parameters.AddWithValue("$imgPrimary", season.ImgPrimary);
cmd.Parameters.AddWithValue("$externalIDs", season.ExternalIDs);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT LAST_INSERT_ROWID()";
return (long)cmd.ExecuteScalar();
}
catch
{
Console.Error.WriteLine("SQL error while trying to insert a season ({0}), season probably already registered.", season.Title);
cmd.CommandText = "SELECT * FROM seasons WHERE showID = $showID AND seasonNumber = $seasonNumber";
cmd.Parameters.AddWithValue("$showID", season.ShowID);
cmd.Parameters.AddWithValue("$seasonNumber", season.SeasonNumber);
return (long)cmd.ExecuteScalar();
}
}
_database.Seasons.Add(season);
_database.SaveChanges();
return season.ID;
}
public long RegisterEpisode(Episode episode)
{
string query = "INSERT INTO episodes (showID, seasonID, seasonNumber, episodeNumber, absoluteNumber, path, title, overview, releaseDate, runtime, imgPrimary, externalIDs) VALUES($showID, $seasonID, $seasonNumber, $episodeNumber, $absoluteNumber, $path, $title, $overview, $releaseDate, $runtime, $imgPrimary, $externalIDs);";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
try
{
cmd.Parameters.AddWithValue("$showID", episode.ShowID);
cmd.Parameters.AddWithValue("$seasonID", episode.SeasonID);
cmd.Parameters.AddWithValue("$seasonNUmber", episode.SeasonNumber);
cmd.Parameters.AddWithValue("$episodeNumber", episode.EpisodeNumber);
cmd.Parameters.AddWithValue("$absoluteNumber", episode.AbsoluteNumber);
cmd.Parameters.AddWithValue("$path", episode.Path);
cmd.Parameters.AddWithValue("$title", episode.Title);
cmd.Parameters.AddWithValue("$overview", episode.Overview);
cmd.Parameters.AddWithValue("$releaseDate", episode.ReleaseDate);
cmd.Parameters.AddWithValue("$runtime", episode.Runtime);
cmd.Parameters.AddWithValue("$imgPrimary", episode.ImgPrimary);
cmd.Parameters.AddWithValue("$externalIDs", episode.ExternalIDs);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT LAST_INSERT_ROWID()";
return (long)cmd.ExecuteScalar();
}
catch
{
Console.Error.WriteLine("SQL error while trying to insert an episode ({0}), episode probably already registered.", episode.Link);
cmd.CommandText = "SELECT * FROM episodes WHERE showID = $showID AND seasonNumber = $seasonNumber AND episodeNumber = $episodeNumber";
cmd.Parameters.AddWithValue("$showID", episode.ShowID);
cmd.Parameters.AddWithValue("$seasonNumber", episode.SeasonNumber);
cmd.Parameters.AddWithValue("$episodeNumber", episode.EpisodeNumber);
return (long)cmd.ExecuteScalar();
}
}
_database.Episodes.Add(episode);
_database.SaveChanges();
return episode.ID;
}
public void RegisterTrack(Track track)
public long RegisterTrack(Track track)
{
string query = "INSERT INTO tracks (episodeID, streamType, title, language, codec, isDefault, isForced, isExternal, path) VALUES($episodeID, $streamType, $title, $language, $codec, $isDefault, $isForced, $isExternal, $path);";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$episodeID", track.EpisodeID);
cmd.Parameters.AddWithValue("$streamType", track.Type);
cmd.Parameters.AddWithValue("$title", track.Title);
cmd.Parameters.AddWithValue("$language", track.Language);
cmd.Parameters.AddWithValue("$codec", track.Codec);
cmd.Parameters.AddWithValue("$isDefault", track.IsDefault);
cmd.Parameters.AddWithValue("$isForced", track.IsForced);
cmd.Parameters.AddWithValue("$isExternal", track.IsExternal);
cmd.Parameters.AddWithValue("$path", track.Path);
cmd.ExecuteNonQuery();
}
_database.Tracks.Add(track);
_database.SaveChanges();
return track.ID;
}
public void RegisterShowPeople(long showID, IEnumerable<People> people)
public void RegisterShowLinks(Library library, Collection collection, Show show)
{
if (people == null)
return;
string linkQuery = "INSERT INTO peopleLinks (peopleID, showID, role, type) VALUES($peopleID, $showID, $role, $type);";
foreach (People peop in people)
if (collection != null)
{
using (SQLiteCommand cmd = new SQLiteCommand(linkQuery, sqlConnection))
{
cmd.Parameters.AddWithValue("$peopleID", GetOrCreatePeople(peop));
cmd.Parameters.AddWithValue("$showID", showID);
cmd.Parameters.AddWithValue("$role", peop.Role);
cmd.Parameters.AddWithValue("$type", peop.Type);
cmd.ExecuteNonQuery();
}
_database.LibraryLinks.Add(new LibraryLink {LibraryID = library.ID, CollectionID = collection.ID});
_database.CollectionLinks.Add(new CollectionLink { CollectionID = collection.ID, ShowID = show.ID});
}
_database.LibraryLinks.Add(new LibraryLink {LibraryID = library.ID, ShowID = show.ID});
_database.SaveChanges();
}
public void AddShowToCollection(long showID, long collectionID)
{
string linkQuery = "INSERT INTO collectionsLinks (collectionID, showID) VALUES($collectionID, $showID);";
using (SQLiteCommand cmd = new SQLiteCommand(linkQuery, sqlConnection))
{
cmd.Parameters.AddWithValue("$collectionID", collectionID);
cmd.Parameters.AddWithValue("$showID", showID);
cmd.ExecuteNonQuery();
}
}
public void RemoveShow(long showID)
{
string query = "DELETE FROM shows WHERE id = $showID;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$showID", showID);
cmd.ExecuteNonQuery();
}
_database.Shows.Remove(new Show {ID = showID});
}
public void RemoveSeason(long showID, long seasonID)
public void RemoveSeason(long seasonID)
{
string query = "DELETE FROM seasons WHERE id = $seasonID;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$seasonID", seasonID);
cmd.ExecuteNonQuery();
}
if (GetSeasons(showID).Count() == 0)
RemoveShow(showID);
_database.Seasons.Remove(new Season {ID = seasonID});
}
public void RemoveEpisode(Episode episode)
public void RemoveEpisode(long episodeID)
{
string query = "DELETE FROM episodes WHERE id = $episodeID;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$episodeID", episode.ID);
cmd.ExecuteNonQuery();
}
if (GetEpisodes(episode.ShowID, episode.SeasonNumber).Count() == 0)
RemoveSeason(episode.ShowID, episode.SeasonID);
_database.Episodes.Remove(new Episode {ID = episodeID});
}
public void ClearSubtitles(long episodeID)
{
string query = "DELETE FROM tracks WHERE episodeID = $episodeID;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$episodeID", episodeID);
cmd.ExecuteNonQuery();
}
_database.Tracks.RemoveRange(_database.Tracks.Where(x => x.EpisodeID == episodeID));
}
#endregion
}

View File

@ -31,7 +31,7 @@ namespace Kyoo.Controllers
if (library == null)
return NotFound();
return _libraryManager.GetShowsInLibrary(library.Id).ToList();
return _libraryManager.GetShowsInLibrary(library.ID).ToList();
}
}
}

View File

@ -23,7 +23,7 @@ namespace Kyoo.Controllers
if (people == null)
return NotFound();
Collection collection = new Collection(0, people.Slug, people.Name, null, null)
Collection collection = new Collection(people.Slug, people.Name, null, null)
{
Shows = libraryManager.GetShowsByPeople(people.ID),
Poster = "peopleimg/" + people.Slug