Scanner Fix (#2998)

This commit is contained in:
Joe Milazzo 2024-06-12 16:39:08 -05:00 committed by GitHub
parent 6139b3fbdf
commit 11635c6696
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 78 additions and 4 deletions

View File

@ -742,6 +742,9 @@ public class DirectoryServiceTests
[InlineData(new [] {"C:/Manga/"}, [InlineData(new [] {"C:/Manga/"},
new [] {"C:/Manga/Love Hina/Vol. 01.cbz", "C:/Manga/Love Hina/Specials/Sp01.cbz"}, new [] {"C:/Manga/Love Hina/Vol. 01.cbz", "C:/Manga/Love Hina/Specials/Sp01.cbz"},
"C:/Manga/Love Hina")] "C:/Manga/Love Hina")]
[InlineData(new [] {"/manga"},
new [] {"/manga/Love Hina/Vol. 01.cbz", "/manga/Love Hina/Specials/Sp01.cbz"},
"/manga/Love Hina")]
public void FindLowestDirectoriesFromFilesTest(string[] rootDirectories, string[] files, string expectedDirectory) public void FindLowestDirectoriesFromFilesTest(string[] rootDirectories, string[] files, string expectedDirectory)
{ {
var fileSystem = new MockFileSystem(); var fileSystem = new MockFileSystem();

View File

@ -0,0 +1,59 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using API.Entities;
using API.Services;
using API.Services.Tasks.Scanner.Parser;
using Kavita.Common.EnvironmentInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace API.Data.ManualMigrations;
#nullable enable
/// <summary>
/// Some linux-based users are having non-rooted LowestFolderPaths. This will attempt to fix it or null them.
/// Fixed in v0.8.2
/// </summary>
public static class MigrateSeriesLowestFolderPath
{
public static async Task Migrate(DataContext dataContext, ILogger<Program> logger, IDirectoryService directoryService)
{
if (await dataContext.ManualMigrationHistory.AnyAsync(m => m.Name == "MigrateSeriesLowestFolderPath"))
{
return;
}
logger.LogCritical("Running MigrateSeriesLowestFolderPath migration - Please be patient, this may take some time. This is not an error");
var seriesWithFolderPath =
await dataContext.Series.Where(s => !string.IsNullOrEmpty(s.LowestFolderPath))
.Include(s => s.Library)
.ThenInclude(l => l.Folders)
.ToListAsync();
foreach (var series in seriesWithFolderPath)
{
var isValidPath = series.Library.Folders
.Any(folder => Parser.NormalizePath(series.LowestFolderPath!).StartsWith(Parser.NormalizePath(folder.Path), StringComparison.OrdinalIgnoreCase));
if (isValidPath) continue;
series.LowestFolderPath = null;
dataContext.Entry(series).State = EntityState.Modified;
}
await dataContext.SaveChangesAsync();
dataContext.ManualMigrationHistory.Add(new ManualMigrationHistory()
{
Name = "MigrateSeriesLowestFolderPath",
ProductVersion = BuildInfo.Version.ToString(),
RanAt = DateTime.UtcNow
});
await dataContext.SaveChangesAsync();
logger.LogCritical("Running MigrateSeriesLowestFolderPath migration - Completed. This is not an error");
}
}

View File

@ -3,7 +3,9 @@ using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.DTOs.Filtering.v2; using API.DTOs.Filtering.v2;
using API.Entities;
using API.Helpers; using API.Helpers;
using Kavita.Common.EnvironmentInfo;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -29,7 +31,7 @@ public static class MigrateSmartFilterEncoding
logger.LogCritical("Running MigrateSmartFilterEncoding migration - Please be patient, this may take some time. This is not an error"); logger.LogCritical("Running MigrateSmartFilterEncoding migration - Please be patient, this may take some time. This is not an error");
var smartFilters = dataContext.AppUserSmartFilter.ToList(); var smartFilters = await dataContext.AppUserSmartFilter.ToListAsync();
foreach (var filter in smartFilters) foreach (var filter in smartFilters)
{ {
if (!ShouldMigrateFilter(filter.Filter)) continue; if (!ShouldMigrateFilter(filter.Filter)) continue;
@ -43,6 +45,14 @@ public static class MigrateSmartFilterEncoding
await unitOfWork.CommitAsync(); await unitOfWork.CommitAsync();
} }
dataContext.ManualMigrationHistory.Add(new ManualMigrationHistory()
{
Name = "MigrateSmartFilterEncoding",
ProductVersion = BuildInfo.Version.ToString(),
RanAt = DateTime.UtcNow
});
await dataContext.SaveChangesAsync();
logger.LogCritical("Running MigrateSmartFilterEncoding migration - Completed. This is not an error"); logger.LogCritical("Running MigrateSmartFilterEncoding migration - Completed. This is not an error");
} }

View File

@ -745,12 +745,12 @@ public class DirectoryService : IDirectoryService
/// <summary> /// <summary>
/// Recursively scans a folder and returns the max last write time on any folders and files /// Recursively scans a folder and returns the max last write time on any folders and files
/// </summary> /// </summary>
/// <remarks>If the folder is empty, this will return MaxValue for a DateTime</remarks> /// <remarks>If the folder is empty or non-existant, this will return MaxValue for a DateTime</remarks>
/// <param name="folderPath"></param> /// <param name="folderPath"></param>
/// <returns>Max Last Write Time</returns> /// <returns>Max Last Write Time</returns>
public DateTime GetLastWriteTime(string folderPath) public DateTime GetLastWriteTime(string folderPath)
{ {
if (!FileSystem.Directory.Exists(folderPath)) throw new IOException($"{folderPath} does not exist"); if (!FileSystem.Directory.Exists(folderPath)) return DateTime.MaxValue;
var fileEntries = FileSystem.Directory.GetFileSystemEntries(folderPath, "*.*", SearchOption.AllDirectories); var fileEntries = FileSystem.Directory.GetFileSystemEntries(folderPath, "*.*", SearchOption.AllDirectories);
if (fileEntries.Length == 0) return DateTime.MaxValue; if (fileEntries.Length == 0) return DateTime.MaxValue;
return fileEntries.Max(path => FileSystem.File.GetLastWriteTime(path)); return fileEntries.Max(path => FileSystem.File.GetLastWriteTime(path));

View File

@ -143,7 +143,8 @@ public class ParseScannedFiles
_logger.LogDebug("[ProcessFiles] Dirty check passed, series list: {@SeriesModified}", series2); _logger.LogDebug("[ProcessFiles] Dirty check passed, series list: {@SeriesModified}", series2);
foreach (var s in series2) foreach (var s in series2)
{ {
_logger.LogDebug("[ProcessFiles] Last Scanned: {LastScanned} vs Directory Check: {DirectoryLastScanned}", s.LastScanned, _directoryService _logger.LogDebug("[ProcessFiles] Last Scanned: {LastScanned} vs Directory Check: {DirectoryLastScanned}",
s.LastScanned, _directoryService
.GetLastWriteTime(s.LowestFolderPath!) .GetLastWriteTime(s.LowestFolderPath!)
.Truncate(TimeSpan.TicksPerSecond)); .Truncate(TimeSpan.TicksPerSecond));
} }

View File

@ -269,6 +269,7 @@ public class Startup
// v0.8.2 // v0.8.2
await ManualMigrateThemeDescription.Migrate(dataContext, logger); await ManualMigrateThemeDescription.Migrate(dataContext, logger);
await MigrateInitialInstallData.Migrate(dataContext, logger, directoryService); await MigrateInitialInstallData.Migrate(dataContext, logger, directoryService);
await MigrateSeriesLowestFolderPath.Migrate(dataContext, logger, directoryService);
// Update the version in the DB after all migrations are run // Update the version in the DB after all migrations are run
var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion); var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion);