diff --git a/Kyoo.sln b/Kyoo.sln index 73bcb2bd..c62dd9b4 100644 --- a/Kyoo.sln +++ b/Kyoo.sln @@ -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 diff --git a/Kyoo/ClientApp/src/app/app-routing.module.ts b/Kyoo/ClientApp/src/app/app-routing.module.ts index 392c8767..c0aa7cf2 100644 --- a/Kyoo/ClientApp/src/app/app-routing.module.ts +++ b/Kyoo/ClientApp/src/app/app-routing.module.ts @@ -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 } ]; diff --git a/Kyoo/ClientApp/src/app/services/people-resolver.service.ts b/Kyoo/ClientApp/src/app/services/people-resolver.service.ts new file mode 100644 index 00000000..053ce283 --- /dev/null +++ b/Kyoo/ClientApp/src/app/services/people-resolver.service.ts @@ -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 +{ + constructor(private http: HttpClient, private snackBar: MatSnackBar) { } + + resolve(route: ActivatedRouteSnapshot): Collection | Observable | Promise + { + let people: string = route.paramMap.get("people-slug"); + return this.http.get("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; + })); + } +} diff --git a/Kyoo/Controllers/PeopleController.cs b/Kyoo/Controllers/PeopleController.cs new file mode 100644 index 00000000..3ef6c53c --- /dev/null +++ b/Kyoo/Controllers/PeopleController.cs @@ -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 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; + } + } +} \ No newline at end of file diff --git a/Kyoo/InternalAPI/Crawler/Crawler.cs b/Kyoo/InternalAPI/Crawler/Crawler.cs index d6b035f3..eb783413 100644 --- a/Kyoo/InternalAPI/Crawler/Crawler.cs +++ b/Kyoo/InternalAPI/Crawler/Crawler.cs @@ -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(); + IEnumerable 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("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("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 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 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 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); } } } diff --git a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs index fe7b2045..6a9bcb1a 100644 --- a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs +++ b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs @@ -16,6 +16,8 @@ namespace Kyoo.InternalAPI List GetSeasons(long showID); int GetSeasonCount(string showSlug, long seasonNumber); IEnumerable GetShowsInCollection(long collectionID); + IEnumerable GetShowsByPeople(long peopleID); + IEnumerable GetLibrariesPath(); //Internal HTML read (List audios, List subtitles) GetStreams(long episodeID, string showSlug); @@ -55,6 +57,7 @@ namespace Kyoo.InternalAPI void RegisterShowPeople(long showID, List actors); void AddShowToCollection(long showID, long collectionID); + void RegisterInLibrary(long showID, string libraryPath); void ClearSubtitles(long episodeID); } diff --git a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs index 07ce0dd3..d73f505d 100644 --- a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs +++ b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs @@ -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 GetLibrariesPath() + { + string query = "SELECT path FROM libraries;"; + + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) + { + SQLiteDataReader reader = cmd.ExecuteReader(); + + List libraries = new List(); + + 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 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 shows = new List(); + 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);"; diff --git a/Kyoo/InternalAPI/MetadataProvider/ProviderManager.cs b/Kyoo/InternalAPI/MetadataProvider/ProviderManager.cs index cbb053a2..4847ebed 100644 --- a/Kyoo/InternalAPI/MetadataProvider/ProviderManager.cs +++ b/Kyoo/InternalAPI/MetadataProvider/ProviderManager.cs @@ -120,7 +120,7 @@ namespace Kyoo.InternalAPI } Show show = Merge(datas); - return thumbnailsManager.Validate(show); + return await thumbnailsManager.Validate(show); } public async Task 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> GetPeople(string id) { List actors = await providers[0].GetPeople(id); - return thumbnailsManager.Validate(actors); + return await thumbnailsManager.Validate(actors); } } } diff --git a/Kyoo/InternalAPI/ThumbnailsManager/IThumbnailsManager.cs b/Kyoo/InternalAPI/ThumbnailsManager/IThumbnailsManager.cs index 8207d2da..4d11d7f3 100644 --- a/Kyoo/InternalAPI/ThumbnailsManager/IThumbnailsManager.cs +++ b/Kyoo/InternalAPI/ThumbnailsManager/IThumbnailsManager.cs @@ -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 Validate(List actors); - Episode Validate(Episode episode); + Task Validate(Show show); + Task> Validate(List actors); + Task Validate(Episode episode); } } diff --git a/Kyoo/InternalAPI/ThumbnailsManager/ThumbnailsManager.cs b/Kyoo/InternalAPI/ThumbnailsManager/ThumbnailsManager.cs index b213d804..0a4d8f3b 100644 --- a/Kyoo/InternalAPI/ThumbnailsManager/ThumbnailsManager.cs +++ b/Kyoo/InternalAPI/ThumbnailsManager/ThumbnailsManager.cs @@ -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 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 Validate(List people) + public async Task> Validate(List 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 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); } } diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj index fc679713..c767bc03 100644 --- a/Kyoo/Kyoo.csproj +++ b/Kyoo/Kyoo.csproj @@ -22,7 +22,7 @@ - + diff --git a/Kyoo/Models/Library.cs b/Kyoo/Models/Library.cs index 31f072e8..200a7c1d 100644 --- a/Kyoo/Models/Library.cs +++ b/Kyoo/Models/Library.cs @@ -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); } } } diff --git a/Kyoo/Models/Show.cs b/Kyoo/Models/Show.cs index eb4b6639..c6fb6784 100644 --- a/Kyoo/Models/Show.cs +++ b/Kyoo/Models/Show.cs @@ -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; diff --git a/Kyoo/Transcoder/Kyoo.Transcoder.dll b/Kyoo/Transcoder/Kyoo.Transcoder.dll index db26c246..4406502e 100644 Binary files a/Kyoo/Transcoder/Kyoo.Transcoder.dll and b/Kyoo/Transcoder/Kyoo.Transcoder.dll differ diff --git a/Kyoo/appsettings.json b/Kyoo/appsettings.json index 1ff0ec3c..6fb127c3 100644 --- a/Kyoo/appsettings.json +++ b/Kyoo/appsettings.json @@ -13,9 +13,6 @@ "peoplePath": "D:\\\\Videos\\People", "plugins": "C:\\Projects\\Kyoo\\Debug", "providerPlugins": "C://Projects/Plugins/Providers", - "libraryPaths": [ - "\\\\sdg\\video\\Anime" - ], - "regex": ".*\\\\(?.+?)?\\\\.*\\\\(?.+?) S(?\\d+)E(?\\d+)", + "regex": "^(\\\\(?.+?))?\\\\.*\\\\(?.+?) S(?\\d+)E(?\\d+)", "absoluteRegex": ".*\\\\(?.+?) (?\\d+)" } diff --git a/Unit Tests/Kyoo-InternalAPI/Thumbnails-Tests.cs b/Unit Tests/Kyoo-InternalAPI/Thumbnails-Tests.cs new file mode 100644 index 00000000..021bbdf0 --- /dev/null +++ b/Unit Tests/Kyoo-InternalAPI/Thumbnails-Tests.cs @@ -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 + ")"); + } + } +} diff --git a/Unit Tests/Unit Tests.csproj b/Unit Tests/Unit Tests.csproj new file mode 100644 index 00000000..7fcc014e --- /dev/null +++ b/Unit Tests/Unit Tests.csproj @@ -0,0 +1,29 @@ + + + + netcoreapp3.0 + UnitTests + + false + + UnitTests + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/Unit Tests/appsettings.json b/Unit Tests/appsettings.json new file mode 100644 index 00000000..6fb127c3 --- /dev/null +++ b/Unit Tests/appsettings.json @@ -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": "^(\\\\(?.+?))?\\\\.*\\\\(?.+?) S(?\\d+)E(?\\d+)", + "absoluteRegex": ".*\\\\(?.+?) (?\\d+)" +}