forked from sim0n00ps/OF-DL
Add FFprobe Path and DRM Video Duration Match Threshold to the config page
This commit is contained in:
parent
fccee9a520
commit
da40f3d0c5
@ -10,6 +10,7 @@ internal static class ConfigValidationService
|
||||
|
||||
ValidatePath(config.DownloadPath, nameof(Config.DownloadPath), errors, requireExistingFile: false);
|
||||
ValidatePath(config.FFmpegPath, nameof(Config.FFmpegPath), errors, requireExistingFile: true);
|
||||
ValidatePath(config.FFprobePath, nameof(Config.FFprobePath), errors, requireExistingFile: true);
|
||||
|
||||
if (config.Timeout.HasValue && config.Timeout.Value <= 0 && config.Timeout.Value != -1)
|
||||
{
|
||||
|
||||
@ -49,8 +49,12 @@ public partial class MainWindowViewModel(
|
||||
{
|
||||
[nameof(Config.FFmpegPath)] =
|
||||
"Path to the FFmpeg executable. If blank, OF-DL will try the app directory and PATH.",
|
||||
[nameof(Config.FFprobePath)] =
|
||||
"Path to the FFprobe executable. If blank, OF-DL will try FFmpeg's directory, the app directory, and PATH.",
|
||||
[nameof(Config.DownloadPath)] =
|
||||
"Base download folder. If blank, OF-DL uses __user_data__/sites/OnlyFans/{username}.",
|
||||
[nameof(Config.DrmVideoDurationMatchThreshold)] =
|
||||
"Minimum DRM video duration match threshold. Higher values are stricter. 100% requires an exact duration match. 98% is the recommended value.",
|
||||
[nameof(Config.DownloadVideos)] = "Download video media when enabled.",
|
||||
[nameof(Config.DownloadImages)] = "Download image media when enabled.",
|
||||
[nameof(Config.DownloadAudios)] = "Download audio media when enabled.",
|
||||
@ -164,6 +168,7 @@ public partial class MainWindowViewModel(
|
||||
[ObservableProperty] private string _errorMessage = string.Empty;
|
||||
|
||||
private string _actualFfmpegPath = string.Empty;
|
||||
private string _actualFfprobePath = string.Empty;
|
||||
private string _actualDownloadPath = string.Empty;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(FfmpegPathDisplay))]
|
||||
@ -172,12 +177,21 @@ public partial class MainWindowViewModel(
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(HasFfmpegPathError))]
|
||||
private string _ffmpegPathError = string.Empty;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(HasFfprobePathError))]
|
||||
private string _ffprobePath = string.Empty;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(HasFfprobePathError))]
|
||||
private string _ffprobePathError = string.Empty;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(DownloadPathDisplay))]
|
||||
private string _downloadPath = string.Empty;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(HasDownloadPathError))]
|
||||
private string _downloadPathError = string.Empty;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(DrmVideoDurationMatchThresholdPercentLabel))]
|
||||
private double _drmVideoDurationMatchThresholdPercent = 98;
|
||||
|
||||
[ObservableProperty] [NotifyPropertyChangedFor(nameof(HasMediaTypesError))]
|
||||
private string _mediaTypesError = string.Empty;
|
||||
|
||||
@ -218,6 +232,8 @@ public partial class MainWindowViewModel(
|
||||
|
||||
public bool HasFfmpegPathError => !string.IsNullOrWhiteSpace(FfmpegPathError);
|
||||
|
||||
public bool HasFfprobePathError => !string.IsNullOrWhiteSpace(FfprobePathError);
|
||||
|
||||
public bool HasDownloadPathError => !string.IsNullOrWhiteSpace(DownloadPathError);
|
||||
|
||||
public bool HasMediaTypesError => !string.IsNullOrWhiteSpace(MediaTypesError);
|
||||
@ -233,8 +249,16 @@ public partial class MainWindowViewModel(
|
||||
|
||||
public string FfmpegPathHelpText => GetConfigHelpText(nameof(Config.FFmpegPath));
|
||||
|
||||
public string FfprobePathHelpText => GetConfigHelpText(nameof(Config.FFprobePath));
|
||||
|
||||
public string DownloadPathHelpText => GetConfigHelpText(nameof(Config.DownloadPath));
|
||||
|
||||
public string DrmVideoDurationMatchThresholdHelpText =>
|
||||
GetConfigHelpText(nameof(Config.DrmVideoDurationMatchThreshold));
|
||||
|
||||
public string DrmVideoDurationMatchThresholdPercentLabel =>
|
||||
$"{Math.Round(DrmVideoDurationMatchThresholdPercent)}%";
|
||||
|
||||
public string SelectedUsersSummary =>
|
||||
$"{AvailableUsers.Count(user => user.IsSelected)} / {AvailableUsers.Count} selected";
|
||||
|
||||
@ -319,6 +343,16 @@ public partial class MainWindowViewModel(
|
||||
FfmpegPathError = string.Empty;
|
||||
}
|
||||
|
||||
public void SetFfprobePath(string? path)
|
||||
{
|
||||
string normalizedPath = NormalizePathForDisplay(path);
|
||||
_actualFfprobePath = normalizedPath;
|
||||
FfprobePath = HidePrivateInfo && !string.IsNullOrWhiteSpace(normalizedPath)
|
||||
? "[Hidden for Privacy]"
|
||||
: normalizedPath;
|
||||
FfprobePathError = string.Empty;
|
||||
}
|
||||
|
||||
public void SetDownloadPath(string? path)
|
||||
{
|
||||
string normalizedPath = NormalizePathForDisplay(path);
|
||||
@ -760,6 +794,16 @@ public partial class MainWindowViewModel(
|
||||
FfmpegPathError = string.Empty;
|
||||
}
|
||||
|
||||
partial void OnFfprobePathChanged(string value)
|
||||
{
|
||||
if (value != "[Hidden for Privacy]")
|
||||
{
|
||||
_actualFfprobePath = value;
|
||||
}
|
||||
|
||||
FfprobePathError = string.Empty;
|
||||
}
|
||||
|
||||
partial void OnDownloadPathChanged(string value)
|
||||
{
|
||||
if (value != "[Hidden for Privacy]")
|
||||
@ -1009,6 +1053,12 @@ public partial class MainWindowViewModel(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (error.Key == nameof(Config.FFprobePath))
|
||||
{
|
||||
FfprobePathError = error.Value;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (fieldMap.TryGetValue(error.Key, out ConfigFieldViewModel? field))
|
||||
{
|
||||
field.SetError(error.Value);
|
||||
@ -1122,12 +1172,18 @@ public partial class MainWindowViewModel(
|
||||
_actualFfmpegPath = ffmpegPath;
|
||||
FfmpegPath = HidePrivateInfo && !string.IsNullOrWhiteSpace(ffmpegPath) ? "[Hidden for Privacy]" : ffmpegPath;
|
||||
|
||||
string ffprobePath = NormalizePathForDisplay(config.FFprobePath);
|
||||
_actualFfprobePath = ffprobePath;
|
||||
FfprobePath = HidePrivateInfo && !string.IsNullOrWhiteSpace(ffprobePath) ? "[Hidden for Privacy]" : ffprobePath;
|
||||
|
||||
string downloadPath = ResolveDownloadPathForDisplay(config.DownloadPath);
|
||||
_actualDownloadPath = downloadPath;
|
||||
DownloadPath = HidePrivateInfo && !string.IsNullOrWhiteSpace(downloadPath)
|
||||
? "[Hidden for Privacy]"
|
||||
: downloadPath;
|
||||
|
||||
DrmVideoDurationMatchThresholdPercent = Math.Clamp(config.DrmVideoDurationMatchThreshold * 100, 0, 100);
|
||||
|
||||
ClearSpecialConfigErrors();
|
||||
|
||||
PopulateSelectionOptions(MediaTypeOptions, s_mediaTypeOptions, config);
|
||||
@ -1168,11 +1224,19 @@ public partial class MainWindowViewModel(
|
||||
? string.Empty
|
||||
: EscapePathForConfig(normalizedFfmpegPath);
|
||||
|
||||
string ffprobePathToUse = HidePrivateInfo ? _actualFfprobePath : FfprobePath;
|
||||
string normalizedFfprobePath = NormalizePathForDisplay(ffprobePathToUse);
|
||||
config.FFprobePath = string.IsNullOrWhiteSpace(normalizedFfprobePath)
|
||||
? string.Empty
|
||||
: EscapePathForConfig(normalizedFfprobePath);
|
||||
|
||||
string downloadPathToUse = HidePrivateInfo ? _actualDownloadPath : DownloadPath;
|
||||
string normalizedDownloadPath = NormalizePathForDisplay(downloadPathToUse);
|
||||
config.DownloadPath = string.IsNullOrWhiteSpace(normalizedDownloadPath)
|
||||
? EscapePathForConfig(s_defaultDownloadPath)
|
||||
: EscapePathForConfig(normalizedDownloadPath);
|
||||
config.DrmVideoDurationMatchThreshold =
|
||||
Math.Clamp(Math.Round(DrmVideoDurationMatchThresholdPercent / 100d, 2), 0d, 1d);
|
||||
|
||||
ApplySelectionOptionsToConfig(config, MediaTypeOptions);
|
||||
ApplySelectionOptionsToConfig(config, MediaSourceOptions);
|
||||
@ -1208,13 +1272,14 @@ public partial class MainWindowViewModel(
|
||||
private void ClearSpecialConfigErrors()
|
||||
{
|
||||
FfmpegPathError = string.Empty;
|
||||
FfprobePathError = string.Empty;
|
||||
DownloadPathError = string.Empty;
|
||||
MediaTypesError = string.Empty;
|
||||
MediaSourcesError = string.Empty;
|
||||
}
|
||||
|
||||
private bool HasSpecialConfigErrors() =>
|
||||
HasFfmpegPathError || HasDownloadPathError || HasMediaTypesError || HasMediaSourcesError;
|
||||
HasFfmpegPathError || HasFfprobePathError || HasDownloadPathError || HasMediaTypesError || HasMediaSourcesError;
|
||||
|
||||
private static string ResolveDownloadPathForDisplay(string? configuredPath)
|
||||
{
|
||||
@ -1404,7 +1469,9 @@ public partial class MainWindowViewModel(
|
||||
or nameof(Config.NonInteractiveModePurchasedTab)
|
||||
or nameof(Config.DisableBrowserAuth)
|
||||
or nameof(Config.FFmpegPath)
|
||||
or nameof(Config.FFprobePath)
|
||||
or nameof(Config.DownloadPath)
|
||||
or nameof(Config.DrmVideoDurationMatchThreshold)
|
||||
or nameof(Config.DownloadVideos)
|
||||
or nameof(Config.DownloadImages)
|
||||
or nameof(Config.DownloadAudios)
|
||||
|
||||
@ -142,6 +142,42 @@
|
||||
Foreground="#FF5A5A"
|
||||
Text="{Binding FfmpegPathError}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="6" Margin="0,8,0,0">
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Text="FFprobe Path" />
|
||||
<Button Width="20"
|
||||
Height="20"
|
||||
MinWidth="20"
|
||||
MinHeight="20"
|
||||
Padding="0"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
ToolTip.Tip="{Binding FfprobePathHelpText}" />
|
||||
</StackPanel>
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBox Grid.Column="0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding FfprobePath}"
|
||||
Watermark="Select ffprobe executable" />
|
||||
<Button Grid.Column="1"
|
||||
Margin="8,0,0,0"
|
||||
Classes="secondary"
|
||||
Content="Browse..."
|
||||
Click="OnBrowseFfprobePathClick" />
|
||||
</Grid>
|
||||
<TextBlock IsVisible="{Binding HasFfprobePathError}"
|
||||
Foreground="#FF5A5A"
|
||||
Text="{Binding FfprobePathError}"
|
||||
TextWrapping="Wrap" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
@ -291,6 +327,51 @@
|
||||
Foreground="#FF5A5A"
|
||||
Text="{Binding ViewModel.DownloadPathError, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue=''}"
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<Grid Margin="0,8,0,2" ColumnDefinitions="190,*">
|
||||
<Grid Grid.Column="0"
|
||||
ColumnDefinitions="*,Auto"
|
||||
Margin="0,6,10,0"
|
||||
ClipToBounds="True">
|
||||
<TextBlock Grid.Column="0"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#1F2A44"
|
||||
Text="DRM Video Duration Match Threshold"
|
||||
TextWrapping="Wrap"
|
||||
VerticalAlignment="Top" />
|
||||
<Button Grid.Column="1"
|
||||
Width="20"
|
||||
Height="20"
|
||||
MinWidth="20"
|
||||
MinHeight="20"
|
||||
Margin="6,0,0,0"
|
||||
Padding="0"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
HorizontalContentAlignment="Center"
|
||||
VerticalContentAlignment="Center"
|
||||
FontSize="12"
|
||||
FontWeight="Bold"
|
||||
Background="#EAF0FB"
|
||||
BorderBrush="#C5D4EC"
|
||||
BorderThickness="1"
|
||||
CornerRadius="10"
|
||||
Content="?"
|
||||
ToolTip.Tip="{Binding ViewModel.DrmVideoDurationMatchThresholdHelpText, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue=''}" />
|
||||
</Grid>
|
||||
<Grid Grid.Column="1" ColumnDefinitions="*,Auto" VerticalAlignment="Center">
|
||||
<Slider Grid.Column="0"
|
||||
Minimum="0"
|
||||
Maximum="100"
|
||||
Value="{Binding ViewModel.DrmVideoDurationMatchThresholdPercent, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue=98}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Margin="10,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="#4A5B78"
|
||||
Text="{Binding ViewModel.DrmVideoDurationMatchThresholdPercentLabel, RelativeSource={RelativeSource AncestorType=views:MainWindow}, FallbackValue='98%'}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
<StackPanel IsVisible="{Binding HasSpecificDateFilterFields}"
|
||||
Margin="0,0,0,6"
|
||||
|
||||
@ -70,6 +70,42 @@ public partial class MainWindow : Window
|
||||
vm.SetFfmpegPath(selectedFile.Name);
|
||||
}
|
||||
|
||||
private async void OnBrowseFfprobePathClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not MainWindowViewModel vm)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TopLevel? topLevel = TopLevel.GetTopLevel(this);
|
||||
if (topLevel?.StorageProvider == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<IStorageFile> selectedFiles = await topLevel.StorageProvider.OpenFilePickerAsync(
|
||||
new FilePickerOpenOptions
|
||||
{
|
||||
Title = "Select FFprobe executable",
|
||||
AllowMultiple = false
|
||||
});
|
||||
|
||||
IStorageFile? selectedFile = selectedFiles.FirstOrDefault();
|
||||
if (selectedFile == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string? localPath = selectedFile.TryGetLocalPath();
|
||||
if (!string.IsNullOrWhiteSpace(localPath))
|
||||
{
|
||||
vm.SetFfprobePath(localPath);
|
||||
return;
|
||||
}
|
||||
|
||||
vm.SetFfprobePath(selectedFile.Name);
|
||||
}
|
||||
|
||||
private async void OnBrowseDownloadPathClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is not MainWindowViewModel vm)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user