67 lines
3.8 KiB
Markdown
67 lines
3.8 KiB
Markdown
# PLib
|
|
|
|
Менеджер видеотеки на Avalonia: сканирует папки, вытаскивает превью через ffmpeg и
|
|
показывает всё сеткой карточек.
|
|
|
|
## Что уже работает
|
|
|
|
- Сканирование указанных папок, инкрементальное — файл, который не изменился, не переиндексируется.
|
|
- Метаданные (длительность, разрешение, кодек) через ffprobe.
|
|
- Постеры кадром из видео через ffmpeg, с кэшем на диске.
|
|
- Виртуализированная сетка карточек, ленивая загрузка превью, поиск и сортировка.
|
|
- Светлая и тёмная темы.
|
|
- Клик или Enter по карточке — открыть в системном плеере, правая кнопка — контекстное меню.
|
|
|
|
## Требования
|
|
|
|
- .NET 10 SDK
|
|
- `ffmpeg` и `ffprobe` в `PATH`
|
|
|
|
## Запуск
|
|
|
|
```bash
|
|
dotnet run --project src/PLib.Desktop
|
|
```
|
|
|
|
```bash
|
|
dotnet test
|
|
```
|
|
|
|
## Архитектура
|
|
|
|
Четыре слоя, зависимости направлены только внутрь:
|
|
|
|
| Проект | Отвечает за | Знает о |
|
|
| --- | --- | --- |
|
|
| `PLib.Domain` | Сущность `VideoItem` и её инварианты | ни о чём |
|
|
| `PLib.Application` | Сценарии (`LibraryService`) и абстракции портов | Domain |
|
|
| `PLib.Infrastructure` | EF Core + SQLite, ffmpeg, файловая система | Application |
|
|
| `PLib.Desktop` | Avalonia, ViewModel'и, composition root | Infrastructure |
|
|
|
|
Ключевые решения:
|
|
|
|
- **Сканирование — поток событий.** `ILibraryService.ScanAsync` возвращает
|
|
`IAsyncEnumerable<LibraryScanEvent>`: карточки появляются по мере находок, а не после
|
|
завершения всего прохода. Тяжёлая часть (ffprobe + ffmpeg) идёт параллельно через
|
|
`Parallel.ForEachAsync`, результаты собираются в `Channel` и применяются к сущностям
|
|
по одному — трекер изменений EF не потокобезопасен.
|
|
- **Вся работа вне UI-потока.** ViewModel оборачивает конвейер в `Task.Run` и возвращает
|
|
каждое событие в UI явно через `Dispatcher.UIThread`.
|
|
- **Превью живут только пока видны.** `AsyncImage` запрашивает битмап при попадании в
|
|
визуальное дерево и отпускает при выходе; `ThumbnailCache` — LRU на 256 записей с
|
|
декодированием в нужную ширину. Память зависит от размера окна, а не от размера библиотеки.
|
|
- **Scope на операцию.** `DbContext` живёт ровно одну операцию — ViewModel берёт
|
|
`IServiceScopeFactory` и создаёт scope на каждый вызов.
|
|
|
|
## Данные
|
|
|
|
Всё пользовательское лежит в `%LOCALAPPDATA%\PLib`:
|
|
|
|
- `library.db` — SQLite с метаданными;
|
|
- `thumbnails/` — кэш постеров (ключ = путь + размер + время изменения файла);
|
|
- `settings.json` — список папок, перечитывается на лету;
|
|
- `logs/` — Serilog, ротация по дням.
|
|
|
|
Схема создаётся через `EnsureCreated`. Когда форма таблицы устоится — заменить на
|
|
миграции EF Core (`DatabaseInitializer` — единственное место, которое надо будет тронуть).
|