Enhance output path selection in the GUI

Enables the use of template tokens when exporting multiple channels
Closes #676
pull/1003/head
Tyrrrz 2 years ago
parent f1ae0266f1
commit c8d83beb8d

@ -26,7 +26,11 @@ public abstract class ExportCommandBase : TokenCommandBase
[CommandOption( [CommandOption(
"output", "output",
'o', 'o',
Description = "Output file or directory path. Directory path should end in a slash." Description =
"Output file or directory path. " +
"If a directory is specified, file names will be generated automatically based on the channel names and other parameters. " +
"Directory path should end with a slash to avoid ambiguity. " +
"Supports template tokens, see the documentation for more info."
)] )]
public string OutputPath public string OutputPath
{ {
@ -58,7 +62,8 @@ public abstract class ExportCommandBase : TokenCommandBase
[CommandOption( [CommandOption(
"partition", "partition",
'p', 'p',
Description = "Split output into partitions, each limited to this number of messages (e.g. '100') or file size (e.g. '10mb')." Description =
"Split output into partitions, each limited to this number of messages (e.g. '100') or file size (e.g. '10mb')."
)] )]
public PartitionLimit PartitionLimit { get; init; } = PartitionLimit.Null; public PartitionLimit PartitionLimit { get; init; } = PartitionLimit.Null;

@ -158,22 +158,27 @@ public class DashboardViewModel : PropertyChangedBase
var exporter = new ChannelExporter(_discord); var exporter = new ChannelExporter(_discord);
var progresses = Enumerable var channelProgressPairs = dialog
.Range(0, dialog.Channels!.Count) .Channels!
.Select(_ => _progressMuxer.CreateInput()) .Select(c => new
{
Channel = c,
Progress = _progressMuxer.CreateInput()
})
.ToArray(); .ToArray();
var successfulExportCount = 0; var successfulExportCount = 0;
await Parallel.ForEachAsync( await Parallel.ForEachAsync(
dialog.Channels.Zip(progresses), channelProgressPairs,
new ParallelOptions new ParallelOptions
{ {
MaxDegreeOfParallelism = Math.Max(1, _settingsService.ParallelLimit) MaxDegreeOfParallelism = Math.Max(1, _settingsService.ParallelLimit)
}, },
async (tuple, cancellationToken) => async (pair, cancellationToken) =>
{ {
var (channel, progress) = tuple; var channel = pair.Channel;
var progress = pair.Progress;
try try
{ {

@ -86,15 +86,8 @@ public class ExportSetupViewModel : DialogScreen
public void ToggleAdvancedSection() => IsAdvancedSectionDisplayed = !IsAdvancedSectionDisplayed; public void ToggleAdvancedSection() => IsAdvancedSectionDisplayed = !IsAdvancedSectionDisplayed;
public void Confirm() public void ShowOutputPathPrompt()
{ {
// Persist preferences
_settingsService.LastExportFormat = SelectedFormat;
_settingsService.LastPartitionLimitValue = PartitionLimitValue;
_settingsService.LastMessageFilterValue = MessageFilterValue;
_settingsService.LastShouldDownloadAssets = ShouldDownloadAssets;
// If single channel - prompt file path
if (IsSingleChannel) if (IsSingleChannel)
{ {
var defaultFileName = ExportRequest.GetDefaultOutputFileName( var defaultFileName = ExportRequest.GetDefaultOutputFileName(
@ -105,20 +98,26 @@ public class ExportSetupViewModel : DialogScreen
Before?.Pipe(Snowflake.FromDate) Before?.Pipe(Snowflake.FromDate)
); );
// Filter var extension = SelectedFormat.GetFileExtension();
var ext = SelectedFormat.GetFileExtension(); var filter = $"{extension.ToUpperInvariant()} files|*.{extension}";
var filter = $"{ext.ToUpperInvariant()} files|*.{ext}";
OutputPath = _dialogManager.PromptSaveFilePath(filter, defaultFileName); OutputPath = _dialogManager.PromptSaveFilePath(filter, defaultFileName);
} }
// If multiple channels - prompt dir path
else else
{ {
OutputPath = _dialogManager.PromptDirectoryPath(); OutputPath = _dialogManager.PromptDirectoryPath();
} }
}
if (string.IsNullOrWhiteSpace(OutputPath)) public bool CanConfirm => !string.IsNullOrWhiteSpace(OutputPath);
return;
public void Confirm()
{
// Persist preferences
_settingsService.LastExportFormat = SelectedFormat;
_settingsService.LastPartitionLimitValue = PartitionLimitValue;
_settingsService.LastMessageFilterValue = MessageFilterValue;
_settingsService.LastShouldDownloadAssets = ShouldDownloadAssets;
Close(true); Close(true);
} }

@ -76,6 +76,86 @@
BorderThickness="0,1"> BorderThickness="0,1">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel> <StackPanel>
<!-- Output path -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox
Grid.Column="0"
Margin="16,8,8,8"
materialDesign:HintAssist.Hint="Output path"
materialDesign:HintAssist.IsFloating="True"
Style="{DynamicResource MaterialDesignOutlinedTextBox}"
Text="{Binding OutputPath}">
<TextBox.ToolTip>
<TextBlock>
<Run Text="Output file or directory path." />
<Run Text="If a directory is specified, file names will be generated automatically based on the channel names and other parameters." />
<Run Text="Directory path should end with a slash to avoid ambiguity." />
<LineBreak />
<LineBreak />
<Run Text="Available template tokens:" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%g" />
<Run Text="— guild ID" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%G" />
<Run Text="— guild name" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%t" />
<Run Text="— category ID" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%T" />
<Run Text="— category name" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%c" />
<Run Text="— channel ID" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%C" />
<Run Text="— channel name" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%p" />
<Run Text="— channel position" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%P" />
<Run Text="— category position" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%a" />
<Run Text="— after date" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%b" />
<Run Text="— before date" />
<LineBreak />
<Run FontWeight="SemiBold" Text="%d" />
<Run Text="— current date" />
</TextBlock>
</TextBox.ToolTip>
</TextBox>
<Button
Grid.Column="1"
Height="48"
Margin="0,8,16,8"
Command="{s:Action ShowOutputPathPrompt}"
Style="{DynamicResource MaterialDesignOutlinedButton}">
<materialDesign:PackIcon Width="24" Height="24">
<materialDesign:PackIcon.Style>
<Style TargetType="{x:Type materialDesign:PackIcon}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSingleChannel}" Value="True">
<Setter Property="Kind" Value="FileFind" />
</DataTrigger>
<DataTrigger Binding="{Binding IsSingleChannel}" Value="False">
<Setter Property="Kind" Value="FolderSearch" />
</DataTrigger>
</Style.Triggers>
</Style>
</materialDesign:PackIcon.Style>
</materialDesign:PackIcon>
</Button>
</Grid>
<!-- Format --> <!-- Format -->
<ComboBox <ComboBox
Margin="16,8" Margin="16,8"
@ -84,7 +164,8 @@
IsReadOnly="True" IsReadOnly="True"
ItemsSource="{Binding AvailableFormats}" ItemsSource="{Binding AvailableFormats}"
SelectedItem="{Binding SelectedFormat}" SelectedItem="{Binding SelectedFormat}"
Style="{DynamicResource MaterialDesignOutlinedComboBox}"> Style="{DynamicResource MaterialDesignOutlinedComboBox}"
ToolTip="Export format">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<TextBlock Text="{Binding Converter={x:Static converters:ExportFormatToStringConverter.Instance}, ConverterCulture={x:Static globalization:CultureInfo.CurrentCulture}}" /> <TextBlock Text="{Binding Converter={x:Static converters:ExportFormatToStringConverter.Instance}, ConverterCulture={x:Static globalization:CultureInfo.CurrentCulture}}" />

@ -40,7 +40,7 @@
<TextBlock <TextBlock
VerticalAlignment="Center" VerticalAlignment="Center"
DockPanel.Dock="Left" DockPanel.Dock="Left"
Text="Auto-updates" /> Text="Auto-update" />
<ToggleButton <ToggleButton
VerticalAlignment="Center" VerticalAlignment="Center"
DockPanel.Dock="Right" DockPanel.Dock="Right"
@ -75,7 +75,7 @@
<TextBlock <TextBlock
VerticalAlignment="Center" VerticalAlignment="Center"
DockPanel.Dock="Left" DockPanel.Dock="Left"
Text="Save token" /> Text="Persist token" />
<ToggleButton <ToggleButton
VerticalAlignment="Center" VerticalAlignment="Center"
DockPanel.Dock="Right" DockPanel.Dock="Right"

Loading…
Cancel
Save