116 lines
3.7 KiB
C#
116 lines
3.7 KiB
C#
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace EmbyToolbox.Services;
|
|
|
|
public sealed class FileDiscoveryService
|
|
{
|
|
/// <summary>Стабильная сортировка списка видеофайлов по полному нормализованному пути (без учёта регистра).</summary>
|
|
public static StringComparer QueuePathOrderComparer { get; } = StringComparer.OrdinalIgnoreCase;
|
|
|
|
/// <summary>
|
|
/// Собирает пути к поддерживаемым видео: отдельные файлы, из каталогов — рекурсивно, без дублей.
|
|
/// </summary>
|
|
public IReadOnlyList<string> CollectVideoFilesFromFileSystemEntries(IEnumerable<string>? entryPaths, Action<string>? onError = null)
|
|
{
|
|
if (entryPaths is null)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var set = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
foreach (var entry in entryPaths)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(entry))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var full = Path.GetFullPath(entry);
|
|
if (File.Exists(full))
|
|
{
|
|
if (SupportedVideoFormats.IsSupportedVideoFile(full))
|
|
{
|
|
set.Add(full);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (Directory.Exists(full))
|
|
{
|
|
foreach (var file in DiscoverVideoFiles(full, onError))
|
|
{
|
|
set.Add(file);
|
|
}
|
|
}
|
|
}
|
|
|
|
return SortVideoPathsByFullPath(set);
|
|
}
|
|
|
|
/// <summary>Возвращает новый список путей, отсортированный по <see cref="QueuePathOrderComparer"/> (стабильно).</summary>
|
|
public static IReadOnlyList<string> SortVideoPathsByFullPath(IEnumerable<string> paths) =>
|
|
paths.OrderBy(p => p, QueuePathOrderComparer).ToList();
|
|
|
|
public IReadOnlyList<string> DiscoverVideoFiles(string rootDirectory, Action<string>? onError = null)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(rootDirectory) || !Directory.Exists(rootDirectory))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var result = new List<string>();
|
|
var pending = new Stack<string>();
|
|
pending.Push(rootDirectory);
|
|
|
|
while (pending.Count > 0)
|
|
{
|
|
var current = pending.Pop();
|
|
|
|
try
|
|
{
|
|
foreach (var file in Directory.EnumerateFiles(current))
|
|
{
|
|
if (!SupportedVideoFormats.IsSupportedVideoFile(file))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string normalized;
|
|
try
|
|
{
|
|
normalized = Path.GetFullPath(file);
|
|
}
|
|
catch
|
|
{
|
|
continue;
|
|
}
|
|
|
|
result.Add(normalized);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
onError?.Invoke($"ошибка чтения каталога '{current}': {ex.Message}");
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (var childDirectory in Directory.EnumerateDirectories(current))
|
|
{
|
|
pending.Push(childDirectory);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
onError?.Invoke($"ошибка чтения вложенных каталогов '{current}': {ex.Message}");
|
|
}
|
|
}
|
|
|
|
return SortVideoPathsByFullPath(result);
|
|
}
|
|
|
|
public bool IsSupportedVideoFile(string path) => SupportedVideoFormats.IsSupportedVideoFile(path);
|
|
}
|