diff --git a/API.Tests/Comparers/NaturalSortComparerTest.cs b/API.Tests/Comparers/NaturalSortComparerTest.cs
index d7c58d45a..b624caac8 100644
--- a/API.Tests/Comparers/NaturalSortComparerTest.cs
+++ b/API.Tests/Comparers/NaturalSortComparerTest.cs
@@ -8,42 +8,42 @@ namespace API.Tests.Comparers
public class NaturalSortComparerTest
{
private readonly NaturalSortComparer _nc = new NaturalSortComparer();
-
+
[Theory]
[InlineData(
- new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
+ new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
)]
[InlineData(
- new[] {"Beelzebub_153b_RHS.zip", "Beelzebub_01_[Noodles].zip",},
+ new[] {"Beelzebub_153b_RHS.zip", "Beelzebub_01_[Noodles].zip",},
new[] {"Beelzebub_01_[Noodles].zip", "Beelzebub_153b_RHS.zip"}
)]
[InlineData(
- new[] {"[SCX-Scans]_Vandread_v02_Act02.zip", "[SCX-Scans]_Vandread_v02_Act01.zip",},
+ new[] {"[SCX-Scans]_Vandread_v02_Act02.zip", "[SCX-Scans]_Vandread_v02_Act01.zip",},
new[] {"[SCX-Scans]_Vandread_v02_Act01.zip", "[SCX-Scans]_Vandread_v02_Act02.zip",}
)]
[InlineData(
- new[] {"Frogman v01 001.jpg", "Frogman v01 ch01 p00 Credits.jpg",},
+ new[] {"Frogman v01 001.jpg", "Frogman v01 ch01 p00 Credits.jpg",},
new[] {"Frogman v01 001.jpg", "Frogman v01 ch01 p00 Credits.jpg",}
)]
[InlineData(
- new[] {"001.jpg", "10.jpg",},
+ new[] {"001.jpg", "10.jpg",},
new[] {"001.jpg", "10.jpg",}
)]
[InlineData(
- new[] {"10/001.jpg", "10.jpg",},
+ new[] {"10/001.jpg", "10.jpg",},
new[] {"10.jpg", "10/001.jpg",}
)]
[InlineData(
- new[] {"Batman - Black white vol 1 #04.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr"},
+ new[] {"Batman - Black white vol 1 #04.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr"},
new[] {"Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #04.cbr"}
)]
[InlineData(
- new[] {"3and4.cbz", "The World God Only Knows - Oneshot.cbz", "5.cbz", "1and2.cbz"},
+ new[] {"3and4.cbz", "The World God Only Knows - Oneshot.cbz", "5.cbz", "1and2.cbz"},
new[] {"1and2.cbz", "3and4.cbz", "5.cbz", "The World God Only Knows - Oneshot.cbz"}
)]
[InlineData(
- new[] {"Solo Leveling - c000 (v01) - p000 [Cover] [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p001 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p002 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p003 [dig] [Yen Press] [LuCaZ].jpg"},
+ new[] {"Solo Leveling - c000 (v01) - p000 [Cover] [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p001 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p002 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p003 [dig] [Yen Press] [LuCaZ].jpg"},
new[] {"Solo Leveling - c000 (v01) - p000 [Cover] [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p001 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p002 [dig] [Yen Press] [LuCaZ].jpg", "Solo Leveling - c000 (v01) - p003 [dig] [Yen Press] [LuCaZ].jpg"}
)]
public void TestNaturalSortComparer(string[] input, string[] expected)
@@ -57,39 +57,39 @@ namespace API.Tests.Comparers
i++;
}
}
-
-
+
+
[Theory]
[InlineData(
- new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
+ new[] {"x1.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
new[] {"x1.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
)]
[InlineData(
- new[] {"x2.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
+ new[] {"x2.jpg", "x10.jpg", "x3.jpg", "x4.jpg", "x11.jpg"},
new[] {"x2.jpg", "x3.jpg", "x4.jpg", "x10.jpg", "x11.jpg"}
)]
[InlineData(
- new[] {"Beelzebub_153b_RHS.zip", "Beelzebub_01_[Noodles].zip",},
+ new[] {"Beelzebub_153b_RHS.zip", "Beelzebub_01_[Noodles].zip",},
new[] {"Beelzebub_01_[Noodles].zip", "Beelzebub_153b_RHS.zip"}
)]
[InlineData(
- new[] {"[SCX-Scans]_Vandread_v02_Act02.zip", "[SCX-Scans]_Vandread_v02_Act01.zip","[SCX-Scans]_Vandread_v02_Act07.zip",},
+ new[] {"[SCX-Scans]_Vandread_v02_Act02.zip", "[SCX-Scans]_Vandread_v02_Act01.zip","[SCX-Scans]_Vandread_v02_Act07.zip",},
new[] {"[SCX-Scans]_Vandread_v02_Act01.zip", "[SCX-Scans]_Vandread_v02_Act02.zip","[SCX-Scans]_Vandread_v02_Act07.zip",}
)]
[InlineData(
- new[] {"Frogman v01 001.jpg", "Frogman v01 ch01 p00 Credits.jpg",},
+ new[] {"Frogman v01 001.jpg", "Frogman v01 ch01 p00 Credits.jpg",},
new[] {"Frogman v01 001.jpg", "Frogman v01 ch01 p00 Credits.jpg",}
)]
[InlineData(
- new[] {"001.jpg", "10.jpg",},
+ new[] {"001.jpg", "10.jpg",},
new[] {"001.jpg", "10.jpg",}
)]
[InlineData(
- new[] {"10/001.jpg", "10.jpg",},
+ new[] {"10/001.jpg", "10.jpg",},
new[] {"10.jpg", "10/001.jpg",}
)]
[InlineData(
- new[] {"Batman - Black white vol 1 #04.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr"},
+ new[] {"Batman - Black white vol 1 #04.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr"},
new[] {"Batman - Black white vol 1 #01.cbr", "Batman - Black white vol 1 #02.cbr", "Batman - Black white vol 1 #03.cbr", "Batman - Black white vol 1 #04.cbr"}
)]
public void TestNaturalSortComparerLinq(string[] input, string[] expected)
@@ -104,4 +104,4 @@ namespace API.Tests.Comparers
}
}
}
-}
\ No newline at end of file
+}
diff --git a/API.Tests/Services/ArchiveServiceTests.cs b/API.Tests/Services/ArchiveServiceTests.cs
index fc3e21dd4..7bdc18f1d 100644
--- a/API.Tests/Services/ArchiveServiceTests.cs
+++ b/API.Tests/Services/ArchiveServiceTests.cs
@@ -140,9 +140,10 @@ namespace API.Tests.Services
[InlineData(new [] {"page 2.jpg", "page 10.jpg"}, "page 2.jpg")]
[InlineData(new [] {"__MACOSX/cover.jpg", "vol1/page 01.jpg"}, "vol1/page 01.jpg")]
[InlineData(new [] {"Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg", "Akame ga KILL! ZERO - c060 (v10) - p200 [Digital] [LuCaZ].jpg", "folder.jpg"}, "Akame ga KILL! ZERO - c055 (v10) - p000 [Digital] [LuCaZ].jpg")]
+ [InlineData(new [] {"001.jpg", "001 - chapter 1/001.jpg"}, "001.jpg")]
public void FindFirstEntry(string[] files, string expected)
{
- var foundFile = _archiveService.FirstFileEntry(files);
+ var foundFile = ArchiveService.FirstFileEntry(files, string.Empty);
Assert.Equal(expected, string.IsNullOrEmpty(foundFile) ? "" : foundFile);
}
diff --git a/API/Comparators/NaturalSortComparer.cs b/API/Comparators/NaturalSortComparer.cs
index 9bf79db81..8fb0a74a5 100644
--- a/API/Comparators/NaturalSortComparer.cs
+++ b/API/Comparators/NaturalSortComparer.cs
@@ -6,6 +6,10 @@ using static System.String;
namespace API.Comparators
{
+ ///
+ /// Attempts to emulate Windows explorer sorting
+ ///
+ /// This is not thread-safe
public sealed class NaturalSortComparer : IComparer, IDisposable
{
private readonly bool _isAscending;
@@ -23,7 +27,6 @@ namespace API.Comparators
{
if (x == y) return 0;
- // Should be fixed: Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
if (!_table.TryGetValue(x ?? Empty, out var x1))
{
x1 = Regex.Split(x ?? Empty, "([0-9]+)");
@@ -33,7 +36,6 @@ namespace API.Comparators
if (!_table.TryGetValue(y ?? Empty, out var y1))
{
y1 = Regex.Split(y ?? Empty, "([0-9]+)");
- // Should be fixed: EXCEPTION: An item with the same key has already been added. Key: M:\Girls of the Wild's\Girls of the Wild's - Ep. 083 (Season 1) [LINE Webtoon].cbz
_table.Add(y ?? Empty, y1);
}
@@ -59,6 +61,7 @@ namespace API.Comparators
returnVal = 0;
}
+
return _isAscending ? returnVal : -returnVal;
}
diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs
index 621d42322..10d45f232 100644
--- a/API/Services/ArchiveService.cs
+++ b/API/Services/ArchiveService.cs
@@ -123,12 +123,24 @@ namespace API.Services
///
///
/// Entry name of match, null if no match
- public string FirstFileEntry(IEnumerable entryFullNames)
+ public static string FirstFileEntry(IEnumerable entryFullNames, string archiveName)
{
- var result = entryFullNames.OrderBy(Path.GetFileName, new NaturalSortComparer())
- .FirstOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x)
- && Parser.Parser.IsImage(x)
- && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith));
+ // First check if there are any files that are not in a nested folder before just comparing by filename. This is needed
+ // because NaturalSortComparer does not work with paths and doesn't seem 001.jpg as before chapter 1/001.jpg.
+ var fullNames = entryFullNames.Where(x =>!Parser.Parser.HasBlacklistedFolderInPath(x)
+ && Parser.Parser.IsImage(x)
+ && !x.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith)).ToList();
+ if (fullNames.Count == 0) return null;
+
+ var nonNestedFile = fullNames.Where(entry => (Path.GetDirectoryName(entry) ?? string.Empty).Equals(archiveName))
+ .OrderBy(Path.GetFullPath, new NaturalSortComparer())
+ .FirstOrDefault();
+
+ if (!string.IsNullOrEmpty(nonNestedFile)) return nonNestedFile;
+
+ var result = fullNames
+ .OrderBy(Path.GetFileName, new NaturalSortComparer())
+ .FirstOrDefault();
return string.IsNullOrEmpty(result) ? null : result;
}
@@ -158,7 +170,7 @@ namespace API.Services
using var archive = ZipFile.OpenRead(archivePath);
var entryNames = archive.Entries.Select(e => e.FullName).ToArray();
- var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames);
+ var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath));
var entry = archive.Entries.Single(e => e.FullName == entryName);
using var stream = entry.Open();
@@ -169,7 +181,7 @@ namespace API.Services
using var archive = ArchiveFactory.Open(archivePath);
var entryNames = archive.Entries.Where(archiveEntry => !archiveEntry.IsDirectory).Select(e => e.Key).ToList();
- var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames);
+ var entryName = FindFolderEntry(entryNames) ?? FirstFileEntry(entryNames, Path.GetFileName(archivePath));
var entry = archive.Entries.Single(e => e.Key == entryName);
using var stream = entry.OpenEntryStream();
diff --git a/API/Startup.cs b/API/Startup.cs
index d0577d06d..da8f24582 100644
--- a/API/Startup.cs
+++ b/API/Startup.cs
@@ -138,7 +138,10 @@ namespace API
app.UseResponseCompression();
- app.UseForwardedHeaders();
+ app.UseForwardedHeaders(new ForwardedHeadersOptions
+ {
+ ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
+ });
app.UseRouting();