Implement animated previews and perceptual hashing in PLib video library manager. Introduce IAnimatedPreviewGenerator and IVideoPerceptualHasher interfaces, enhancing video item metadata with animated preview paths and perceptual hashes. Update LibraryService to manage indexing in three passes: metadata, animated previews, and perceptual hashes. Revise UI components to display animated previews and manage duplicate video detection. Enhance README.md to document these new features and usage instructions.

This commit is contained in:
Leonid Pershin
2026-08-09 07:48:45 +03:00
parent 10c66baea8
commit 3c77baced7
36 changed files with 2711 additions and 471 deletions
+49 -1
View File
@@ -1,5 +1,6 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:PLib.Desktop.Controls">
<!-- ============================ Card ============================ -->
@@ -76,6 +77,15 @@
<Setter Property="Opacity" Value="1" />
</Style>
<!--
The animated preview follows the same hover state as the play affordance, rather than
watching the pointer itself: the pointer is over the card even while it is over the
caption, and a preview that stopped when the pointer crossed the title would flicker.
-->
<Style Selector="Button.card:pointerover controls|FilmstripImage">
<Setter Property="IsPlaying" Value="True" />
</Style>
<!-- ============================ Text ============================ -->
<Style Selector="TextBlock.cardTitle">
@@ -188,6 +198,44 @@
<Setter Property="Fill" Value="{DynamicResource PanelDividerBrush}" />
</Style>
<!-- ========================== Task panel ========================== -->
<!--
Anchored to the bottom-right corner above the status bar. Kept in the tree and hidden by
opacity so the slide has something to animate from, the same trick the settings panel uses.
-->
<Style Selector="Border.taskPanel">
<Setter Property="Width" Value="330" />
<Setter Property="Margin" Value="0,0,16,8" />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Background" Value="{DynamicResource SurfaceBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource PanelDividerBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="CornerRadius" Value="12" />
<Setter Property="Padding" Value="14,12" />
<Setter Property="Opacity" Value="0" />
<Setter Property="IsHitTestVisible" Value="False" />
<Setter Property="RenderTransform" Value="translateY(10px)" />
<Setter Property="Transitions">
<Transitions>
<DoubleTransition Property="Opacity" Duration="0:0:0.16" Easing="CubicEaseOut" />
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.18" Easing="CubicEaseOut" />
</Transitions>
</Setter>
</Style>
<Style Selector="Border.taskPanel.open">
<Setter Property="Opacity" Value="1" />
<Setter Property="IsHitTestVisible" Value="True" />
<Setter Property="RenderTransform" Value="none" />
</Style>
<Style Selector="TextBlock.taskTitle">
<Setter Property="Foreground" Value="{DynamicResource TextPrimaryBrush}" />
<Setter Property="FontSize" Value="12.5" />
</Style>
<!-- ============================ Badge ============================ -->
<Style Selector="Border.badge">