added metadata loading to scanner
This commit is contained in:
@@ -1,11 +1,19 @@
|
||||
|
||||
using AZKiServer.Models;
|
||||
|
||||
using FFMpegCore;
|
||||
|
||||
using MaybeError;
|
||||
using MaybeError.Errors;
|
||||
|
||||
using SixLabors.ImageSharp;
|
||||
|
||||
namespace AZKiServer.Services;
|
||||
|
||||
public class FileScannerService(MediaService mediaService, IConfiguration config, ILogger<FileScannerService> logger) : IHostedService, IDisposable
|
||||
{
|
||||
private Timer? _timer;
|
||||
private bool _isRunning;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
@@ -19,7 +27,11 @@ public class FileScannerService(MediaService mediaService, IConfiguration config
|
||||
return Task.CompletedTask;
|
||||
_timer = new Timer((_) =>
|
||||
{
|
||||
if (_isRunning)
|
||||
return;
|
||||
_isRunning = true;
|
||||
ScanFilesAsync(path).Wait();
|
||||
_isRunning = false;
|
||||
}, null, TimeSpan.FromMinutes(0), TimeSpan.FromHours(1));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@@ -31,37 +43,94 @@ public class FileScannerService(MediaService mediaService, IConfiguration config
|
||||
}
|
||||
|
||||
|
||||
private async Task ScanFilesAsync(string path)
|
||||
private async Task ScanFilesAsync(string path, CancellationToken cancellationToken = default)
|
||||
{
|
||||
logger.LogInformation("Scanning Files");
|
||||
try
|
||||
{
|
||||
var files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
|
||||
var existingFiles = await mediaService.GetExistingFilePathsAsync();
|
||||
var existingFiles = await mediaService.GetExistingFilePathsAsync(cancellationToken);
|
||||
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;
|
||||
if (existingFiles.Contains(relativePath))
|
||||
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);
|
||||
}
|
||||
var entry = MediaEntry.Parse(relativePath, metadata);
|
||||
if(entry.HasError)
|
||||
{
|
||||
logger.LogError(entry.Error.GetException(), "Failed to parse file data");
|
||||
continue;
|
||||
}
|
||||
entries.Add(entry);
|
||||
if(isUpgrade)
|
||||
upgradeEntries.Add(entry);
|
||||
else
|
||||
entries.Add(entry);
|
||||
}
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
if(entries.Count > 0) {
|
||||
await mediaService.AddMediaBulkAsync(entries);
|
||||
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);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Failed to read directory contents");
|
||||
}
|
||||
}
|
||||
|
||||
private static Maybe<MediaMetadata> ReadMetadata(string filePath)
|
||||
{
|
||||
var ext = Path.GetExtension(filePath);
|
||||
return ext switch
|
||||
{
|
||||
".jpg" or ".png" or ".jpeg" => ReadImageMetadata(filePath),
|
||||
".mp4" => ReadVideoMetadata(filePath),
|
||||
_ => throw new NotSupportedException($"Files of type {ext} are not supported")
|
||||
};
|
||||
}
|
||||
|
||||
private static Maybe<MediaMetadata> ReadImageMetadata(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var info = Image.Identify(filePath);
|
||||
return new MediaMetadata(0, info.Height, info.Width);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static Maybe<MediaMetadata> ReadVideoMetadata(string filePath)
|
||||
{
|
||||
var info = FFProbe.Analyse(filePath);
|
||||
if (info.PrimaryVideoStream == null)
|
||||
return new Error($"Could not find a primirary video stream in file.");
|
||||
return new MediaMetadata((int)info.Duration.TotalSeconds, info.PrimaryVideoStream.Height, info.PrimaryVideoStream.Width);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user