mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-07-09 03:04:19 -04:00
Scanner Fix (#2998)
This commit is contained in:
parent
6139b3fbdf
commit
11635c6696
@ -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();
|
||||||
|
59
API/Data/ManualMigrations/MigrateSeriesLowestFolderPath.cs
Normal file
59
API/Data/ManualMigrations/MigrateSeriesLowestFolderPath.cs
Normal 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");
|
||||||
|
}
|
||||||
|
}
|
@ -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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user