Calibre_EntityFrameworkCore
Changes
src/Calibre.Model.Database/CalibreContext.cs 21(+2 -19)
src/Calibre.Model.Domain/Dal/SearchProvider.cs 172(+172 -0)
src/Calibre.Model.Domain/Entities/Library.cs 134(+134 -0)
src/Calibre.sln 16(+15 -1)
src/Calibre/Calibre.csproj 2(+2 -0)
src/Calibre/Program.cs 269(+142 -127)
src/LibraryText/ApplicationContext.cs 26(+26 -0)
src/LibraryText/Entities/BookTextData.cs 16(+16 -0)
src/LibraryText/LibraryText.csproj 12(+12 -0)
src/Tools.PdfProvider/ImmutableProxy.cs 50(+50 -0)
src/Tools.PdfProvider/SimplePdfReader.cs 65(+41 -24)
Details
src/Calibre.Model.Database/CalibreContext.cs 21(+2 -19)
diff --git a/src/Calibre.Model.Database/CalibreContext.cs b/src/Calibre.Model.Database/CalibreContext.cs
index bbfda10..ab153ee 100644
--- a/src/Calibre.Model.Database/CalibreContext.cs
+++ b/src/Calibre.Model.Database/CalibreContext.cs
@@ -18,7 +18,7 @@ namespace Calibre.Model.Database
public string ConnectionString { private set; get; }
public bool AsNoTracking { set; get; }
- public DirectoryInfo LibraryDirectory { set; get; }
+ //public DirectoryInfo LibraryDirectory { set; get; }
#region Sets
@@ -364,24 +364,7 @@ namespace Calibre.Model.Database
modelBuilder.Entity<BooksLanguagesLink>(entity =>
{
- entity.ToTable("books_languages_link");
-
- entity.HasIndex(e => new { e.Book, e.LangCode }, "IX_books_languages_link_book_lang_code")
- .IsUnique();
-
- entity.HasIndex(e => e.LangCode, "books_languages_link_aidx");
-
- entity.HasIndex(e => e.Book, "books_languages_link_bidx");
-
- entity.Property(e => e.Id)
- .ValueGeneratedNever()
- .HasColumnName("id");
-
- entity.Property(e => e.Book).HasColumnName("book");
-
- entity.Property(e => e.ItemOrder).HasColumnName("item_order");
-
- entity.Property(e => e.LangCode).HasColumnName("lang_code");
+ BooksLanguagesLink.EfSetup(entity);
});
modelBuilder.Entity<BooksPluginDatum>(entity =>
diff --git a/src/Calibre.Model.Database/Entities/Book.cs b/src/Calibre.Model.Database/Entities/Book.cs
index 4012422..badfe05 100644
--- a/src/Calibre.Model.Database/Entities/Book.cs
+++ b/src/Calibre.Model.Database/Entities/Book.cs
@@ -31,7 +31,9 @@ namespace Calibre.Model.Database.Entities
public virtual List<BooksTagsLink> Tags { get; set; }
= new List<BooksTagsLink>();
public virtual List<BooksAuthorsLink> Autors { get; set; }
- = new List<BooksAuthorsLink>();
+ = new List<BooksAuthorsLink>();
+ public virtual List<BooksLanguagesLink> Languages { get; set; }
+ = new List<BooksLanguagesLink>();
public virtual List<Data> FileData { get; set; }
= new List<Data>();
diff --git a/src/Calibre.Model.Database/Entities/Languages/BooksLanguagesLink.cs b/src/Calibre.Model.Database/Entities/Languages/BooksLanguagesLink.cs
index 268b52e..cb6bf1b 100644
--- a/src/Calibre.Model.Database/Entities/Languages/BooksLanguagesLink.cs
+++ b/src/Calibre.Model.Database/Entities/Languages/BooksLanguagesLink.cs
@@ -3,13 +3,62 @@ using System.Collections.Generic;
#nullable disable
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Metadata.Builders;
+
namespace Calibre.Model.Database.Entities
{
public partial class BooksLanguagesLink
{
public long Id { get; set; }
+
+
public long Book { get; set; }
+ public virtual Book BookItem { get; set; }
+
public long LangCode { get; set; }
+ public virtual Language LangItem { get; set; }
+
public long ItemOrder { get; set; }
+
+
+ public override string ToString()
+ {
+ return LangItem?.LangCode;
+ }
+
+
+ internal static void EfSetup(
+ EntityTypeBuilder<BooksLanguagesLink> entity
+ )
+ {
+ entity.ToTable("books_languages_link");
+
+ entity.HasIndex(e => new { e.Book, e.LangCode }, "IX_books_languages_link_book_lang_code")
+ .IsUnique();
+
+ entity.HasIndex(e => e.LangCode, "books_languages_link_aidx");
+
+ entity.HasIndex(e => e.Book, "books_languages_link_bidx");
+
+ entity.Property(e => e.Id)
+ .ValueGeneratedNever()
+ .HasColumnName("id");
+
+ entity.Property(e => e.Book).HasColumnName("book");
+
+ entity.Property(e => e.ItemOrder).HasColumnName("item_order");
+
+ entity.Property(e => e.LangCode).HasColumnName("lang_code");
+
+ entity
+ .HasOne(e => e.BookItem)
+ .WithMany(e => e.Languages)
+ .HasForeignKey(e => e.Book);
+ entity
+ .HasOne(e => e.LangItem)
+ .WithMany(e => e.Books)
+ .HasForeignKey(e => e.LangCode);
+ }
}
}
diff --git a/src/Calibre.Model.Database/Entities/Languages/Language.cs b/src/Calibre.Model.Database/Entities/Languages/Language.cs
index 600c035..4327b70 100644
--- a/src/Calibre.Model.Database/Entities/Languages/Language.cs
+++ b/src/Calibre.Model.Database/Entities/Languages/Language.cs
@@ -9,5 +9,14 @@ namespace Calibre.Model.Database.Entities
{
public long Id { get; set; }
public string LangCode { get; set; }
+
+ public virtual List<BooksLanguagesLink> Books { get; set; }
+ = new List<BooksLanguagesLink>();
+
+
+ public override string ToString()
+ {
+ return LangCode;
+ }
}
}
diff --git a/src/Calibre.Model.Domain/Calibre.Model.Domain.csproj b/src/Calibre.Model.Domain/Calibre.Model.Domain.csproj
new file mode 100644
index 0000000..58d422b
--- /dev/null
+++ b/src/Calibre.Model.Domain/Calibre.Model.Domain.csproj
@@ -0,0 +1,17 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
+ </ItemGroup>
+
+ <ItemGroup>
+ <ProjectReference Include="..\Calibre.Model.Database\Calibre.Model.Database.csproj" />
+ <ProjectReference Include="..\LibraryText\LibraryText.csproj" />
+ <ProjectReference Include="..\Tools.PdfProvider\Tools.PdfProvider.csproj" />
+ </ItemGroup>
+
+</Project>
src/Calibre.Model.Domain/Dal/SearchProvider.cs 172(+172 -0)
diff --git a/src/Calibre.Model.Domain/Dal/SearchProvider.cs b/src/Calibre.Model.Domain/Dal/SearchProvider.cs
new file mode 100644
index 0000000..1822bbf
--- /dev/null
+++ b/src/Calibre.Model.Domain/Dal/SearchProvider.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.IO;
+
+using Microsoft.EntityFrameworkCore;
+
+using Tools.PdfProvider;
+
+using Calibre.Model.Database;
+using Calibre.Model.Database.Entities;
+
+using Calibre.Model.Domain.Entities;
+
+using LibraryText.Entities;
+
+namespace Calibre.Model.Domain.Dal
+{
+ public class SearchProvider
+ {
+ private readonly SimplePdfReader SimplePdfReader;
+
+
+ public SearchProvider(
+ SimplePdfReader simplePdfReader
+ )
+ {
+ SimplePdfReader = simplePdfReader;
+ }
+
+
+ public async Task<Dictionary<Library, BookWithLibraryContainer[]>> GetBooksByLibrariesAsync(
+ Func<Book, bool> whereExpression = null,
+ bool includeTags = true,
+ bool includeAutors = true,
+ bool includeFileData = true,
+ bool includeLang = true,
+ params Library[] libraries
+ )
+ {
+ List<CalibreContext> contexts
+ = new List<CalibreContext>(libraries.Length);
+
+ Dictionary<Library, Task<Book[]>> data
+ = new Dictionary<Library, Task<Book[]>>(libraries.Length);
+
+ try
+ {
+ foreach (var elem in libraries)
+ {
+ var connectionString = Library.BuildConnectionStringFromPath(elem.DbFile.FullName);
+
+ var context = new CalibreContext(connectionString)
+ {
+ AsNoTracking = false,
+ //LibraryDirectory = libraryDirectory
+ };
+ contexts.Add(context);
+
+ IQueryable<Book> selectExpr = context
+ .Books;
+
+ //1) Подгружаем теги
+ if (includeTags)
+ {
+ selectExpr = selectExpr
+ .Include(e => e.Tags)
+ .ThenInclude(e => e.TagItem);
+ }
+
+ //2) Подгружаем авторов
+ if (includeAutors)
+ {
+ selectExpr = selectExpr
+ .Include(e => e.Autors)
+ .ThenInclude(e => e.AuthorItem);
+ }
+
+ //3) Подгружаем данные о фалах
+ if (includeFileData)
+ {
+ selectExpr = selectExpr
+ .Include(e => e.FileData);
+ }
+
+ if (includeLang)
+ {
+ selectExpr = selectExpr
+ .Include(e => e.Languages)
+ .ThenInclude(e => e.LangItem);
+ }
+
+ //4) Условие поиска
+ if (whereExpression != null)
+ {
+ selectExpr = selectExpr
+ .Where(whereExpression)
+ .AsQueryable();
+ }
+
+ var selectResultTask = selectExpr.ToArrayAsync();
+ data.Add(elem, selectResultTask);
+ }
+
+ await Task.WhenAll(
+ data.Values.ToArray()
+ );
+ }
+ finally
+ {
+ contexts.ForEach(
+ e => e.Dispose()
+ );
+ }
+
+
+ Dictionary<Library, BookWithLibraryContainer[]> result
+ = new Dictionary<Library, BookWithLibraryContainer[]>(libraries.Length);
+ foreach (var elem in data)
+ {
+ var library = elem.Key;
+ var libraryProxy = new ImmutableProxy<Library>(library);
+
+ var books = elem.Value.Result
+ .Select(
+ e2 => BookWithLibraryContainer.Create(e2, libraryProxy)
+ )
+ .ToArray();
+
+ result.Add(library, books);
+ }
+
+ return result;
+ }
+
+ public async Task<Dictionary<BookWithLibraryContainer, string>> GetTextByBooksAsync(
+ IList<BookWithLibraryContainer> books,
+ bool ignoreError,
+ Func<BookWithLibraryContainer, string, bool> whereExpression = null
+ )
+ {
+ Dictionary<BookWithLibraryContainer, string> result
+ = new Dictionary<BookWithLibraryContainer, string>(books.Count);
+
+ foreach (var elem in books)
+ {
+ var bookText = await elem.ReadFileAsync(
+ async (s) =>
+ {
+ var res = await SimplePdfReader.ReadPdfAsync(s, ignoreError);
+ return res;
+ }
+ );
+
+ if (whereExpression != null)
+ {
+ if (!whereExpression(elem, bookText))
+ {
+ continue;
+ }
+ }
+
+ result.Add(elem, bookText);
+ }
+
+ return result;
+ }
+ }
+}
diff --git a/src/Calibre.Model.Domain/Entities/BookWithLibraryContainer.cs b/src/Calibre.Model.Domain/Entities/BookWithLibraryContainer.cs
new file mode 100644
index 0000000..0b5296d
--- /dev/null
+++ b/src/Calibre.Model.Domain/Entities/BookWithLibraryContainer.cs
@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.IO;
+
+using Tools.PdfProvider;
+
+using Calibre.Model.Database.Entities;
+
+using LibraryClass = Calibre.Model.Domain.Entities.Library;
+
+namespace Calibre.Model.Domain.Entities
+{
+ /// <summary>
+ /// Immutable
+ /// </summary>
+ public class BookWithLibraryContainer
+ {
+ #region Properties
+
+ public Book Book { private set; get; }
+ public ImmutableProxy<LibraryClass> Library { private set; get; }
+
+ #endregion
+
+
+ private BookWithLibraryContainer()
+ {
+
+ }
+
+
+ #region methods
+
+ public async Task ReadFileAsync(
+ Func<Stream, Task> readActionAsync
+ )
+ {
+ var filePath = LibraryClass.GetPdfFilePath(Library.Data, Book);
+ using (var stream = new FileStream(filePath, FileMode.Open))
+ {
+ await readActionAsync(stream);
+ }
+ }
+
+ public async Task<T> ReadFileAsync<T>(
+ Func<Stream, Task<T>> readActionAsync
+ )
+ {
+ var filePath = LibraryClass.GetPdfFilePath(Library.Data, Book);
+ using (var stream = new FileStream(filePath, FileMode.Open))
+ {
+ var result = await readActionAsync(stream);
+ return result;
+ }
+ }
+
+ #endregion
+
+
+ #region override
+
+ public override int GetHashCode()
+ {
+ return Book.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return Book.ToString();
+ }
+
+ #endregion
+
+
+ #region static
+
+ public static BookWithLibraryContainer Create(
+ Book book,
+ ImmutableProxy<LibraryClass> library
+ )
+ {
+ var item = new BookWithLibraryContainer()
+ {
+ Book = book,
+ Library = library
+ };
+
+ library.MutateValue(
+ e => LibraryClass.AddBookContainer(library.Data, item)
+ );
+
+ return item;
+ }
+
+ #endregion
+ }
+}
src/Calibre.Model.Domain/Entities/Library.cs 134(+134 -0)
diff --git a/src/Calibre.Model.Domain/Entities/Library.cs b/src/Calibre.Model.Domain/Entities/Library.cs
new file mode 100644
index 0000000..7999c51
--- /dev/null
+++ b/src/Calibre.Model.Domain/Entities/Library.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using System.IO;
+using System.Collections.Immutable;
+
+using Calibre.Model.Database.Entities;
+
+namespace Calibre.Model.Domain.Entities
+{
+ /// <summary>
+ /// Immutable
+ /// </summary>
+ public class Library
+ {
+ #region Properties
+
+ public string Name { private set; get; }
+ public string FullName { private set; get; }
+
+ public FileInfo DbFile => new FileInfo(
+ Path.Combine(FullName, DbFileName)
+ );
+
+ public ImmutableDictionary<string, BookWithLibraryContainer> Books { private set; get; }
+ = ImmutableDictionary<string, BookWithLibraryContainer>.Empty;
+
+ #endregion
+
+
+ private Library() { }
+
+
+
+ #region override
+
+ public override int GetHashCode()
+ {
+ return FullName.GetHashCode();
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Library l)
+ {
+ return string.Equals(FullName, l.FullName);
+ }
+
+ return false;
+ }
+
+ public override string ToString()
+ {
+ return FullName;
+ }
+
+ #endregion
+
+
+ #region static
+
+ public static string DbFileName
+ => "metadata.db";
+
+ public static Library[] SearchAll(DirectoryInfo directory)
+ {
+ var dbFiles = directory
+ .GetFiles(
+ DbFileName,
+ SearchOption.AllDirectories
+ )
+ .ToArray();
+
+ var result = dbFiles.Select(
+ e => new Library()
+ {
+ FullName = e.Directory.FullName,
+ Name = e.Directory.Name
+ })
+ .ToArray();
+
+ return result;
+ }
+
+ public static string BuildConnectionStringFromPath(
+ string pathToDbFile
+ )
+ {
+ return $"Filename={pathToDbFile}";
+ }
+
+ public static Library AddBookContainer(
+ Library library,
+ BookWithLibraryContainer bookContainer
+ )
+ {
+ var result = new Library()
+ {
+ Name = library.Name,
+ FullName = library.FullName
+ };
+
+ result.Books = library.Books.Add(
+ bookContainer.Book.Title,
+ bookContainer
+ );
+
+ return result;
+ }
+
+ public static string GetPdfFilePath(
+ Library library,
+ Book book
+ )
+ {
+ var file = book.FileData.First(
+ e => string.Equals(e.Format, "PDF", StringComparison.OrdinalIgnoreCase)
+ );
+
+ var result = Path.Combine(
+ library.FullName,
+ book.Path.Replace('/', '\\'),
+ $"{file.Name}.{file.Format}"
+ );
+
+ return result;
+ }
+
+ #endregion
+ }
+}
src/Calibre.sln 16(+15 -1)
diff --git a/src/Calibre.sln b/src/Calibre.sln
index cb6c14a..c5a1d79 100644
--- a/src/Calibre.sln
+++ b/src/Calibre.sln
@@ -11,7 +11,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Model", "Model", "{951387AC
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{5654144E-E0B3-4C6D-AFEB-799E77215B4E}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tools.PdfProvider", "Tools.PdfProvider\Tools.PdfProvider.csproj", "{057A6C6C-DC6B-4BA2-9D25-C263C6F04B68}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools.PdfProvider", "Tools.PdfProvider\Tools.PdfProvider.csproj", "{057A6C6C-DC6B-4BA2-9D25-C263C6F04B68}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryText", "LibraryText\LibraryText.csproj", "{EA856697-8295-45DF-A730-D9A082AEEFCE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Calibre.Model.Domain", "Calibre.Model.Domain\Calibre.Model.Domain.csproj", "{81BA693F-7887-4155-B877-B65966EB9B76}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -31,6 +35,14 @@ Global
{057A6C6C-DC6B-4BA2-9D25-C263C6F04B68}.Debug|Any CPU.Build.0 = Debug|Any CPU
{057A6C6C-DC6B-4BA2-9D25-C263C6F04B68}.Release|Any CPU.ActiveCfg = Release|Any CPU
{057A6C6C-DC6B-4BA2-9D25-C263C6F04B68}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EA856697-8295-45DF-A730-D9A082AEEFCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EA856697-8295-45DF-A730-D9A082AEEFCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EA856697-8295-45DF-A730-D9A082AEEFCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EA856697-8295-45DF-A730-D9A082AEEFCE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {81BA693F-7887-4155-B877-B65966EB9B76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {81BA693F-7887-4155-B877-B65966EB9B76}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {81BA693F-7887-4155-B877-B65966EB9B76}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {81BA693F-7887-4155-B877-B65966EB9B76}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -39,6 +51,8 @@ Global
{39E1440C-9955-4744-8A22-02ED52502C11} = {5654144E-E0B3-4C6D-AFEB-799E77215B4E}
{4AA0EAB2-7B70-495A-9769-1665B857A91B} = {951387AC-1771-4B72-B885-B5DFAFB55D4D}
{057A6C6C-DC6B-4BA2-9D25-C263C6F04B68} = {951387AC-1771-4B72-B885-B5DFAFB55D4D}
+ {EA856697-8295-45DF-A730-D9A082AEEFCE} = {951387AC-1771-4B72-B885-B5DFAFB55D4D}
+ {81BA693F-7887-4155-B877-B65966EB9B76} = {951387AC-1771-4B72-B885-B5DFAFB55D4D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {362F0FEB-FB13-46F0-825D-15E6F10100D4}
src/Calibre/Calibre.csproj 2(+2 -0)
diff --git a/src/Calibre/Calibre.csproj b/src/Calibre/Calibre.csproj
index a69768f..6c3d137 100644
--- a/src/Calibre/Calibre.csproj
+++ b/src/Calibre/Calibre.csproj
@@ -15,6 +15,8 @@
<ItemGroup>
<ProjectReference Include="..\Calibre.Model.Database\Calibre.Model.Database.csproj" />
+ <ProjectReference Include="..\Calibre.Model.Domain\Calibre.Model.Domain.csproj" />
+ <ProjectReference Include="..\LibraryText\LibraryText.csproj" />
<ProjectReference Include="..\Tools.PdfProvider\Tools.PdfProvider.csproj" />
</ItemGroup>
src/Calibre/Program.cs 269(+142 -127)
diff --git a/src/Calibre/Program.cs b/src/Calibre/Program.cs
index f90f828..ed5ec33 100644
--- a/src/Calibre/Program.cs
+++ b/src/Calibre/Program.cs
@@ -4,104 +4,24 @@ using System.Threading.Tasks;
using System.Linq;
using System.IO;
using System.Diagnostics;
-using System.IO;
using Microsoft.EntityFrameworkCore;
using Tools.PdfProvider;
+using LibraryText;
+using LibraryText.Entities;
+
using Calibre.Model.Database;
using Calibre.Model.Database.Entities;
+using Calibre.Model.Domain.Entities;
+using Calibre.Model.Domain.Dal;
namespace Calibre
{
class Program
{
- private static string[] SelectDbFiles(DirectoryInfo directory)
- {
- var dbFiles = directory
- .GetFiles("metadata.db", SearchOption.AllDirectories)
- .Select(e => e.FullName)
- .ToArray();
-
- return dbFiles;
- }
-
- private static string BuildConnectionStringFromPath(string path)
- {
- return $"Filename={path}";
- }
-
- private static async Task<Dictionary<string, Book[]>> SearchBooksByTitle(
- string[] dbFiles,
- string containsTitle
- )
- {
- List<CalibreContext> contexts
- = new List<CalibreContext>(containsTitle.Length);
- Dictionary<string, Task<Book[]>> data
- = new Dictionary<string, Task<Book[]>>(containsTitle.Length);
-
- try
- {
- foreach (var elem in dbFiles)
- {
- var connectionString = BuildConnectionStringFromPath(elem);
- var libraryDirectory = new DirectoryInfo(
- Path.GetDirectoryName(elem)
- );
-
- var context = new CalibreContext(connectionString)
- {
- AsNoTracking = false,
- LibraryDirectory = libraryDirectory
- };
- contexts.Add(context);
-
- IQueryable<Book> selectExpr = context
- .Books
- .Include(e => e.Tags)
- .ThenInclude(e => e.TagItem);
-
- selectExpr = selectExpr
- .Include(e => e.FileData);
-
- selectExpr = selectExpr
- .Include(e => e.Autors)
- .ThenInclude(e => e.AuthorItem);
-
- if (string.IsNullOrEmpty(containsTitle))
- {
- selectExpr = selectExpr
- .Where(
- e => e.Title.Contains(containsTitle)
- );
- }
-
- var selectResultTask = selectExpr.ToArrayAsync();
- data.Add(elem, selectResultTask);
- }
-
- await Task.WhenAll(
- data.Values.ToArray()
- );
- }
- finally
- {
- contexts.ForEach(
- e => e.Dispose()
- );
- }
-
- var result = data
- .ToDictionary(
- e => e.Key,
- e => e.Value.Result
- );
- return result;
- }
-
- static void Main(string[] args)
+ static async Task Main(string[] args)
{
//var connectionString = @"";
@@ -109,28 +29,41 @@ namespace Calibre
//{
// var books = context.Books
// .OrderBy(e => e.Id)
- // .ToArray();
+ // .ToArray();
//}
+ //await SearchByTitleInDirectory(
+ // new DirectoryInfo(@"S:\BooksText\Calibre"),
+ // "Python Guide"
+ // );
- SearchByTitleInDirectory(
- new DirectoryInfo(@""),
- ""
- )
- .GetAwaiter()
- .GetResult();
+
+ //await SearchInPdfText(
+ // new DirectoryInfo(@"S:\BooksText\Calibre"),
+ // "NumPy"
+ // );
+
+ await LoadToDb(
+ new DirectoryInfo(@"S:\BooksText\Calibre")
+ );
}
- static async Task SearchByTitleInDirectory(
- DirectoryInfo directory,
- string containsTitle
+ static async Task<BookWithLibraryContainer[]> SearchByTitleInDirectory(
+ DirectoryInfo directory,
+ string containsTitle,
+ bool printLine = true
)
{
var watch = Stopwatch.StartNew();
+ var searchProvider = new SearchProvider(
+ new SimplePdfReader()
+ );
- var dbFiles = SelectDbFiles(directory);
- var searchResult = await SearchBooksByTitle(dbFiles, "")
+ var libraries = Library.SearchAll(directory);
+ var searchResult = await searchProvider.GetBooksByLibrariesAsync(
+ libraries: libraries
+ )
.ConfigureAwait(false);
watch.Stop();
@@ -140,60 +73,142 @@ namespace Calibre
.ToArray();
var allTags = allBooks
- .SelectMany(e => e.Tags)
+ .SelectMany(e => e.Book.Tags)
.Select(e => e.TagItem)
.Distinct()
.ToHashSet();
- var searchIgnoreCase = allBooks
+ var result = allBooks;
+
+ if (!string.IsNullOrEmpty(containsTitle))
+ {
+ result = allBooks
.Where(
- e =>
+ e =>
//Заголовок
- e.Title.Contains(containsTitle, StringComparison.OrdinalIgnoreCase)
+ e.Book.Title.Contains(containsTitle, StringComparison.OrdinalIgnoreCase)
//Теги
- || e.Tags.Any(
+ || e.Book.Tags.Any(
e => e.TagItem.Name.Contains(containsTitle, StringComparison.OrdinalIgnoreCase)
)
)
.ToArray();
+ }
- foreach (var elem in searchIgnoreCase)
+ if (printLine)
{
- Console.WriteLine($"{elem.Title}|{elem.AuthorSort}");
+ foreach (var elem in result)
+ {
+ Console.WriteLine($"{elem.Library.Data.Name}|{elem.Book.Title}|{elem.Book.AuthorSort}");
+ }
}
- var book = searchIgnoreCase.First();
+ return result;
+ }
- var dbFile = searchResult
- .First(
- e => e.Value.Any(e2 => e2.Title == book.Title)
- )
- .Key;
- BookFileProvider bookFileProvider = new BookFileProvider();
- //var path = await bookFileProvider.BuildFilePathAsync(
- // Path.GetDirectoryName(dbFile),
- // book,
- // (b) => Task.FromResult(b.FileData.First())
- // );
+ static async Task<Dictionary<BookWithLibraryContainer, string>> SearchInPdfText(
+ DirectoryInfo directory,
+ string containsText = null,
+ string containsTitle = null,
+ bool printLine = true
+ )
+ {
+ var searchProvider = new SearchProvider(
+ new SimplePdfReader()
+ );
+
+ var books = await SearchByTitleInDirectory(directory, containsTitle, false);
+ books = books
+ .Where(
+ e => e.Book.FileData
+ .Any(
+ e2 => string.Equals(e2.Format, "pdf", StringComparison.OrdinalIgnoreCase)
+ )
+ )
+ .ToArray();
- var bookText = await bookFileProvider.ReadFileAsync(
- Path.GetDirectoryName(dbFile),
- book,
- (b) => Task.FromResult(b.FileData.First()),
- async (s) =>
+ var result = await searchProvider.GetTextByBooksAsync(
+ books,
+ true,
+ (item, text) =>
+ {
+ if (string.IsNullOrEmpty(containsText))
{
- SimplePdfReader simplePdfReader = new SimplePdfReader();
- var result = await simplePdfReader.ReadPdfAsync(s);
- return result;
+ return true;
}
+ return text.Contains(containsText, StringComparison.OrdinalIgnoreCase);
+ }
+ );
+
+ if (printLine)
+ {
+ foreach (var elem in result)
+ {
+ Console.WriteLine($"{elem.Key.Library.Data.Name}|{elem.Key.Book.Title}|{elem.Key.Book.AuthorSort}");
+ }
+ }
+
+ return result;
+ }
+
+
+ static async Task LoadToDb(
+ DirectoryInfo directory,
+ string containsText = null,
+ string containsTitle = null,
+ bool printLine = true
+ )
+ {
+ var searchProvider = new SearchProvider(
+ new SimplePdfReader()
);
- var booksWithPdf = allBooks
+ var books = await SearchByTitleInDirectory(directory, containsTitle, false);
+ books = books
.Where(
- e => e.FileData.Any(e2 => e2.Format == "PDF")
+ e => e.Book.FileData
+ .Any(
+ e2 => string.Equals(e2.Format, "pdf", StringComparison.OrdinalIgnoreCase)
+ )
)
.ToArray();
+
+
+ await searchProvider.GetTextByBooksAsync(
+ books,
+ true,
+ (item, text) =>
+ {
+ if (!string.IsNullOrEmpty(containsText))
+ {
+ if (!text.Contains(containsText, StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ }
+ using (ApplicationContext context = new ApplicationContext())
+ {
+
+ context.Books.Add(
+ new BookTextData()
+ {
+ Directory = item.Library.Data.FullName,
+ Text = text,
+ Title = item.Book.Title
+ }
+ );
+ context.SaveChanges();
+ }
+
+ if (printLine)
+ {
+ Console.WriteLine($"{item.Library.Data.Name}|{item.Book.Title}|{item.Book.AuthorSort}|{text?.Length}");
+ }
+
+ return false;
+ }
+ );
}
}
}
src/LibraryText/ApplicationContext.cs 26(+26 -0)
diff --git a/src/LibraryText/ApplicationContext.cs b/src/LibraryText/ApplicationContext.cs
new file mode 100644
index 0000000..326b088
--- /dev/null
+++ b/src/LibraryText/ApplicationContext.cs
@@ -0,0 +1,26 @@
+using System;
+
+using Microsoft.EntityFrameworkCore;
+
+using LibraryText.Entities;
+
+namespace LibraryText
+{
+ public class ApplicationContext
+ : DbContext
+ {
+ public DbSet<BookTextData> Books { get; set; }
+
+
+ public ApplicationContext()
+ : base()
+ {
+ Database.EnsureCreated(); // создаем базу данных при первом обращении
+ }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ {
+ optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Books;Trusted_Connection=True;MultipleActiveResultSets=true");
+ }
+ }
+}
src/LibraryText/Entities/BookTextData.cs 16(+16 -0)
diff --git a/src/LibraryText/Entities/BookTextData.cs b/src/LibraryText/Entities/BookTextData.cs
new file mode 100644
index 0000000..e43be4b
--- /dev/null
+++ b/src/LibraryText/Entities/BookTextData.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LibraryText.Entities
+{
+ public class BookTextData
+ {
+ public int Id { set; get; }
+ public string Directory { set; get; }
+ public string Title { set; get; }
+ public string Text { set; get; }
+ }
+}
src/LibraryText/LibraryText.csproj 12(+12 -0)
diff --git a/src/LibraryText/LibraryText.csproj b/src/LibraryText/LibraryText.csproj
new file mode 100644
index 0000000..7664622
--- /dev/null
+++ b/src/LibraryText/LibraryText.csproj
@@ -0,0 +1,12 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+ <PropertyGroup>
+ <TargetFramework>net5.0</TargetFramework>
+ </PropertyGroup>
+
+ <ItemGroup>
+ <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
+ <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="5.0.10" />
+ </ItemGroup>
+
+</Project>
src/Tools.PdfProvider/ImmutableProxy.cs 50(+50 -0)
diff --git a/src/Tools.PdfProvider/ImmutableProxy.cs b/src/Tools.PdfProvider/ImmutableProxy.cs
new file mode 100644
index 0000000..ee75db2
--- /dev/null
+++ b/src/Tools.PdfProvider/ImmutableProxy.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tools.PdfProvider
+{
+ public class ImmutableProxy<T>
+ {
+ public T Data { private set; get; }
+
+
+ public ImmutableProxy(T data)
+ {
+ Data = data;
+ }
+ public static ImmutableProxy<T> Create<T>(T data)
+ {
+ return new ImmutableProxy<T>(data);
+ }
+
+
+ public ImmutableProxy<T> MutateValue(Func<T, T> mutateFunc)
+ {
+ Data = mutateFunc(Data);
+ return this;
+ }
+
+
+ #region override
+
+ public override bool Equals(object obj)
+ {
+ return Data.Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return Data.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return Data.ToString();
+ }
+
+ #endregion
+ }
+}
src/Tools.PdfProvider/SimplePdfReader.cs 65(+41 -24)
diff --git a/src/Tools.PdfProvider/SimplePdfReader.cs b/src/Tools.PdfProvider/SimplePdfReader.cs
index a429748..1493589 100644
--- a/src/Tools.PdfProvider/SimplePdfReader.cs
+++ b/src/Tools.PdfProvider/SimplePdfReader.cs
@@ -11,36 +11,53 @@ namespace Tools.PdfProvider
{
public class SimplePdfReader
{
- public Task<string> ReadPdfAsync(Stream stream)
+ public Task<string> ReadPdfAsync(
+ Stream stream,
+ bool ignoreError
+ )
{
- StringBuilder text = new StringBuilder();
-
- using (PdfReader iTextReader = new PdfReader(stream))
- using (PdfDocument pdfDoc = new PdfDocument(iTextReader))
+ try
{
- int numberofpages = pdfDoc.GetNumberOfPages();
- for (int page = 1; page <= numberofpages; page++)
+
+ StringBuilder text = new StringBuilder();
+
+ using (PdfReader iTextReader = new PdfReader(stream))
+ using (PdfDocument pdfDoc = new PdfDocument(iTextReader))
{
- ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
- string currentText = PdfTextExtractor.GetTextFromPage(
- pdfDoc.GetPage(page),
- strategy
- );
-
- //currentText = Encoding.UTF8.GetString(
- // ASCIIEncoding.Convert(
- // Encoding.Default,
- // Encoding.UTF8,
- // Encoding.Default.GetBytes(currentText)
- // )
- // );
- text.Append(currentText);
+ int numberofpages = pdfDoc.GetNumberOfPages();
+ for (int page = 1; page <= numberofpages; page++)
+ {
+ ITextExtractionStrategy strategy = new SimpleTextExtractionStrategy();
+ string currentText = PdfTextExtractor.GetTextFromPage(
+ pdfDoc.GetPage(page),
+ strategy
+ );
+
+ //currentText = Encoding.UTF8.GetString(
+ // ASCIIEncoding.Convert(
+ // Encoding.Default,
+ // Encoding.UTF8,
+ // Encoding.Default.GetBytes(currentText)
+ // )
+ // );
+ text.Append(currentText);
+ }
}
+
+
+ return Task.FromResult(
+ text.ToString()
+ );
}
+ catch (Exception ex)
+ {
+ if (ignoreError)
+ {
+ return Task.FromResult(ex.Message);
+ }
- return Task.FromResult(
- text.ToString()
- );
+ throw;
+ }
}
}
}