Solving a bug with images and adding unit tests.

This commit is contained in:
Zoe Roux 2019-10-19 17:30:47 +02:00
parent 0829a7aba0
commit 8b0dca8fbf
18 changed files with 385 additions and 146 deletions

View File

@ -10,6 +10,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo", "Kyoo\Kyoo.csproj",
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Kyoo.Transcoder", "Kyoo.Transcoder\Kyoo.Transcoder.vcxproj", "{E5EFA4B2-F09D-4C4F-83DD-A436CD60BB77}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Unit Tests", "Unit Tests\Unit Tests.csproj", "{CC8144B5-8868-4EA7-B171-4E47746ED003}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -42,6 +44,18 @@ Global
{E5EFA4B2-F09D-4C4F-83DD-A436CD60BB77}.Release|x64.Build.0 = Release|x64
{E5EFA4B2-F09D-4C4F-83DD-A436CD60BB77}.Release|x86.ActiveCfg = Release|Win32
{E5EFA4B2-F09D-4C4F-83DD-A436CD60BB77}.Release|x86.Build.0 = Release|Win32
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Debug|x64.ActiveCfg = Debug|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Debug|x64.Build.0 = Debug|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Debug|x86.ActiveCfg = Debug|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Debug|x86.Build.0 = Debug|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Release|Any CPU.Build.0 = Release|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Release|x64.ActiveCfg = Release|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Release|x64.Build.0 = Release|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Release|x86.ActiveCfg = Release|Any CPU
{CC8144B5-8868-4EA7-B171-4E47746ED003}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -10,13 +10,15 @@ import { PlayerComponent } from "./player/player.component";
import { StreamResolverService } from "./services/stream-resolver.service";
import { CollectionComponent } from "./collection/collection.component";
import { CollectionResolverService } from "./services/collection-resolver.service";
import { PeopleResolverService } from "./services/people-resolver.service";
const routes: Routes = [
{ path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService } },
{ path: "browse/:library-slug", component: BrowseComponent, resolve: { shows: LibraryResolverService } },
{ path: "show/:show-slug", component: ShowDetailsComponent, resolve: { show: ShowResolverService } },
{ path: "collection/:collection-slug", component: CollectionComponent, resolve: { collection: CollectionResolverService } },
{ path: "collection/:collection-slug", component: CollectionComponent, resolve: { collection: CollectionResolverService } },
{ path: "people/:people-slug", component: CollectionComponent, resolve: { collection: PeopleResolverService } },
{ path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService } },
{ path: "**", component: NotFoundComponent }
];

View File

@ -0,0 +1,34 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { EMPTY, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Collection } from "../../models/collection";
import { People } from "../../models/people";
@Injectable({
providedIn: 'root'
})
export class PeopleResolverService implements Resolve<Collection>
{
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
resolve(route: ActivatedRouteSnapshot): Collection | Observable<Collection> | Promise<Collection>
{
let people: string = route.paramMap.get("people-slug");
return this.http.get<Collection>("api/people/" + people).pipe(catchError((error: HttpErrorResponse) =>
{
console.log(error.status + " - " + error.message);
if (error.status == 404)
{
this.snackBar.open("People \"" + people + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
}
else
{
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
}
return EMPTY;
}));
}
}

View File

@ -0,0 +1,36 @@
using Kyoo.InternalAPI;
using Kyoo.Models;
using Microsoft.AspNetCore.Mvc;
using System.Diagnostics;
namespace Kyoo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PeopleController : ControllerBase
{
private readonly ILibraryManager libraryManager;
public PeopleController(ILibraryManager libraryManager)
{
this.libraryManager = libraryManager;
}
[HttpGet("{people-slug}")]
public ActionResult<Collection> GetPeople(string slug)
{
People people = libraryManager.GetPeopleBySlug(slug);
//This always return not found
if (people == null)
return NotFound();
Debug.WriteLine("&People: " + people.Name);
Collection collection = new Collection(0, people.slug, people.Name, null, null)
{
Shows = libraryManager.GetShowsByPeople(people.id)
};
return collection;
}
}
}

View File

@ -26,7 +26,7 @@ namespace Kyoo.InternalAPI
this.libraryManager = libraryManager;
this.metadataProvider = metadataProvider;
this.transcoder = transcoder;
config = configuration;
this.config = configuration;
cancellation = new CancellationTokenSource();
}
@ -39,7 +39,7 @@ namespace Kyoo.InternalAPI
private Task StartAsync(bool watch, CancellationToken cancellationToken)
{
Debug.WriteLine("&Crawler started");
string[] paths = config.GetSection("libraryPaths").Get<string[]>();
IEnumerable<string> paths = libraryManager.GetLibrariesPath();
foreach (string path in paths)
{
@ -65,71 +65,72 @@ namespace Kyoo.InternalAPI
return;
if (IsVideo(file))
await TryRegisterEpisode(file);
await ExtractEpisodeData(file, folderPath);
}
}
public void Watch(string folderPath, CancellationToken cancellationToken)
{
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 TryRegisterEpisode(string path)
{
if (!libraryManager.IsEpisodeRegistered(path))
//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))
{
string relativePath = episodePath.Substring(libraryPath.Length);
string patern = config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
Match match = regex.Match(path);
Match match = regex.Match(relativePath);
string showPath = Path.GetDirectoryName(path);
string showPath = Path.GetDirectoryName(episodePath);
string collectionName = match.Groups["Collection"]?.Value;
string showName = match.Groups["ShowTitle"].Value;
bool seasonSuccess = long.TryParse(match.Groups["Season"].Value, out long seasonNumber);
@ -143,81 +144,93 @@ namespace Kyoo.InternalAPI
episodeNumber = -1;
regex = new Regex(config.GetValue<string>("absoluteRegex"));
match = regex.Match(path);
match = regex.Match(relativePath);
showName = match.Groups["ShowTitle"].Value;
bool absoluteSucess = long.TryParse(match.Groups["AbsoluteNumber"].Value, out absoluteNumber);
if (!absoluteSucess)
{
Debug.WriteLine("&Couldn't find basic data for the episode (regexs didn't match) at " + path);
Debug.WriteLine("&Couldn't find basic data for the episode (regexs didn't match) at " + episodePath);
return;
}
}
string showProviderIDs;
if (!libraryManager.IsShowRegistered(showPath, out long showID))
{
Show show = await metadataProvider.GetShowFromName(showName, showPath);
showProviderIDs = show.ExternalIDs;
showID = libraryManager.RegisterShow(show);
Show show = await RegisterOrGetShow(collectionName, showName, showPath, libraryPath);
await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, episodePath);
}
}
if (collectionName != null)
private async Task<Show> RegisterOrGetShow(string collectionName, string showTitle, string showPath, string libraryPath)
{
string showProviderIDs;
if (!libraryManager.IsShowRegistered(showPath, out long showID))
{
Show show = await metadataProvider.GetShowFromName(showTitle, showPath);
showProviderIDs = show.ExternalIDs;
showID = libraryManager.RegisterShow(show);
libraryManager.RegisterInLibrary(showID, libraryPath);
if (collectionName != null)
{
if (!libraryManager.IsCollectionRegistered(Slugifier.ToSlug(collectionName), out long collectionID))
{
if (!libraryManager.IsCollectionRegistered(Slugifier.ToSlug(collectionName), out long collectionID))
Collection collection = await metadataProvider.GetCollectionFromName(collectionName);
collectionID = libraryManager.RegisterCollection(collection);
}
libraryManager.AddShowToCollection(showID, collectionID);
}
List<People> actors = await metadataProvider.GetPeople(show.ExternalIDs);
libraryManager.RegisterShowPeople(showID, actors);
}
else
showProviderIDs = libraryManager.GetShowExternalIDs(showID);
return new Show { id = showID, ExternalIDs = showProviderIDs, Title = showTitle };
}
private async Task RegisterEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath)
{
long seasonID = -1;
if (seasonNumber != -1)
{
if (!libraryManager.IsSeasonRegistered(show.id, seasonNumber, out seasonID))
{
Season season = await metadataProvider.GetSeason(show.Title, seasonNumber);
season.ShowID = show.id;
seasonID = libraryManager.RegisterSeason(season);
}
}
Episode episode = await metadataProvider.GetEpisode(show.ExternalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath);
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.ShowID = show.id;
seasonID = libraryManager.RegisterSeason(season);
}
}
episode.SeasonID = seasonID;
episode.id = libraryManager.RegisterEpisode(episode);
if (episode.Path.EndsWith(".mkv"))
{
if (!FindExtractedSubtitles(episode))
{
Track[] tracks = transcoder.ExtractSubtitles(episode.Path);
if (tracks != null)
{
foreach (Track track in tracks)
{
Collection collection = await metadataProvider.GetCollectionFromName(collectionName);
collectionID = libraryManager.RegisterCollection(collection);
}
libraryManager.AddShowToCollection(showID, collectionID);
}
List<People> actors = await metadataProvider.GetPeople(show.ExternalIDs);
libraryManager.RegisterShowPeople(showID, actors);
}
else
showProviderIDs = libraryManager.GetShowExternalIDs(showID);
long seasonID = -1;
if (seasonNumber != -1)
{
if (!libraryManager.IsSeasonRegistered(showID, seasonNumber, out seasonID))
{
Season season = await metadataProvider.GetSeason(showName, seasonNumber);
season.ShowID = showID;
seasonID = libraryManager.RegisterSeason(season);
}
}
Episode episode = await metadataProvider.GetEpisode(showProviderIDs, seasonNumber, episodeNumber, absoluteNumber, path);
episode.ShowID = showID;
if (seasonID == -1)
{
if (!libraryManager.IsSeasonRegistered(showID, episode.seasonNumber, out seasonID))
{
Season season = await metadataProvider.GetSeason(showName, episode.seasonNumber);
season.ShowID = showID;
seasonID = libraryManager.RegisterSeason(season);
}
}
episode.SeasonID = seasonID;
long episodeID = libraryManager.RegisterEpisode(episode);
episode.id = episodeID;
if (episode.Path.EndsWith(".mkv"))
{
if (!FindExtractedSubtitles(episode))
{
Track[] tracks = transcoder.ExtractSubtitles(episode.Path);
if (tracks != null)
{
foreach (Track track in tracks)
{
track.episodeID = episode.id;
libraryManager.RegisterTrack(track);
}
track.episodeID = episode.id;
libraryManager.RegisterTrack(track);
}
}
}

View File

@ -16,6 +16,8 @@ namespace Kyoo.InternalAPI
List<Season> GetSeasons(long showID);
int GetSeasonCount(string showSlug, long seasonNumber);
IEnumerable<Show> GetShowsInCollection(long collectionID);
IEnumerable<Show> GetShowsByPeople(long peopleID);
IEnumerable<string> GetLibrariesPath();
//Internal HTML read
(List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string showSlug);
@ -55,6 +57,7 @@ namespace Kyoo.InternalAPI
void RegisterShowPeople(long showID, List<People> actors);
void AddShowToCollection(long showID, long collectionID);
void RegisterInLibrary(long showID, string libraryPath);
void ClearSubtitles(long episodeID);
}

View File

@ -88,12 +88,13 @@ namespace Kyoo.InternalAPI
CREATE TABLE libraries(
id INTEGER PRIMARY KEY UNIQUE,
slug TEXT UNIQUE,
name TEXT
name TEXT,
path TEXT
);
CREATE TABLE librariesLinks(
librarieID INTEGER,
libraryID INTEGER,
showID INTEGER,
FOREIGN KEY(librarieID) REFERENCES libraries(id),
FOREIGN KEY(libraryID) REFERENCES libraries(id),
FOREIGN KEY(showID) REFERENCES shows(id)
);
@ -190,6 +191,23 @@ namespace Kyoo.InternalAPI
}
}
public IEnumerable<string> GetLibrariesPath()
{
string query = "SELECT path FROM libraries;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
SQLiteDataReader reader = cmd.ExecuteReader();
List<string> libraries = new List<string>();
while (reader.Read())
libraries.Add(reader["path"] as string);
return libraries;
}
}
public string GetShowExternalIDs(long showID)
{
string query = string.Format("SELECT * FROM shows WHERE id = {0};", showID);
@ -561,6 +579,22 @@ namespace Kyoo.InternalAPI
return shows;
}
}
public IEnumerable<Show> GetShowsByPeople(long peopleID)
{
string query = "SELECT * FROM shows JOIN peopleLinks l ON l.showID = shows.id WHERE l.peopleID = $id;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$id", peopleID);
SQLiteDataReader reader = cmd.ExecuteReader();
List<Show> shows = new List<Show>();
while (reader.Read())
shows.Add(Show.FromReader(reader));
return shows;
}
}
#endregion
#region Check if items exists
@ -726,6 +760,18 @@ namespace Kyoo.InternalAPI
}
}
public void RegisterInLibrary(long showID, string libraryPath)
{
string query = "INSERT INTO librariesLinks (libraryID, showID) SELECT id, $showID FROM libraries WHERE libraries.path = $libraryPath;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$libraryPath", libraryPath);
cmd.Parameters.AddWithValue("$showID", showID);
cmd.ExecuteNonQuery();
}
}
public long RegisterShow(Show show)
{
string query = "INSERT INTO shows (slug, title, aliases, path, overview, trailerUrl, startYear, endYear, imgPrimary, imgThumb, imgLogo, imgBackdrop, externalIDs) VALUES($slug, $title, $aliases, $path, $overview, $trailerUrl, $startYear, $endYear, $imgPrimary, $imgThumb, $imgLogo, $imgBackdrop, $externalIDs);";

View File

@ -120,7 +120,7 @@ namespace Kyoo.InternalAPI
}
Show show = Merge(datas);
return thumbnailsManager.Validate(show);
return await thumbnailsManager.Validate(show);
}
public async Task<Season> GetSeason(string showName, long seasonNumber)
@ -151,13 +151,13 @@ namespace Kyoo.InternalAPI
Episode episode = Merge(datas);
episode.Path = episodePath;
return thumbnailsManager.Validate(episode);
return await thumbnailsManager.Validate(episode);
}
public async Task<List<People>> GetPeople(string id)
{
List<People> actors = await providers[0].GetPeople(id);
return thumbnailsManager.Validate(actors);
return await thumbnailsManager.Validate(actors);
}
}
}

View File

@ -1,12 +1,13 @@
using Kyoo.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Kyoo.InternalAPI.ThumbnailsManager
{
public interface IThumbnailsManager
{
Show Validate(Show show);
List<People> Validate(List<People> actors);
Episode Validate(Episode episode);
Task<Show> Validate(Show show);
Task<List<People>> Validate(List<People> actors);
Task<Episode> Validate(Episode episode);
}
}

View File

@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading.Tasks;
namespace Kyoo.InternalAPI.ThumbnailsManager
{
@ -17,7 +18,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
config = configuration;
}
public Show Validate(Show show)
public async Task<Show> Validate(Show show)
{
string localThumb = Path.Combine(show.Path, "poster.jpg");
string localLogo = Path.Combine(show.Path, "logo.png");
@ -30,7 +31,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
{
using (WebClient client = new WebClient())
{
client.DownloadFileAsync(new Uri(show.ImgPrimary), localThumb);
await client.DownloadFileTaskAsync(new Uri(show.ImgPrimary), localThumb);
}
}
}
@ -41,7 +42,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
{
using (WebClient client = new WebClient())
{
client.DownloadFileAsync(new Uri(show.ImgLogo), localLogo);
await client.DownloadFileTaskAsync(new Uri(show.ImgLogo), localLogo);
}
}
}
@ -52,7 +53,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
{
using (WebClient client = new WebClient())
{
client.DownloadFileAsync(new Uri(show.ImgBackdrop), localBackdrop);
await client.DownloadFileTaskAsync(new Uri(show.ImgBackdrop), localBackdrop);
}
}
}
@ -60,7 +61,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
return show;
}
public List<People> Validate(List<People> people)
public async Task<List<People>> Validate(List<People> people)
{
for (int i = 0; i < people?.Count; i++)
{
@ -73,7 +74,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
using (WebClient client = new WebClient())
{
Debug.WriteLine("&" + localThumb);
client.DownloadFileAsync(new Uri(people[i].imgPrimary), localThumb);
await client.DownloadFileTaskAsync(new Uri(people[i].imgPrimary), localThumb);
}
}
}
@ -81,7 +82,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
return people;
}
public Episode Validate(Episode episode)
public async Task<Episode> Validate(Episode episode)
{
//string localThumb = Path.ChangeExtension(episode.Path, "jpg");
string localThumb = episode.Path.Replace(Path.GetExtension(episode.Path), "-thumb.jpg");
@ -89,7 +90,7 @@ namespace Kyoo.InternalAPI.ThumbnailsManager
{
using (WebClient client = new WebClient())
{
client.DownloadFileAsync(new Uri(episode.ImgPrimary), localThumb);
await client.DownloadFileTaskAsync(new Uri(episode.ImgPrimary), localThumb);
}
}

View File

@ -22,7 +22,7 @@
<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.Extensions.Options.ConfigurationExtensions" Version="2.1.1" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.9" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.10" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="System.Data.SQLite" Version="1.0.111" />
</ItemGroup>

View File

@ -7,19 +7,22 @@ namespace Kyoo.Models
[JsonIgnore] public readonly long id;
public string Slug;
public string Name;
public string Path;
public Library(long id, string slug, string name)
public Library(long id, string slug, string name, string path)
{
this.id = id;
Slug = slug;
Name = name;
Path = path;
}
public static Library FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Library((long)reader["id"],
reader["slug"] as string,
reader["name"] as string);
reader["name"] as string,
reader["path"] as string);
}
}
}

View File

@ -6,7 +6,7 @@ namespace Kyoo.Models
{
public class Show
{
[JsonIgnore] public readonly long id = -1;
[JsonIgnore] public long id = -1;
public string Slug;
public string Title;

Binary file not shown.

View File

@ -13,9 +13,6 @@
"peoplePath": "D:\\\\Videos\\People",
"plugins": "C:\\Projects\\Kyoo\\Debug",
"providerPlugins": "C://Projects/Plugins/Providers",
"libraryPaths": [
"\\\\sdg\\video\\Anime"
],
"regex": ".*\\\\(?<Collection>.+?)?\\\\.*\\\\(?<ShowTitle>.+?) S(?<Season>\\d+)E(?<Episode>\\d+)",
"regex": "^(\\\\(?<Collection>.+?))?\\\\.*\\\\(?<ShowTitle>.+?) S(?<Season>\\d+)E(?<Episode>\\d+)",
"absoluteRegex": ".*\\\\(?<ShowTitle>.+?) (?<AbsoluteNumber>\\d+)"
}

View File

@ -0,0 +1,42 @@
using Kyoo;
using Kyoo.InternalAPI;
using Kyoo.InternalAPI.ThumbnailsManager;
using Kyoo.Models;
using Microsoft.AspNetCore.Mvc.Testing;
using Microsoft.Extensions.Configuration;
using NUnit.Framework;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace UnitTests.Kyoo_InternalAPI
{
public class Tests
{
private IConfiguration config;
[SetUp]
public void Setup()
{
config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
}
[Test]
public async Task DownloadShowImages()
{
LibraryManager library = new LibraryManager(config);
ThumbnailsManager manager = new ThumbnailsManager(config);
Show show = library.GetShowBySlug(library.QueryShows(null).FirstOrDefault().Slug);
Debug.WriteLine("&Show: " + show.Path);
string posterPath = Path.Combine(show.Path, "poster.jpg");
File.Delete(posterPath);
await manager.Validate(show);
long posterLength = new FileInfo(posterPath).Length;
Assert.IsTrue(posterLength > 0, "Poster size is zero for the tested show (" + posterPath + ")");
}
}
}

View File

@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<RootNamespace>UnitTests</RootNamespace>
<IsPackable>false</IsPackable>
<AssemblyName>UnitTests</AssemblyName>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.0.0" />
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Kyoo\Kyoo.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -0,0 +1,18 @@
{
"server.urls": "http://0.0.0.0:5000",
"https_port": 44300,
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"databasePath": "C://Projects/database.db",
"tempPath": "C:\\\\Projects\\temp",
"peoplePath": "D:\\\\Videos\\People",
"plugins": "C:\\Projects\\Kyoo\\Debug",
"providerPlugins": "C://Projects/Plugins/Providers",
"regex": "^(\\\\(?<Collection>.+?))?\\\\.*\\\\(?<ShowTitle>.+?) S(?<Season>\\d+)E(?<Episode>\\d+)",
"absoluteRegex": ".*\\\\(?<ShowTitle>.+?) (?<AbsoluteNumber>\\d+)"
}