├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── build.yml
├── .gitignore
├── .gitmodules
├── .nuke
├── build.schema.json
└── parameters.json
├── GitVersion.yml
├── LICENSE
├── README.md
├── build.cmd
├── build.ps1
├── build.sh
├── build
├── .editorconfig
├── Build.cs
├── Configuration.cs
├── Directory.Build.props
├── Directory.Build.targets
├── DownloadTools.cs
├── PackInstaller.cs
├── PlistWriter.cs
├── rmbox-build.csproj
└── rmbox-build.csproj.DotSettings
├── common
├── Assets
│ ├── rmbox-transparent.png
│ ├── rmbox.icns
│ ├── rmbox.ico
│ └── rmbox.png
├── installer
│ └── nsis
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ ├── assistedInstaller.nsh
│ │ ├── common.nsh
│ │ ├── include
│ │ ├── StdUtils.nsh
│ │ ├── StrContains.nsh
│ │ ├── extractAppPackage.nsh
│ │ ├── installUtil.nsh
│ │ └── installer.nsh
│ │ ├── installSection.nsh
│ │ ├── installer.nsi
│ │ ├── messages.nsh
│ │ ├── multiUser.nsh
│ │ └── uninstaller.nsh
└── meta
│ └── rmbenv.exe.manifest
├── examples
├── lua
│ └── rmbox-plugin-lua-example
│ │ ├── .editorconfig
│ │ ├── .gitignore
│ │ └── rmbox-plugin-lua-example.lua
├── node
│ └── rmbox-plugin-node-example
│ │ ├── .editorconfig
│ │ ├── .eslintrc.js
│ │ ├── .gitignore
│ │ ├── .prettierrc.js
│ │ ├── jsconfig.json
│ │ ├── package.json
│ │ ├── src
│ │ ├── index.ts
│ │ └── rmbox.d.ts
│ │ └── tsconfig.json
└── python
│ └── rmbox-plugin-python-example
│ ├── .editorconfig
│ ├── .gitignore
│ └── rmbox-plugin-python-example.py
├── lgtm.yml
├── plugins
├── rmbox-plugin-audio
│ ├── AudioMeta.cs
│ ├── ConfigSections
│ │ ├── ViewModels
│ │ │ ├── AudioConfigSectionViewModel.cs
│ │ │ └── AudioQualityConfigSectionViewModel.cs
│ │ └── Views
│ │ │ ├── AudioConfigSection.axaml
│ │ │ ├── AudioConfigSection.axaml.cs
│ │ │ ├── AudioQualityConfigSection.axaml
│ │ │ └── AudioQualityConfigSection.axaml.cs
│ ├── Operations
│ │ └── AudioEncodeOperation.cs
│ └── rmbox-plugin-audio.csproj
├── rmbox-plugin-common
│ ├── CommonMeta.cs
│ ├── ConfigSections
│ │ ├── ViewModels
│ │ │ ├── AdvancedTrackConfigSectionViewModel.cs
│ │ │ ├── CustomArgsConfigSectionViewModel.cs
│ │ │ ├── IOConfigSectionViewModel.cs
│ │ │ ├── IntroConfigSectionViewModel.cs
│ │ │ ├── MuxConfigSectionViewModel.cs
│ │ │ ├── MuxOptionsConfigSectionViewModel.cs
│ │ │ ├── OutputConfigSectionViewModel.cs
│ │ │ └── PictureFlowConfigSectionViewModel.cs
│ │ └── Views
│ │ │ ├── AdvancedTrackConfigSection.axaml
│ │ │ ├── AdvancedTrackConfigSection.axaml.cs
│ │ │ ├── CustomArgsConfigSection.axaml
│ │ │ ├── CustomArgsConfigSection.axaml.cs
│ │ │ ├── IOConfigSection.axaml
│ │ │ ├── IOConfigSection.axaml.cs
│ │ │ ├── IntroConfigSection.axaml
│ │ │ ├── IntroConfigSection.axaml.cs
│ │ │ ├── MuxConfigSection.axaml
│ │ │ ├── MuxConfigSection.axaml.cs
│ │ │ ├── MuxOptionsConfigSection.axaml
│ │ │ ├── MuxOptionsConfigSection.axaml.cs
│ │ │ ├── OutputConfigSection.axaml
│ │ │ ├── OutputConfigSection.axaml.cs
│ │ │ ├── PictureFlowConfigSection.axaml
│ │ │ └── PictureFlowConfigSection.axaml.cs
│ ├── Formatters
│ │ └── NullFormatter.cs
│ └── rmbox-plugin-common.csproj
├── rmbox-plugin-ffmpeg
│ ├── FFmpegMeta.cs
│ ├── Formatters
│ │ └── FFmpegFormatter.cs
│ ├── Operations
│ │ ├── BilibiliLoudnormOperation.cs
│ │ ├── FFmpegAddAudioTrackOperation.cs
│ │ ├── FFmpegAddBlankVideoTrackOperation.cs
│ │ ├── FFmpegAddMuteAudioTrackOperation.cs
│ │ ├── FFmpegAudioSilenceRemoveOperation.cs
│ │ ├── FFmpegBlankVideoOperation.cs
│ │ ├── FFmpegClearSubtitleOperation.cs
│ │ ├── FFmpegCopyOperation.cs
│ │ ├── FFmpegEncodeOperation.cs
│ │ ├── FFmpegExtractAudioOperation.cs
│ │ ├── FFmpegExtractVideoOperation.cs
│ │ ├── FFmpegFillBlackOperation.cs
│ │ ├── FFmpegLoudnormOperation.cs
│ │ ├── FFmpegMetaRotateOperation.cs
│ │ ├── FFmpegMuxAudioOperation.cs
│ │ ├── FFmpegMuxOperation.cs
│ │ ├── FFmpegMuxSubtitleOperation.cs
│ │ ├── FFmpegPictureFlowOperation.cs
│ │ ├── FFmpegRemoveAudioTrackOperation.cs
│ │ ├── FFmpegReplaceAudioTrackOperation.cs
│ │ ├── FFmpegStillImageOperation.cs
│ │ └── FFmpegVfrFixOperation.cs
│ ├── Resources
│ │ └── Markdowns
│ │ │ ├── FFmpegCopyOperation.md
│ │ │ └── FFmpegMetaRotateOperation.md
│ └── rmbox-plugin-ffmpeg.csproj
├── rmbox-plugin-hwenc
│ ├── ConfigSections
│ │ ├── ViewModels
│ │ │ ├── HwEncCodecConfigSectionViewModel.cs
│ │ │ ├── HwEncCoreConfigSectionViewModel.cs
│ │ │ └── HwEncQualityConfigSectionViewModel.cs
│ │ └── Views
│ │ │ ├── HwEncCodecConfigSection.axaml
│ │ │ ├── HwEncCodecConfigSection.axaml.cs
│ │ │ ├── HwEncCoreConfigSection.axaml
│ │ │ ├── HwEncCoreConfigSection.axaml.cs
│ │ │ ├── HwEncQualityConfigSection.axaml
│ │ │ └── HwEncQualityConfigSection.axaml.cs
│ ├── Formatters
│ │ └── HwEncFormatter.cs
│ ├── HwEncMeta.cs
│ ├── Operations
│ │ └── HwEncOperation.cs
│ └── rmbox-plugin-hwenc.csproj
└── rmbox-plugin-x264
│ ├── ConfigSections
│ ├── ViewModels
│ │ ├── X264CoreConfigSectionViewModel.cs
│ │ ├── X264DemuxerConfigSectionViewModel.cs
│ │ └── X264EncodeQualityConfigSectionViewModel.cs
│ └── Views
│ │ ├── X264CoreConfigSection.axaml
│ │ ├── X264CoreConfigSection.axaml.cs
│ │ ├── X264DemuxerConfigSection.axaml
│ │ ├── X264DemuxerConfigSection.axaml.cs
│ │ ├── X264EncodeQualityConfigSection.axaml
│ │ └── X264EncodeQualityConfigSection.axaml.cs
│ ├── Formatters
│ └── X26xFormatter.cs
│ ├── Operations
│ └── X264EncodeOperation.cs
│ ├── Resources
│ └── Markdowns
│ │ └── X264EncodeOperation.md
│ ├── X264Meta.cs
│ └── rmbox-plugin-x264.csproj
├── rmbox.sln
├── src
├── rmbenv
│ ├── .gitignore
│ ├── go.mod
│ ├── go.sum
│ ├── main.go
│ └── versioninfo.json
├── rmbox-plugbase
│ ├── Core
│ │ ├── Interfaces
│ │ │ ├── ConfigSectionBase.cs
│ │ │ ├── IMeta.cs
│ │ │ └── IOperation.cs
│ │ ├── OperationException.cs
│ │ ├── ProcessRunnerException.cs
│ │ ├── ProjectParseException.cs
│ │ └── TaskCommand.cs
│ ├── Formatting
│ │ ├── FormattedEvent.cs
│ │ └── IFormatter.cs
│ ├── Utils
│ │ ├── Converters
│ │ │ ├── ConverterExtension.cs
│ │ │ └── StringBoolConverter.cs
│ │ ├── Extensions
│ │ │ ├── CommandExtension.cs
│ │ │ ├── FormatPath.cs
│ │ │ ├── GetAllFiles.cs
│ │ │ ├── PathExtension.cs
│ │ │ ├── ProcessExtension.cs
│ │ │ └── StringExtension.cs
│ │ └── StorageHelper.cs
│ └── rmbox-plugbase.csproj
├── rmbox-shell
│ ├── App.axaml
│ ├── App.axaml.cs
│ ├── Core
│ │ └── Exporter.cs
│ ├── Helpers
│ │ └── CommandHelper.cs
│ ├── Models
│ │ └── OperationModel.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Resources
│ │ └── Markdowns
│ │ │ └── ReleaseNote.md
│ ├── Services
│ │ ├── OperationService.cs
│ │ ├── QueueService.cs
│ │ └── RunnerService.cs
│ ├── Styles
│ │ └── Accent.xaml
│ ├── Utils
│ │ └── ConfigSections
│ │ │ ├── BatchIOConfigSection.axaml
│ │ │ ├── BatchIOConfigSection.axaml.cs
│ │ │ └── BatchIOConfigSectionViewModel.cs
│ ├── ViewModels
│ │ ├── Operations
│ │ │ ├── BatchOperationViewModel.cs
│ │ │ ├── OperationViewModelBase.cs
│ │ │ └── SingleOperationViewModel.cs
│ │ └── Project
│ │ │ ├── BatchProjectViewModel.cs
│ │ │ ├── ProjectViewModel.cs
│ │ │ └── SingleProjectViewModel.cs
│ ├── Views
│ │ ├── AboutView.axaml
│ │ ├── AboutView.axaml.cs
│ │ ├── Operations
│ │ │ ├── BatchOperationView.axaml
│ │ │ ├── BatchOperationView.axaml.cs
│ │ │ ├── SingleOperationView.axaml
│ │ │ └── SingleOperationView.axaml.cs
│ │ ├── PluginManagerView.axaml
│ │ ├── PluginManagerView.axaml.cs
│ │ ├── PluginView.axaml
│ │ ├── PluginView.axaml.cs
│ │ ├── QueueStatus.cs
│ │ ├── QueueView.axaml
│ │ ├── QueueView.axaml.cs
│ │ ├── StartView.axaml
│ │ └── StartView.axaml.cs
│ ├── Windows
│ │ ├── MainWindow.axaml
│ │ ├── MainWindow.axaml.cs
│ │ ├── SplashWindow.axaml
│ │ └── SplashWindow.axaml.cs
│ └── rmbox-shell.csproj
├── rmbox-vpygen
│ ├── .editorconfig
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── .prettierrc.js
│ ├── jsconfig.json
│ ├── package.json
│ ├── src
│ │ └── index.ts
│ └── tsconfig.json
└── rmbox
│ ├── Composition
│ ├── IPluginGenerator.cs
│ ├── Roslim
│ │ ├── IRoslimGenerator.cs
│ │ ├── RoslimException.cs
│ │ ├── RoslimGenerator.cs
│ │ ├── RoslimMeta.cs
│ │ └── RoslimOperation.cs
│ └── Services
│ │ ├── IPluginService.cs
│ │ ├── PluginCompositionException.cs
│ │ ├── PluginLoadContext.cs
│ │ ├── PluginService.cs
│ │ └── PluginServiceInitialize.cs
│ ├── Core
│ ├── Parser
│ │ ├── BatchProjectParser.cs
│ │ ├── IParser.cs
│ │ ├── ProjectParser.cs
│ │ ├── QueueProjectParser.cs
│ │ └── SingleProjectParser.cs
│ ├── ProcessRunner.cs
│ └── Processor.cs
│ ├── Formatting
│ └── FormattingService.cs
│ ├── Program.cs
│ ├── Properties
│ └── launchSettings.json
│ ├── Services
│ └── CommandLine
│ │ ├── CommandLineService.cs
│ │ └── ProcessOptions.cs
│ ├── Utils
│ └── RmboxConsoleFormatter.cs
│ └── rmbox.csproj
└── test
└── rmbox-test
└── rmbox-test.csproj
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Default settings:
7 | # A newline ending every file
8 | # Use 4 spaces as indentation
9 | [*]
10 | insert_final_newline = true
11 | indent_style = space
12 | indent_size = 4
13 | trim_trailing_whitespace = true
14 |
15 | [project.json]
16 | indent_size = 2
17 |
18 | # Generated code
19 | [*{_AssemblyInfo.cs,.notsupported.cs}]
20 | generated_code = true
21 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "lib/rmnd-metro"]
2 | path = lib/rmnd-metro
3 | url = https://github.com/Ruminoid/rmnd-metro.git
4 | [submodule "lib/rmnd-common2"]
5 | path = lib/rmnd-common2
6 | url = https://github.com/Ruminoid/Common2.git
7 |
--------------------------------------------------------------------------------
/.nuke/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./build.schema.json",
3 | "Solution": "rmbox.sln"
4 | }
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | assembly-versioning-scheme: MajorMinorPatchTag
2 | mode: ContinuousDelivery
3 | tag-prefix: 'v'
4 | increment: Patch
5 | branches: {}
6 | ignore:
7 | sha: []
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
12 |
13 | ## 许可
14 |
15 | Ruminoid Toolbox 使用 AGPL 协议授权。使用本产品或其源代码时,你不能将其闭源,改变许可协议或进行商业销售。
16 |
17 | 如果你发现了任何违规行为,请告知开发者。
18 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | :; set -eo pipefail
2 | :; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
3 | :; ${SCRIPT_DIR}/build.sh "$@"
4 | :; exit $?
5 |
6 | @ECHO OFF
7 | powershell -ExecutionPolicy ByPass -NoProfile "%~dp0build.ps1" %*
8 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | bash --version 2>&1 | head -n 1
4 |
5 | set -eo pipefail
6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
7 |
8 | ###########################################################################
9 | # CONFIGURATION
10 | ###########################################################################
11 |
12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/build/rmbox-build.csproj"
13 | TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
14 |
15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
16 | DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
17 | DOTNET_CHANNEL="Current"
18 |
19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
20 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
21 | export DOTNET_MULTILEVEL_LOOKUP=0
22 |
23 | ###########################################################################
24 | # EXECUTION
25 | ###########################################################################
26 |
27 | function FirstJsonValue {
28 | perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
29 | }
30 |
31 | # If dotnet CLI is installed globally and it matches requested version, use for execution
32 | if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
33 | export DOTNET_EXE="$(command -v dotnet)"
34 | else
35 | # Download install script
36 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
37 | mkdir -p "$TEMP_DIRECTORY"
38 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
39 | chmod +x "$DOTNET_INSTALL_FILE"
40 |
41 | # If global.json exists, load expected version
42 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
43 | DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
44 | if [[ "$DOTNET_VERSION" == "" ]]; then
45 | unset DOTNET_VERSION
46 | fi
47 | fi
48 |
49 | # Install by channel or version
50 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
51 | if [[ -z ${DOTNET_VERSION+x} ]]; then
52 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
53 | else
54 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
55 | fi
56 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
57 | fi
58 |
59 | echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
60 |
61 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
62 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
63 |
--------------------------------------------------------------------------------
/build/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.cs]
2 | dotnet_style_qualification_for_field = false:warning
3 | dotnet_style_qualification_for_property = false:warning
4 | dotnet_style_qualification_for_method = false:warning
5 | dotnet_style_qualification_for_event = false:warning
6 | dotnet_style_require_accessibility_modifiers = never:warning
7 |
8 | csharp_style_expression_bodied_methods = true:silent
9 | csharp_style_expression_bodied_properties = true:warning
10 | csharp_style_expression_bodied_indexers = true:warning
11 | csharp_style_expression_bodied_accessors = true:warning
12 |
--------------------------------------------------------------------------------
/build/Configuration.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using Nuke.Common.Tooling;
3 |
4 | [TypeConverter(typeof(TypeConverter))]
5 | public class Configuration : Enumeration
6 | {
7 | public static Configuration Debug = new Configuration { Value = nameof(Debug) };
8 | public static Configuration Release = new Configuration { Value = nameof(Release) };
9 |
10 | public static implicit operator string(Configuration configuration)
11 | {
12 | return configuration.Value;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/build/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build/PackInstaller.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.IO;
3 | using Nuke.Common.Tooling;
4 | using Nuke.Common.Utilities.Collections;
5 | using static Nuke.Common.IO.FileSystemTasks;
6 |
7 | partial class Build
8 | {
9 | Target PackMac => _ => _
10 | .Executes(() =>
11 | {
12 | AbsolutePath MacDirectory = DistDirectory / "RuminoidToolbox.app";
13 | AbsolutePath MacContentsDirectory = MacDirectory / "Contents";
14 | AbsolutePath MacMacOSDirectory = MacContentsDirectory / "MacOS";
15 | AbsolutePath MacResourcesDirectory = MacContentsDirectory / "Resources";
16 |
17 | new[]
18 | {
19 | MacDirectory,
20 | MacContentsDirectory,
21 | MacMacOSDirectory,
22 | MacResourcesDirectory
23 | }.ForEach(EnsureCleanDirectory);
24 |
25 | Logger.Info("Copying contents.");
26 | ForceCopyDirectoryRecursively(
27 | PackDirectory,
28 | MacMacOSDirectory);
29 |
30 | Logger.Info("Copying icon.");
31 | CopyFileToDirectory(
32 | RootDirectory / "common" / "Assets" / "rmbox.icns",
33 | MacResourcesDirectory,
34 | FileExistsPolicy.Overwrite);
35 |
36 | new Plist
37 | {
38 | CFBundleName = "Toolbox",
39 | CFBundleDisplayName = "Ruminoid Toolbox",
40 | CFBundleSpokenName = "Ruminoid Toolbox",
41 | CFBundleIdentifier = "world.ruminoid.toolbox",
42 | LSApplicationCategoryType = "public.app-category.developer-tools",
43 | CFBundleVersion = GitVersion.MajorMinorPatch,
44 | CFBundleExecutable = "rmbenv",
45 | CFBundleIconFile = "rmbox.icns",
46 | CFBundleShortVersionString = GitVersion.MajorMinorPatch
47 | }.Write(MacContentsDirectory);
48 |
49 | Logger.Info("Configuring privileges.");
50 | ProcessTasks.StartShell(
51 | "chmod -R 775 RuminoidToolbox.app",
52 | DistDirectory)
53 | .AssertZeroExitCode();
54 | });
55 |
56 | Target PackWindows => _ => _
57 | .Executes(() =>
58 | {
59 | ProcessTasks.StartShell(
60 | $"makensis -DVersion={GitVersion.MajorMinorPatch} common/installer/nsis/installer.nsi")
61 | .AssertZeroExitCode();
62 | });
63 | }
64 |
--------------------------------------------------------------------------------
/build/rmbox-build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 | CS0649;CS0169
8 | ..
9 | ..
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/common/Assets/rmbox-transparent.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ruminoid/Toolbox/3cb3b1747c95b29d2a326863e8192d6bbb69821e/common/Assets/rmbox-transparent.png
--------------------------------------------------------------------------------
/common/Assets/rmbox.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ruminoid/Toolbox/3cb3b1747c95b29d2a326863e8192d6bbb69821e/common/Assets/rmbox.icns
--------------------------------------------------------------------------------
/common/Assets/rmbox.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ruminoid/Toolbox/3cb3b1747c95b29d2a326863e8192d6bbb69821e/common/Assets/rmbox.ico
--------------------------------------------------------------------------------
/common/Assets/rmbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ruminoid/Toolbox/3cb3b1747c95b29d2a326863e8192d6bbb69821e/common/Assets/rmbox.png
--------------------------------------------------------------------------------
/common/installer/nsis/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{nsh,nsi}]
2 | indent_size = 2
3 |
--------------------------------------------------------------------------------
/common/installer/nsis/.gitignore:
--------------------------------------------------------------------------------
1 | *.exe
2 |
--------------------------------------------------------------------------------
/common/installer/nsis/assistedInstaller.nsh:
--------------------------------------------------------------------------------
1 | !include StrContains.nsh
2 | !insertmacro MUI_PAGE_DIRECTORY
3 | # pageDirectory leave doesn't work (it seems because $INSTDIR is set after custom leave function)
4 | # so, we use instfiles pre
5 | !define MUI_PAGE_CUSTOMFUNCTION_PRE instFilesPre
6 | # sanitize the MUI_PAGE_DIRECTORY result to make sure it has a application name sub-folder
7 | Function instFilesPre
8 | ${If} ${FileExists} "$INSTDIR\*"
9 | ${StrContains} $0 "${APP_FILENAME}" $INSTDIR
10 | ${If} $0 == ""
11 | StrCpy $INSTDIR "$INSTDIR\${APP_FILENAME}"
12 | ${endIf}
13 | ${endIf}
14 | FunctionEnd
15 | !insertmacro MUI_PAGE_INSTFILES
16 | !insertmacro MUI_PAGE_FINISH
17 |
--------------------------------------------------------------------------------
/common/installer/nsis/common.nsh:
--------------------------------------------------------------------------------
1 | !include x64.nsh
2 | !include WinVer.nsh
3 |
4 | BrandingText "${PRODUCT_NAME} ${VERSION}"
5 | ; ShowInstDetails nevershow
6 | SpaceTexts none
7 | FileBufSize 64
8 | Name "${PRODUCT_NAME}"
9 |
10 | !macro check64BitAndSetRegView
11 | ${If} ${IsWin2000}
12 | ${OrIf} ${IsWinME}
13 | ${OrIf} ${IsWinXP}
14 | ${OrIf} ${IsWinVista}
15 | MessageBox MB_OK "$(win7Required)"
16 | Quit
17 | ${EndIf}
18 |
19 | ${If} ${RunningX64}
20 | SetRegView 64
21 | ${Else}
22 | MessageBox MB_OK|MB_ICONEXCLAMATION "$(x64WinRequired)"
23 | Quit
24 | ${EndIf}
25 | !macroend
26 |
27 | !macro setLinkVars
28 | # old desktop shortcut (could exist or not since the user might has selected to delete it)
29 | ReadRegStr $oldShortcutName SHELL_CONTEXT "${INSTALL_REGISTRY_KEY}" ShortcutName
30 | ${if} $oldShortcutName == ""
31 | StrCpy $oldShortcutName "${SHORTCUT_NAME}"
32 | ${endIf}
33 | StrCpy $oldDesktopLink "$DESKTOP\$oldShortcutName.lnk"
34 |
35 | # new desktop shortcut (will be created/renamed in case of a fresh installation or if the user haven't deleted the initial one)
36 | StrCpy $newDesktopLink "$DESKTOP\${SHORTCUT_NAME}.lnk"
37 |
38 | ReadRegStr $oldMenuDirectory SHELL_CONTEXT "${INSTALL_REGISTRY_KEY}" MenuDirectory
39 | ${if} $oldMenuDirectory == ""
40 | StrCpy $oldStartMenuLink "$SMPROGRAMS\$oldShortcutName.lnk"
41 | ${else}
42 | StrCpy $oldStartMenuLink "$SMPROGRAMS\$oldMenuDirectory\$oldShortcutName.lnk"
43 | ${endIf}
44 |
45 | # new menu shortcut (will be created/renamed in case of a fresh installation or if the user haven't deleted the initial one)
46 | !ifdef MENU_FILENAME
47 | StrCpy $newStartMenuLink "$SMPROGRAMS\${MENU_FILENAME}\${SHORTCUT_NAME}.lnk"
48 | !else
49 | StrCpy $newStartMenuLink "$SMPROGRAMS\${SHORTCUT_NAME}.lnk"
50 | !endif
51 | !macroend
52 |
--------------------------------------------------------------------------------
/common/installer/nsis/include/StrContains.nsh:
--------------------------------------------------------------------------------
1 | ; StrContains
2 | ; This function does a case sensitive searches for an occurrence of a substring in a string.
3 | ; It returns the substring if it is found.
4 | ; Otherwise it returns null("").
5 | ; Written by kenglish_hi
6 | ; Adapted from StrReplace written by dandaman32
7 |
8 |
9 | Var STR_HAYSTACK
10 | Var STR_NEEDLE
11 | Var STR_CONTAINS_VAR_1
12 | Var STR_CONTAINS_VAR_2
13 | Var STR_CONTAINS_VAR_3
14 | Var STR_CONTAINS_VAR_4
15 | Var STR_RETURN_VAR
16 |
17 | Function StrContains
18 | Exch $STR_NEEDLE
19 | Exch 1
20 | Exch $STR_HAYSTACK
21 | ; Uncomment to debug
22 | ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK '
23 | StrCpy $STR_RETURN_VAR ""
24 | StrCpy $STR_CONTAINS_VAR_1 -1
25 | StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE
26 | StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK
27 | loop:
28 | IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1
29 | StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1
30 | StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found
31 | StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done
32 | Goto loop
33 | found:
34 | StrCpy $STR_RETURN_VAR $STR_NEEDLE
35 | Goto done
36 | done:
37 | Pop $STR_NEEDLE ;Prevent "invalid opcode" errors and keep the
38 | Exch $STR_RETURN_VAR
39 | FunctionEnd
40 |
41 | !macro _StrContainsConstructor OUT NEEDLE HAYSTACK
42 | Push `${HAYSTACK}`
43 | Push `${NEEDLE}`
44 | Call StrContains
45 | Pop `${OUT}`
46 | !macroend
47 |
48 | !define StrContains '!insertmacro "_StrContainsConstructor"'
--------------------------------------------------------------------------------
/common/installer/nsis/include/extractAppPackage.nsh:
--------------------------------------------------------------------------------
1 | !macro extractEmbeddedAppPackage
2 | !ifdef COMPRESS
3 | SetCompress off
4 | !endif
5 |
6 | File /oname=$PLUGINSDIR\app-bundle.7z "${APP_BUNDLE}"
7 |
8 | !ifdef COMPRESS
9 | SetCompress "${COMPRESS}"
10 | !endif
11 |
12 | Nsis7z::ExtractWithDetails "$PLUGINSDIR\app-bundle.7z" "Unpacking bundle %s..."
13 |
14 | DetailPrint "Copying files..."
15 | nsExec::ExecToStack '"$SYSDIR\cmd.exe" /c xcopy.exe "$INSTDIR\RuminoidToolbox\*" "$INSTDIR" /Y /E /I'
16 | Pop $0
17 | Pop $1
18 | RMDir /r "$INSTDIR\RuminoidToolbox"
19 |
20 | WriteUninstaller "$INSTDIR\${UNINSTALLER_OUT_FILE}"
21 | !macroend
22 |
--------------------------------------------------------------------------------
/common/installer/nsis/installSection.nsh:
--------------------------------------------------------------------------------
1 | !include installer.nsh
2 |
3 | InitPluginsDir
4 |
5 | StrCpy $appExe "$INSTDIR\${APP_EXECUTABLE_FILENAME}"
6 |
7 | # must be called before uninstallOldVersion
8 | !insertmacro setLinkVars
9 |
10 | Var /GLOBAL keepShortcuts
11 | StrCpy $keepShortcuts "false"
12 | !insertMacro setIsTryToKeepShortcuts
13 | ${if} $isTryToKeepShortcuts == "true"
14 | ReadRegStr $R1 SHELL_CONTEXT "${INSTALL_REGISTRY_KEY}" KeepShortcuts
15 |
16 | ${if} $R1 == "true"
17 | ${andIf} ${FileExists} "$appExe"
18 | StrCpy $keepShortcuts "true"
19 | ${endIf}
20 | ${endif}
21 |
22 | !insertmacro uninstallOldVersion SHELL_CONTEXT
23 |
24 | SetOutPath $INSTDIR
25 |
26 | !insertmacro installApplicationFiles
27 | !insertmacro registryAddInstallInfo
28 | !insertmacro addStartMenuLink $keepShortcuts
29 | !insertmacro addDesktopLink $keepShortcuts
30 |
--------------------------------------------------------------------------------
/common/installer/nsis/multiUser.nsh:
--------------------------------------------------------------------------------
1 | !include FileFunc.nsh
2 |
3 | !define FOLDERID_UserProgramFiles {5CD7AEE2-2219-4A67-B85D-6C9CE15660CB}
4 | !define KF_FLAG_CREATE 0x00008000
5 |
6 | # allow user to define own custom
7 | !define /ifndef INSTALL_REGISTRY_KEY "Software\${APP_GUID}"
8 | !define /ifndef UNINSTALL_REGISTRY_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${APP_GUID}"
9 |
10 | Var PerUserInstallationFolder
11 |
12 | !macro setInstallModePerUser
13 | SetShellVarContext current
14 | # сhecks registry for previous installation path
15 | ReadRegStr $perUserInstallationFolder HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation
16 | ${if} $perUserInstallationFolder != ""
17 | StrCpy $INSTDIR $perUserInstallationFolder
18 | ${else}
19 | StrCpy $0 "$LocalAppData\Programs"
20 | System::Store S
21 | # Win7 has a per-user programfiles known folder and this can be a non-default location
22 | System::Call 'SHELL32::SHGetKnownFolderPath(g "${FOLDERID_UserProgramFiles}", i ${KF_FLAG_CREATE}, p 0, *p .r2)i.r1'
23 | ${If} $1 == 0
24 | System::Call '*$2(&w${NSIS_MAX_STRLEN} .s)'
25 | StrCpy $0 $1
26 | System::Call 'OLE32::CoTaskMemFree(p r2)'
27 | ${endif}
28 | System::Store L
29 | StrCpy $INSTDIR "$0\${APP_FILENAME}"
30 | ${endif}
31 | !macroend
32 |
--------------------------------------------------------------------------------
/common/installer/nsis/uninstaller.nsh:
--------------------------------------------------------------------------------
1 | Function un.onInit
2 | !insertmacro check64BitAndSetRegView
3 |
4 | MessageBox MB_OKCANCEL "$(areYouSureToUninstall)" IDOK +2
5 | Quit
6 |
7 | !insertmacro setInstallModePerUser
8 | FunctionEnd
9 |
10 | Section "Uninstall"
11 | !insertmacro setLinkVars
12 |
13 | WinShell::UninstAppUserModelId "${APP_ID}"
14 |
15 | WinShell::UninstShortcut "$oldDesktopLink"
16 | Delete "$oldDesktopLink"
17 |
18 | WinShell::UninstShortcut "$oldStartMenuLink"
19 |
20 | Delete "$oldStartMenuLink"
21 | ReadRegStr $R1 SHELL_CONTEXT "${INSTALL_REGISTRY_KEY}" MenuDirectory
22 | ${ifNot} $R1 == ""
23 | RMDir "$SMPROGRAMS\$R1"
24 | ${endIf}
25 |
26 | # refresh the desktop
27 | System::Call 'shell32::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
28 |
29 | # delete the installed files
30 | RMDir /r $INSTDIR
31 |
32 | DeleteRegKey SHELL_CONTEXT "${UNINSTALL_REGISTRY_KEY}"
33 | DeleteRegKey SHELL_CONTEXT "${INSTALL_REGISTRY_KEY}"
34 | SectionEnd
35 |
--------------------------------------------------------------------------------
/common/meta/rmbenv.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/examples/lua/rmbox-plugin-lua-example/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org/
2 |
3 | [*]
4 | indent_style = space
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 | end_of_line = lf
8 | charset = utf-8
9 | indent_size = 2
10 | table_width = 2
11 |
12 | [*.lua]
13 | indent_size = 4
14 | table_width = 4
15 |
16 | [*.json]
17 | indent_size = 2
18 |
--------------------------------------------------------------------------------
/examples/lua/rmbox-plugin-lua-example/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Lua sources
2 | luac.out
3 |
4 | # luarocks build files
5 | *.src.rock
6 | *.zip
7 | *.tar.gz
8 |
9 | # Object files
10 | *.o
11 | *.os
12 | *.ko
13 | *.obj
14 | *.elf
15 |
16 | # Precompiled Headers
17 | *.gch
18 | *.pch
19 |
20 | # Libraries
21 | *.lib
22 | *.a
23 | *.la
24 | *.lo
25 | *.def
26 | *.exp
27 |
28 | # Shared objects (inc. Windows DLLs)
29 | *.dll
30 | *.so
31 | *.so.*
32 | *.dylib
33 |
34 | # Executables
35 | *.exe
36 | *.out
37 | *.app
38 | *.i*86
39 | *.x86_64
40 | *.hex
41 |
42 | # Visual Studio Code config
43 | .vscode/
44 |
--------------------------------------------------------------------------------
/examples/lua/rmbox-plugin-lua-example/rmbox-plugin-lua-example.lua:
--------------------------------------------------------------------------------
1 | json = require 'json'
2 |
3 | local meta = {
4 | id = 'Ruminoid.Toolbox.Plugins.Examples.RmboxPluginLuaExample',
5 | class_name = 'RmboxPluginLuaExample',
6 | name = 'Lua 插件示例',
7 | type = 'operation',
8 | description = 'Lua 编写的 Ruminoid Toolbox 插件示例。',
9 | rate = 2,
10 | category = '示例插件',
11 | author = 'Il Harper',
12 | config_sections = {
13 | ["Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection"] = {}
14 | }
15 | }
16 |
17 | if (type(arg[1]) == "nil") then
18 | print(json.encode(meta))
19 | os.exit(0)
20 | end
21 |
22 | io.input(arg[1])
23 | local config_section_data = io.read("a")
24 |
25 | local config_sections = json.decode(config_section_data)
26 | local io_section =
27 | config_sections["Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection"]
28 |
29 | local commands = {
30 | target = "ffmpeg",
31 | args = "-i " + io_section["input"] + " " + io_section["output"],
32 | formatter = "ffmpeg"
33 | }
34 |
35 | print(json.encode(commands))
36 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true,
5 | es2020: true,
6 | },
7 | parser: '@typescript-eslint/parser',
8 | plugins: ['prettier', '@typescript-eslint'],
9 | extends: [
10 | 'eslint:recommended',
11 | 'plugin:@typescript-eslint/recommended',
12 | 'prettier',
13 | 'plugin:prettier/recommended',
14 | 'prettier/@typescript-eslint',
15 | ],
16 | }
17 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Node template
3 | # Logs
4 | /logs
5 | *.log
6 | npm-debug.log*
7 | yarn-debug.log*
8 | yarn-error.log*
9 |
10 | # Runtime data
11 | pids
12 | *.pid
13 | *.seed
14 | *.pid.lock
15 |
16 | # Directory for instrumented libs generated by jscoverage/JSCover
17 | lib-cov
18 |
19 | # Coverage directory used by tools like istanbul
20 | coverage
21 |
22 | # nyc test coverage
23 | .nyc_output
24 |
25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
26 | .grunt
27 |
28 | # Bower dependency directory (https://bower.io/)
29 | bower_components
30 |
31 | # node-waf configuration
32 | .lock-wscript
33 |
34 | # Compiled binary addons (https://nodejs.org/api/addons.html)
35 | build/Release
36 |
37 | # Dependency directories
38 | node_modules/
39 | jspm_packages/
40 |
41 | # TypeScript v1 declaration files
42 | typings/
43 |
44 | # Optional npm cache directory
45 | .npm
46 |
47 | # Optional eslint cache
48 | .eslintcache
49 |
50 | # Optional REPL history
51 | .node_repl_history
52 |
53 | # Output of 'npm pack'
54 | *.tgz
55 |
56 | # Yarn Integrity file
57 | .yarn-integrity
58 |
59 | # dotenv environment variables file
60 | .env
61 |
62 | # parcel-bundler cache (https://parceljs.org/)
63 | .cache
64 |
65 | # next.js build output
66 | .next
67 |
68 | # nuxt.js build output
69 | .nuxt
70 |
71 | # Nuxt generate
72 | dist
73 |
74 | # vuepress build output
75 | .vuepress/dist
76 |
77 | # Serverless directories
78 | .serverless
79 |
80 | # IDE / Editor
81 | .idea
82 |
83 | # Service worker
84 | sw.*
85 |
86 | # macOS
87 | .DS_Store
88 |
89 | # Vim swap files
90 | *.swp
91 |
92 | # Visual Studio Code config
93 | .vscode/
94 |
95 | # Package lock
96 | package-lock.json
97 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/.prettierrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | arrowParens: 'always',
4 | singleQuote: true,
5 | }
6 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "esnext",
4 | "target": "esnext",
5 | "moduleResolution": "node"
6 | },
7 | "exclude": [
8 | "node_modules",
9 | "dist"
10 | ]
11 | }
12 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rmbox-plugin-node-example",
3 | "version": "0.1.0",
4 | "description": "The node example plugin for Ruminoid Toolbox.",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "dev": "ts-node src/index.ts",
8 | "build": "tsc -b",
9 | "lint": "eslint src --ext .js,.ts --ignore-path .gitignore --fix"
10 | },
11 | "author": "Il Harper",
12 | "license": "MIT",
13 | "devDependencies": {
14 | "@types/node": "^14.14.16",
15 | "@typescript-eslint/eslint-plugin": "^4.11.1",
16 | "@typescript-eslint/parser": "^4.11.1",
17 | "cross-env": "^7.0.3",
18 | "eslint": "^7.16.0",
19 | "eslint-config-prettier": "^7.1.0",
20 | "eslint-plugin-prettier": "^3.3.0",
21 | "prettier": "^2.2.1",
22 | "ts-node": "^9.1.1",
23 | "typescript": "^4.1.3"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/src/index.ts:
--------------------------------------------------------------------------------
1 | import * as fs from 'fs'
2 | import { Command, Meta } from './rmbox'
3 |
4 | const meta: Meta = {
5 | id: 'Ruminoid.Toolbox.Plugins.Examples.RmboxPluginNodeExample',
6 | class_name: 'RmboxPluginNodeExample',
7 | name: 'Node 插件示例',
8 | type: 'operation',
9 | description: 'Node 编写的 Ruminoid Toolbox 插件示例。',
10 | rate: 2,
11 | category: '示例插件',
12 | author: 'Il Harper',
13 | config_sections: {
14 | 'Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection': {},
15 | },
16 | }
17 |
18 | if (process.argv.length <= 2) {
19 | console.log(JSON.stringify(meta))
20 | process.exit(0)
21 | }
22 |
23 | const configSectionData: string = fs.readFileSync(process.argv[2], {
24 | encoding: 'utf-8',
25 | })
26 | const configSections = JSON.parse(configSectionData)
27 | const ioSection =
28 | configSections[
29 | 'Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection'
30 | ]
31 |
32 | const commands: Command[] = [
33 | {
34 | target: 'ffmpeg',
35 | args: `-i ${ioSection['input']} ${ioSection['output']}`,
36 | formatter: 'ffmpeg',
37 | },
38 | ]
39 |
40 | console.log(JSON.stringify(commands))
41 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/src/rmbox.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-explicit-any */
2 |
3 | export interface Meta {
4 | id: string
5 | class_name: string
6 | name: string
7 | type: string
8 | description: string
9 | config_sections: { [K: string]: any }
10 | [K: string]: any
11 | }
12 |
13 | export interface Command {
14 | target: string
15 | args: string
16 | formatter: string
17 | }
18 |
--------------------------------------------------------------------------------
/examples/node/rmbox-plugin-node-example/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "CommonJS",
5 | "moduleResolution": "Node",
6 | "lib": [
7 | "ESNext",
8 | "ESNext.AsyncIterable"
9 | ],
10 | "outDir": "dist",
11 | "esModuleInterop": true,
12 | "sourceMap": true,
13 | "strict": true,
14 | "experimentalDecorators": true,
15 | "types": [
16 | "@types/node"
17 | ]
18 | },
19 | "include": [
20 | "src"
21 | ]
22 | }
23 |
--------------------------------------------------------------------------------
/examples/python/rmbox-plugin-python-example/.editorconfig:
--------------------------------------------------------------------------------
1 | # https://editorconfig.org/
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | insert_final_newline = true
7 | trim_trailing_whitespace = true
8 | end_of_line = lf
9 | charset = utf-8
10 |
11 | [*.json]
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/examples/python/rmbox-plugin-python-example/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | pip-wheel-metadata/
24 | share/python-wheels/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 | MANIFEST
29 |
30 | # PyInstaller
31 | # Usually these files are written by a python script from a template
32 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
33 | *.manifest
34 | *.spec
35 |
36 | # Installer logs
37 | pip-log.txt
38 | pip-delete-this-directory.txt
39 |
40 | # Unit test / coverage reports
41 | htmlcov/
42 | .tox/
43 | .nox/
44 | .coverage
45 | .coverage.*
46 | .cache
47 | nosetests.xml
48 | coverage.xml
49 | *.cover
50 | *.py,cover
51 | .hypothesis/
52 | .pytest_cache/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow
95 | __pypackages__/
96 |
97 | # Celery stuff
98 | celerybeat-schedule
99 | celerybeat.pid
100 |
101 | # SageMath parsed files
102 | *.sage.py
103 |
104 | # Environments
105 | .env
106 | .venv
107 | env/
108 | venv/
109 | ENV/
110 | env.bak/
111 | venv.bak/
112 |
113 | # Spyder project settings
114 | .spyderproject
115 | .spyproject
116 |
117 | # Rope project settings
118 | .ropeproject
119 |
120 | # mkdocs documentation
121 | /site
122 |
123 | # mypy
124 | .mypy_cache/
125 | .dmypy.json
126 | dmypy.json
127 |
128 | # Pyre type checker
129 | .pyre/
130 |
131 | # Rasa
132 | models/
133 |
134 | # Visual Studio Code config
135 | .vscode/
136 |
--------------------------------------------------------------------------------
/examples/python/rmbox-plugin-python-example/rmbox-plugin-python-example.py:
--------------------------------------------------------------------------------
1 | import json
2 | import sys
3 | from typing import Any
4 |
5 | argv: str = sys.argv
6 |
7 | meta = {
8 | 'id': 'Ruminoid.Toolbox.Plugins.Examples.RmboxPluginPythonExample',
9 | 'class_name': 'RmboxPluginPythonExample',
10 | 'name': 'Python 插件示例',
11 | 'type': 'operation',
12 | 'description': 'Python 编写的 Ruminoid Toolbox 插件示例。',
13 | 'rate': 2,
14 | 'category': '示例插件',
15 | 'author': 'Il Harper',
16 | 'config_sections': {
17 | 'Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection': {},
18 | },
19 | }
20 |
21 | if len(argv) == 1:
22 | print(json.dumps(meta))
23 | sys.exit(0)
24 |
25 | config_sections: Any
26 |
27 | with open(argv[1], 'r', encoding='utf-8') as config_section_file:
28 | config_sections = json.load(config_section_file)
29 |
30 | io_section: Any = config_sections['Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection']
31 |
32 | commands = [
33 | {
34 | 'target': 'ffmpeg',
35 | 'args': f'-i {io_section["input"]} {io_section["output"]}',
36 | 'formatter': 'ffmpeg',
37 | },
38 | ]
39 |
40 | print(json.dumps(commands))
41 |
--------------------------------------------------------------------------------
/lgtm.yml:
--------------------------------------------------------------------------------
1 | extraction:
2 | csharp:
3 | index:
4 | build_command:
5 | - ./build.sh Compile --configuration Release
6 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-audio/AudioMeta.cs:
--------------------------------------------------------------------------------
1 | using Ruminoid.Toolbox.Core;
2 |
3 | namespace Ruminoid.Toolbox.Plugins.Audio
4 | {
5 | [RmboxPlugin]
6 | public class AudioMeta : IMeta
7 | {
8 | public string Name => "音频压制";
9 | public string Description => "提供了音频压制相关的功能。";
10 | public string Author => "Il Harper";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-audio/ConfigSections/ViewModels/AudioConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ReactiveUI;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.Audio.ConfigSections.ViewModels
5 | {
6 | [JsonObject(MemberSerialization.OptIn)]
7 | public class AudioConfigSectionViewModel : ReactiveObject
8 | {
9 | #region Data
10 |
11 | [JsonProperty("mode")]
12 | private string _encodeMode = "copy";
13 |
14 | public string EncodeMode
15 | {
16 | get => _encodeMode;
17 | set => this.RaiseAndSetIfChanged(ref _encodeMode, value);
18 | }
19 |
20 | [JsonProperty("bitrate")]
21 | private int _bitrate = 320;
22 |
23 | public int Bitrate
24 | {
25 | get => _bitrate;
26 | set => this.RaiseAndSetIfChanged(ref _bitrate, value);
27 | }
28 |
29 | #endregion
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-audio/ConfigSections/ViewModels/AudioQualityConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ReactiveUI;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.Audio.ConfigSections.ViewModels
5 | {
6 | [JsonObject(MemberSerialization.OptIn)]
7 | public class AudioQualityConfigSectionViewModel : ReactiveObject
8 | {
9 | #region Data
10 |
11 | [JsonProperty("bitrate")]
12 | private int _bitrate = 320;
13 |
14 | public int Bitrate
15 | {
16 | get => _bitrate;
17 | set => this.RaiseAndSetIfChanged(ref _bitrate, value);
18 | }
19 |
20 | #endregion
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-audio/ConfigSections/Views/AudioConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.Audio.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.Audio.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.Audio.ConfigSections.AudioConfigSection",
10 | "音频")]
11 | public class AudioConfigSection : ConfigSectionBase
12 | {
13 | public AudioConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public AudioConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as AudioConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-audio/ConfigSections/Views/AudioQualityConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.Audio.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.Audio.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.Audio.ConfigSections.AudioQualityConfigSection",
10 | "音频质量")]
11 | public class AudioQualityConfigSection : ConfigSectionBase
12 | {
13 | public AudioQualityConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public AudioQualityConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as AudioQualityConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-audio/rmbox-plugin-audio.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Ruminoid.Toolbox.Plugins.Audio
6 |
7 |
8 |
9 |
10 | false
11 | runtime
12 |
13 |
14 |
15 |
16 |
17 | false
18 | runtime
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/CommonMeta.cs:
--------------------------------------------------------------------------------
1 | using Ruminoid.Toolbox.Core;
2 |
3 | namespace Ruminoid.Toolbox.Plugins.Common
4 | {
5 | [RmboxPlugin]
6 | public class CommonMeta : IMeta
7 | {
8 | public string Name => "Ruminoid Toolbox 基础";
9 | public string Description => "提供了工具箱的基础功能。";
10 | public string Author => "Il Harper";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/ViewModels/AdvancedTrackConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ReactiveUI;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels
5 | {
6 | [JsonObject(MemberSerialization.OptIn)]
7 | public class AdvancedTrackConfigSectionViewModel : ReactiveObject
8 | {
9 | #region Data
10 |
11 | [JsonProperty("process_mode")]
12 | private string _processMode = "auto";
13 |
14 | public string ProcessMode
15 | {
16 | get => _processMode;
17 | set => this.RaiseAndSetIfChanged(ref _processMode, value);
18 | }
19 |
20 | #endregion
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/ViewModels/CustomArgsConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using ReactiveUI;
4 |
5 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels
6 | {
7 | [JsonObject(MemberSerialization.OptIn)]
8 | public class CustomArgsConfigSectionViewModel : ReactiveObject
9 | {
10 | #region Constructor
11 |
12 | public CustomArgsConfigSectionViewModel(
13 | JToken sectionConfig)
14 | {
15 | _defaultArgs = sectionConfig["default_args"]?.ToObject() ?? string.Empty;
16 | _args = _defaultArgs;
17 | }
18 |
19 | #endregion
20 |
21 | private readonly string _defaultArgs;
22 |
23 | #region Bindings
24 |
25 | [JsonProperty("use_custom_args")]
26 | private bool _useCustom;
27 |
28 | public bool UseCustom
29 | {
30 | get => _useCustom;
31 | set
32 | {
33 | if (_useCustom == value)
34 | return;
35 |
36 | Args = value ? _args : _defaultArgs;
37 |
38 | _useCustom = value;
39 | this.RaisePropertyChanged(nameof(UseCustom));
40 | }
41 | }
42 |
43 | [JsonProperty("args")]
44 | private string _args;
45 |
46 | public string Args
47 | {
48 | get => _args;
49 | set => this.RaiseAndSetIfChanged(ref _args, value);
50 | }
51 |
52 | #endregion
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/ViewModels/IntroConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using Newtonsoft.Json.Linq;
3 | using ReactiveUI;
4 |
5 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels
6 | {
7 | [JsonObject(MemberSerialization.OptIn)]
8 | public class IntroConfigSectionViewModel : ReactiveObject
9 | {
10 | #region Constructor
11 |
12 | public IntroConfigSectionViewModel(
13 | JToken sectionConfig)
14 | {
15 | MdText = sectionConfig["intro_text"]?.ToObject() ?? "# 介绍获取失败\n\n插件似乎出现了问题。\n";
16 | }
17 |
18 | #endregion
19 |
20 | #region Data
21 |
22 | public string MdText { get; }
23 |
24 | #endregion
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/ViewModels/MuxOptionsConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ReactiveUI;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels
5 | {
6 | [JsonObject(MemberSerialization.OptIn)]
7 | public class MuxOptionsConfigSectionViewModel : ReactiveObject
8 | {
9 | #region Data
10 |
11 | [JsonProperty("use_shortest")]
12 | private bool _useShortest;
13 |
14 | public bool UseShortest
15 | {
16 | get => _useShortest;
17 | set => this.RaiseAndSetIfChanged(ref _useShortest, value);
18 | }
19 |
20 | #endregion
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/ViewModels/OutputConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Avalonia.Controls;
3 | using Avalonia.VisualTree;
4 | using Newtonsoft.Json;
5 | using ReactiveUI;
6 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views;
7 |
8 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels
9 | {
10 | [JsonObject(MemberSerialization.OptIn)]
11 | class OutputConfigSectionViewModel : ReactiveObject
12 | {
13 | #region Constructor
14 |
15 | public OutputConfigSectionViewModel(
16 | OutputConfigSection view)
17 | {
18 | _view = view;
19 | }
20 |
21 | #endregion
22 |
23 | #region Data
24 |
25 | [JsonProperty("output")]
26 | private string _output = "";
27 |
28 | public string Output
29 | {
30 | get => _output;
31 | set => this.RaiseAndSetIfChanged(ref _output, value);
32 | }
33 |
34 | #endregion
35 |
36 | #region View
37 |
38 | private readonly OutputConfigSection _view;
39 |
40 | #endregion
41 |
42 | #region Operations
43 |
44 | public async Task SaveFile()
45 | {
46 | SaveFileDialog dialog = new SaveFileDialog
47 | {
48 | Title = "选择输出文件",
49 | DefaultExtension = ".mp4"
50 | };
51 |
52 | var result = await dialog.ShowAsync((Window)_view.GetVisualRoot());
53 |
54 | if (string.IsNullOrWhiteSpace(result)) return;
55 |
56 | Output = result;
57 | }
58 |
59 | #endregion
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/AdvancedTrackConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia.Markup.Xaml;
3 | using Newtonsoft.Json.Linq;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
8 | {
9 | [ConfigSection(
10 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.AdvancedTrackConfigSection",
11 | "高级 (流)")]
12 | public class AdvancedTrackConfigSection : ConfigSectionBase
13 | {
14 | public AdvancedTrackConfigSection()
15 | {
16 | throw new InvalidOperationException();
17 | }
18 |
19 | public AdvancedTrackConfigSection(
20 | JToken sectionConfig)
21 | {
22 | DataContext = new AdvancedTrackConfigSectionViewModel();
23 |
24 | InitializeComponent();
25 | }
26 |
27 | private void InitializeComponent()
28 | {
29 | AvaloniaXamlLoader.Load(this);
30 | }
31 |
32 | public override object Config => DataContext as AdvancedTrackConfigSectionViewModel;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/CustomArgsConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
18 |
19 |
22 |
23 |
24 |
27 |
28 |
29 | 自定义参数
30 |
31 |
32 |
33 |
34 | 如果启用自定义参数,那么操作内所有的默认参数都将失效。确保你提供了所有必须的参数。
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 | 参数
47 |
48 |
49 |
50 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/CustomArgsConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia.Markup.Xaml;
3 | using Newtonsoft.Json.Linq;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
8 | {
9 | [ConfigSection(
10 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
11 | "自定义参数")]
12 | public class CustomArgsConfigSection : ConfigSectionBase
13 | {
14 | public CustomArgsConfigSection()
15 | {
16 | throw new InvalidOperationException();
17 | }
18 |
19 | public CustomArgsConfigSection(
20 | JToken sectionConfig)
21 | {
22 | DataContext = new CustomArgsConfigSectionViewModel(sectionConfig);
23 |
24 | InitializeComponent();
25 | }
26 |
27 | private void InitializeComponent()
28 | {
29 | AvaloniaXamlLoader.Load(this);
30 | }
31 |
32 | public override object Config => DataContext as CustomArgsConfigSectionViewModel;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/IOConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Avalonia.Controls;
4 | using Avalonia.Input;
5 | using Avalonia.Markup.Xaml;
6 | using Newtonsoft.Json.Linq;
7 | using Ruminoid.Toolbox.Core;
8 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
9 |
10 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
11 | {
12 | [ConfigSection(
13 | IOConfigSectionId,
14 | "输入/输出")]
15 | public sealed class IOConfigSection : ConfigSectionBase
16 | {
17 | public IOConfigSection()
18 | {
19 | throw new InvalidOperationException();
20 | }
21 |
22 | public IOConfigSection(
23 | JToken sectionConfig)
24 | {
25 | DataContext = new IOConfigSectionViewModel(this, sectionConfig);
26 |
27 | InitializeComponent();
28 |
29 | _inputFileGrid = this.FindControl("InputFileGrid");
30 | _subtitleGrid = this.FindControl("SubtitleFileGrid");
31 |
32 | _inputFileGrid.AddHandler(DragDrop.DropEvent, InputDropHandler);
33 | _subtitleGrid.AddHandler(DragDrop.DropEvent, SubtitleDropHandler);
34 | }
35 |
36 | private void InputDropHandler(object sender, DragEventArgs e)
37 | {
38 | if (e.Data.Contains(DataFormats.Text))
39 | (DataContext as IOConfigSectionViewModel).Input = e.Data.GetText();
40 | else if (e.Data.Contains(DataFormats.FileNames))
41 | (DataContext as IOConfigSectionViewModel).Input = (e.Data.GetFileNames() ?? Array.Empty()).FirstOrDefault();
42 | }
43 |
44 | private void SubtitleDropHandler(object sender, DragEventArgs e)
45 | {
46 | if (e.Data.Contains(DataFormats.Text))
47 | (DataContext as IOConfigSectionViewModel).Subtitle = e.Data.GetText();
48 | else if (e.Data.Contains(DataFormats.FileNames))
49 | (DataContext as IOConfigSectionViewModel).Subtitle = (e.Data.GetFileNames() ?? Array.Empty()).FirstOrDefault();
50 | }
51 |
52 | private readonly Grid _inputFileGrid;
53 | private readonly Grid _subtitleGrid;
54 |
55 | private void InitializeComponent()
56 | {
57 | AvaloniaXamlLoader.Load(this);
58 | }
59 |
60 | #region Data
61 |
62 | public override IOConfigSectionViewModel Config => DataContext as IOConfigSectionViewModel;
63 |
64 | #endregion
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/IntroConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
9 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/IntroConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia.Markup.Xaml;
3 | using Newtonsoft.Json.Linq;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
8 | {
9 | [ConfigSection(
10 | IntroConfigSectionId,
11 | "介绍")]
12 | public class IntroConfigSection : ConfigSectionBase
13 | {
14 | public IntroConfigSection()
15 | {
16 | throw new InvalidOperationException();
17 | }
18 |
19 | public IntroConfigSection(
20 | JToken sectionConfig)
21 | {
22 | DataContext = new IntroConfigSectionViewModel(sectionConfig);
23 |
24 | InitializeComponent();
25 | }
26 |
27 | private void InitializeComponent()
28 | {
29 | AvaloniaXamlLoader.Load(this);
30 | }
31 |
32 | public override object Config => DataContext as IntroConfigSectionViewModel;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/MuxOptionsConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.MuxOptionsConfigSection",
10 | "混流选项")]
11 | public class MuxOptionsConfigSection : ConfigSectionBase
12 | {
13 | public MuxOptionsConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public MuxOptionsConfigSection(
19 | JToken sectionConfig)
20 | {
21 | DataContext = new MuxOptionsConfigSectionViewModel();
22 |
23 | InitializeComponent();
24 | }
25 |
26 | private void InitializeComponent()
27 | {
28 | AvaloniaXamlLoader.Load(this);
29 | }
30 |
31 | public override object Config => DataContext as MuxOptionsConfigSectionViewModel;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/OutputConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
19 |
20 |
24 |
25 |
28 |
29 |
30 |
31 | 输出
32 |
33 | 指定输出文件。输出文件可以是操作所支持的任何文件格式。
34 |
35 |
37 |
40 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/OutputConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.OutputConfigSection",
10 | "输出")]
11 | public class OutputConfigSection : ConfigSectionBase
12 | {
13 | public OutputConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public OutputConfigSection(
19 | JToken sectionConfig)
20 | {
21 | DataContext = new OutputConfigSectionViewModel(this);
22 |
23 | InitializeComponent();
24 | }
25 |
26 | private void InitializeComponent()
27 | {
28 | AvaloniaXamlLoader.Load(this);
29 | }
30 |
31 | public override object Config => DataContext as OutputConfigSectionViewModel;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/ConfigSections/Views/PictureFlowConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Avalonia.Controls;
4 | using Avalonia.Input;
5 | using Avalonia.Markup.Xaml;
6 | using Newtonsoft.Json.Linq;
7 | using Ruminoid.Toolbox.Core;
8 | using Ruminoid.Toolbox.Plugins.Common.ConfigSections.ViewModels;
9 |
10 | namespace Ruminoid.Toolbox.Plugins.Common.ConfigSections.Views
11 | {
12 | [ConfigSection(
13 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.PictureFlowConfigSection",
14 | "一图流")]
15 | public class PictureFlowConfigSection : ConfigSectionBase
16 | {
17 | public PictureFlowConfigSection()
18 | {
19 | throw new InvalidOperationException();
20 | }
21 |
22 | public PictureFlowConfigSection(
23 | JToken sectionConfig)
24 | {
25 | DataContext = new PictureFlowConfigSectionViewModel(this, sectionConfig);
26 |
27 | InitializeComponent();
28 |
29 | _pictureFileGrid = this.FindControl("PictureFileGrid");
30 |
31 | _pictureFileGrid.AddHandler(DragDrop.DropEvent, PictureDropHandler);
32 | }
33 |
34 | private void PictureDropHandler(object sender, DragEventArgs e)
35 | {
36 | if (e.Data.Contains(DataFormats.Text))
37 | (DataContext as PictureFlowConfigSectionViewModel).Picture = e.Data.GetText();
38 | else if (e.Data.Contains(DataFormats.FileNames))
39 | (DataContext as PictureFlowConfigSectionViewModel).Picture = (e.Data.GetFileNames() ?? Array.Empty()).FirstOrDefault();
40 | }
41 |
42 | private void InitializeComponent()
43 | {
44 | AvaloniaXamlLoader.Load(this);
45 | }
46 |
47 | private readonly Grid _pictureFileGrid;
48 |
49 | public override object Config => DataContext as PictureFlowConfigSectionViewModel;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/Formatters/NullFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Ruminoid.Toolbox.Formatting;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.Common.Formatters
5 | {
6 | [Formatter("null")]
7 | public class NullFormatter : IFormatter
8 | {
9 | public FormattedEvent Format(
10 | string target,
11 | string data,
12 | Dictionary sessionStorage)
13 | {
14 | return new(target, 0, true, "正在运行命令", data);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-common/rmbox-plugin-common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Ruminoid.Toolbox.Plugins.Common
6 |
7 |
8 |
9 |
10 | false
11 | runtime
12 |
13 |
14 |
15 |
16 |
17 | false
18 | runtime
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/FFmpegMeta.cs:
--------------------------------------------------------------------------------
1 | using Ruminoid.Toolbox.Core;
2 |
3 | namespace Ruminoid.Toolbox.Plugins.FFmpeg
4 | {
5 | [RmboxPlugin]
6 | public class FFmpegMeta : IMeta
7 | {
8 | public string Name => "FFmpeg";
9 | public string Description => "提供了 FFmpeg 的基础功能和格式器。";
10 | public string Author => "Il Harper";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Formatters/FFmpegFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text.RegularExpressions;
3 | using Ruminoid.Toolbox.Formatting;
4 |
5 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Formatters
6 | {
7 | [Formatter("ffmpeg*")]
8 | public class FFmpegFormatter : IFormatter
9 | {
10 | public FormattedEvent Format(
11 | string target,
12 | string data,
13 | Dictionary sessionStorage)
14 | {
15 | Regex progressRegex = new Regex(@"time=(.*) bitrate=");
16 | Match match = progressRegex.Match(data);
17 | if (string.IsNullOrWhiteSpace(match.Value)) return null;
18 |
19 | return new(target, 0, true, $"已编码长度:{match.Groups[1].Value}", "");
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/BilibiliLoudnormOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.BilibiliLoudnormOperation",
11 | "哔哩哔哩音频标准化",
12 | "用于在哔哩哔哩投稿的音频标准化。视频也可以使用。",
13 | RateValue.FourStars,
14 | "音频处理")]
15 | public class BilibiliLoudnormOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new()
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y -c:v copy {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-af loudnorm=i=-9:tp=-2 -b:a 320k";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_bilibili"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegAddAudioTrackOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegAddAudioTrackOperation",
11 | "添加音轨",
12 | "为MKV视频添加另外一条音轨。",
13 | RateValue.ThreeStars,
14 | "封装转换")]
15 | public class FFmpegAddAudioTrackOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken muxSection =
20 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.MuxConfigSection"];
21 |
22 | string videoPath = PathExtension.GetFullPathOrEmpty(muxSection["video"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string audioPath = PathExtension.GetFullPathOrEmpty(muxSection["audio"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 | string outputPath = PathExtension.GetFullPathOrEmpty(muxSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
25 |
26 | #region 自定义参数
27 |
28 | JToken customArgsSection =
29 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
30 |
31 | string customArgs = customArgsSection["args"]?.ToObject();
32 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
33 |
34 | #endregion
35 |
36 | return new List
37 | {
38 | new(
39 | "ffmpeg",
40 | $"-y -i {videoPath} -i {audioPath} {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
41 | "ffmpeg")
42 | };
43 | }
44 |
45 | private const string DefaultArgs = "-map 0 -map 1:a -c:v copy";
46 |
47 | public Dictionary RequiredConfigSections => new()
48 | {
49 | {"Ruminoid.Toolbox.Plugins.Common.ConfigSections.MuxConfigSection", new JObject()},
50 | {
51 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
52 | JObject.FromObject(new
53 | {
54 | default_args = DefaultArgs
55 | })
56 | }
57 | };
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegAddMuteAudioTrackOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegAddMuteAudioTrackOperation",
11 | "添加静音音轨",
12 | "为视频轨添加静音音轨。",
13 | RateValue.ThreeStars,
14 | "视频处理")]
15 | public class FFmpegAddMuteAudioTrackOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new List
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-y -i {inputPath} {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-f lavfi -i anullsrc=channel_layout=stereo:sample_rate=44100 -c:v copy -shortest";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_mute"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegAudioSilenceRemoveOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegAudioSilenceRemoveOperation",
11 | "去除静音",
12 | "将音频中的无声部分裁剪去除。",
13 | RateValue.ThreeStars,
14 | "音频处理")]
15 | public class FFmpegAudioSilenceRemoveOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new()
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y -c:v copy -af {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = @"silenceremove=stop_periods=-1:stop_duration=1:stop_threshold=-40dB";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_processed"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegClearSubtitleOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegClearSubtitleOperation",
11 | "消除内封字幕",
12 | "消除媒体文件中的内封字幕,但保留所有媒体轨道。",
13 | RateValue.ThreeStars,
14 | "封装转换")]
15 | public class FFmpegClearSubtitleOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new()
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-map 0 -map -0:s -c copy";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {ConfigSectionBase.IOConfigSectionId, new JObject()},
49 | {
50 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
51 | JObject.FromObject(new
52 | {
53 | default_args = DefaultArgs
54 | })
55 | }
56 | };
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegEncodeOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegEncodeOperation",
11 | "FFmpeg 压制",
12 | "使用 FFmpeg 进行媒体压制(重编码)。",
13 | RateValue.ThreeStars,
14 | "通用")]
15 | public class FFmpegEncodeOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new List
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_encoded",
53 | output_extension = ".mp4"
54 | })
55 | },
56 | {
57 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
58 | JObject.FromObject(new
59 | {
60 | default_args = DefaultArgs
61 | })
62 | }
63 | };
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegExtractAudioOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegExtractAudioOperation",
11 | "抽取音频",
12 | "使用 FFmpeg 抽取音频。",
13 | RateValue.ThreeStars,
14 | "封装转换")]
15 | public class FFmpegExtractAudioOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new List
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-vn -sn -c:a copy -map 0:a:0";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_audio",
53 | output_extension = ".m4a"
54 | })
55 | },
56 | {
57 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
58 | JObject.FromObject(new
59 | {
60 | default_args = DefaultArgs
61 | })
62 | }
63 | };
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegExtractVideoOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegExtractVideoOperation",
11 | "抽取视频",
12 | "使用 FFmpeg 抽取视频。",
13 | RateValue.ThreeStars,
14 | "封装转换")]
15 | public class FFmpegExtractVideoOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new List
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-c:v copy -an -sn -map 0:v:0";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_video"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegFillBlackOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegFillBlackOperation",
11 | "移除视频画面(使画面黑屏)",
12 | "将视频画面变为黑屏。",
13 | RateValue.ThreeStars,
14 | "视频处理")]
15 | public class FFmpegFillBlackOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new List
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-y -i {inputPath} -c:a copy {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-vf drawbox=color=black:t=fill";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_novideo"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegLoudnormOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegLoudnormOperation",
11 | "音频标准化",
12 | "对音频进行标准化。视频也可以使用。",
13 | RateValue.ThreeStars,
14 | "音频处理")]
15 | public class FFmpegLoudnormOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new()
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-i {inputPath} -y -c:v copy -af {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "loudnorm";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_loudnorm"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegRemoveAudioTrackOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegRemoveAudioTrackOperation",
11 | "移除音频轨",
12 | "移除视频中的音频轨。视频画面和字幕会保留。",
13 | RateValue.ThreeStars,
14 | "视频处理")]
15 | public class FFmpegRemoveAudioTrackOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new List
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-y -i {inputPath} {(useCustomArgs ? customArgs : DefaultArgs)} {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-map 0 -map -0:a -c copy";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_noaudio"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Operations/FFmpegVfrFixOperation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Common2.Utils.UserTypes;
4 | using Ruminoid.Toolbox.Core;
5 | using Ruminoid.Toolbox.Utils.Extensions;
6 |
7 | namespace Ruminoid.Toolbox.Plugins.FFmpeg.Operations
8 | {
9 | [Operation(
10 | "Ruminoid.Toolbox.Plugins.FFmpeg.Operations.FFmpegVfrFixOperation",
11 | "修复音画不同步视频",
12 | "修复音画不同步(VFR)视频。",
13 | RateValue.ThreeStars,
14 | "视频处理")]
15 | public class FFmpegVfrFixOperation : IOperation
16 | {
17 | public List Generate(Dictionary sectionData)
18 | {
19 | JToken ioSection =
20 | sectionData[ConfigSectionBase.IOConfigSectionId];
21 |
22 | string inputPath = PathExtension.GetFullPathOrEmpty(ioSection["input"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
23 | string outputPath = PathExtension.GetFullPathOrEmpty(ioSection["output"]?.ToObject() ?? string.Empty).EscapePathStringForArg();
24 |
25 | #region 自定义参数
26 |
27 | JToken customArgsSection =
28 | sectionData["Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection"];
29 |
30 | string customArgs = customArgsSection["args"]?.ToObject();
31 | bool useCustomArgs = customArgsSection["use_custom_args"]?.ToObject() ?? false;
32 |
33 | #endregion
34 |
35 | return new()
36 | {
37 | new(
38 | "ffmpeg",
39 | $"-y -i {inputPath} -c:v libx264 -vsync cfr {(useCustomArgs ? customArgs : DefaultArgs)} -af aresample=async=1000 -c:a aac {outputPath}",
40 | "ffmpeg")
41 | };
42 | }
43 |
44 | private const string DefaultArgs = "-crf 21";
45 |
46 | public Dictionary RequiredConfigSections => new()
47 | {
48 | {
49 | ConfigSectionBase.IOConfigSectionId,
50 | JToken.FromObject(new
51 | {
52 | output_suffix = "_fixed"
53 | })
54 | },
55 | {
56 | "Ruminoid.Toolbox.Plugins.Common.ConfigSections.CustomArgsConfigSection",
57 | JObject.FromObject(new
58 | {
59 | default_args = DefaultArgs
60 | })
61 | }
62 | };
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Resources/Markdowns/FFmpegCopyOperation.md:
--------------------------------------------------------------------------------
1 | # 格式转换(不压制)
2 |
3 | 使用 `FFmpeg` 进行视频格式的转换(封装)。
4 |
5 | ## 介绍
6 |
7 | 这项操作可以使用 `FFmpeg` 实现媒体流封装容器的转换,即在不重编码任何媒体流的情况下实现文件格式的转换。
8 |
9 | ## 使用场景
10 |
11 | - `flv` 格式文件转换 `mp4` 格式
12 |
13 | `flv` 格式文件无法导入某些媒体编辑软件,如 Premiere Pro。你可以使用这个操作在不降低媒体质量的同时转换文件格式。
14 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/Resources/Markdowns/FFmpegMetaRotateOperation.md:
--------------------------------------------------------------------------------
1 | # 画面方向纠正
2 |
3 | 纠正由于压制导致错误显示的画面方向。
4 |
5 | ## 介绍
6 |
7 | 如果你发现你的视频在 Rmbox 进行处理之后,或放入 Premiere 等软件之后「画面反转」,说明你的画面本来就是反的。
8 |
9 | 若只是想正常观看视频,你可以使用本操作直接修复。本操作不经过重编码,不会耗时。
10 |
11 | 若想要在 Premiere 等软件中进行剪辑,请直接使用软件的「旋转」功能对素材进行旋转。使用本操作进行处理将不会有任何效果。
12 |
13 | ## 自定义旋转角度
14 |
15 | 默认的旋转角度为 180°。你可以在「自定义参数」配置项中更改。
16 |
17 | 要注意这是「要旋转」的角度。如果你的视频发生了「向右旋转 90°」的错误,你需要将旋转参数改为 270° 以修复。
18 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-ffmpeg/rmbox-plugin-ffmpeg.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Ruminoid.Toolbox.Plugins.FFmpeg
6 |
7 |
8 |
9 |
10 | false
11 | runtime
12 |
13 |
14 |
15 |
16 |
17 | false
18 | runtime
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/ViewModels/HwEncCodecConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using Newtonsoft.Json;
4 | using ReactiveUI;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.ViewModels
7 | {
8 | [JsonObject(MemberSerialization.OptIn)]
9 | public class HwEncCodecConfigSectionViewModel : ReactiveObject
10 | {
11 | #region List
12 |
13 | private readonly Dictionary _codecDictionary = new()
14 | {
15 | {"h264", "AVC(H.264)"},
16 | {"h265", "HEVC(H.265)"}
17 | };
18 |
19 | private List _codecList;
20 |
21 | public List CodecList => _codecList ??= _codecDictionary.Values.ToList();
22 |
23 | #endregion
24 |
25 | [JsonProperty("codec")]
26 | private string _codec = "h264";
27 |
28 | public string Codec
29 | {
30 | get => _codecDictionary[_codec];
31 | set
32 | {
33 | string key = _codecDictionary.FirstOrDefault(x => x.Value == value).Key;
34 |
35 | if (key == _codec) return;
36 |
37 | _codec = key;
38 | this.RaisePropertyChanged(nameof(Codec));
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/ViewModels/HwEncCoreConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using Newtonsoft.Json;
6 | using ReactiveUI;
7 | using Ruminoid.Toolbox.Utils;
8 |
9 | namespace Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.ViewModels
10 | {
11 | [JsonObject(MemberSerialization.OptIn)]
12 | public class HwEncCoreConfigSectionViewModel : ReactiveObject
13 | {
14 | #region List
15 |
16 | public List CoreList { get; } =
17 | Directory.EnumerateFiles(
18 | StorageHelper.GetSectionFolderPath("tools"),
19 | "*")
20 | .Select(Path.GetFileName)
21 | .Select(x => x.ToLower())
22 | .Where(x =>
23 | x.StartsWith("nvencc") ||
24 | x.StartsWith("qsvencc") ||
25 | x.StartsWith("vceencc"))
26 | .Where(x => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || x.EndsWith(".exe"))
27 | .Select(x => x.EndsWith(".exe") ? x[..^4] : x)
28 | .ToList();
29 |
30 | #endregion
31 |
32 | [JsonProperty("core")]
33 | private string _core = "nvencc64";
34 |
35 | public string Core
36 | {
37 | get => _core;
38 | set => this.RaiseAndSetIfChanged(ref _core, value);
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/ViewModels/HwEncQualityConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ReactiveUI;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.ViewModels
5 | {
6 | [JsonObject(MemberSerialization.OptIn)]
7 | public class HwEncQualityConfigSectionViewModel : ReactiveObject
8 | {
9 | #region Data
10 |
11 | [JsonProperty("encode_mode")]
12 | private string _encodeMode = "cqp";
13 |
14 | public string EncodeMode
15 | {
16 | get => _encodeMode;
17 | set => this.RaiseAndSetIfChanged(ref _encodeMode, value);
18 | }
19 |
20 | [JsonProperty("cqp_value")]
21 | private string _cqpValue = "16:18:20";
22 |
23 | public string CqpValue
24 | {
25 | get => _cqpValue;
26 | set => this.RaiseAndSetIfChanged(ref _cqpValue, value);
27 | }
28 |
29 | [JsonProperty("2pass_value")]
30 | private int _twoPassValue = 5000;
31 |
32 | public int TwoPassValue
33 | {
34 | get => _twoPassValue;
35 | set => this.RaiseAndSetIfChanged(ref _twoPassValue, value);
36 | }
37 |
38 | #endregion
39 |
40 | #region Commands
41 |
42 | public void ApplyCqpPreset(string value) => CqpValue = value;
43 |
44 | #endregion
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/Views/HwEncCodecConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
23 |
24 |
27 |
28 |
29 |
32 |
33 |
34 | 核心
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 | 选择视频编码。如果你不知道这是什么,请选择AVC(H.264).
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/Views/HwEncCodecConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.HwEncCodecConfigSection",
10 | "编码")]
11 | public class HwEncCodecConfigSection : ConfigSectionBase
12 | {
13 | public HwEncCodecConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public HwEncCodecConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as HwEncCodecConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/Views/HwEncCoreConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
23 |
24 |
27 |
28 |
29 |
32 |
33 |
34 | 核心
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 | 选择与你的显卡对应的显卡压制核心。下面是一份对应列表:
NVIDIA:nvencc64
Intel:qsvencc64
如果你使用 AMD 显卡,请使用 CPU 压制。
如果你有 MOD 版的显卡压制核心,你可以将其放在 Toolbox 安装位置的「tools」文件夹下,程序会在启动时自动扫描。
46 |
47 |
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/Views/HwEncCoreConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.HwEncCoreConfigSection",
10 | "核心")]
11 | public class HwEncCoreConfigSection : ConfigSectionBase
12 | {
13 | public HwEncCoreConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public HwEncCoreConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as HwEncCoreConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/ConfigSections/Views/HwEncQualityConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.HwEnc.ConfigSections.HwEncQualityConfigSection",
10 | "视频质量")]
11 | public class HwEncQualityConfigSection : ConfigSectionBase
12 | {
13 | public HwEncQualityConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public HwEncQualityConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as HwEncQualityConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/Formatters/HwEncFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text;
3 | using Ruminoid.Toolbox.Formatting;
4 | using Ruminoid.Toolbox.Utils.Extensions;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.HwEnc.Formatters
7 | {
8 | [Formatter("nvencc*|qsvencc*|vceencc*")]
9 | public class HwEncFormatter : IFormatter
10 | {
11 | public FormattedEvent Format(
12 | string target,
13 | string data,
14 | Dictionary sessionStorage)
15 | {
16 | bool parseProgress = double.TryParse(data.GetMidString("[", "%] "), out double progress);
17 | string frames = data.GetMidString("%] ", " frames: ");
18 | //string fps = data.GetMidString(" frames, ", " fps, ");
19 | string speed = data.GetMidString(" fps, ", " kb/s, remain ");
20 | string eta = data.GetMidString(" kb/s, remain ", ", GPU");
21 | string estSize = data.GetMidString(", est out size ", "MB");
22 |
23 | StringBuilder summaryBuilder = new();
24 | StringBuilder detailBuilder = new();
25 |
26 | if (parseProgress)
27 | {
28 | summaryBuilder.Append(progress.ToString("F1"));
29 | summaryBuilder.Append("% - ");
30 | }
31 |
32 | summaryBuilder.Append($"正在使用 {target} 压制 - ");
33 | summaryBuilder.Append(speed);
34 | summaryBuilder.Append(" kb/s");
35 |
36 | if (!string.IsNullOrWhiteSpace(frames))
37 | {
38 | detailBuilder.Append("编码 ");
39 | detailBuilder.Append(frames);
40 | detailBuilder.Append(" 帧");
41 | }
42 |
43 | if (!string.IsNullOrWhiteSpace(eta))
44 | {
45 | detailBuilder.Append(",剩余 ");
46 | detailBuilder.Append(eta);
47 | }
48 |
49 | return new(
50 | target,
51 | progress,
52 | !parseProgress,
53 | summaryBuilder.ToString(),
54 | detailBuilder.ToString());
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/HwEncMeta.cs:
--------------------------------------------------------------------------------
1 | using Ruminoid.Toolbox.Core;
2 |
3 | namespace Ruminoid.Toolbox.Plugins.HwEnc
4 | {
5 | [RmboxPlugin]
6 | public class HwEncMeta : IMeta
7 | {
8 | public string Name => "显卡压制";
9 | public string Description => "提供了显卡压制(NVEnc/QSVEnc/VCEEnc)的基础功能、操作和格式器。";
10 | public string Author => "Il Harper";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-hwenc/rmbox-plugin-hwenc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Ruminoid.Toolbox.Plugins.HwEnc
6 |
7 |
8 |
9 |
10 | false
11 | runtime
12 |
13 |
14 |
15 |
16 |
17 | false
18 | runtime
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/ViewModels/X264CoreConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 | using Newtonsoft.Json;
6 | using ReactiveUI;
7 | using Ruminoid.Toolbox.Utils;
8 |
9 | namespace Ruminoid.Toolbox.Plugins.X264.ConfigSections.ViewModels
10 | {
11 | [JsonObject(MemberSerialization.OptIn)]
12 | public class X264CoreConfigSectionViewModel : ReactiveObject
13 | {
14 | #region List
15 |
16 | public List CoreList { get; } =
17 | Directory.EnumerateFiles(
18 | StorageHelper.GetSectionFolderPath("tools"),
19 | "*")
20 | .Select(Path.GetFileName)
21 | .Where(x => x.StartsWith("x264"))
22 | .Where(x => !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || x.EndsWith(".exe"))
23 | .Select(x => x.EndsWith(".exe") ? x[..^4] : x)
24 | .ToList();
25 |
26 | #endregion
27 |
28 | [JsonProperty("core")]
29 | private string _core = "x264";
30 |
31 | public string Core
32 | {
33 | get => _core;
34 | set => this.RaiseAndSetIfChanged(ref _core, value);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/ViewModels/X264DemuxerConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 | using ReactiveUI;
4 |
5 | namespace Ruminoid.Toolbox.Plugins.X264.ConfigSections.ViewModels
6 | {
7 | [JsonObject(MemberSerialization.OptIn)]
8 | public class X264DemuxerConfigSectionViewModel : ReactiveObject
9 | {
10 | public List DemuxerList { get; } = new() {"auto", "ffms", "lavf", "avs", "raw", "y4m"};
11 |
12 | [JsonProperty("demuxer")]
13 | private string _demuxer = "auto";
14 |
15 | public string Demuxer
16 | {
17 | get => _demuxer;
18 | set => this.RaiseAndSetIfChanged(ref _demuxer, value);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/ViewModels/X264EncodeQualityConfigSectionViewModel.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using ReactiveUI;
3 |
4 | namespace Ruminoid.Toolbox.Plugins.X264.ConfigSections.ViewModels
5 | {
6 | [JsonObject(MemberSerialization.OptIn)]
7 | public class X264EncodeQualityConfigSectionViewModel : ReactiveObject
8 | {
9 | #region Data
10 |
11 | [JsonProperty("encode_mode")]
12 | private string _encodeMode = "crf";
13 |
14 | public string EncodeMode
15 | {
16 | get => _encodeMode;
17 | set => this.RaiseAndSetIfChanged(ref _encodeMode, value);
18 | }
19 |
20 | [JsonProperty("crf_value")]
21 | private double _crfValue = 21;
22 |
23 | public double CrfValue
24 | {
25 | get => _crfValue;
26 | set => this.RaiseAndSetIfChanged(ref _crfValue, value);
27 | }
28 |
29 | [JsonProperty("2pass_value")]
30 | private int _twoPassValue = 5000;
31 |
32 | public int TwoPassValue
33 | {
34 | get => _twoPassValue;
35 | set => this.RaiseAndSetIfChanged(ref _twoPassValue, value);
36 | }
37 |
38 | #endregion
39 |
40 | #region Commands
41 |
42 | public void ApplyCrfPreset(double value) => CrfValue = value;
43 |
44 | public void ApplyTwoPassPreset(int value) => TwoPassValue = value;
45 |
46 | #endregion
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/Views/X264CoreConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
23 |
24 |
27 |
28 |
29 |
32 |
33 |
34 | 核心
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 | 如果你有 MOD 版的 X264/X265 核心,你可以将其放在 Toolbox 安装位置的「tools」文件夹下,程序会在启动时自动扫描。
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/Views/X264CoreConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.X264.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.X264.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.X264.ConfigSections.X264CoreConfigSection",
10 | "核心")]
11 | public class X264CoreConfigSection : ConfigSectionBase
12 | {
13 | public X264CoreConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public X264CoreConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as X264CoreConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/Views/X264DemuxerConfigSection.axaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
23 |
24 |
27 |
28 |
29 |
32 |
33 |
34 | 分离器
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 | 如果你不知道这是什么,请不要修改它。
如果你压制的视频音画不同步,请将其修改为lavf。
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/Views/X264DemuxerConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.X264.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.X264.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.X264.ConfigSections.X264DemuxerConfigSection",
10 | "分离器")]
11 | public class X264DemuxerConfigSection : ConfigSectionBase
12 | {
13 | public X264DemuxerConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public X264DemuxerConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | public override object Config => DataContext as X264DemuxerConfigSectionViewModel;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/ConfigSections/Views/X264EncodeQualityConfigSection.axaml.cs:
--------------------------------------------------------------------------------
1 | using Avalonia.Markup.Xaml;
2 | using Newtonsoft.Json.Linq;
3 | using Ruminoid.Toolbox.Core;
4 | using Ruminoid.Toolbox.Plugins.X264.ConfigSections.ViewModels;
5 |
6 | namespace Ruminoid.Toolbox.Plugins.X264.ConfigSections.Views
7 | {
8 | [ConfigSection(
9 | "Ruminoid.Toolbox.Plugins.X264.ConfigSections.X264EncodeQualityConfigSection",
10 | "视频质量")]
11 | public class X264EncodeQualityConfigSection : ConfigSectionBase
12 | {
13 | public X264EncodeQualityConfigSection()
14 | {
15 | InitializeComponent();
16 | }
17 |
18 | public X264EncodeQualityConfigSection(
19 | JToken sectionConfig)
20 | {
21 | InitializeComponent();
22 | }
23 |
24 | private void InitializeComponent()
25 | {
26 | AvaloniaXamlLoader.Load(this);
27 | }
28 |
29 | #region Data
30 |
31 | public override X264EncodeQualityConfigSectionViewModel Config => DataContext as X264EncodeQualityConfigSectionViewModel;
32 |
33 | #endregion
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/Formatters/X26xFormatter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Text;
3 | using Ruminoid.Toolbox.Formatting;
4 | using Ruminoid.Toolbox.Utils.Extensions;
5 |
6 | // ReSharper disable InvertIf
7 |
8 | namespace Ruminoid.Toolbox.Plugins.X264.Formatters
9 | {
10 | [Formatter("x26*")]
11 | public class X26xFormatter : IFormatter
12 | {
13 | public FormattedEvent Format(
14 | string target,
15 | string data,
16 | Dictionary sessionStorage)
17 | {
18 | bool parseProgress = double.TryParse(data.GetMidString("[", "%] "), out double progress);
19 | string frames = data.GetMidString("%] ", " frames, ");
20 | //string fps = data.GetMidString(" frames, ", " fps, ");
21 | string speed = data.GetMidString(" fps, ", " kb/s, ");
22 | string size = data.GetMidString(" kb/s, ", " MB, eta ");
23 | string eta = data.GetMidString(" MB, eta ", ", est.size ");
24 | string estSize = data.GetMidString(", est.size ", "MB");
25 |
26 | StringBuilder summaryBuilder = new();
27 | StringBuilder detailBuilder = new();
28 |
29 | if (parseProgress)
30 | {
31 | summaryBuilder.Append(progress.ToString("F1"));
32 | summaryBuilder.Append("% - ");
33 | }
34 |
35 | summaryBuilder.Append($"正在使用 {target} 压制 - ");
36 | summaryBuilder.Append(speed);
37 | summaryBuilder.Append(" kb/s");
38 |
39 | if (!string.IsNullOrWhiteSpace(frames))
40 | {
41 | detailBuilder.Append("编码 ");
42 | detailBuilder.Append(frames);
43 | detailBuilder.Append(" 帧");
44 | }
45 |
46 | if (!string.IsNullOrWhiteSpace(size) &&
47 | !string.IsNullOrWhiteSpace(estSize))
48 | {
49 | detailBuilder.Append(",大小 ");
50 | detailBuilder.Append(size);
51 | detailBuilder.Append('/');
52 | detailBuilder.Append(estSize);
53 | detailBuilder.Append(" MB");
54 | }
55 |
56 | if (!string.IsNullOrWhiteSpace(eta))
57 | {
58 | detailBuilder.Append(",剩余 ");
59 | detailBuilder.Append(eta);
60 | }
61 |
62 | return new(
63 | target,
64 | progress,
65 | !parseProgress,
66 | summaryBuilder.ToString(),
67 | detailBuilder.ToString());
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/Resources/Markdowns/X264EncodeOperation.md:
--------------------------------------------------------------------------------
1 | # CPU 压制
2 |
3 | 使用 CPU 进行 H.264(AVC)视频压制。
4 |
5 | ## 介绍
6 |
7 | 这项操作使用 CPU 进行 H.264(AVC)视频压制,以达到最高质量压制。
8 |
9 | 如果需要 X265 压制,请使用「X265 压制」操作。
10 |
11 | 如果需要带有显卡加速的压制,请使用「显卡压制」操作。
12 |
13 | ## 使用
14 |
15 | 请参阅「关于」选项卡中的视频教程。
16 |
17 | ## 核心
18 |
19 | 使用 `x264` 二进制文件进行压制。默认使用 VideoLAN 提供的官方 `x264` 版本。你也可以使用下方推荐的第三方 `x264` 版本。
20 |
21 | - [x264 7mod](https://maruko.appinn.me/7mod.html)(推荐)——目前最好用的 `x264` 版本,在极大地优化了性能的同时添加了 [7mod 专属参数](https://maruko.appinn.me/7mod_feature.html)。
22 |
23 | - [down.7086.in](https://down.7086.in/)——该网站提供了 `x264` Yuuki 版本。
24 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/X264Meta.cs:
--------------------------------------------------------------------------------
1 | using Ruminoid.Toolbox.Core;
2 |
3 | namespace Ruminoid.Toolbox.Plugins.X264
4 | {
5 | [RmboxPlugin]
6 | public class X264Meta : IMeta
7 | {
8 | public string Name => "X264";
9 | public string Description => "提供了 X264 的基础功能、压制操作和格式器。";
10 | public string Author => "Il Harper";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugins/rmbox-plugin-x264/rmbox-plugin-x264.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Ruminoid.Toolbox.Plugins.X264
6 |
7 |
8 |
9 |
10 | false
11 | runtime
12 |
13 |
14 |
15 |
16 |
17 | false
18 | runtime
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/rmbenv/.gitignore:
--------------------------------------------------------------------------------
1 | # Binaries for programs and plugins
2 | *.exe
3 | *.exe~
4 | *.dll
5 | *.so
6 | *.dylib
7 |
8 | # Test binary, built with `go test -c`
9 | *.test
10 |
11 | # Output of the go coverage tool, specifically when used with LiteIDE
12 | *.out
13 |
14 | # Dependency directories (remove the comment below to include it)
15 | # vendor/
16 |
17 | # Exe resources
18 | /resource.syso
19 |
--------------------------------------------------------------------------------
/src/rmbenv/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/Ruminoid/Toolbox/rmbenv
2 |
3 | go 1.15
4 |
5 | require github.com/josephspurrier/goversioninfo v1.2.0 // indirect
6 |
--------------------------------------------------------------------------------
/src/rmbenv/go.sum:
--------------------------------------------------------------------------------
1 | github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
2 | github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
4 | github.com/josephspurrier/goversioninfo v1.2.0 h1:tpLHXAxLHKHg/dCU2AAYx08A4m+v9/CWg6+WUvTF4uQ=
5 | github.com/josephspurrier/goversioninfo v1.2.0/go.mod h1:AGP2a+Y/OVJZ+s6XM4IwFUpkETwvn0orYurY8qpw1+0=
6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
7 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
8 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
10 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
11 |
--------------------------------------------------------------------------------
/src/rmbenv/main.go:
--------------------------------------------------------------------------------
1 | //go:generate goversioninfo
2 |
3 | package main
4 |
5 | import (
6 | "fmt"
7 | "log"
8 | "os"
9 | "os/exec"
10 | "path"
11 | "path/filepath"
12 | "runtime"
13 | )
14 |
15 | func main() {
16 | var suffix string
17 | if runtime.GOOS == "windows" {
18 | suffix = ".exe"
19 | } else {
20 | suffix = ""
21 | }
22 | filename := "rmbox/rmbox" + suffix
23 |
24 | basePath, err := filepath.Abs(filepath.Dir(os.Args[0]))
25 |
26 | if err != nil {
27 | log.Printf("解析进程路径 %v 时出现错误。", filename)
28 | fmt.Println(err)
29 | b := make([]byte, 1)
30 | _, _ = os.Stdin.Read(b)
31 | os.Exit(1)
32 | }
33 |
34 | filename = path.Join(basePath, filename)
35 |
36 | _, err = os.Stat(filename)
37 |
38 | if err != nil {
39 | log.Printf("未寻找到 %v 文件。", filename)
40 | fmt.Println(err)
41 | b := make([]byte, 1)
42 | _, _ = os.Stdin.Read(b)
43 | os.Exit(1)
44 | }
45 |
46 | cmd := exec.Command(filename, os.Args[1:]...)
47 | cmd.Stderr = os.Stderr
48 | cmd.Stdout = os.Stdout
49 |
50 | _ = cmd.Run()
51 | }
52 |
--------------------------------------------------------------------------------
/src/rmbenv/versioninfo.json:
--------------------------------------------------------------------------------
1 | {
2 | "FixedFileInfo": {
3 | "FileVersion": {
4 | "Major": 0,
5 | "Minor": 3,
6 | "Patch": 0,
7 | "Build": 0
8 | },
9 | "ProductVersion": {
10 | "Major": 0,
11 | "Minor": 0,
12 | "Patch": 3,
13 | "Build": 0
14 | },
15 | "FileFlagsMask": "3f",
16 | "FileFlags ": "00",
17 | "FileOS": "040004",
18 | "FileType": "01",
19 | "FileSubType": "00"
20 | },
21 | "StringFileInfo": {
22 | "Comments": "rmbenv",
23 | "CompanyName": "Ruminoid",
24 | "FileDescription": "rmbenv",
25 | "FileVersion": "v0.3.0.0",
26 | "InternalName": "rmbenv",
27 | "LegalCopyright": "2021 Il Harper",
28 | "LegalTrademarks": "2021 Il Harper",
29 | "OriginalFilename": "rmbenv",
30 | "PrivateBuild": "v0.3.0.0",
31 | "ProductName": "rmbenv",
32 | "ProductVersion": "v0.3.0.0",
33 | "SpecialBuild": "v0.3.0.0"
34 | },
35 | "VarFileInfo": {
36 | "Translation": {
37 | "LangID": "0409",
38 | "CharsetID": "04B0"
39 | }
40 | },
41 | "IconPath": "../../common/Assets/rmbox.ico",
42 | "ManifestPath": "../../common/meta/rmbenv.exe.manifest"
43 | }
44 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/Interfaces/ConfigSectionBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia.Controls;
3 |
4 | namespace Ruminoid.Toolbox.Core
5 | {
6 | public abstract class ConfigSectionBase : UserControl
7 | {
8 | public abstract object Config { get; }
9 |
10 | public string CurrentHelpText { get; }
11 |
12 | #region Consts
13 |
14 | // ReSharper disable InconsistentNaming
15 |
16 | public const string IOConfigSectionId = "Ruminoid.Toolbox.Plugins.Common.ConfigSections.IOConfigSection";
17 |
18 | public const string BatchIOConfigSectionId = "Ruminoid.Toolbox.Shell.Utils.ConfigSections.BatchIOConfigSection";
19 |
20 | public const string IntroConfigSectionId = "Ruminoid.Toolbox.Plugins.Common.ConfigSections.IntroConfigSection";
21 |
22 | // ReSharper restore InconsistentNaming
23 |
24 | #endregion
25 | }
26 |
27 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
28 | public sealed class ConfigSectionAttribute : Attribute
29 | {
30 | public ConfigSectionAttribute(
31 | string id,
32 | string name)
33 | {
34 | Id = id;
35 | Name = name;
36 | }
37 |
38 | public readonly string Id;
39 |
40 | public readonly string Name;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/Interfaces/IMeta.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ruminoid.Toolbox.Core
4 | {
5 | public interface IMeta
6 | {
7 | public string Name { get; }
8 |
9 | public string Description { get; }
10 |
11 | public string Author { get; }
12 | }
13 |
14 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
15 | public sealed class RmboxPluginAttribute : Attribute
16 | {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/Interfaces/IOperation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json.Linq;
4 | using Ruminoid.Common2.Utils.UserTypes;
5 |
6 | namespace Ruminoid.Toolbox.Core
7 | {
8 | public interface IOperation
9 | {
10 | public List Generate(Dictionary sectionData);
11 |
12 | public Dictionary RequiredConfigSections { get; }
13 | }
14 |
15 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
16 | public sealed class OperationAttribute : Attribute
17 | {
18 | public OperationAttribute(
19 | string id,
20 | string name,
21 | string description,
22 | RateValue rate,
23 | string category)
24 | {
25 | Id = id;
26 | Name = name;
27 | Description = description;
28 | Rate = rate;
29 | Category = category;
30 | }
31 |
32 | public readonly string Id;
33 |
34 | public readonly string Name;
35 |
36 | public readonly string Description;
37 |
38 | public readonly Rate Rate;
39 |
40 | public readonly string Category;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/OperationException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ruminoid.Toolbox.Core
4 | {
5 | [Serializable]
6 | public class OperationException : Exception
7 | {
8 | #region Constructor
9 |
10 | public OperationException(
11 | string message,
12 | Type operationType,
13 | Exception inner = null) : base(message, inner)
14 | {
15 | OperationType = operationType;
16 | }
17 |
18 | #endregion
19 |
20 | public Type OperationType { get; }
21 |
22 | public override string ToString()
23 | {
24 | return $"操作 {OperationType.Name} 引发了异常:\n{base.ToString()}";
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/ProcessRunnerException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ruminoid.Toolbox.Core
4 | {
5 | [Serializable]
6 | public class ProcessRunnerException : Exception
7 | {
8 | public ProcessRunnerException()
9 | {
10 | }
11 |
12 | public ProcessRunnerException(string message) : base(message)
13 | {
14 | }
15 |
16 | public ProcessRunnerException(string message, Exception inner) : base(message, inner)
17 | {
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/ProjectParseException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Ruminoid.Toolbox.Core
4 | {
5 | [Serializable]
6 | public class ProjectParseException : Exception
7 | {
8 | public ProjectParseException()
9 | {
10 | }
11 |
12 | public ProjectParseException(string message) : base(message)
13 | {
14 | }
15 |
16 | public ProjectParseException(string message, Exception inner) : base(message, inner)
17 | {
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Core/TaskCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Ruminoid.Toolbox.Core
2 | {
3 | public record TaskCommand
4 | {
5 | public TaskCommand()
6 | {
7 | }
8 |
9 | public TaskCommand(string target, string args, string formatter)
10 | {
11 | Target = target;
12 | Args = args;
13 | Formatter = formatter;
14 | }
15 |
16 | public readonly string Target = "";
17 | public readonly string Args = "";
18 | public readonly string Formatter = "";
19 |
20 | public static implicit operator (string Target, string Args, string Formatter)(TaskCommand command) =>
21 | (command.Target, command.Args, command.Formatter);
22 |
23 | public static implicit operator TaskCommand((string Target, string Args, string Formatter) command) =>
24 | new(command.Target, command.Args, command.Formatter);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Formatting/FormattedEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.Serialization;
3 | using System.Text;
4 | using Newtonsoft.Json;
5 |
6 | // ReSharper disable ClassWithVirtualMembersNeverInherited.Global
7 |
8 | namespace Ruminoid.Toolbox.Formatting
9 | {
10 | [Serializable]
11 | [DataContract]
12 | [JsonObject(MemberSerialization.OptIn)]
13 | public record FormattedEvent
14 | {
15 | public FormattedEvent()
16 | {
17 | }
18 |
19 | public FormattedEvent(
20 | string target,
21 | double progress,
22 | bool isIndeterminate,
23 | string summary,
24 | string detail) =>
25 | (
26 | Target,
27 | Progress,
28 | IsIndeterminate,
29 | Summary,
30 | Detail
31 | ) =
32 | (
33 | target,
34 | progress,
35 | isIndeterminate,
36 | summary,
37 | detail
38 | );
39 |
40 | [DataMember]
41 | [JsonProperty("target")]
42 | public string Target;
43 |
44 | ///
45 | /// 在0-100之间用来表示进度的浮点数。
46 | ///
47 | [DataMember]
48 | [JsonProperty("progress")]
49 | public double Progress;
50 |
51 | [DataMember]
52 | [JsonProperty("isIndeterminate")]
53 | public bool IsIndeterminate;
54 |
55 | [DataMember]
56 | [JsonProperty("summary")]
57 | public string Summary;
58 |
59 | [DataMember]
60 | [JsonProperty("detail")]
61 | public string Detail;
62 |
63 | protected virtual bool PrintMembers(StringBuilder builder)
64 | {
65 | builder.Append('[');
66 | builder.Append(Target);
67 | builder.Append(']');
68 | if (!IsIndeterminate) builder.Append(Progress);
69 |
70 | if (!IsIndeterminate &&
71 | !string.IsNullOrWhiteSpace(Summary))
72 |
73 | builder.Append('|');
74 |
75 | builder.Append(Summary);
76 | if (!string.IsNullOrWhiteSpace(Detail))
77 | {
78 | builder.Append('|');
79 | builder.Append(Detail);
80 | }
81 |
82 | return true;
83 | }
84 |
85 | public override string ToString()
86 | {
87 | StringBuilder builder = new StringBuilder();
88 | PrintMembers(builder);
89 | return builder.ToString();
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Formatting/IFormatter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Ruminoid.Toolbox.Formatting
5 | {
6 | public interface IFormatter
7 | {
8 | public FormattedEvent Format(string target, string data, Dictionary sessionStorage);
9 | }
10 |
11 | [AttributeUsage(AttributeTargets.Class, Inherited = false)]
12 | public sealed class FormatterAttribute : Attribute
13 | {
14 | public FormatterAttribute(string targets) => Targets = targets;
15 |
16 | public readonly string Targets;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Converters/ConverterExtension.cs:
--------------------------------------------------------------------------------
1 | namespace Ruminoid.Toolbox.Utils.Converters
2 | {
3 | public static class ConverterExtension
4 | {
5 | public static StringBoolConverter StringBoolConverter = new();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Converters/StringBoolConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using Avalonia.Data;
4 | using Avalonia.Data.Converters;
5 |
6 | namespace Ruminoid.Toolbox.Utils.Converters
7 | {
8 | public class StringBoolConverter : IValueConverter
9 | {
10 | internal StringBoolConverter()
11 | {
12 | }
13 |
14 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
15 | {
16 | if (!(value is string stringValue) ||
17 | !(parameter is string stringParameter))
18 | return false;
19 |
20 | return stringValue == stringParameter;
21 | }
22 |
23 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
24 | {
25 | if (!(value is bool boolValue) ||
26 | !(parameter is string stringParameter))
27 | return BindingOperations.DoNothing;
28 |
29 | return boolValue ? stringParameter : BindingOperations.DoNothing;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Extensions/CommandExtension.cs:
--------------------------------------------------------------------------------
1 | using Ruminoid.Toolbox.Core;
2 |
3 | namespace Ruminoid.Toolbox.Utils.Extensions
4 | {
5 | public static class CommandExtension
6 | {
7 | public static TaskCommand GenerateTryDeleteCommand(
8 | string path) =>
9 | new("pwsh",
10 | "-Command If (Test-Path " + path + " ) { Remove-Item " + path + " }",
11 | "null");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Extensions/FormatPath.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using FormatWith;
3 |
4 | namespace Ruminoid.Toolbox.Utils.Extensions
5 | {
6 | public static partial class PathExtension
7 | {
8 | ///
9 | /// 格式化文件路径。
10 | ///
11 | /// 文件路径。
12 | /// 格式字符串。
13 | /// 格式化的文件路径。
14 | public static string FormatPath(
15 | this string path,
16 | string formatter) =>
17 | formatter.FormatWith(new
18 | {
19 | folder = Path.GetDirectoryName(path) +
20 | (Path.GetDirectoryName(path) is null
21 | ? ""
22 | : (Path.GetDirectoryName(path) ?? "").EndsWith(Path.DirectorySeparatorChar)
23 | ? ""
24 | : Path.DirectorySeparatorChar),
25 | name = Path.GetFileNameWithoutExtension(path),
26 | fileName = Path.GetFileName(path),
27 | extension = Path.GetExtension(path)
28 | });
29 |
30 | public static string Suffix(
31 | this string path,
32 | string suffix,
33 | string extension = null) =>
34 | Path.GetDirectoryName(path) +
35 | (Path.GetDirectoryName(path) is null
36 | ? ""
37 | : (Path.GetDirectoryName(path) ?? "").EndsWith(Path.DirectorySeparatorChar)
38 | ? ""
39 | : Path.DirectorySeparatorChar) +
40 | Path.GetFileNameWithoutExtension(path) +
41 | suffix +
42 | (string.IsNullOrWhiteSpace(extension) ? Path.GetExtension(path) : extension);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Extensions/GetAllFiles.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 |
4 | namespace Ruminoid.Toolbox.Utils.Extensions
5 | {
6 | public static partial class PathExtension
7 | {
8 | public static List GetAllFiles(
9 | string directory)
10 | {
11 | List result = new();
12 | if (string.IsNullOrEmpty(directory)) return result;
13 |
14 | GetAllFilesIntl(directory, result);
15 | return result;
16 | }
17 |
18 | private static void GetAllFilesIntl(
19 | string directory,
20 | List result)
21 | {
22 | result.AddRange(Directory.GetFiles(directory));
23 | foreach (string d in Directory.GetDirectories(directory)) GetAllFilesIntl(d, result);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Extensions/PathExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 | using System.Runtime.InteropServices;
5 |
6 | // ReSharper disable MemberCanBePrivate.Global
7 |
8 | namespace Ruminoid.Toolbox.Utils.Extensions
9 | {
10 | public static partial class PathExtension
11 | {
12 | #region Consts
13 |
14 | public static readonly char[] InvalidChars = { '<', '>', '(', ')', '@', '^', '|', ' ' };
15 |
16 | #endregion
17 |
18 | public static string EscapePathStringForArg(
19 | this string path,
20 | bool useSingleQuote = false) =>
21 | useSingleQuote ? $"'{path}'" : $"\"{path}\"";
22 |
23 | public static string EscapeQuote(
24 | this string str) =>
25 | str.Replace("\"", "\\\"");
26 |
27 | public static string EscapeForCode(
28 | this string str) =>
29 | str.Aggregate(string.Empty, (s, c) => s + c.EscapeForCode());
30 |
31 | public static string EscapeForCode(
32 | this char c) =>
33 | "\\" + "u" + ((int)c).ToString("x4");
34 |
35 | public static string GetTargetPath(
36 | string target) =>
37 | Path.Combine(
38 | StorageHelper.GetSectionFolderPath("tools"),
39 | target + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : ""));
40 |
41 | public static string GetFullPathOrEmpty(
42 | string path) =>
43 | string.IsNullOrWhiteSpace(path) ? string.Empty : Path.GetFullPath(path, Environment.CurrentDirectory);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/Extensions/StringExtension.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Linq;
4 |
5 | namespace Ruminoid.Toolbox.Utils.Extensions
6 | {
7 | public static class StringExtension
8 | {
9 | public static string GetMidString(
10 | this string source,
11 | string before,
12 | string after)
13 | {
14 | var result = string.Empty;
15 | try
16 | {
17 | var startIndex = source.IndexOf(before, StringComparison.Ordinal);
18 |
19 | if (startIndex == -1)
20 | return result;
21 |
22 | var substring = source.Substring(startIndex + before.Length);
23 |
24 | var endIndex = substring.IndexOf(after, StringComparison.Ordinal);
25 |
26 | if (endIndex == -1)
27 | return result;
28 |
29 | result = substring.Remove(endIndex);
30 | }
31 | catch (Exception)
32 | {
33 | // Ignore
34 | }
35 |
36 | return result;
37 | }
38 |
39 | public static string[] GetLines(
40 | this string str) =>
41 | str
42 | .Split(Environment.NewLine.ToCharArray(), StringSplitOptions.None)
43 | .Where(x => !string.IsNullOrWhiteSpace(x))
44 | .ToArray();
45 |
46 | public static string ReadStreamToEnd(
47 | this Stream stream)
48 | {
49 | using StreamReader reader = new StreamReader(stream);
50 | return reader.ReadToEnd();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/Utils/StorageHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 |
4 | namespace Ruminoid.Toolbox.Utils
5 | {
6 | ///
7 | /// 提供访问应用存储能力的帮助类型。
8 | ///
9 | public static class StorageHelper
10 | {
11 | #region Basic
12 |
13 | ///
14 | /// 获取分类文件夹。
15 | ///
16 | /// 分类的名称。
17 | /// 文件夹的完整路径。
18 | public static string GetSectionFolderPath(string sectionName)
19 | {
20 | string folderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, sectionName + Path.DirectorySeparatorChar);
21 | Directory.CreateDirectory(folderPath);
22 | return folderPath;
23 | }
24 |
25 | ///
26 | /// 从分类存储目录中获取文件。
27 | ///
28 | /// 分类的名称。
29 | /// 要获取的文件的文件名。
30 | /// 文件的完整路径。
31 | public static string GetSectionFilePath(string sectionName, string filename) =>
32 | Path.Combine(GetSectionFolderPath(sectionName), filename);
33 |
34 | #endregion
35 |
36 | #region Temp Section
37 |
38 | public static TempSection CreateTempSection()
39 | {
40 | string sectionPath = Path.Combine(GetSectionFolderPath("temp"), Guid.NewGuid().ToString() + Path.DirectorySeparatorChar);
41 | Directory.CreateDirectory(sectionPath);
42 | return new TempSection(sectionPath);
43 | }
44 |
45 | #endregion
46 | }
47 |
48 | public class TempSection : IDisposable
49 | {
50 | internal TempSection(string sectionPath) => SectionPath = sectionPath;
51 |
52 | public readonly string SectionPath;
53 |
54 | ~TempSection() => Dispose();
55 |
56 | public void Dispose() => Directory.Delete(SectionPath, true);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/rmbox-plugbase/rmbox-plugbase.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 | Ruminoid.Toolbox
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/rmbox-shell/App.axaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/rmbox-shell/App.axaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Avalonia;
3 | using Avalonia.Controls.ApplicationLifetimes;
4 | using Avalonia.Markup.Xaml;
5 | using JetBrains.Annotations;
6 | using ReactiveUI;
7 | using Ruminoid.Toolbox.Shell.Windows;
8 |
9 | namespace Ruminoid.Toolbox.Shell
10 | {
11 | public class App : Application
12 | {
13 | public App()
14 | {
15 | DataContext = new AppViewModel();
16 | }
17 |
18 | public override void Initialize()
19 | {
20 | AvaloniaXamlLoader.Load(this);
21 | }
22 |
23 | public override void OnFrameworkInitializationCompleted()
24 | {
25 | if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
26 | {
27 | SplashWindow splash = new();
28 | splash.Show();
29 |
30 | splash.ViewModel.Initialize
31 | .Subscribe(
32 | _ => { },
33 | _ => { },
34 | () =>
35 | {
36 | desktop.MainWindow.Show();
37 | splash.Close();
38 | });
39 | }
40 |
41 | base.OnFrameworkInitializationCompleted();
42 | }
43 | }
44 |
45 | public class AppViewModel : ReactiveObject
46 | {
47 | [UsedImplicitly]
48 | public void DoShowAboutWindow()
49 | {
50 | if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime
51 | {
52 | MainWindow: MainWindow mainWindow
53 | })
54 | mainWindow.ViewModel.CurrentTabIndex = (int) CommonTabIndex.AboutView;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/rmbox-shell/Helpers/CommandHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Reactive;
2 | using Avalonia.Controls;
3 | using ReactiveUI;
4 |
5 | namespace Ruminoid.Toolbox.Shell.Helpers
6 | {
7 | public static class CommandHelper
8 | {
9 | public static ReactiveCommand