forked from sim0n00ps/OF-DL
Update progress messaging for consistency
This commit is contained in:
parent
35bde51e7d
commit
a74ebc810a
@ -177,7 +177,8 @@ public class DownloadOrchestrationService(
|
|||||||
if (config.DownloadAvatarHeaderPhoto)
|
if (config.DownloadAvatarHeaderPhoto)
|
||||||
{
|
{
|
||||||
eventHandler.CancellationToken.ThrowIfCancellationRequested();
|
eventHandler.CancellationToken.ThrowIfCancellationRequested();
|
||||||
UserEntities.User? userInfo = await apiService.GetUserInfo($"/users/{username}", eventHandler.CancellationToken);
|
UserEntities.User? userInfo =
|
||||||
|
await apiService.GetUserInfo($"/users/{username}", eventHandler.CancellationToken);
|
||||||
if (userInfo != null)
|
if (userInfo != null)
|
||||||
{
|
{
|
||||||
await downloadService.DownloadAvatarHeader(userInfo.Avatar, userInfo.Header, path, username);
|
await downloadService.DownloadAvatarHeader(userInfo.Avatar, userInfo.Header, path, username);
|
||||||
@ -256,7 +257,7 @@ public class DownloadOrchestrationService(
|
|||||||
: tempStories.Count;
|
: tempStories.Count;
|
||||||
|
|
||||||
DownloadResult result = await eventHandler.WithProgressAsync(
|
DownloadResult result = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {tempStories.Count} Stories", totalSize, config.ShowScrapeSize,
|
$"Downloading {tempStories.Count} stories", totalSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadStories(username, userId, path,
|
async reporter => await downloadService.DownloadStories(username, userId, path,
|
||||||
PaidPostIds.ToHashSet(), reporter));
|
PaidPostIds.ToHashSet(), reporter));
|
||||||
|
|
||||||
@ -285,7 +286,7 @@ public class DownloadOrchestrationService(
|
|||||||
: tempHighlights.Count;
|
: tempHighlights.Count;
|
||||||
|
|
||||||
DownloadResult result = await eventHandler.WithProgressAsync(
|
DownloadResult result = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {tempHighlights.Count} Highlights", totalSize, config.ShowScrapeSize,
|
$"Downloading {tempHighlights.Count} highlights", totalSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadHighlights(username, userId, path,
|
async reporter => await downloadService.DownloadHighlights(username, userId, path,
|
||||||
PaidPostIds.ToHashSet(), reporter));
|
PaidPostIds.ToHashSet(), reporter));
|
||||||
|
|
||||||
@ -359,9 +360,12 @@ public class DownloadOrchestrationService(
|
|||||||
long totalSize = config.ShowScrapeSize
|
long totalSize = config.ShowScrapeSize
|
||||||
? await downloadService.CalculateTotalFileSize(post.SinglePosts.Values.ToList())
|
? await downloadService.CalculateTotalFileSize(post.SinglePosts.Values.ToList())
|
||||||
: post.SinglePosts.Count;
|
: post.SinglePosts.Count;
|
||||||
|
int postCount = post.SinglePostObjects.Count;
|
||||||
|
string postLabel = postCount == 1 ? "Post" : "Posts";
|
||||||
|
|
||||||
DownloadResult result = await eventHandler.WithProgressAsync(
|
DownloadResult result = await eventHandler.WithProgressAsync(
|
||||||
"Downloading Post", totalSize, config.ShowScrapeSize,
|
$"Downloading {post.SinglePosts.Count} media from {postCount} {postLabel.ToLowerInvariant()}", totalSize,
|
||||||
|
config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadSinglePost(username, path, users,
|
async reporter => await downloadService.DownloadSinglePost(username, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, post, reporter));
|
clientIdBlobMissing, devicePrivateKeyMissing, post, reporter));
|
||||||
|
|
||||||
@ -455,7 +459,7 @@ public class DownloadOrchestrationService(
|
|||||||
: purchasedTabCollection.PaidPosts.PaidPosts.Count;
|
: purchasedTabCollection.PaidPosts.PaidPosts.Count;
|
||||||
|
|
||||||
DownloadResult postResult = await eventHandler.WithProgressAsync(
|
DownloadResult postResult = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {purchasedTabCollection.PaidPosts.PaidPosts.Count} Media from {purchasedTabCollection.PaidPosts.PaidPostObjects.Count} Paid Posts",
|
$"Downloading {purchasedTabCollection.PaidPosts.PaidPosts.Count} media from {purchasedTabCollection.PaidPosts.PaidPostObjects.Count} paid posts",
|
||||||
totalSize, config.ShowScrapeSize,
|
totalSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadPaidPostsPurchasedTab(
|
async reporter => await downloadService.DownloadPaidPostsPurchasedTab(
|
||||||
purchasedTabCollection.Username, path, users,
|
purchasedTabCollection.Username, path, users,
|
||||||
@ -483,7 +487,7 @@ public class DownloadOrchestrationService(
|
|||||||
: purchasedTabCollection.PaidMessages.PaidMessages.Count;
|
: purchasedTabCollection.PaidMessages.PaidMessages.Count;
|
||||||
|
|
||||||
DownloadResult msgResult = await eventHandler.WithProgressAsync(
|
DownloadResult msgResult = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {purchasedTabCollection.PaidMessages.PaidMessages.Count} Media from {purchasedTabCollection.PaidMessages.PaidMessageObjects.Count} Paid Messages",
|
$"Downloading {purchasedTabCollection.PaidMessages.PaidMessages.Count} media from {purchasedTabCollection.PaidMessages.PaidMessageObjects.Count} paid messages",
|
||||||
totalSize, config.ShowScrapeSize,
|
totalSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadPaidMessagesPurchasedTab(
|
async reporter => await downloadService.DownloadPaidMessagesPurchasedTab(
|
||||||
purchasedTabCollection.Username, path, users,
|
purchasedTabCollection.Username, path, users,
|
||||||
@ -554,7 +558,7 @@ public class DownloadOrchestrationService(
|
|||||||
: totalCount;
|
: totalCount;
|
||||||
|
|
||||||
DownloadResult result = await eventHandler.WithProgressAsync(
|
DownloadResult result = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {totalCount} Media from {messageCount} {messageLabel} ({paidCount} Paid + {previewCount} Preview)",
|
$"Downloading {totalCount} media from {messageCount} {messageLabel} ({paidCount} paid + {previewCount} preview)",
|
||||||
totalSize, config.ShowScrapeSize,
|
totalSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadSinglePaidMessage(username, path, users,
|
async reporter => await downloadService.DownloadSinglePaidMessage(username, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, singlePaidMessageCollection, reporter));
|
clientIdBlobMissing, devicePrivateKeyMissing, singlePaidMessageCollection, reporter));
|
||||||
@ -574,7 +578,7 @@ public class DownloadOrchestrationService(
|
|||||||
: previewCount;
|
: previewCount;
|
||||||
|
|
||||||
DownloadResult previewResult = await eventHandler.WithProgressAsync(
|
DownloadResult previewResult = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {previewCount} Preview Media from {messageCount} {messageLabel}",
|
$"Downloading {previewCount} preview media from {messageCount} {messageLabel.ToLowerInvariant()}",
|
||||||
previewSize, config.ShowScrapeSize,
|
previewSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadSinglePaidMessage(username, path, users,
|
async reporter => await downloadService.DownloadSinglePaidMessage(username, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, singlePaidMessageCollection, reporter));
|
clientIdBlobMissing, devicePrivateKeyMissing, singlePaidMessageCollection, reporter));
|
||||||
@ -594,7 +598,7 @@ public class DownloadOrchestrationService(
|
|||||||
: paidCount;
|
: paidCount;
|
||||||
|
|
||||||
DownloadResult result = await eventHandler.WithProgressAsync(
|
DownloadResult result = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {paidCount} Paid Media from {messageCount} {messageLabel}",
|
$"Downloading {paidCount} paid media from {messageCount} {messageLabel.ToLowerInvariant()}",
|
||||||
totalSize, config.ShowScrapeSize,
|
totalSize, config.ShowScrapeSize,
|
||||||
async reporter => await downloadService.DownloadSinglePaidMessage(username, path, users,
|
async reporter => await downloadService.DownloadSinglePaidMessage(username, path, users,
|
||||||
clientIdBlobMissing, devicePrivateKeyMissing, singlePaidMessageCollection, reporter));
|
clientIdBlobMissing, devicePrivateKeyMissing, singlePaidMessageCollection, reporter));
|
||||||
@ -658,7 +662,8 @@ public class DownloadOrchestrationService(
|
|||||||
: mediaCount;
|
: mediaCount;
|
||||||
|
|
||||||
DownloadResult result = await eventHandler.WithProgressAsync(
|
DownloadResult result = await eventHandler.WithProgressAsync(
|
||||||
$"Downloading {mediaCount} Media from {objectCount} {contentType}", totalSize, config.ShowScrapeSize,
|
$"Downloading {mediaCount} media from {objectCount} {contentType.ToLowerInvariant()}", totalSize,
|
||||||
|
config.ShowScrapeSize,
|
||||||
async reporter => await downloadData(data, reporter));
|
async reporter => await downloadData(data, reporter));
|
||||||
|
|
||||||
eventHandler.OnDownloadComplete(contentType, result);
|
eventHandler.OnDownloadComplete(contentType, result);
|
||||||
|
|||||||
@ -12,6 +12,8 @@ internal sealed class AvaloniaDownloadEventHandler(
|
|||||||
Func<bool> isCancellationRequested,
|
Func<bool> isCancellationRequested,
|
||||||
CancellationToken cancellationToken) : IDownloadEventHandler
|
CancellationToken cancellationToken) : IDownloadEventHandler
|
||||||
{
|
{
|
||||||
|
private string _lastProgressDescription = string.Empty;
|
||||||
|
|
||||||
public CancellationToken CancellationToken { get; } = cancellationToken;
|
public CancellationToken CancellationToken { get; } = cancellationToken;
|
||||||
|
|
||||||
public async Task<T> WithStatusAsync<T>(string statusMessage, Func<IStatusReporter, Task<T>> work)
|
public async Task<T> WithStatusAsync<T>(string statusMessage, Func<IStatusReporter, Task<T>> work)
|
||||||
@ -33,6 +35,7 @@ internal sealed class AvaloniaDownloadEventHandler(
|
|||||||
Func<IProgressReporter, Task<T>> work)
|
Func<IProgressReporter, Task<T>> work)
|
||||||
{
|
{
|
||||||
ThrowIfCancellationRequested();
|
ThrowIfCancellationRequested();
|
||||||
|
_lastProgressDescription = description;
|
||||||
progressStart(description, maxValue, showSize);
|
progressStart(description, maxValue, showSize);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -87,7 +90,8 @@ internal sealed class AvaloniaDownloadEventHandler(
|
|||||||
public void OnScrapeComplete(TimeSpan elapsed)
|
public void OnScrapeComplete(TimeSpan elapsed)
|
||||||
{
|
{
|
||||||
ThrowIfCancellationRequested();
|
ThrowIfCancellationRequested();
|
||||||
activitySink($"Scrape completed in {elapsed.TotalMinutes:0.00} minutes.");
|
string summary = BuildCompletionSummary(elapsed);
|
||||||
|
activitySink(summary);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnMessage(string message)
|
public void OnMessage(string message)
|
||||||
@ -103,4 +107,21 @@ internal sealed class AvaloniaDownloadEventHandler(
|
|||||||
throw new OperationCanceledException("Operation canceled by user.");
|
throw new OperationCanceledException("Operation canceled by user.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string BuildCompletionSummary(TimeSpan elapsed)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(_lastProgressDescription))
|
||||||
|
{
|
||||||
|
return $"Download completed in {elapsed.TotalMinutes:0.0} minutes.";
|
||||||
|
}
|
||||||
|
|
||||||
|
string normalized = _lastProgressDescription.Trim().TrimEnd('.');
|
||||||
|
if (normalized.StartsWith("Downloading ", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
string remainder = normalized["Downloading ".Length..].ToLowerInvariant();
|
||||||
|
return $"Downloaded {remainder} in {elapsed.TotalMinutes:0.0} minutes.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{normalized} in {elapsed.TotalMinutes:0.0} minutes.";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -181,8 +181,6 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
|||||||
|
|
||||||
[ObservableProperty] private string _textValue = string.Empty;
|
[ObservableProperty] private string _textValue = string.Empty;
|
||||||
|
|
||||||
private bool _isNormalizingFileNameFormatInput;
|
|
||||||
|
|
||||||
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(InsertSelectedFileNameVariableCommand))]
|
[ObservableProperty] [NotifyCanExecuteChangedFor(nameof(InsertSelectedFileNameVariableCommand))]
|
||||||
private string? _selectedFileNameVariable;
|
private string? _selectedFileNameVariable;
|
||||||
|
|
||||||
@ -370,18 +368,6 @@ public partial class ConfigFieldViewModel : ViewModelBase
|
|||||||
|
|
||||||
partial void OnTextValueChanged(string value)
|
partial void OnTextValueChanged(string value)
|
||||||
{
|
{
|
||||||
if (IsFileNameFormatField && !_isNormalizingFileNameFormatInput)
|
|
||||||
{
|
|
||||||
string trimmedValue = value.Trim();
|
|
||||||
if (!string.Equals(value, trimmedValue, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
_isNormalizingFileNameFormatInput = true;
|
|
||||||
TextValue = trimmedValue;
|
|
||||||
_isNormalizingFileNameFormatInput = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store actual value if not the privacy placeholder
|
// Store actual value if not the privacy placeholder
|
||||||
if (value != "[Hidden for Privacy]")
|
if (value != "[Hidden for Privacy]")
|
||||||
{
|
{
|
||||||
|
|||||||
@ -19,7 +19,6 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
private readonly Action<bool> _onClose;
|
private readonly Action<bool> _onClose;
|
||||||
private readonly Func<bool> _isUsernameDuplicate;
|
private readonly Func<bool> _isUsernameDuplicate;
|
||||||
private bool _isNormalizingUsername;
|
private bool _isNormalizingUsername;
|
||||||
private bool _isNormalizingFileNameFormat;
|
|
||||||
|
|
||||||
[ObservableProperty] private bool _isOpen;
|
[ObservableProperty] private bool _isOpen;
|
||||||
[ObservableProperty] private bool _isEditMode;
|
[ObservableProperty] private bool _isEditMode;
|
||||||
@ -238,30 +237,22 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
partial void OnPaidPostFileNameFormatChanged(string value) =>
|
partial void OnPaidPostFileNameFormatChanged(string value) =>
|
||||||
NormalizeFileNameFormat(
|
HandleFileNameFormatChanged(
|
||||||
value,
|
|
||||||
trimmed => PaidPostFileNameFormat = trimmed,
|
|
||||||
() => PaidPostFileNameFormatError = string.Empty,
|
() => PaidPostFileNameFormatError = string.Empty,
|
||||||
UpdatePaidPostPreview);
|
UpdatePaidPostPreview);
|
||||||
|
|
||||||
partial void OnPostFileNameFormatChanged(string value) =>
|
partial void OnPostFileNameFormatChanged(string value) =>
|
||||||
NormalizeFileNameFormat(
|
HandleFileNameFormatChanged(
|
||||||
value,
|
|
||||||
trimmed => PostFileNameFormat = trimmed,
|
|
||||||
() => PostFileNameFormatError = string.Empty,
|
() => PostFileNameFormatError = string.Empty,
|
||||||
UpdatePostPreview);
|
UpdatePostPreview);
|
||||||
|
|
||||||
partial void OnPaidMessageFileNameFormatChanged(string value) =>
|
partial void OnPaidMessageFileNameFormatChanged(string value) =>
|
||||||
NormalizeFileNameFormat(
|
HandleFileNameFormatChanged(
|
||||||
value,
|
|
||||||
trimmed => PaidMessageFileNameFormat = trimmed,
|
|
||||||
() => PaidMessageFileNameFormatError = string.Empty,
|
() => PaidMessageFileNameFormatError = string.Empty,
|
||||||
UpdatePaidMessagePreview);
|
UpdatePaidMessagePreview);
|
||||||
|
|
||||||
partial void OnMessageFileNameFormatChanged(string value) =>
|
partial void OnMessageFileNameFormatChanged(string value) =>
|
||||||
NormalizeFileNameFormat(
|
HandleFileNameFormatChanged(
|
||||||
value,
|
|
||||||
trimmed => MessageFileNameFormat = trimmed,
|
|
||||||
() => MessageFileNameFormatError = string.Empty,
|
() => MessageFileNameFormatError = string.Empty,
|
||||||
UpdateMessagePreview);
|
UpdateMessagePreview);
|
||||||
|
|
||||||
@ -341,24 +332,10 @@ public partial class CreatorConfigModalViewModel : ViewModelBase
|
|||||||
isValid = false;
|
isValid = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void NormalizeFileNameFormat(
|
private static void HandleFileNameFormatChanged(
|
||||||
string value,
|
|
||||||
Action<string> setValue,
|
|
||||||
Action clearError,
|
Action clearError,
|
||||||
Action updatePreview)
|
Action updatePreview)
|
||||||
{
|
{
|
||||||
if (!_isNormalizingFileNameFormat)
|
|
||||||
{
|
|
||||||
string trimmedValue = value.Trim();
|
|
||||||
if (!string.Equals(value, trimmedValue, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
_isNormalizingFileNameFormat = true;
|
|
||||||
setValue(trimmedValue);
|
|
||||||
_isNormalizingFileNameFormat = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearError();
|
clearError();
|
||||||
updatePreview();
|
updatePreview();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -428,6 +428,11 @@ public partial class MainWindowViewModel(
|
|||||||
_isUpdatingAllUsersSelected = true;
|
_isUpdatingAllUsersSelected = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(SelectedListName))
|
||||||
|
{
|
||||||
|
SelectedListName = null;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (SelectableUserViewModel user in AvailableUsers)
|
foreach (SelectableUserViewModel user in AvailableUsers)
|
||||||
{
|
{
|
||||||
user.IsSelected = shouldSelectAll;
|
user.IsSelected = shouldSelectAll;
|
||||||
@ -614,7 +619,8 @@ public partial class MainWindowViewModel(
|
|||||||
{
|
{
|
||||||
if (!TryBuildConfig(out Config newConfig))
|
if (!TryBuildConfig(out Config newConfig))
|
||||||
{
|
{
|
||||||
StatusMessage = "Fix configuration validation errors and save again.";
|
ConfigScreenMessage = "Fix configuration validation errors and save again.";
|
||||||
|
StatusMessage = ConfigScreenMessage;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,12 +643,12 @@ public partial class MainWindowViewModel(
|
|||||||
ConfigScreenMessage = "Configuration saved.";
|
ConfigScreenMessage = "Configuration saved.";
|
||||||
StatusMessage = "Configuration saved.";
|
StatusMessage = "Configuration saved.";
|
||||||
|
|
||||||
if (!await ValidateEnvironmentAsync())
|
if (!await ValidateEnvironmentAsync(false))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await EnsureAuthenticationAndLoadUsersAsync();
|
await EnsureAuthenticationAndLoadUsersAsync(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[RelayCommand]
|
[RelayCommand]
|
||||||
@ -677,7 +683,7 @@ public partial class MainWindowViewModel(
|
|||||||
|
|
||||||
|
|
||||||
await authService.SaveToFileAsync();
|
await authService.SaveToFileAsync();
|
||||||
bool isAuthValid = await ValidateCurrentAuthAsync();
|
bool isAuthValid = await ValidateCurrentAuthAsync(true);
|
||||||
if (!isAuthValid)
|
if (!isAuthValid)
|
||||||
{
|
{
|
||||||
AuthScreenMessage = "Authentication is still invalid after login. Please retry.";
|
AuthScreenMessage = "Authentication is still invalid after login. Please retry.";
|
||||||
@ -1041,12 +1047,17 @@ public partial class MainWindowViewModel(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await ValidateEnvironmentAsync())
|
if (!ValidateConfiguredToolPathsOnStartup())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await EnsureAuthenticationAndLoadUsersAsync();
|
if (!await ValidateEnvironmentAsync(true))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await EnsureAuthenticationAndLoadUsersAsync(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RunSinglePostOrMessageDownloadAsync(SingleDownloadRequest request)
|
private async Task RunSinglePostOrMessageDownloadAsync(SingleDownloadRequest request)
|
||||||
@ -1288,9 +1299,9 @@ public partial class MainWindowViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EnsureAuthenticationAndLoadUsersAsync()
|
private async Task EnsureAuthenticationAndLoadUsersAsync(bool logAuthenticationMessage)
|
||||||
{
|
{
|
||||||
bool hasValidAuth = await TryLoadAndValidateExistingAuthAsync();
|
bool hasValidAuth = await TryLoadAndValidateExistingAuthAsync(logAuthenticationMessage);
|
||||||
if (!hasValidAuth)
|
if (!hasValidAuth)
|
||||||
{
|
{
|
||||||
if (configService.CurrentConfig.DisableBrowserAuth)
|
if (configService.CurrentConfig.DisableBrowserAuth)
|
||||||
@ -1310,12 +1321,14 @@ public partial class MainWindowViewModel(
|
|||||||
await LoadUsersAndListsAsync();
|
await LoadUsersAndListsAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> ValidateEnvironmentAsync()
|
private async Task<bool> ValidateEnvironmentAsync(bool logMissingCdmKeysWarning)
|
||||||
{
|
{
|
||||||
SetLoading("Validating environment...");
|
SetLoading("Validating environment...");
|
||||||
_startupResult = await startupService.ValidateEnvironmentAsync();
|
_startupResult = await startupService.ValidateEnvironmentAsync();
|
||||||
OnPropertyChanged(nameof(FfmpegVersion));
|
OnPropertyChanged(nameof(FfmpegVersion));
|
||||||
OnPropertyChanged(nameof(FfprobeVersion));
|
OnPropertyChanged(nameof(FfprobeVersion));
|
||||||
|
FfmpegPathError = string.Empty;
|
||||||
|
FfprobePathError = string.Empty;
|
||||||
|
|
||||||
if (!_startupResult.IsWindowsVersionValid)
|
if (!_startupResult.IsWindowsVersionValid)
|
||||||
{
|
{
|
||||||
@ -1325,7 +1338,33 @@ public partial class MainWindowViewModel(
|
|||||||
|
|
||||||
if (!_startupResult.FfmpegFound)
|
if (!_startupResult.FfmpegFound)
|
||||||
{
|
{
|
||||||
ConfigScreenMessage = "FFmpeg was not found. Set a valid FFmpegPath before continuing.";
|
FfmpegPathError = BuildToolPathError(
|
||||||
|
nameof(Config.FFmpegPath),
|
||||||
|
configService.CurrentConfig.FFmpegPath,
|
||||||
|
"FFmpeg");
|
||||||
|
ConfigScreenMessage = "FFmpeg was not found. Fix FFmpeg Path and save to continue.";
|
||||||
|
BuildConfigFields(configService.CurrentConfig);
|
||||||
|
FfmpegPathError = BuildToolPathError(
|
||||||
|
nameof(Config.FFmpegPath),
|
||||||
|
configService.CurrentConfig.FFmpegPath,
|
||||||
|
"FFmpeg");
|
||||||
|
CurrentScreen = AppScreen.Config;
|
||||||
|
StatusMessage = ConfigScreenMessage;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_startupResult.FfprobeFound)
|
||||||
|
{
|
||||||
|
FfprobePathError = BuildToolPathError(
|
||||||
|
nameof(Config.FFprobePath),
|
||||||
|
configService.CurrentConfig.FFprobePath,
|
||||||
|
"FFprobe");
|
||||||
|
ConfigScreenMessage = "FFprobe was not found. Fix FFprobe Path and save to continue.";
|
||||||
|
BuildConfigFields(configService.CurrentConfig);
|
||||||
|
FfprobePathError = BuildToolPathError(
|
||||||
|
nameof(Config.FFprobePath),
|
||||||
|
configService.CurrentConfig.FFprobePath,
|
||||||
|
"FFprobe");
|
||||||
CurrentScreen = AppScreen.Config;
|
CurrentScreen = AppScreen.Config;
|
||||||
StatusMessage = ConfigScreenMessage;
|
StatusMessage = ConfigScreenMessage;
|
||||||
return false;
|
return false;
|
||||||
@ -1338,7 +1377,8 @@ public partial class MainWindowViewModel(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_startupResult.ClientIdBlobMissing || _startupResult.DevicePrivateKeyMissing)
|
if (logMissingCdmKeysWarning &&
|
||||||
|
(_startupResult.ClientIdBlobMissing || _startupResult.DevicePrivateKeyMissing))
|
||||||
{
|
{
|
||||||
AppendLog(
|
AppendLog(
|
||||||
"CDM key files are missing. Fallback decrypt services will be used for DRM protected videos.");
|
"CDM key files are missing. Fallback decrypt services will be used for DRM protected videos.");
|
||||||
@ -1347,7 +1387,7 @@ public partial class MainWindowViewModel(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> TryLoadAndValidateExistingAuthAsync()
|
private async Task<bool> TryLoadAndValidateExistingAuthAsync(bool logAuthenticationMessage)
|
||||||
{
|
{
|
||||||
bool loadedFromFile = await authService.LoadFromFileAsync();
|
bool loadedFromFile = await authService.LoadFromFileAsync();
|
||||||
if (!loadedFromFile)
|
if (!loadedFromFile)
|
||||||
@ -1357,10 +1397,40 @@ public partial class MainWindowViewModel(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await ValidateCurrentAuthAsync();
|
return await ValidateCurrentAuthAsync(logAuthenticationMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<bool> ValidateCurrentAuthAsync()
|
private bool ValidateConfiguredToolPathsOnStartup()
|
||||||
|
{
|
||||||
|
IReadOnlyDictionary<string, string> validationErrors = ConfigValidationService.Validate(configService.CurrentConfig);
|
||||||
|
bool hasToolPathErrors = false;
|
||||||
|
FfmpegPathError = string.Empty;
|
||||||
|
FfprobePathError = string.Empty;
|
||||||
|
|
||||||
|
if (validationErrors.TryGetValue(nameof(Config.FFmpegPath), out string? ffmpegError))
|
||||||
|
{
|
||||||
|
FfmpegPathError = ffmpegError;
|
||||||
|
hasToolPathErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (validationErrors.TryGetValue(nameof(Config.FFprobePath), out string? ffprobeError))
|
||||||
|
{
|
||||||
|
FfprobePathError = ffprobeError;
|
||||||
|
hasToolPathErrors = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasToolPathErrors)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigScreenMessage = "Configuration has invalid FFmpeg/FFprobe path values. Fix and save to continue.";
|
||||||
|
CurrentScreen = AppScreen.Config;
|
||||||
|
StatusMessage = ConfigScreenMessage;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> ValidateCurrentAuthAsync(bool logAuthenticationMessage)
|
||||||
{
|
{
|
||||||
authService.ValidateCookieString();
|
authService.ValidateCookieString();
|
||||||
UserEntities.User? user = await authService.ValidateAuthAsync();
|
UserEntities.User? user = await authService.ValidateAuthAsync();
|
||||||
@ -1383,13 +1453,19 @@ public partial class MainWindowViewModel(
|
|||||||
if (HidePrivateInfo)
|
if (HidePrivateInfo)
|
||||||
{
|
{
|
||||||
AuthenticatedUserDisplay = "[Hidden for Privacy]";
|
AuthenticatedUserDisplay = "[Hidden for Privacy]";
|
||||||
|
if (logAuthenticationMessage)
|
||||||
|
{
|
||||||
AppendLog("Authenticated as [Hidden for Privacy].");
|
AppendLog("Authenticated as [Hidden for Privacy].");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AuthenticatedUserDisplay = $"{displayName} ({displayUsername})";
|
AuthenticatedUserDisplay = $"{displayName} ({displayUsername})";
|
||||||
|
if (logAuthenticationMessage)
|
||||||
|
{
|
||||||
AppendLog($"Authenticated as {AuthenticatedUserDisplay}.");
|
AppendLog($"Authenticated as {AuthenticatedUserDisplay}.");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IsAuthenticated = true;
|
IsAuthenticated = true;
|
||||||
return true;
|
return true;
|
||||||
@ -1802,6 +1878,18 @@ public partial class MainWindowViewModel(
|
|||||||
private static string EscapePathForConfig(string path) =>
|
private static string EscapePathForConfig(string path) =>
|
||||||
path.Replace(@"\", @"\\");
|
path.Replace(@"\", @"\\");
|
||||||
|
|
||||||
|
private static string BuildToolPathError(string propertyName, string? configuredPath, string toolName)
|
||||||
|
{
|
||||||
|
string normalizedPath = NormalizePathForDisplay(configuredPath);
|
||||||
|
if (string.IsNullOrWhiteSpace(normalizedPath))
|
||||||
|
{
|
||||||
|
return
|
||||||
|
$"{toolName} was not found automatically. Set {propertyName} to a valid executable path or add {toolName.ToLowerInvariant()} to PATH.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{propertyName} does not point to an existing file: {normalizedPath}";
|
||||||
|
}
|
||||||
|
|
||||||
private static string ResolveProgramVersion()
|
private static string ResolveProgramVersion()
|
||||||
{
|
{
|
||||||
Version? version = Assembly.GetEntryAssembly()?.GetName().Version
|
Version? version = Assembly.GetEntryAssembly()?.GetName().Version
|
||||||
@ -1916,6 +2004,11 @@ public partial class MainWindowViewModel(
|
|||||||
{
|
{
|
||||||
if (e.PropertyName == nameof(SelectableUserViewModel.IsSelected))
|
if (e.PropertyName == nameof(SelectableUserViewModel.IsSelected))
|
||||||
{
|
{
|
||||||
|
if (!_isApplyingListSelection && !string.IsNullOrWhiteSpace(SelectedListName))
|
||||||
|
{
|
||||||
|
SelectedListName = null;
|
||||||
|
}
|
||||||
|
|
||||||
OnPropertyChanged(nameof(SelectedUsersSummary));
|
OnPropertyChanged(nameof(SelectedUsersSummary));
|
||||||
if (!_isUpdatingAllUsersSelected)
|
if (!_isUpdatingAllUsersSelected)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1065,9 +1065,10 @@
|
|||||||
</ListBox.Styles>
|
</ListBox.Styles>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="vm:SelectableUserViewModel">
|
<DataTemplate x:DataType="vm:SelectableUserViewModel">
|
||||||
<CheckBox Content="{Binding Username}"
|
<CheckBox IsChecked="{Binding IsSelected}"
|
||||||
IsChecked="{Binding IsSelected}"
|
HorizontalAlignment="Stretch">
|
||||||
HorizontalAlignment="Stretch" />
|
<TextBlock Text="{Binding Username}" />
|
||||||
|
</CheckBox>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user