From bc4e3af5bc945826fbb6a70f7ffbd70f49b0aae6 Mon Sep 17 00:00:00 2001 From: aNNiMON Date: Wed, 3 Jul 2024 22:21:17 +0300 Subject: [PATCH] Dynamically updating parameters list based on a user's input --- .../ffmpeg/MediaProcessingBundle.java | 1 + .../parameters/BooleanParameter.java | 4 ++ .../ffmpegbot/parameters/OutputFormat.java | 26 +++++++++- .../ffmpegbot/parameters/Parameter.java | 13 +++++ .../ffmpegbot/parameters/Parameters.java | 48 ++++++++++++++----- .../parameters/resolvers/AudioResolver.java | 24 ++++++++++ .../resolvers/GlobalParametersResolver.java | 7 +++ .../resolvers/MultiAudioStreamsResolver.java | 15 +++++- .../resolvers/ParametersResolver.java | 11 +++++ .../parameters/resolvers/VideoResolver.java | 23 +++++++++ 10 files changed, 157 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/annimon/ffmpegbot/commands/ffmpeg/MediaProcessingBundle.java b/src/main/java/com/annimon/ffmpegbot/commands/ffmpeg/MediaProcessingBundle.java index a56f34c..a93a7be 100644 --- a/src/main/java/com/annimon/ffmpegbot/commands/ffmpeg/MediaProcessingBundle.java +++ b/src/main/java/com/annimon/ffmpegbot/commands/ffmpeg/MediaProcessingBundle.java @@ -83,6 +83,7 @@ public class MediaProcessingBundle implements CommandBundle { if (param != null && ctx.argumentsLength() == 2) { final int index = Integer.parseInt(ctx.argument(1)); param.select(index); + parametersResolver.refine(session.getParams()); session.setSelectedParam(null); } } diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/BooleanParameter.java b/src/main/java/com/annimon/ffmpegbot/parameters/BooleanParameter.java index 42b19e5..05b002b 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/BooleanParameter.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/BooleanParameter.java @@ -7,6 +7,10 @@ public abstract class BooleanParameter extends Parameter { super(id, name, List.of(false, true), value); } + public boolean getValueAsPrimitive() { + return (value != null && value); + } + @Override public String describeValue(Boolean value) { if (value != null && value) { diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/OutputFormat.java b/src/main/java/com/annimon/ffmpegbot/parameters/OutputFormat.java index 9d68b7a..97fcad6 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/OutputFormat.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/OutputFormat.java @@ -2,7 +2,9 @@ package com.annimon.ffmpegbot.parameters; import com.annimon.ffmpegbot.commands.ffmpeg.Visitor; +import java.util.ArrayList; import java.util.List; +import java.util.Objects; public class OutputFormat extends StringParameter { public static final String ID = "output"; @@ -12,7 +14,29 @@ public class OutputFormat extends StringParameter { public static final String VIDEO_NOTE = "VIDEO NOTE"; public OutputFormat(List values, String initialValue) { - super(ID, "➡\uFE0F Output", values, initialValue); + super(ID, "➡️ Output", values, initialValue); + } + + public OutputFormat disableFormat(String format) { + if (possibleValues.size() <= 1) return this; + final var values = possibleValues.stream() + .filter(f -> !Objects.equals(f, format)) + .map(Objects::toString) + .toList(); + if (possibleValues.size() == values.size()) { + return this; + } + return new OutputFormat(values, values.get(0)); + } + + public OutputFormat enableFormat(String format) { + boolean contains = possibleValues.stream() + .anyMatch(f -> Objects.equals(f, format)); + if (contains) return this; + + final var values = new ArrayList(possibleValues); + values.add(format); + return new OutputFormat(values, values.get(0)); } @Override diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/Parameter.java b/src/main/java/com/annimon/ffmpegbot/parameters/Parameter.java index 4141eb5..81c2df6 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/Parameter.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/Parameter.java @@ -12,12 +12,14 @@ public abstract class Parameter { protected final String displayName; protected final List possibleValues; protected T value; + private boolean enabled; protected Parameter(String id, String displayName, List values, T value) { this.id = id; this.displayName = displayName; this.possibleValues = values; this.value = value; + this.enabled = true; checkArgument(!values.isEmpty(), "possible values cannot be empty"); checkArgument(values.contains(value), "possible values must contain a value"); } @@ -34,6 +36,17 @@ public abstract class Parameter { return possibleValues.size(); } + public boolean isEnabled() { + return enabled; + } + + public void enable() { + enabled = true; + } + + public void disable() { + enabled = false; + } public abstract void accept(Visitor visitor, I input); diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/Parameters.java b/src/main/java/com/annimon/ffmpegbot/parameters/Parameters.java index a14a9f3..3371136 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/Parameters.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/Parameters.java @@ -2,44 +2,68 @@ package com.annimon.ffmpegbot.parameters; import org.jetbrains.annotations.NotNull; import java.util.*; +import java.util.stream.Stream; public class Parameters extends AbstractCollection> { - private final Map> enabledParameters; - private final Map> disabledParameters; + private final Map> parameters; public Parameters() { - enabledParameters = new LinkedHashMap<>(); - disabledParameters = new LinkedHashMap<>(); + parameters = new LinkedHashMap<>(); } @Override public boolean add(Parameter parameter) { - return !Objects.equals(parameter, enabledParameters.put(parameter.id, parameter)); + parameter.enable(); + return !Objects.equals(parameter, parameters.put(parameter.id, parameter)); } public Parameter findById(String id) { - return enabledParameters.get(id); + final var parameter = parameters.get(id); + if (parameter != null && parameter.isEnabled()) { + return parameter; + } + return null; + } + + public

> Optional

findById(String id, Class

clazz) { + return Optional.ofNullable(findById(id)) + .filter(clazz::isInstance) + .map(clazz::cast); } public void disable(String id) { - Optional.ofNullable(findById(id)) - .ifPresent(p -> disabledParameters.put(p.id, p)); + Optional.ofNullable(parameters.get(id)) + .ifPresent(Parameter::disable); + } + + public void disableAll(Collection ids) { + ids.forEach(this::disable); } public void enable(String id) { - Optional.ofNullable(disabledParameters.get(id)) - .ifPresent(this::add); + Optional.ofNullable(parameters.get(id)) + .ifPresent(Parameter::enable); + } + + public void enableAll(Collection ids) { + ids.forEach(this::enable); } @NotNull @Override public Iterator> iterator() { - return enabledParameters.values().iterator(); + return enabledParameters().iterator(); } @Override public int size() { - return enabledParameters.size(); + return (int) enabledParameters().count(); + } + + private Stream> enabledParameters() { + return parameters.values() + .stream() + .filter(Parameter::isEnabled); } } diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/AudioResolver.java b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/AudioResolver.java index abcd9c2..7a8d30c 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/AudioResolver.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/AudioResolver.java @@ -5,6 +5,8 @@ import com.annimon.ffmpegbot.session.FileInfo; import com.annimon.ffmpegbot.session.FileType; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Optional; +import java.util.Set; public class AudioResolver implements ParametersResolver { @@ -28,6 +30,28 @@ public class AudioResolver implements ParametersResolver { } } + @Override + public void refine(@NotNull Parameters parameters) { + parameters.findById(DisableAudio.ID, DisableAudio.class) + .ifPresent(p -> { + final Set parameterIds = Set.of( + AudioBitrate.ID, + AudioCrystalizer.ID, + AudioEffect.ID, + AudioPitch.ID, + AudioVolume.ID + ); + Optional outputFormat = parameters.findById(OutputFormat.ID, OutputFormat.class); + if (p.getValueAsPrimitive()) { + parameters.disableAll(parameterIds); + outputFormat.ifPresent(par -> parameters.add(par.disableFormat(OutputFormat.AUDIO))); + } else { + parameters.enableAll(parameterIds); + outputFormat.ifPresent(par -> parameters.add(par.enableFormat(OutputFormat.AUDIO))); + } + }); + } + private void disableAudioParam(@NotNull Parameters parameters, @NotNull FileType fileType) { final boolean canAudioBeDisabled = switch (fileType) { case ANIMATION, AUDIO, VOICE -> false; diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/GlobalParametersResolver.java b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/GlobalParametersResolver.java index e477fe9..8ce912d 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/GlobalParametersResolver.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/GlobalParametersResolver.java @@ -24,4 +24,11 @@ public class GlobalParametersResolver implements ParametersResolver { resolver.resolve(parameters, fileInfo); } } + + @Override + public void refine(@NotNull Parameters parameters) { + for (ParametersResolver resolver : resolvers) { + resolver.refine(parameters); + } + } } diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/MultiAudioStreamsResolver.java b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/MultiAudioStreamsResolver.java index d99d469..7ab9912 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/MultiAudioStreamsResolver.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/MultiAudioStreamsResolver.java @@ -1,7 +1,6 @@ package com.annimon.ffmpegbot.parameters.resolvers; -import com.annimon.ffmpegbot.parameters.AudioStreamByLanguage; -import com.annimon.ffmpegbot.parameters.Parameters; +import com.annimon.ffmpegbot.parameters.*; import com.annimon.ffmpegbot.session.FileInfo; import com.annimon.ffmpegbot.session.FileType; import org.jetbrains.annotations.NotNull; @@ -19,4 +18,16 @@ public class MultiAudioStreamsResolver implements ParametersResolver { parameters.add(new AudioStreamByLanguage()); } } + + @Override + public void refine(@NotNull Parameters parameters) { + parameters.findById(DisableAudio.ID, DisableAudio.class) + .ifPresent(p -> { + if (p.getValueAsPrimitive()) { + parameters.disable(AudioStreamByLanguage.ID); + } else { + parameters.enable(AudioStreamByLanguage.ID); + } + }); + } } diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/ParametersResolver.java b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/ParametersResolver.java index a1bcb6e..bf609ea 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/ParametersResolver.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/ParametersResolver.java @@ -7,4 +7,15 @@ import org.jetbrains.annotations.NotNull; public interface ParametersResolver { void resolve(@NotNull Parameters parameters, @NotNull FileInfo fileInfo); + + /** + * Refines all parameters based on user input. + *

+ * Example: if Disable audio is ON -> removes all audio parameters. + * + * @param parameters all parameters + */ + default void refine(@NotNull Parameters parameters) { + + } } diff --git a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/VideoResolver.java b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/VideoResolver.java index f32f946..9bfd2ca 100644 --- a/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/VideoResolver.java +++ b/src/main/java/com/annimon/ffmpegbot/parameters/resolvers/VideoResolver.java @@ -4,6 +4,8 @@ import com.annimon.ffmpegbot.parameters.*; import com.annimon.ffmpegbot.session.FileInfo; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.Objects; +import java.util.Set; public class VideoResolver implements ParametersResolver { @@ -25,4 +27,25 @@ public class VideoResolver implements ParametersResolver { )); } } + + @Override + public void refine(@NotNull Parameters parameters) { + parameters.findById(OutputFormat.ID, OutputFormat.class) + .map(Parameter::getValue) + .ifPresent(format -> { + final Set parameterIds = Set.of( + Contrast.ID, + Gamma.ID, + Saturation.ID, + VideoBitrate.ID, + VideoScale.ID, + VideoFrameRate.ID + ); + if (Objects.equals(format, OutputFormat.AUDIO)) { + parameters.disableAll(parameterIds); + } else { + parameters.enableAll(parameterIds); + } + }); + } }