|
|
|
|
@@ -8,6 +8,9 @@ using MaybeError.Errors;
|
|
|
|
|
|
|
|
|
|
using SixLabors.ImageSharp;
|
|
|
|
|
|
|
|
|
|
using System.Collections.Frozen;
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
|
|
|
|
namespace AZKiServer.Services;
|
|
|
|
|
|
|
|
|
|
public class FileScannerService(MediaService mediaService, IConfiguration config, ILogger<FileScannerService> logger) : IHostedService, IDisposable
|
|
|
|
|
@@ -50,49 +53,11 @@ public class FileScannerService(MediaService mediaService, IConfiguration config
|
|
|
|
|
{
|
|
|
|
|
var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
|
|
|
|
|
var existingFiles = await mediaService.GetExistingFilePathsAsync(cancellationToken);
|
|
|
|
|
var entries = new List<MediaEntry>();
|
|
|
|
|
var upgradeEntries = new List<MediaEntry>();
|
|
|
|
|
foreach (var filePath in files)
|
|
|
|
|
var total = 0;
|
|
|
|
|
foreach (var chunk in files.Chunk(50))
|
|
|
|
|
{
|
|
|
|
|
if (cancellationToken.IsCancellationRequested)
|
|
|
|
|
break;
|
|
|
|
|
var relativePath = Path.GetRelativePath(path, filePath);
|
|
|
|
|
if (relativePath[0] == '.') //Ignore hidden folders
|
|
|
|
|
continue;
|
|
|
|
|
var isUpgrade = false;
|
|
|
|
|
if (existingFiles.TryGetValue(relativePath, out var version))
|
|
|
|
|
{
|
|
|
|
|
if(version < MediaEntry.CUR_VERSION)
|
|
|
|
|
continue;
|
|
|
|
|
isUpgrade = true;
|
|
|
|
|
}
|
|
|
|
|
var metadata = ReadMetadata(filePath);
|
|
|
|
|
if(metadata.HasError)
|
|
|
|
|
{
|
|
|
|
|
logger.LogError(metadata.Error.GetException(), $"Failed to get metadata for file: {filePath}");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var entry = MediaEntry.Parse(relativePath, metadata);
|
|
|
|
|
if(entry.HasError)
|
|
|
|
|
{
|
|
|
|
|
logger.LogError(entry.Error.GetException(), "Failed to parse file data");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if(isUpgrade)
|
|
|
|
|
upgradeEntries.Add(entry);
|
|
|
|
|
else
|
|
|
|
|
entries.Add(entry);
|
|
|
|
|
}
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
if(entries.Count > 0) {
|
|
|
|
|
await mediaService.AddMediaBulkAsync(entries, cancellationToken);
|
|
|
|
|
logger.LogInformation("Added {count} file entries", entries.Count);
|
|
|
|
|
}
|
|
|
|
|
if (upgradeEntries.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
await mediaService.DeleteAllEntriesAsync(upgradeEntries.Select(e => e.Filepath), cancellationToken);
|
|
|
|
|
await mediaService.AddMediaBulkAsync(upgradeEntries, cancellationToken);
|
|
|
|
|
logger.LogInformation("Upgraded {count} file entries", entries.Count);
|
|
|
|
|
total += await ScanFileChunkAsync(path, chunk, existingFiles, cancellationToken);
|
|
|
|
|
logger.LogInformation("Added {updated} of {count}", total, existingFiles.Count);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
@@ -101,6 +66,56 @@ public class FileScannerService(MediaService mediaService, IConfiguration config
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async Task<int> ScanFileChunkAsync(string path, IEnumerable<string> files, FrozenDictionary<string, int> existingFiles, CancellationToken cancellationToken = default)
|
|
|
|
|
{
|
|
|
|
|
var entries = new List<MediaEntry>();
|
|
|
|
|
var upgradeEntries = new List<MediaEntry>();
|
|
|
|
|
foreach (var filePath in files)
|
|
|
|
|
{
|
|
|
|
|
if (cancellationToken.IsCancellationRequested)
|
|
|
|
|
break;
|
|
|
|
|
var relativePath = Path.GetRelativePath(path, filePath);
|
|
|
|
|
if (relativePath[0] == '.') //Ignore hidden folders
|
|
|
|
|
continue;
|
|
|
|
|
var isUpgrade = false;
|
|
|
|
|
if (existingFiles.TryGetValue(relativePath, out var version))
|
|
|
|
|
{
|
|
|
|
|
if (version < MediaEntry.CUR_VERSION)
|
|
|
|
|
continue;
|
|
|
|
|
isUpgrade = true;
|
|
|
|
|
}
|
|
|
|
|
var metadata = ReadMetadata(filePath);
|
|
|
|
|
if (metadata.HasError)
|
|
|
|
|
{
|
|
|
|
|
logger.LogError(metadata.Error.GetException(), $"Failed to get metadata for file: {filePath}");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var entry = MediaEntry.Parse(relativePath, metadata);
|
|
|
|
|
if (entry.HasError)
|
|
|
|
|
{
|
|
|
|
|
logger.LogError(entry.Error.GetException(), "Failed to parse file data");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (isUpgrade)
|
|
|
|
|
upgradeEntries.Add(entry);
|
|
|
|
|
else
|
|
|
|
|
entries.Add(entry);
|
|
|
|
|
}
|
|
|
|
|
cancellationToken.ThrowIfCancellationRequested();
|
|
|
|
|
if (entries.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
await mediaService.AddMediaBulkAsync(entries, cancellationToken);
|
|
|
|
|
logger.LogInformation("Added {count} file entries", entries.Count);
|
|
|
|
|
}
|
|
|
|
|
if (upgradeEntries.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
await mediaService.DeleteAllEntriesAsync(upgradeEntries.Select(e => e.Filepath), cancellationToken);
|
|
|
|
|
await mediaService.AddMediaBulkAsync(upgradeEntries, cancellationToken);
|
|
|
|
|
logger.LogInformation("Upgraded {count} file entries", entries.Count);
|
|
|
|
|
}
|
|
|
|
|
return entries.Count + upgradeEntries.Count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Maybe<MediaMetadata> ReadMetadata(string filePath)
|
|
|
|
|
{
|
|
|
|
|
var ext = Path.GetExtension(filePath);
|
|
|
|
|
|