diff --git a/API/API.csproj b/API/API.csproj
index 52664396f..bdfb017a6 100644
--- a/API/API.csproj
+++ b/API/API.csproj
@@ -19,4 +19,8 @@
+
+
+
+
diff --git a/API/Controllers/LibraryController.cs b/API/Controllers/LibraryController.cs
index 4800a8cbb..5aee3e0bc 100644
--- a/API/Controllers/LibraryController.cs
+++ b/API/Controllers/LibraryController.cs
@@ -99,5 +99,16 @@ namespace API.Controllers
return BadRequest("Not Implemented");
}
+
+ [Authorize(Policy = "RequireAdminRole")]
+ [HttpGet("scan")]
+ public async Task ScanLibrary(int libraryId)
+ {
+ var library = await _libraryRepository.GetLibraryForIdAsync(libraryId);
+
+ _directoryService.ScanLibrary(library);
+
+ return Ok();
+ }
}
}
\ No newline at end of file
diff --git a/API/Data/LibraryRepository.cs b/API/Data/LibraryRepository.cs
index 68e6371bd..b7bd978a1 100644
--- a/API/Data/LibraryRepository.cs
+++ b/API/Data/LibraryRepository.cs
@@ -37,6 +37,15 @@ namespace API.Data
.Include(f => f.Folders)
.ProjectTo(_mapper.ConfigurationProvider).ToListAsync();
}
+
+ public async Task GetLibraryForIdAsync(int libraryId)
+ {
+ return await _context.Library
+ .Where(x => x.Id == libraryId)
+ .Include(f => f.Folders)
+ .ProjectTo(_mapper.ConfigurationProvider).SingleAsync();
+ }
+
public async Task LibraryExists(string libraryName)
{
diff --git a/API/Interfaces/IDirectoryService.cs b/API/Interfaces/IDirectoryService.cs
index 87a2b9f98..3c7151794 100644
--- a/API/Interfaces/IDirectoryService.cs
+++ b/API/Interfaces/IDirectoryService.cs
@@ -1,10 +1,14 @@
using System.Collections.Generic;
using System.Threading.Tasks;
+using API.DTOs;
+using API.Entities;
namespace API.Interfaces
{
public interface IDirectoryService
{
IEnumerable ListDirectory(string rootPath);
+
+ void ScanLibrary(LibraryDto library);
}
}
\ No newline at end of file
diff --git a/API/Interfaces/ILibraryRepository.cs b/API/Interfaces/ILibraryRepository.cs
index 3f929efda..ae2cf88d8 100644
--- a/API/Interfaces/ILibraryRepository.cs
+++ b/API/Interfaces/ILibraryRepository.cs
@@ -17,6 +17,6 @@ namespace API.Interfaces
///
Task LibraryExists(string libraryName);
- Task> GetLibrariesForUserAsync(AppUser user);
+ public Task GetLibraryForIdAsync(int libraryId);
}
}
\ No newline at end of file
diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs
index 49de3db48..1109f2305 100644
--- a/API/Services/DirectoryService.cs
+++ b/API/Services/DirectoryService.cs
@@ -1,16 +1,28 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.Diagnostics;
using System.IO;
using System.Linq;
+using System.Security;
+using System.Threading;
using System.Threading.Tasks;
+using API.DTOs;
using API.Interfaces;
+using Microsoft.Extensions.Logging;
namespace API.Services
{
public class DirectoryService : IDirectoryService
{
- ///
+ private readonly ILogger _logger;
+
+ public DirectoryService(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ ///
/// Lists out top-level folders for a given directory. Filters out System and Hidden folders.
///
/// Absolute path
@@ -27,5 +39,132 @@ namespace API.Services
return dirs;
}
+
+ public void ScanLibrary(LibraryDto library)
+ {
+ foreach (var folderPath in library.Folders)
+ {
+ try {
+ TraverseTreeParallelForEach(folderPath, (f) =>
+ {
+ // Exceptions are no-ops.
+ try {
+ // Do nothing with the data except read it.
+ //byte[] data = File.ReadAllBytes(f);
+ ProcessManga(f);
+ }
+ catch (FileNotFoundException) {}
+ catch (IOException) {}
+ catch (UnauthorizedAccessException) {}
+ catch (SecurityException) {}
+ // Display the filename.
+ Console.WriteLine(f);
+ });
+ }
+ catch (ArgumentException) {
+ Console.WriteLine(@"The directory 'C:\Program Files' does not exist.");
+ }
+ }
+ }
+
+ private static void ProcessManga(string filename)
+ {
+ Console.WriteLine($"Found {filename}");
+ }
+
+ public static void TraverseTreeParallelForEach(string root, Action action)
+ {
+ //Count of files traversed and timer for diagnostic output
+ int fileCount = 0;
+ var sw = Stopwatch.StartNew();
+
+ // Determine whether to parallelize file processing on each folder based on processor count.
+ int procCount = System.Environment.ProcessorCount;
+
+ // Data structure to hold names of subfolders to be examined for files.
+ Stack dirs = new Stack();
+
+ if (!Directory.Exists(root)) {
+ throw new ArgumentException();
+ }
+ dirs.Push(root);
+
+ while (dirs.Count > 0) {
+ string currentDir = dirs.Pop();
+ string[] subDirs = {};
+ string[] files = {};
+
+ try {
+ subDirs = Directory.GetDirectories(currentDir);
+ }
+ // Thrown if we do not have discovery permission on the directory.
+ catch (UnauthorizedAccessException e) {
+ Console.WriteLine(e.Message);
+ continue;
+ }
+ // Thrown if another process has deleted the directory after we retrieved its name.
+ catch (DirectoryNotFoundException e) {
+ Console.WriteLine(e.Message);
+ continue;
+ }
+
+ try {
+ files = Directory.GetFiles(currentDir);
+ }
+ catch (UnauthorizedAccessException e) {
+ Console.WriteLine(e.Message);
+ continue;
+ }
+ catch (DirectoryNotFoundException e) {
+ Console.WriteLine(e.Message);
+ continue;
+ }
+ catch (IOException e) {
+ Console.WriteLine(e.Message);
+ continue;
+ }
+
+ // Execute in parallel if there are enough files in the directory.
+ // Otherwise, execute sequentially.Files are opened and processed
+ // synchronously but this could be modified to perform async I/O.
+ try {
+ if (files.Length < procCount) {
+ foreach (var file in files) {
+ action(file);
+ fileCount++;
+ }
+ }
+ else {
+ Parallel.ForEach(files, () => 0, (file, loopState, localCount) =>
+ { action(file);
+ return (int) ++localCount;
+ },
+ (c) => {
+ Interlocked.Add(ref fileCount, c);
+ });
+ }
+ }
+ catch (AggregateException ae) {
+ ae.Handle((ex) => {
+ if (ex is UnauthorizedAccessException) {
+ // Here we just output a message and go on.
+ Console.WriteLine(ex.Message);
+ return true;
+ }
+ // Handle other exceptions here if necessary...
+
+ return false;
+ });
+ }
+
+ // Push the subdirectories onto the stack for traversal.
+ // This could also be done before handing the files.
+ foreach (string str in subDirs)
+ dirs.Push(str);
+ }
+
+ // For diagnostic purposes.
+ Console.WriteLine("Processed {0} files in {1} milliseconds", fileCount, sw.ElapsedMilliseconds);
+ }
}
}
\ No newline at end of file