From bc1e3143267dbd85880c0a6085455cf14fbbcc8d Mon Sep 17 00:00:00 2001 From: tjarls Date: Thu, 22 Sep 2022 22:44:01 +0100 Subject: [PATCH] Fallback to other locations when ComicInfo.xml not at root of archive (#1551) * Fallback to other locations when ComicInfo.xml not at root of archive * Better ComicInfo test coverage and benchmarks * Add a rar archive to the ComicInfo test cases --- API.Benchmark/API.Benchmark.csproj | 6 ++ API.Benchmark/ArchiveSerivceBenchmark.cs | 7 --- API.Benchmark/ArchiveServiceBenchmark.cs | 54 ++++++++++++++++++ API.Tests/Services/ArchiveServiceTests.cs | 20 ++++++- .../ComicInfos/ComicInfo_duplicateInfos.rar | Bin 0 -> 1655 bytes .../ComicInfo_duplicateInfos_reversed.zip | Bin 0 -> 1803 bytes .../ComicInfos/ComicInfo_outside_root.zip | Bin 0 -> 993 bytes API/Services/ArchiveService.cs | 15 ++--- 8 files changed, 85 insertions(+), 17 deletions(-) delete mode 100644 API.Benchmark/ArchiveSerivceBenchmark.cs create mode 100644 API.Benchmark/ArchiveServiceBenchmark.cs create mode 100644 API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_duplicateInfos.rar create mode 100644 API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_duplicateInfos_reversed.zip create mode 100644 API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_outside_root.zip diff --git a/API.Benchmark/API.Benchmark.csproj b/API.Benchmark/API.Benchmark.csproj index 5461138d5..11ef151a2 100644 --- a/API.Benchmark/API.Benchmark.csproj +++ b/API.Benchmark/API.Benchmark.csproj @@ -20,5 +20,11 @@ Always + + + Data + Always + + diff --git a/API.Benchmark/ArchiveSerivceBenchmark.cs b/API.Benchmark/ArchiveSerivceBenchmark.cs deleted file mode 100644 index 11a66d7bc..000000000 --- a/API.Benchmark/ArchiveSerivceBenchmark.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace API.Benchmark; - -public class ArchiveSerivceBenchmark -{ - // Benchmark to test default GetNumberOfPages from archive - // vs a new method where I try to open the archive and return said stream -} diff --git a/API.Benchmark/ArchiveServiceBenchmark.cs b/API.Benchmark/ArchiveServiceBenchmark.cs new file mode 100644 index 000000000..d8418ee26 --- /dev/null +++ b/API.Benchmark/ArchiveServiceBenchmark.cs @@ -0,0 +1,54 @@ +using System; +using System.IO.Abstractions; +using Microsoft.Extensions.Logging.Abstractions; +using API.Services; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Order; + +namespace API.Benchmark; + +[StopOnFirstError] +[MemoryDiagnoser] +[RankColumn] +[Orderer(SummaryOrderPolicy.FastestToSlowest)] +[SimpleJob(launchCount: 1, warmupCount: 5, targetCount: 20)] +public class ArchiveServiceBenchmark +{ + private readonly ArchiveService _archiveService; + private readonly IDirectoryService _directoryService; + private readonly IImageService _imageService; + + public ArchiveServiceBenchmark() + { + _directoryService = new DirectoryService(null, new FileSystem()); + _imageService = new ImageService(null, _directoryService); + _archiveService = new ArchiveService(new NullLogger(), _directoryService, _imageService); + } + + [Benchmark(Baseline = true)] + public void TestGetComicInfo_baseline() + { + if (_archiveService.GetComicInfo("Data/ComicInfo.zip") == null) { + throw new Exception("ComicInfo not found"); + } + } + + [Benchmark] + public void TestGetComicInfo_duplicate() + { + if (_archiveService.GetComicInfo("Data/ComicInfo_duplicateInfos.zip") == null) { + throw new Exception("ComicInfo not found"); + } + } + + [Benchmark] + public void TestGetComicInfo_outside_root() + { + if (_archiveService.GetComicInfo("Data/ComicInfo_outside_root.zip") == null) { + throw new Exception("ComicInfo not found"); + } + } + + // Benchmark to test default GetNumberOfPages from archive + // vs a new method where I try to open the archive and return said stream +} diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs index 7fc267869..f399cb790 100644 --- a/API.Tests/Services/ArchiveServiceTests.cs +++ b/API.Tests/Services/ArchiveServiceTests.cs @@ -256,17 +256,31 @@ public class ArchiveServiceTests Assert.Equal("Junya Inoue", comicInfo.Writer); } - [Fact] - public void ShouldHaveComicInfo_TopLevelFileOnly() + [Theory] + [InlineData("ComicInfo_duplicateInfos.zip")] + [InlineData("ComicInfo_duplicateInfos_reversed.zip")] + [InlineData("ComicInfo_duplicateInfos.rar")] + public void ShouldHaveComicInfo_TopLevelFileOnly(string filename) { var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos"); - var archive = Path.Join(testDirectory, "ComicInfo_duplicateInfos.zip"); + var archive = Path.Join(testDirectory, filename); var comicInfo = _archiveService.GetComicInfo(archive); Assert.NotNull(comicInfo); Assert.Equal("BTOOOM!", comicInfo.Series); } + [Fact] + public void ShouldHaveComicInfo_OutsideRoot() + { + var testDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Services/Test Data/ArchiveService/ComicInfos"); + var archive = Path.Join(testDirectory, "ComicInfo_outside_root.zip"); + + var comicInfo = _archiveService.GetComicInfo(archive); + Assert.NotNull(comicInfo); + Assert.Equal("BTOOOM! - Duplicate", comicInfo.Series); + } + #endregion #region CanParseComicInfo diff --git a/API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_duplicateInfos.rar b/API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_duplicateInfos.rar new file mode 100644 index 0000000000000000000000000000000000000000..9d5bab5a24691fd4a3786575d24c4341d3144cad GIT binary patch literal 1655 zcmV--28j7mVR9iF2LS-{;ezW60R;yD1_1$pfPer*1TaG*0s@)_29FA)g90|qrD2KM zhgyIG0S!ZMZE0gkZf0*Tcx`OSh86=hWJ5DE^iWmrz7%8Wy)m~qXcoZYf=3{hQ6-R9 z1(J#{K}i(Zkt9%D4};$=a(|^KEVsp&4KjCd=H_YC{DXMT@L}EiGdu@8Ll+*IrB-%R zQ(Zq5?c5uexZw9<#_5|EO!7HNI(oQt)gKk?)z?Q396Aq}G;iQ_IdJc8Zf@c5>*~oC zW=y-^&>Q^X`$1K%c$s*nsaU(4T&#esI6x;X<%uOuxtO3`Cyne_Zl3X9a3zF@5+2Pj ziI5Q1RR=G3Ve_wOm9u`mSy8K!n6^w&MU*Ovw05A6S#J~G$Y6Tjt&50@3#0+rbw5@c zxwvC)Q5LyxzHC@{J_A?d!RCK5+5sds!$O&(PbRi+7v z)B=)Ujft#Ic_$^aJ<7E+O$D?b!bS1Z9BFD}4}q$f@fK~Re8v)ADN#)K2wzpAhI!1q zYVXYCsnKCfw&b#8yy(w7VLOo)#eheOict7uvZPfUEtIEu2VBp>P9<6&fK4((K&4~x6Cu9W}oBnTq zuh9?_`r?xXQ8GC54VP#lSAU*r8YPPl|AY4sy??kH05X_>2q*#q=miF~38aGpvi0;~ zqn|&RfCB*%RAqB?FGFu_X=6!lW^XQdZEVkTTcx#m`uRa~v3iw6EJ>>O|U{aErgd12?GHmM`gUkOl9-{jBIe9O43 zD&@ABybG~_e>ist>|_tRr(c~?6u-5$X34S5J$&=gOCWZ+u(~WSaC{06j{s2V&mU~% zu~x#L*q|)R16xIv?yIk0!7QxH?_BM%s+O`cgSyJ+0sju0o>WL8OjOqVN^Aa#9BEb-EDtFuE=r%k0Y?2^gTGa@0w2;W3a zm)_06oauH@x!JnzjzB|HJ0&>^*gKeIjVTqe-8Xh$3q{NEQt3+kD-I%B9!F4aQ$087U!0kHd3i40f6z&M zwZvUkn*~|bkNy&~)Fai_N7{LC_b~*1{!;sq7MWTnjac?BdVXrp_W-^vZkBY&Lk{_P0mJvCHlQPppvv;T5>j(gM8l5rh(R#5{51OV9R B95es` literal 0 HcmV?d00001 diff --git a/API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_duplicateInfos_reversed.zip b/API.Tests/Services/Test Data/ArchiveService/ComicInfos/ComicInfo_duplicateInfos_reversed.zip new file mode 100644 index 0000000000000000000000000000000000000000..f764a4a600cbbb8ac4905ea8c87e091869052093 GIT binary patch literal 1803 zcmZ{ldo zK|gg*W!&5^CKY#-7{PxDzG#O}q-rB8ttL~+sk-0k%SNF!+^?=UX+jy_=R5nS1?i*w zLWaP&DjZ!_V349MR_9jZY z(`?5W_3(9=eMiNDxTfE?22if3piv_ zvM%NUT`mxKrvf}lcfKjOVGJ62^@JH6>^tFVLoq@e!MfL(kF65(|05X%Xi^o!7CZK1xtkifOuf@|;h^DIJ#D2bt4xiCY7h!!hKU|B-u9R}GWP}qlxxL+4AGY)I zO6A@)ss(4}cIG}o%}t=frrq>3-jUQwvxR3*m(AJ7*0irm?Mh3ctf?=xWFKa{@hFt* zBp-b6fcN}d(UK4@zABCmYz){H3LGBir^0i~IUn<2G=*zcC@SA^9{Z;J-cAN%jUy<(-zW5&en+pH`8v`SeM;Bc=a7Ug4xgcLH%=eLyezBKng#1zV z*Y<|I{EUuFD%7Tp?s~AJYru$DsTyC~pMFAaKPDEVPRVcYqS7-ZP;EgaprUGz7`VqH zO|N4>_T?J_RuStE^zCy5UolO`p5CivT%TTh!GH-rZiYDSohY9osGv>|5(XCXSW9kM zk<9`|=+jZ5ai2>bzK{VGzT_6L53^@CU~d>c-jkO~t|Jh7?zACz>sIZ6txV5#+rD4I zb=eAHvJJ}C#^g+zo6C6=EysE|=y?!JAs=42SedVLO98%RART&iakW}QMmv*jXRHy+ z6`_wEq@f9UE^jIr(W1zJ@-EL(2Xb*uy)tqtYxLx}SNVr7^l(TZWcff_74?w&f^(46 z&xS8MMKAdyaU-nm6sPjAHT&-bX_ShY2;7*`B;?A#u$UR)al3DnjW>CU-5L`sPCveU zveA^~F-@w>ow>wGpoI;3M&0>|UT%erOfKr%6ft?Ibq|Ze(ry258Xxwr41Vxl5Vokg zDC17uC*7Z?bJ}6tL*vi7dAOut5 zoS&PS?3tIAuUC$3J>| zcJf`_?JAu7+ihi{gkRfp^*7mHbGAmUmfx-ady`^!_wIzh{~s(ZQ(UB-srZ#)6Spky z)4y4BSN^n!{QktW_0N|_Z{FmTvv~iwu+?q4gl4e$KFxQNx@p1yd!O5kl1Wv1BePBY(W>g-*&$|b~ALVAP5>1P~vA182_hd$C==zVsZ zYUZYU2T~9FGjECQF`k$re0t*Y8@zj_Uu;XWxpkoR%c~2QK5pUX-0(zA?Xp13AH|1T z#r5SC?iIe`FvoQ=pe`Nd+!t$6XsrPvAAoK@!k=w@14`{sk2 z>67R$g_YX3b$3OJwysdm^c39boYi}q{dX2`U*-ws-_}h2;`Im1#Q=gu7ZWhBiYr%vGu}|%ne%QHOz^F8TPLkcE z&r{xCxN7vNulncp2b{OQ>BiKYzw&18!41oDXIaJXpLYM{KdZ|991iNs&i~##CuW)4 zz32PaxlE6f$~RoAb^gkJvC94{cbiqV?+@^1WRhpVl_ON3c|!n7gYyR$g94b#$RNRR zp!c4amgo&e7~Ny^(h0g?x!Hfl&qYT7gV^Q)HvK{6<>phU|fY}w`&B_LH2on(Q K2GRn|ARYkKbePBh literal 0 HcmV?d00001 diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index 12c0a4029..b370f178d 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -328,12 +328,11 @@ public class ArchiveService : IArchiveService return false; } - private static bool ValidComicInfoArchiveEntry(string fullName, string name) + private static bool IsComicInfoArchiveEntry(string fullName, string name) { - var filenameWithoutExtension = Path.GetFileNameWithoutExtension(name).ToLower(); return !Tasks.Scanner.Parser.Parser.HasBlacklistedFolderInPath(fullName) - && (fullName.Equals(ComicInfoFilename) || (string.IsNullOrEmpty(fullName) && name.Equals(ComicInfoFilename))) - && !filenameWithoutExtension.StartsWith(Tasks.Scanner.Parser.Parser.MacOsMetadataFileStartsWith); + && name.Equals(ComicInfoFilename, StringComparison.OrdinalIgnoreCase) + && !name.StartsWith(Tasks.Scanner.Parser.Parser.MacOsMetadataFileStartsWith); } /// @@ -356,7 +355,8 @@ public class ArchiveService : IArchiveService { using var archive = ZipFile.OpenRead(archivePath); - var entry = archive.Entries.FirstOrDefault(x => ValidComicInfoArchiveEntry(x.FullName, x.Name)); + var entry = archive.Entries.FirstOrDefault(x => (x.FullName ?? x.Name) == ComicInfoFilename) ?? + archive.Entries.FirstOrDefault(x => IsComicInfoArchiveEntry(x.FullName, x.Name)); if (entry != null) { using var stream = entry.Open(); @@ -371,8 +371,9 @@ public class ArchiveService : IArchiveService case ArchiveLibrary.SharpCompress: { using var archive = ArchiveFactory.Open(archivePath); - var entry = archive.Entries.FirstOrDefault(entry => - ValidComicInfoArchiveEntry(Path.GetDirectoryName(entry.Key), entry.Key)); + var entry = archive.Entries.FirstOrDefault(entry => entry.Key == ComicInfoFilename) ?? + archive.Entries.FirstOrDefault(entry => + IsComicInfoArchiveEntry(Path.GetDirectoryName(entry.Key), entry.Key)); if (entry != null) {