Compare commits

...

3 Commits

Author SHA1 Message Date
Leilei Zhang
d3bd7e266a add store search 2025-05-26 18:51:38 +08:00
Leilei Zhang
ea5e0308c4 fix xmal style 2025-05-26 16:21:05 +08:00
Leilei Zhang
9c2aef3f3e Add missing codec detection and warning message in video preview 2025-05-26 15:47:02 +08:00
5 changed files with 89 additions and 0 deletions

View File

@@ -60,6 +60,21 @@
</MediaPlayerElement.TransportControls>
</MediaPlayerElement>
<RichTextBlock
x:Name="VideoWarningMessage"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{StaticResource TextFillColorSecondaryBrush}"
Visibility="{x:Bind IsWarningMessageVisible(VideoPreviewer.MissingCodecName), Mode=OneWay}">
<Paragraph>
<Run Text="{x:Bind GetWarningMessage(VideoPreviewer.MissingCodecName), Mode=OneWay}" />
<Hyperlink Click="CodecSearchHyperlink_Click">
<Run x:Uid="VideoCodecStoreLink" />
</Hyperlink>
</Paragraph>
</RichTextBlock>
<controls:AudioControl
x:Name="AudioPreview"
Source="{x:Bind AudioPreviewer.Preview, Mode=OneWay}"

View File

@@ -14,6 +14,7 @@ using Microsoft.PowerToys.Telemetry;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Documents;
using Microsoft.UI.Xaml.Input;
using Microsoft.Web.WebView2.Core;
using Peek.Common.Extensions;
@@ -149,6 +150,28 @@ namespace Peek.FilePreviewer
return isValidPreview ? Visibility.Visible : Visibility.Collapsed;
}
public Visibility IsWarningMessageVisible(string? missingCodecName)
{
var shouldShow = !string.IsNullOrEmpty(missingCodecName);
return shouldShow ? Visibility.Visible : Visibility.Collapsed;
}
public string GetWarningMessage(string missingCodecName)
{
return ReadableStringHelper.FormatResourceString("VideoMissingCodec_WarningMessage", missingCodecName);
}
private async void CodecSearchHyperlink_Click(Hyperlink sender, HyperlinkClickEventArgs args)
{
string codecName = VideoPreviewer?.MissingCodecName ?? string.Empty;
string searchQuery = Uri.EscapeDataString(codecName);
Uri storeSearchUri = new Uri($"ms-windows-store://search/?query=codec {codecName}");
await Windows.System.Launcher.LaunchUriAsync(storeSearchUri);
}
public Visibility IsUnsupportedPreviewVisible(IUnsupportedFilePreviewer? previewer, PreviewState state)
{
var isValidPreview = previewer != null && (MatchPreviewState(state, PreviewState.Loaded) || MatchPreviewState(state, PreviewState.Error));

View File

@@ -9,5 +9,7 @@ namespace Peek.FilePreviewer.Previewers.Interfaces
public interface IVideoPreviewer : IPreviewer, IPreviewTarget
{
public MediaSource? Preview { get; }
public string? MissingCodecName { get; }
}
}

View File

@@ -8,6 +8,7 @@ using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using ManagedCommon;
using Microsoft.UI.Dispatching;
using Peek.Common.Extensions;
using Peek.Common.Helpers;
@@ -16,6 +17,8 @@ using Peek.FilePreviewer.Models;
using Peek.FilePreviewer.Previewers.Interfaces;
using Windows.Foundation;
using Windows.Media.Core;
using Windows.Media.MediaProperties;
using Windows.Media.Transcoding;
using Windows.Storage;
namespace Peek.FilePreviewer.Previewers
@@ -31,6 +34,9 @@ namespace Peek.FilePreviewer.Previewers
[ObservableProperty]
private Size videoSize;
[ObservableProperty]
private string? missingCodecName;
public VideoPreviewer(IFileSystemItem file)
{
Item = file;
@@ -56,6 +62,7 @@ namespace Peek.FilePreviewer.Previewers
public async Task LoadPreviewAsync(CancellationToken cancellationToken)
{
State = PreviewState.Loading;
MissingCodecName = null;
VideoTask = LoadVideoAsync(cancellationToken);
cancellationToken.ThrowIfCancellationRequested();
await VideoTask;
@@ -90,6 +97,35 @@ namespace Peek.FilePreviewer.Previewers
});
}
private async Task<string> GetMissingCodecAsync(StorageFile? file)
{
try
{
var profile = await MediaEncodingProfile.CreateFromFileAsync(file);
if (profile.Video != null)
{
var codecQuery = new CodecQuery();
var decoders = await codecQuery.FindAllAsync(
CodecKind.Video,
CodecCategory.Decoder,
profile.Video.Subtype);
return decoders.Count > 0 ? string.Empty : profile.Video.Subtype;
}
else
{
Logger.LogWarning($"No video profile found for file {file?.Path}. Cannot determine codec support.");
}
}
catch (Exception ex)
{
Logger.LogError($"Error checking codec support for file {file?.Path}: {ex.Message}");
}
return string.Empty;
}
private Task<bool> LoadVideoAsync(CancellationToken cancellationToken)
{
return TaskExtension.RunSafe(async () =>
@@ -98,10 +134,17 @@ namespace Peek.FilePreviewer.Previewers
var storageFile = await Item.GetStorageItemAsync() as StorageFile;
var missingCodecName = await GetMissingCodecAsync(storageFile);
await Dispatcher.RunOnUiThread(() =>
{
cancellationToken.ThrowIfCancellationRequested();
if (!string.IsNullOrEmpty(missingCodecName))
{
MissingCodecName = missingCodecName;
}
Preview = MediaSource.CreateFromStorageFile(storageFile);
});
});

View File

@@ -372,4 +372,10 @@
<data name="DeleteConfirmationDialog_DontWarnCheckbox.Content" xml:space="preserve">
<value>Don't show this warning again</value>
</data>
<data name="VideoMissingCodec_WarningMessage" xml:space="preserve">
<value>Your device doesn't support the {0} format. To play this file, install a codec that supports this format.</value>
</data>
<data name="VideoCodecStoreLink.Text" xml:space="preserve">
<value>Search in Microsoft Store</value>
</data>
</root>