34 Commits

Author SHA1 Message Date
RatzzFatzz
36bd93bb50 Fix windows artifact upload 2025-02-04 12:33:19 +01:00
RatzzFatzz
ecc5c56c8c Update github action 2025-02-04 00:54:09 +01:00
RatzzFatzz
f6310c71ee Update github action 2025-02-04 00:52:09 +01:00
RatzzFatzz
bb4a686dfc Update github action 2025-02-04 00:39:13 +01:00
RatzzFatzz
c63fcd4f37 Update maven plugins 2025-02-04 00:34:40 +01:00
RatzzFatzz
9f15b542bd Update github action 2025-02-04 00:31:07 +01:00
RatzzFatzz
76321bb904 Update dependencies 2025-02-04 00:03:56 +01:00
RatzzFatzz
895597b91f Fix github action 2025-02-03 23:32:37 +01:00
RatzzFatzz
4fa5448e1c Fix logging on installed app 2025-02-03 01:13:15 +01:00
RatzzFatzz
f3accd77d6 Replace GraalVM with jpackage and wix 2025-02-01 17:00:01 +01:00
RatzzFatzz
2710ea2602 Update graalvm and lombok config 2025-01-28 23:45:06 +01:00
RatzzFatzz
547b5ad86c Update threads test 2024-11-27 21:19:08 +01:00
RatzzFatzz
1863432dc6 Make mkvtoolnix path default value of dependant 2024-11-27 00:32:23 +01:00
RatzzFatzz
7ea0ab17b0 Update mkvtoolnix path test 2024-11-26 23:42:16 +01:00
RatzzFatzz
47b4cdc896 Update path & pattern tests 2024-11-24 23:57:24 +01:00
RatzzFatzz
b638d93358 Improve command description 2024-11-22 00:44:02 +01:00
RatzzFatzz
939f6053dd Update collection config parameter config 2024-11-22 00:21:13 +01:00
RatzzFatzz
4714ef8db1 Update config tests 2024-11-18 23:59:17 +01:00
RatzzFatzz
321115b9ca Rework app to use picocli 2024-11-17 23:42:06 +01:00
RatzzFatzz
ed8e592963 Fix file change detection 2024-05-27 22:24:47 +02:00
RatzzFatzz
0a7996f049 Remove forced audio tracks & minor refactoring 2024-05-24 01:09:11 +02:00
Michael
dd60ca93da Merge pull request #50 from RatzzFatzz/bugfix/file-with-no-default-subtitle-track
Fix setting of default audio track on files with no default subtitle track
2024-02-19 21:11:10 +01:00
RatzzFatzz
ba770abb6a Fix setting of default audio track on files with no default subtitle track 2024-02-19 20:54:44 +01:00
Michael
91f1e8f7bf Merge pull request #48 from RatzzFatzz/dev
Dev
2023-04-30 13:35:03 +02:00
0fda98426e Update use of enum 2023-04-30 13:34:34 +02:00
c74cdde442 Add ConfigLoader test 2023-04-29 20:16:58 +02:00
a8551fdbd5 Add tests 2023-04-22 20:30:35 +02:00
Michael
b2e9762366 Merge pull request #47 from RatzzFatzz/dev
Fix OFF for subtitles
2023-04-19 21:51:40 +02:00
cafb12f22a Fix OFF for subtitles 2023-04-19 21:44:49 +02:00
Michael
f6d65c2d53 Merge pull request #45 from RatzzFatzz/dev
Implement cache & fix minor bugs
2023-04-16 14:44:32 +02:00
1963d1cc5c Fix total file count 2023-04-16 13:45:46 +02:00
686a9a0da1 Implement caching & fix minor bugs 2023-04-16 13:07:58 +02:00
e19f780ff0 Update readme 2023-04-13 21:57:59 +02:00
f928cb035e Update config template 2023-04-10 21:44:43 +02:00
56 changed files with 1388 additions and 764 deletions

View File

@@ -3,27 +3,35 @@
name: Build and release name: Build and release
on: on:
release: release:
types: [created] types: [ created ]
jobs: jobs:
build: portable-build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Install mkvtoolnix
uses: actions/checkout@v2 run: sudo apt-get install -y mkvtoolnix
- name: Set up JDK 11 - name: Checkout
uses: actions/setup-java@v2 uses: actions/checkout@v4
- name: Set timezone
uses: szenius/set-timezone@v2.0
with:
timezoneLinux: "Europe/Berlin"
- name: Set up JDK 21
uses: actions/setup-java@v4.7.0
with: with:
distribution: temurin distribution: temurin
java-version: 11 java-version: 21
- name: Setup workspace - name: Setup workspace
run: mkdir artifacts run: mkdir artifacts
- name: Build with Maven - name: Build with Maven
run: | run: |
mvn clean package --file pom.xml mvn clean package --file pom.xml -P portable
cp target/M*.{zip,tar} artifacts/ cp target/M*.{zip,tar} artifacts/
- name: Upload artifacts - name: Upload artifacts
@@ -33,3 +41,36 @@ jobs:
with: with:
args: 'artifacts/M*' args: 'artifacts/M*'
windows-installer-build:
runs-on: windows-latest
steps:
- name: Install mkvtoolnix
uses: crazy-max/ghaction-chocolatey@v3
with:
args: install mkvtoolnix -y
- name: Checkout
uses: actions/checkout@v4
- name: Set timezone
uses: szenius/set-timezone@v2.0
with:
timezoneWindows: "Berlin Standard Time"
- name: Set up JDK 21
uses: actions/setup-java@v4.7.0
with:
distribution: temurin
java-version: 21
- name: Setup workspace
run: mkdir artifacts
- name: Build with Maven
run: mvn clean package --file pom.xml -P windows
- name: Upload artifacts
uses: AButler/upload-release-assets@v3.0
with:
files: 'target/installer/*'
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -19,23 +19,28 @@ Attribute-config must be entered in pairs: `audio:subtitle`; Example: `jpn:eng`.
[here](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Attribute-Config). [here](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Attribute-Config).
## Available parameters ## Available parameters
```shell
-l,--library <arg> Path to library
-a,--attribute-config <arg> Attribute config to decide which tracks to choose when
-p,--config-path <arg> Path to config file
-m,--mkvtoolnix <arg> Path to mkv tool nix installation
-s,--safe-mode Test run (no files will be changes)
-t,--threads <arg> Thread count (default: 2)
-i,--include-pattern <arg> Include files matching pattern (default: ".*")
-e,--exclude-directories <arg> Directories to be excluded, combines with config file
-fk,--forced-keywords <arg> Additional keywords to identify forced tracks
-ck,--commentary-keywords <arg> Additional keywords to identify commentary tracks
-v,--version Display version
-h,--help "For help this is" - Yoda
``` ```
-l,--library-path <arg> Path to library
-a,--attribute-config <arg> Attribute config to decide which tracks to choose when
-p,--config-path <arg> Path to config file
-m,--mkvtoolnix <arg> Path to mkv tool nix installation
-s,--safe-mode Test run (no files will be changes)
-c,--coherent <arg> Try to match all files in dir of depth with the same config
-cf,--force-coherent Force coherent and don't update anything if config fits not whole config (default: false)
-n,--only-new-files Sets filter-date to last successful execution (Overwrites input of filter-date)
-d,--filter-date <arg> Only consider files created newer than entered date (format: "dd.MM.yyyy-HH:mm:ss")
-t,--threads <arg> Thread count (default: 2)
-i,--include-pattern <arg> Include files matching pattern (default: ".*")
-e,--excluded-directories <arg> Directories to be excluded, combines with config file
-fk,--forced-keywords <arg> Additional keywords to identify forced tracks
-ck,--commentary-keywords <arg> Additional keywords to identify commentary tracks
-ps,--preferred-subtitles <arg> Additional keywords to prefer specific subtitle tracks
-v,--version Display version
-h,--help "For help this is" - Yoda
```
If you need more information about how each parameter works, check out [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/Parameters).
All parameters can also be defined in a config file. All parameters can also be defined in a [config file](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/How-to-config-file).
Please read [this wiki page](https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/wiki/How-to-config-file) for more information.
## Build requirements ## Build requirements
- JDK 11 or higher - JDK 11 or higher

View File

@@ -1,7 +1,7 @@
mkvtoolnix: C:\Program Files\MKVToolNix mkvtoolnix: C:\Program Files\MKVToolNix
library: X:/Files library: X:/Files
config: attribute-config:
1: 1:
audio: ger audio: ger
subtitle: OFF subtitle: OFF
@@ -14,6 +14,7 @@ config:
#forced-keywords: ["forced", "signs"] #forced-keywords: ["forced", "signs"]
#commentary-keywords: ["commentary", "director"] #commentary-keywords: ["commentary", "director"]
#preferred-subtitles: ["unstyled"]
#exclude-directories: #exclude-directories:
# - "D:/Path/To/File.mkv" # - "D:/Path/To/File.mkv"
@@ -22,7 +23,12 @@ config:
# If pattern is negated, can be used to exclude files # If pattern is negated, can be used to exclude files
#include-pattern: "regex" #include-pattern: "regex"
# Only files newer than
#filter-date: 20.03.2021-10:11:12
safe-mode: safe-mode:
#coherent: #coherent:
#force-coherent:
#only-new-files:

310
pom.xml
View File

@@ -6,21 +6,135 @@
<groupId>at.pcgamingfreaks</groupId> <groupId>at.pcgamingfreaks</groupId>
<artifactId>MKVAudioSubtitleChanger</artifactId> <artifactId>MKVAudioSubtitleChanger</artifactId>
<version>3.0</version> <version>4.0.0</version>
<properties>
<mainClass>at.pcgamingfreaks.mkvaudiosubtitlechanger.Main</mainClass>
<lombok-version>1.18.36</lombok-version>
</properties>
<profiles>
<profile>
<id>portable</id>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j2.yml</include>
<include>log4j2-debug.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>maven/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>windows</id>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>log4j2-installed.yaml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
</plugin>
<plugin>
<groupId>org.panteleyev</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>1.6.5</version>
<executions>
<execution>
<id>windows</id>
<configuration>
<resourceDir>${project.basedir}/src/main/resources/</resourceDir>
<type>EXE</type>
<winConsole>true</winConsole>
<winShortcut>false</winShortcut>
<winMenu>false</winMenu>
<javaOptions>
<javaOption>-Dlog4j.configurationFile=log4j2-installed.yaml</javaOption>
</javaOptions>
</configuration>
<phase>package</phase>
<goals>
<goal>jpackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>linux</id>
<build>
<plugins>
<plugin>
<groupId>org.panteleyev</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>1.4.0</version>
<executions>
<execution>
<id>linux-deb</id>
<configuration>
<type>DEB</type>
<installDir>/usr/local/bin</installDir>
<linuxShortcut>false</linuxShortcut>
<linuxPackageName>mkvasc</linuxPackageName>
<linuxDebMaintainer>your@email.com</linuxDebMaintainer>
</configuration>
<phase>package</phase>
<goals>
<goal>jpackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<build> <build>
<defaultGoal>clean package</defaultGoal> <defaultGoal>clean package</defaultGoal>
<sourceDirectory>src/main/java</sourceDirectory> <sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory> <testSourceDirectory>src/test/java</testSourceDirectory>
<resources> <resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource> <resource>
<directory>./</directory> <directory>./</directory>
<includes> <includes>
<include>language-codes</include> <include>language-codes</include>
<include>project.properties</include> <include>project.properties</include>
<include>LICENSE</include>
</includes> </includes>
<filtering>true</filtering> <filtering>true</filtering>
</resource> </resource>
@@ -35,11 +149,11 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId> <artifactId>maven-jar-plugin</artifactId>
<version>3.1.1</version> <version>3.4.2</version>
<configuration> <configuration>
<archive> <archive>
<manifestEntries> <manifestEntries>
<Main-Class>at/pcgamingfreaks/mkvaudiosubtitlechanger/Main</Main-Class> <Main-Class>${mainClass}</Main-Class>
</manifestEntries> </manifestEntries>
</archive> </archive>
</configuration> </configuration>
@@ -47,7 +161,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.2.1</version> <version>3.6.0</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -62,6 +176,13 @@
<include>*:*</include> <include>*:*</include>
</includes> </includes>
</artifactSet> </artifactSet>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Multi-Release>true</Multi-Release>
</manifestEntries>
</transformer>
</transformers>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
@@ -69,36 +190,79 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version> <version>3.5.2</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration> <configuration>
<source>11</source> <source>21</source>
<target>11</target> <target>21</target>
<compilerArgs>
<arg>-Aproject=${project.groupId}/${project.artifactId}</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
</path>
<path>
<groupId>info.picocli</groupId>
<artifactId>picocli-codegen</artifactId>
<version>4.7.6</version>
</path>
</annotationProcessorPaths>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>maven/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>copy-jpackage-input</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/jpackage-input</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.panteleyev</groupId>
<artifactId>jpackage-maven-plugin</artifactId>
<version>1.4.0</version>
<configuration>
<name>${project.artifactId}</name>
<vendor>RatzzFatzz</vendor>
<appVersion>${project.version}</appVersion>
<destination>target/installer</destination>
<input>target/jpackage-input</input>
<mainClass>at.pcgamingfreaks.mkvaudiosubtitlechanger.Main</mainClass>
<mainJar>${project.artifactId}-${project.version}.jar</mainJar>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build> </build>
<repositories> <repositories>
@@ -109,85 +273,139 @@
</repositories> </repositories>
<dependencies> <dependencies>
<!-- https://mvnrepository.com/artifact/com.intellij/forms_rt -->
<dependency> <dependency>
<groupId>com.intellij</groupId> <groupId>com.intellij</groupId>
<artifactId>forms_rt</artifactId> <artifactId>forms_rt</artifactId>
<version>7.0.3</version> <version>7.0.3</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>
<version>1.18.24</version> <version>${lombok-version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/info.picocli/picocli -->
<dependency>
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
<version>4.7.6</version>
</dependency>
<!-- Hibernate Validator -->
<!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator -->
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>8.0.2.Final</version>
</dependency>
<!-- Expression Language Implementation -->
<!-- https://mvnrepository.com/artifact/jakarta.el/jakarta.el-api -->
<dependency>
<groupId>jakarta.el</groupId>
<artifactId>jakarta.el-api</artifactId>
<version>6.0.1</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>jakarta.el</artifactId>
<version>5.0.0-M1</version>
</dependency>
<!-- Jakarta Bean Validation -->
<!-- https://mvnrepository.com/artifact/jakarta.validation/jakarta.validation-api -->
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>3.0.2</version>
</dependency>
<!-- region logging --> <!-- region logging -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId> <artifactId>log4j-api</artifactId>
<version>2.17.1</version> <version>2.24.3</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId> <artifactId>log4j-core</artifactId>
<version>2.17.1</version> <version>2.24.3</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j18-impl -->
<!-- https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j2-impl -->
<dependency> <dependency>
<groupId>org.apache.logging.log4j</groupId> <groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId> <artifactId>log4j-slf4j2-impl</artifactId>
<version>2.17.1</version> <version>2.24.3</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-yaml -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId> <groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId> <artifactId>jackson-dataformat-yaml</artifactId>
<version>2.13.4</version> <version>2.18.2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId> <artifactId>jackson-databind</artifactId>
<version>2.13.4.2</version> <version>2.18.2</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
<dependency> <dependency>
<groupId>commons-cli</groupId> <groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId> <artifactId>commons-cli</artifactId>
<version>1.5.0</version> <version>1.9.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId> <artifactId>commons-lang3</artifactId>
<version>3.12.0</version> <version>3.17.0</version>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/me.tongfei/progressbar -->
<dependency> <dependency>
<groupId>me.tongfei</groupId> <groupId>me.tongfei</groupId>
<artifactId>progressbar</artifactId> <artifactId>progressbar</artifactId>
<version>0.9.5</version> <version>0.10.1</version>
</dependency> </dependency>
<!-- endregion --> <!-- endregion -->
<!-- region unit-tests --> <!-- region unit-tests -->
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId> <artifactId>junit-jupiter-api</artifactId>
<version>5.9.0</version> <version>5.11.4</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-engine -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId> <artifactId>junit-jupiter-engine</artifactId>
<version>5.9.0</version> <version>5.11.4</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all --> <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
<dependency> <dependency>
<groupId>org.mockito</groupId> <groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId> <artifactId>mockito-core</artifactId>
<version>1.10.19</version> <version>5.15.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-params -->
<dependency> <dependency>
<groupId>org.junit.jupiter</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId> <artifactId>junit-jupiter-params</artifactId>
<version>5.9.0</version> <version>5.11.4</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!-- endregion --> <!-- endregion -->
<dependency> <dependency>
<groupId>at.pcgamingfreaks</groupId> <groupId>at.pcgamingfreaks</groupId>
@@ -198,7 +416,7 @@
<dependency> <dependency>
<groupId>net.harawata</groupId> <groupId>net.harawata</groupId>
<artifactId>appdirs</artifactId> <artifactId>appdirs</artifactId>
<version>1.2.1</version> <version>1.3.0</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -1,21 +1,65 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger; package at.pcgamingfreaks.mkvaudiosubtitlechanger;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config; import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ConfigLoader; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.CachedMkvFileProcessor;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.AttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.CoherentAttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.kernel.DefaultAttributeUpdaterKernel;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector; import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileCollector;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.impl.MkvFileProcessor; import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import picocli.CommandLine;
import java.util.Set;
@Slf4j @Slf4j
public class Main { @CommandLine.Command(
public static void main(String[] args) { name = "mkvasc",
ConfigLoader.initConfig(args); usageHelpWidth = 120,
customSynopsis = {
"mkvasc -a <attributeConfig>... -l <libraryPath> [-s]",
"Example: mkvasc -a eng:eng eng:ger -l /mnt/media/ -s"
},
mixinStandardHelpOptions = true,
versionProvider = ProjectUtil.class
)
public class Main implements Runnable {
@Getter
@CommandLine.ArgGroup(exclusive = false)
private Config config;
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@Override
public void run() {
validate();
Config.setInstance(config);
AttributeUpdaterKernel kernel = Config.getInstance().getCoherent() != null AttributeUpdaterKernel kernel = Config.getInstance().getCoherent() != null
? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new MkvFileProcessor()) ? new CoherentAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor())
: new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new MkvFileProcessor()); : new DefaultAttributeUpdaterKernel(new MkvFileCollector(), new CachedMkvFileProcessor());
kernel.execute(); kernel.execute();
} }
private void validate() {
Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
Set<ConstraintViolation<Config>> violations = validator.validate(config);
if (!violations.isEmpty()) {
StringBuilder errorMsg = new StringBuilder();
for (ConstraintViolation<Config> violation : violations) {
errorMsg.append("ERROR: ").append(violation.getPropertyPath()).append(" ").append(violation.getMessage()).append("\n");
}
throw new CommandLine.ParameterException(spec.commandLine(), errorMsg.toString());
}
}
public static void main(String[] args) {
new CommandLine(Main.class).execute(args);
}
} }

View File

@@ -0,0 +1,58 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import picocli.CommandLine;
import java.util.regex.Pattern;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isAudioLanguageValid;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid;
public class AttributeConfigConverter implements CommandLine.ITypeConverter<AttributeConfig> {
private static final String SEPARATOR = ":";
private static final Pattern PATTERN = Pattern.compile("^.{3}:.{3}$");
/**
* Converts the input string into an AttributeConfig object.
*
* @param s The input string containing audio and subtitle language configuration in format "audioLang:subtitleLang"
* @return An AttributeConfig object representing the parsed configuration
* @throws CommandLine.TypeConversionException if the input string is invalid or contains invalid language codes
*/
@Override
public AttributeConfig convert(String s) throws Exception {
validateInput(s);
String[] split = s.split(SEPARATOR);
AttributeConfig attr = new AttributeConfig(split[0], split[1]);
validateResult(attr);
return attr;
}
/**
* Validates that the input string matches the expected pattern.
*
* @param s String to validate
* @throws CommandLine.TypeConversionException if the value doesn't match the expected pattern
*/
private static void validateInput(String s) {
if (!PATTERN.matcher(s).matches()) {
throw new CommandLine.TypeConversionException("Invalid Attribute config: " + s);
}
}
/**
* Validates that both language codes in the AttributeConfig object are valid.
*
* @param attr AttributeConfig object to validate
* @throws CommandLine.TypeConversionException if either language code is invalid
*/
private static void validateResult(AttributeConfig attr) {
if (!isAudioLanguageValid(attr.getAudioLanguage()))
throw new CommandLine.TypeConversionException("Audio language invalid: " + attr.getAudioLanguage());
if (!isLanguageValid(attr.getSubtitleLanguage()))
throw new CommandLine.TypeConversionException("Subtitle language invalid: " + attr.getSubtitleLanguage());
}
}

View File

@@ -2,51 +2,96 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix;
import jakarta.validation.constraints.Min;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.lang3.SystemUtils;
import org.apache.commons.cli.DefaultParser; import picocli.CommandLine;
import org.apache.commons.cli.HelpFormatter;
import java.io.File; import java.io.File;
import java.nio.file.Path;
import java.util.*; import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@Slf4j @Slf4j
@Getter @Getter
@Setter @Setter
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor
public class Config { public class Config {
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
@Setter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
private static Config config = null; private static Config config = null;
@Getter(AccessLevel.NONE)
CommandLineParser parser = new DefaultParser();
@Getter(AccessLevel.NONE)
HelpFormatter formatter = new HelpFormatter();
private File configPath;
private File libraryPath;
@Getter(AccessLevel.NONE)
private File mkvToolNix;
private int threads; private File configPath;
private Pattern includePattern;
@CommandLine.Spec
CommandLine.Model.CommandSpec spec;
@CommandLine.Option(names = {"-a", "--attribute-config"}, required = true, arity = "1..*", converter = AttributeConfigConverter.class)
private List<AttributeConfig> attributeConfig;
@Setter(AccessLevel.NONE)
private File libraryPath;
@CommandLine.Option(names = {"-s", "--safemode"}, description = "test run (no files will be changes)")
private boolean safeMode; private boolean safeMode;
private Integer coherent; @Setter(AccessLevel.NONE)
private boolean forceCoherent; private File mkvToolNix;
private boolean onlyNewFiles;
private Date filterDate;
private Set<String> forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs")); @Min(value = 1)
private Set<String> commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director")); @CommandLine.Option(names = {"-t", "--threads"}, defaultValue = "2", description = "thread count (default: ${DEFAULT-VALUE})")
private int threads;
@CommandLine.Option(names = {"-c", "--coherent"}, description = "try to match all files in dir of depth with the same attribute config")
private Integer coherent;
@CommandLine.Option(names = {"-cf", "--force-coherent"}, description = "changes are only applied if it's a coherent match")
private boolean forceCoherent;
@CommandLine.Option(names = {"-n"}, description = "sets filter-date to last successful execution (overwrites input of filter-date)")
private boolean onlyNewFiles;
@CommandLine.Option(names = {"-d", "--filter-date"}, defaultValue = CommandLine.Option.NULL_VALUE, description = "only consider files created newer than entered date (format: \"dd.MM.yyyy-HH:mm:ss\")")
private Date filterDate;
@CommandLine.Option(names = {"-i", "--include-pattern"}, defaultValue = ".*", description = "include files matching pattern (default: \".*\")")
private Pattern includePattern;
@CommandLine.Option(names = {"-e", "--excluded-directory"}, arity = "1..*",
description = "Directories to be excluded, combines with config file")
private Set<String> excludedDirectories = new HashSet<>(); private Set<String> excludedDirectories = new HashSet<>();
@CommandLine.Option(names = {"-fk", "--force-keywords"}, arity = "1..*",
description = "Additional keywords to identify forced tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}")
private Set<String> forcedKeywords = new HashSet<>(Arrays.asList("forced", "signs", "songs"));
@CommandLine.Option(names = {"-ck", "--commentary-keywords"}, arity = "1..*",
description = "Additional keywords to identify commentary tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}")
private Set<String> commentaryKeywords = new HashSet<>(Arrays.asList("commentary", "director"));
@CommandLine.Option(names = {"-ps", "--preferred-subtiltes"}, arity = "1..*",
description = "Additional keywords to prefer specific subtitle tracks (Defaults are will be overwritten; Default: ${DEFAULT-VALUE}")
private Set<String> preferredSubtitles = new HashSet<>(Arrays.asList("unstyled")); private Set<String> preferredSubtitles = new HashSet<>(Arrays.asList("unstyled"));
private List<AttributeConfig> attributeConfig; @CommandLine.Option(names = {"-l", "--library"}, required = true, description = "path to library")
public void setLibraryPath(File libraryPath) {
if (!libraryPath.exists()) throw new CommandLine.ParameterException(spec.commandLine(), "Path does not exist: " + libraryPath.getAbsolutePath());
this.libraryPath = libraryPath;
}
static {
// Set default value into system properties to picocli can read the conditional value
System.setProperty("DEFAULT_MKV_TOOL_NIX", SystemUtils.IS_OS_WINDOWS ? "C:\\Program Files\\MKVToolNix" : "/usr/bin/");
}
@CommandLine.Option(names = {"-m", "--mkvtoolnix"}, defaultValue = "${DEFAULT_MKV_TOOL_NIX}", description = "path to mkvtoolnix installation")
public void setMkvToolNix(File mkvToolNix) {
this.mkvToolNix = mkvToolNix;
if (!mkvToolNix.exists()
|| !Path.of(getPathFor(MkvToolNix.MKV_MERGE, SystemUtils.IS_OS_WINDOWS)).toFile().exists()
|| !Path.of(getPathFor(MkvToolNix.MKV_PROP_EDIT, SystemUtils.IS_OS_WINDOWS)).toFile().exists()) {
throw new CommandLine.ParameterException(spec.commandLine(),
"Invalid path to mkvtoolnix installation: " + mkvToolNix.getAbsolutePath());
}
}
public static Config getInstance() { public static Config getInstance() {
return getInstance(false); return getInstance(false);
@@ -59,14 +104,23 @@ public class Config {
return config; return config;
} }
public static void setInstance(Config c) {
config = c;
}
/** /**
* Get path to specific mkvtoolnix application. * Get path to specific mkvtoolnix application.
* *
* @return absolute path to desired application. * @return absolute path to desired application.
*/ */
public String getPathFor(MkvToolNix application) { public String getPathFor(MkvToolNix application) {
return mkvToolNix.getAbsolutePath().endsWith("/") ? mkvToolNix.getAbsolutePath() + application : return mkvToolNix.getAbsolutePath().endsWith("/")
mkvToolNix.getAbsolutePath() + "/" + application; ? mkvToolNix.getAbsolutePath() + application
: mkvToolNix.getAbsolutePath() + "/" + application;
}
public String getPathFor(MkvToolNix application, boolean isWindows) {
return getPathFor(application) + (isWindows ? ".exe" : "");
} }
public String getNormalizedLibraryPath() { public String getNormalizedLibraryPath() {
@@ -76,8 +130,6 @@ public class Config {
@Override @Override
public String toString() { public String toString() {
return new StringJoiner(", ", Config.class.getSimpleName() + "[", "]") return new StringJoiner(", ", Config.class.getSimpleName() + "[", "]")
.add("parser=" + parser)
.add("formatter=" + formatter)
.add("configPath=" + configPath) .add("configPath=" + configPath)
.add("libraryPath=" + libraryPath) .add("libraryPath=" + libraryPath)
.add("mkvToolNix=" + mkvToolNix) .add("mkvToolNix=" + mkvToolNix)

View File

@@ -1,110 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator.*;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.util.ProjectUtil;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.*;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
public class ConfigLoader {
private static final List<ConfigValidator<?>> VALIDATORS = Stream.of(
new ConfigPathValidator(CONFIG_PATH, false),
new PathValidator(LIBRARY, true, null),
new ThreadValidator(THREADS, false, 2),
new MkvToolNixPathValidator(MKV_TOOL_NIX, true, Path.of("C:\\Program Files\\MKVToolNix").toFile()),
new BooleanValidator(SAFE_MODE, false),
new BooleanValidator(ONLY_NEW_FILES, false),
new DateValidator(FILTER_DATE, false),
new PatternValidator(INCLUDE_PATTERN, false, Pattern.compile(".*")),
new SetValidator(FORCED_KEYWORDS, false, true),
new SetValidator(COMMENTARY_KEYWORDS, false, true),
new SetValidator(EXCLUDED_DIRECTORY, false, true),
new SetValidator(PREFERRED_SUBTITLES, false, true),
new AttributeConfigValidator(),
new CoherentConfigValidator(COHERENT, false),
new BooleanValidator(FORCE_COHERENT, false)
).sorted(Comparator.comparing((ConfigValidator<?> validator) -> validator.getWeight()).reversed()).collect(Collectors.toList());
public static void initConfig(String[] args) {
HelpFormatter formatter = new HelpFormatter();
formatter.setOptionComparator(null);
YAML yamlConfig = null;
Options options = initOptions();
CommandLine cmd = parseCommandLineArgs(formatter, options, args);
exitIfHelp(cmd, options, formatter);
exitIfVersion(cmd);
List<ValidationResult> results = new ArrayList<>();
for (ConfigValidator<?> validator: VALIDATORS) {
results.add(validator.validate(yamlConfig, cmd));
if (yamlConfig == null) {
try {
yamlConfig = Config.getInstance().getConfigPath() != null
? new YAML(Config.getInstance().getConfigPath())
: new YAML("");
} catch (IOException | YamlInvalidContentException ignored) {}
}
}
if (results.contains(ValidationResult.INVALID) || results.contains(ValidationResult.MISSING)) System.exit(1);
System.out.println();
}
private static Options initOptions() {
Options options = new Options();
Arrays.stream(ConfigProperty.values())
.filter(prop -> prop.abrv() != null)
.map(prop -> optionOf(prop, prop.abrv(), prop.args()))
.forEach(options::addOption);
return options;
}
private static CommandLine parseCommandLineArgs(HelpFormatter formatter, Options options, String[] args) {
CommandLineParser parser = new DefaultParser();
try {
CommandLine cmd = parser.parse(options, args);
if (cmd == null) throw new NullPointerException();
return cmd;
} catch (ParseException | NullPointerException e) {
formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l <path_to_library>",
"\nParameters:", options,
"\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues");
System.exit(1);
}
return null; // can't be reached
}
private static void exitIfHelp(CommandLine cmd, Options options, HelpFormatter formatter) {
if (cmd.hasOption("help")) {
formatter.printHelp(106, "java -jar MKVAudioSubtitlesChanger.jar -l <path_to_library>",
"\nParameters:", options,
"\nFeature requests and bug reports: https://github.com/RatzzFatzz/MKVAudioSubtitleChanger/issues");
System.exit(0);
}
}
private static void exitIfVersion(CommandLine cmd) {
if (cmd.hasOption(VERSION.prop())) {
System.out.printf("MKV Audio Subtitle Changer Version %s%n", ProjectUtil.getVersion());
System.exit(0);
}
}
}

View File

@@ -1,5 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config; package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
@Deprecated
public enum ValidationResult { public enum ValidationResult {
VALID, VALID,
DEFAULT, DEFAULT,

View File

@@ -13,6 +13,7 @@ import java.util.stream.Collectors;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isAudioLanguageValid; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isAudioLanguageValid;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.LanguageValidatorUtil.isLanguageValid;
@Deprecated
public class AttributeConfigValidator extends ConfigValidator<List<AttributeConfig>> { public class AttributeConfigValidator extends ConfigValidator<List<AttributeConfig>> {
private static final String SEPARATOR = ":"; private static final String SEPARATOR = ":";

View File

@@ -12,6 +12,7 @@ import java.util.function.BiFunction;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.ARGUMENTS; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.ARGUMENTS;
@Deprecated
public class BooleanValidator extends ConfigValidator<Boolean> { public class BooleanValidator extends ConfigValidator<Boolean> {
public BooleanValidator(ConfigProperty property, boolean required) { public BooleanValidator(ConfigProperty property, boolean required) {

View File

@@ -3,6 +3,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.math.NumberUtils;
@Deprecated
public class CoherentConfigValidator extends ConfigValidator<Integer> { public class CoherentConfigValidator extends ConfigValidator<Integer> {
private static final Integer DISABLED = -1; private static final Integer DISABLED = -1;

View File

@@ -7,6 +7,7 @@ import java.io.File;
import java.util.Optional; import java.util.Optional;
import java.util.function.BiFunction; import java.util.function.BiFunction;
@Deprecated
public class ConfigPathValidator extends PathValidator { public class ConfigPathValidator extends PathValidator {
public ConfigPathValidator(ConfigProperty property, boolean required) { public ConfigPathValidator(ConfigProperty property, boolean required) {
super(property, required, null); super(property, required, null);

View File

@@ -19,6 +19,7 @@ import java.util.function.Predicate;
@Slf4j @Slf4j
@RequiredArgsConstructor @RequiredArgsConstructor
@Deprecated
public abstract class ConfigValidator<FieldType> { public abstract class ConfigValidator<FieldType> {
protected final ConfigProperty property; protected final ConfigProperty property;
protected final boolean required; protected final boolean required;

View File

@@ -15,6 +15,7 @@ import java.nio.file.Path;
import java.util.Date; import java.util.Date;
@Slf4j @Slf4j
@Deprecated
public class DateValidator extends ConfigValidator<Date> { public class DateValidator extends ConfigValidator<Date> {
private static final Date INVALID_DATE = new Date(0); private static final Date INVALID_DATE = new Date(0);
private static final Date DEFAULT_DATE = new Date(1000); private static final Date DEFAULT_DATE = new Date(1000);

View File

@@ -5,9 +5,10 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_MERGER; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_MERGE;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_PROP_EDIT; import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.MkvToolNix.MKV_PROP_EDIT;
@Deprecated
public class MkvToolNixPathValidator extends PathValidator { public class MkvToolNixPathValidator extends PathValidator {
private static final String EXE = ".exe"; private static final String EXE = ".exe";
@@ -18,9 +19,9 @@ public class MkvToolNixPathValidator extends PathValidator {
@Override @Override
protected boolean isValid(File result) { protected boolean isValid(File result) {
return result.isDirectory() return result.isDirectory()
&& (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER + EXE).toFile().isFile() && (Path.of(result.getAbsolutePath() + "/" + MKV_MERGE + EXE).toFile().isFile()
&& Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT + EXE).toFile().isFile()) && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT + EXE).toFile().isFile())
|| (Path.of(result.getAbsolutePath() + "/" + MKV_MERGER).toFile().isFile() || (Path.of(result.getAbsolutePath() + "/" + MKV_MERGE).toFile().isFile()
&& Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT).toFile().isFile()); && Path.of(result.getAbsolutePath() + "/" + MKV_PROP_EDIT).toFile().isFile());
} }
} }

View File

@@ -5,6 +5,7 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import java.io.File; import java.io.File;
import java.nio.file.Path; import java.nio.file.Path;
@Deprecated
public class PathValidator extends ConfigValidator<File> { public class PathValidator extends ConfigValidator<File> {
public PathValidator(ConfigProperty property, boolean required, File defaultValue) { public PathValidator(ConfigProperty property, boolean required, File defaultValue) {

View File

@@ -5,6 +5,7 @@ import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
@Deprecated
public class PatternValidator extends ConfigValidator<Pattern> { public class PatternValidator extends ConfigValidator<Pattern> {
private static final Pattern EMPTY_PATTERN = Pattern.compile(""); private static final Pattern EMPTY_PATTERN = Pattern.compile("");

View File

@@ -13,6 +13,7 @@ import java.util.*;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Deprecated
public class SetValidator extends ConfigValidator<Set<String>> { public class SetValidator extends ConfigValidator<Set<String>> {
private final boolean append; private final boolean append;

View File

@@ -3,6 +3,7 @@ package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import org.apache.commons.lang3.math.NumberUtils; import org.apache.commons.lang3.math.NumberUtils;
@Deprecated
public class ThreadValidator extends ConfigValidator<Integer>{ public class ThreadValidator extends ConfigValidator<Integer>{
public ThreadValidator(ConfigProperty property, boolean required, Integer defaultValue) { public ThreadValidator(ConfigProperty property, boolean required, Integer defaultValue) {
super(property, required, defaultValue); super(property, required, defaultValue);

View File

@@ -0,0 +1,19 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
public class Cache<Key, Value> {
private final Map<Key, Value> cache = new HashMap<>();
/**
* Retrieve {@link Value} from Cache or run creationFunction and return its value.
* @param key key of cache map
* @param creationFunction function to create missing values
* @return {@link Value} from Cache, or if missing result from creationFunction.
*/
public synchronized Value retrieve(Key key, Function<Key, Value> creationFunction) {
return cache.computeIfAbsent(key, creationFunction::apply);
}
}

View File

@@ -0,0 +1,15 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.impl;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import java.io.File;
import java.util.List;
public class CachedMkvFileProcessor extends MkvFileProcessor {
Cache<File, List<FileAttribute>> cache = new Cache<>();
@Override
public List<FileAttribute> loadAttributes(File file) {
return cache.retrieve(file, super::loadAttributes);
}
}

View File

@@ -21,6 +21,7 @@ public class FileFilter {
return true; return true;
} }
ResultStatistic.getInstance().total();
ResultStatistic.getInstance().excluded(); ResultStatistic.getInstance().excluded();
return false; return false;
} }

View File

@@ -30,9 +30,8 @@ public interface FileProcessor {
/** /**
* Populate FileInfoDto with the desired tracks, based on AttributeConfig. * Populate FileInfoDto with the desired tracks, based on AttributeConfig.
* @param info to be populated * @param info to be populated
* @param nonForcedTracks List of all not forced tracks * @param nonForcedTracks List of all non-forced tracks
* @param nonCommentaryTracks List of all not commentary tracks * @param nonCommentaryTracks List of all non-commentary tracks
* @param configs
*/ */
void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks, void detectDesiredTracks(FileInfoDto info, List<FileAttribute> nonForcedTracks, List<FileAttribute> nonCommentaryTracks,
AttributeConfig... configs); AttributeConfig... configs);
@@ -45,7 +44,7 @@ public interface FileProcessor {
* Update the file. * Update the file.
* @param file to be updated * @param file to be updated
* @param fileInfo information to update file * @param fileInfo information to update file
* @throws IOException * @throws IOException when error occurs accessing file retrieving information
* @throws MkvToolNixException when error occurs while sending query to mkvpropedit * @throws MkvToolNixException when error occurs while sending query to mkvpropedit
*/ */
void update(File file, FileInfoDto fileInfo) throws IOException, MkvToolNixException; void update(File file, FileInfoDto fileInfo) throws IOException, MkvToolNixException;

View File

@@ -30,6 +30,7 @@ public class MkvFileProcessor implements FileProcessor {
private static final String DISABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=0 "; private static final String DISABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=0 ";
private static final String ENABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=1 "; private static final String ENABLE_DEFAULT_TRACK = "--edit track:%s --set flag-default=1 ";
private static final String DISABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=0 ";
private static final String ENABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=1 "; private static final String ENABLE_FORCED_TRACK = "--edit track:%s --set flag-forced=1 ";
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@@ -38,7 +39,7 @@ public class MkvFileProcessor implements FileProcessor {
Map<String, Object> jsonMap; Map<String, Object> jsonMap;
List<FileAttribute> fileAttributes = new ArrayList<>(); List<FileAttribute> fileAttributes = new ArrayList<>();
try { try {
String command = format("\"%s\"", Config.getInstance().getPathFor(MkvToolNix.MKV_MERGER)); String command = format("\"%s\"", Config.getInstance().getPathFor(MkvToolNix.MKV_MERGE));
String[] arguments = new String[]{ String[] arguments = new String[]{
command, command,
"--identify", "--identify",
@@ -69,8 +70,8 @@ public class MkvFileProcessor implements FileProcessor {
log.debug(fileAttributes.toString()); log.debug(fileAttributes.toString());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); log.error("File could not be found or loaded: ", e);
log.error("File could not be found or loaded!"); System.out.println("File could not be found or loaded: " + file.getAbsolutePath());
} }
return fileAttributes; return fileAttributes;
} }
@@ -80,21 +81,17 @@ public class MkvFileProcessor implements FileProcessor {
*/ */
@Override @Override
public void detectDefaultTracks(FileInfoDto info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks) { public void detectDefaultTracks(FileInfoDto info, List<FileAttribute> attributes, List<FileAttribute> nonForcedTracks) {
Set<FileAttribute> detectedForcedSubtitleLanes = new HashSet<>();
for (FileAttribute attribute : attributes) { for (FileAttribute attribute : attributes) {
if (attribute.isDefaultTrack() && AUDIO.equals(attribute.getType())) if (AUDIO.equals(attribute.getType())) {
info.getDefaultAudioLanes().add(attribute); if (attribute.isDefaultTrack()) info.getExistingDefaultAudioLanes().add(attribute);
if (attribute.isDefaultTrack() && SUBTITLES.equals(attribute.getType())) if (attribute.isForcedTrack()) info.getExistingForcedAudioLanes().add(attribute);
info.getDefaultSubtitleLanes().add(attribute); } else if (SUBTITLES.equals(attribute.getType())) {
if (attribute.isForcedTrack() && SUBTITLES.equals(attribute.getType())) if (attribute.isDefaultTrack()) info.getExistingDefaultSubtitleLanes().add(attribute);
detectedForcedSubtitleLanes.add(attribute);
}
info.setDesiredForcedSubtitleLanes(attributes.stream() if (attribute.isForcedTrack()) info.getExistingForcedSubtitleLanes().add(attribute);
.filter(e -> !nonForcedTracks.contains(e)) else if (!nonForcedTracks.contains(attribute)) info.getDesiredForcedSubtitleLanes().add(attribute);
.filter(e -> !detectedForcedSubtitleLanes.contains(e)) }
.collect(Collectors.toSet()) }
);
} }
/** /**
@@ -111,9 +108,10 @@ public class MkvFileProcessor implements FileProcessor {
Optional<FileAttribute> desiredAudio = detectDesiredTrack(config.getAudioLanguage(), audioTracks).findFirst(); Optional<FileAttribute> desiredAudio = detectDesiredTrack(config.getAudioLanguage(), audioTracks).findFirst();
Optional<FileAttribute> desiredSubtitle = detectDesiredSubtitleTrack(config.getSubtitleLanguage(), subtitleTracks).findFirst(); Optional<FileAttribute> desiredSubtitle = detectDesiredSubtitleTrack(config.getSubtitleLanguage(), subtitleTracks).findFirst();
if (desiredAudio.isPresent() && desiredSubtitle.isPresent()) { if (desiredAudio.isPresent() && ("OFF".equals(config.getSubtitleLanguage()) || desiredSubtitle.isPresent())) {
info.setDesiredAudioLane(desiredAudio.get()); info.setMatchedConfig(config);
info.setDesiredSubtitleLane(desiredSubtitle.get()); info.setDesiredDefaultAudioLane(desiredAudio.get());
info.setDesiredDefaultSubtitleLane(desiredSubtitle.orElse(null));
break; break;
} }
} }
@@ -155,21 +153,29 @@ public class MkvFileProcessor implements FileProcessor {
sb.append(format("\"%s\" ", file.getAbsolutePath())); sb.append(format("\"%s\" ", file.getAbsolutePath()));
if (fileInfo.isAudioDifferent()) { if (fileInfo.isAudioDifferent()) {
if (fileInfo.getDefaultAudioLanes() != null && !fileInfo.getDefaultSubtitleLanes().isEmpty()) { if (fileInfo.getExistingDefaultAudioLanes() != null && !fileInfo.getExistingDefaultAudioLanes().isEmpty()) {
for (FileAttribute track: fileInfo.getDefaultAudioLanes()) { for (FileAttribute track: fileInfo.getExistingDefaultAudioLanes()) {
sb.append(format(DISABLE_DEFAULT_TRACK, track.getId())); sb.append(format(DISABLE_DEFAULT_TRACK, track.getId()));
} }
} }
sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredAudioLane().getId())); sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredDefaultAudioLane().getId()));
}
if (!fileInfo.getExistingForcedAudioLanes().isEmpty()) {
for (FileAttribute track: fileInfo.getExistingForcedAudioLanes()) {
sb.append(format(DISABLE_FORCED_TRACK, track.getId()));
}
} }
if (fileInfo.isSubtitleDifferent()) { if (fileInfo.isSubtitleDifferent()) {
if (fileInfo.getDefaultSubtitleLanes() != null && !fileInfo.getDefaultSubtitleLanes().isEmpty()) { if (fileInfo.getExistingDefaultSubtitleLanes() != null && !fileInfo.getExistingDefaultSubtitleLanes().isEmpty()) {
for (FileAttribute track: fileInfo.getDefaultSubtitleLanes()) { for (FileAttribute track: fileInfo.getExistingDefaultSubtitleLanes()) {
sb.append(format(DISABLE_DEFAULT_TRACK, track.getId())); sb.append(format(DISABLE_DEFAULT_TRACK, track.getId()));
} }
} }
sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredSubtitleLane().getId())); if (fileInfo.getDesiredDefaultSubtitleLane() != null) {
sb.append(format(ENABLE_DEFAULT_TRACK, fileInfo.getDesiredDefaultSubtitleLane().getId()));
}
} }
if (fileInfo.areForcedTracksDifferent()) { if (fileInfo.areForcedTracksDifferent()) {
@@ -178,6 +184,7 @@ public class MkvFileProcessor implements FileProcessor {
} }
} }
log.info(sb.toString());
InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream(); InputStream inputstream = Runtime.getRuntime().exec(sb.toString()).getInputStream();
String output = IOUtils.toString(new InputStreamReader(inputstream)); String output = IOUtils.toString(new InputStreamReader(inputstream));
log.debug(output); log.debug(output);

View File

@@ -19,6 +19,7 @@ import me.tongfei.progressbar.ProgressBar;
import me.tongfei.progressbar.ProgressBarBuilder; import me.tongfei.progressbar.ProgressBarBuilder;
import me.tongfei.progressbar.ProgressBarStyle; import me.tongfei.progressbar.ProgressBarStyle;
import net.harawata.appdirs.AppDirsFactory; import net.harawata.appdirs.AppDirsFactory;
import picocli.CommandLine;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -115,6 +116,7 @@ public abstract class AttributeUpdaterKernel {
* @param fileInfoDto contains information about file and desired configuration. * @param fileInfoDto contains information about file and desired configuration.
*/ */
protected void updateFile(FileInfoDto fileInfoDto) { protected void updateFile(FileInfoDto fileInfoDto) {
statistic.total();
switch (fileInfoDto.getStatus()) { switch (fileInfoDto.getStatus()) {
case CHANGE_NECESSARY: case CHANGE_NECESSARY:
statistic.shouldChange(); statistic.shouldChange();
@@ -139,7 +141,6 @@ public abstract class AttributeUpdaterKernel {
} }
try { try {
statistic.total();
processor.update(fileInfo.getFile(), fileInfo); processor.update(fileInfo.getFile(), fileInfo);
statistic.success(); statistic.success();
log.info("Updated {}", fileInfo.getFile().getAbsolutePath()); log.info("Updated {}", fileInfo.getFile().getAbsolutePath());

View File

@@ -11,9 +11,7 @@ import me.tongfei.progressbar.ProgressBarBuilder;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.io.File; import java.io.File;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@@ -34,8 +32,12 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
*/ */
@Override @Override
List<File> loadFiles(String path) { List<File> loadFiles(String path) {
return loadFiles(path, Config.getInstance().getCoherent());
}
List<File> loadFiles(String path, int depth) {
List<File> excludedFiles = loadExcludedFiles(); List<File> excludedFiles = loadExcludedFiles();
List<File> directories = collector.loadDirectories(path, Config.getInstance().getCoherent()) List<File> directories = collector.loadDirectories(path, depth)
.stream().filter(file -> !excludedFiles.contains(file)) .stream().filter(file -> !excludedFiles.contains(file))
.collect(Collectors.toList()); .collect(Collectors.toList());
return directories.stream() return directories.stream()
@@ -59,25 +61,20 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
*/ */
@Override @Override
void process(File file) { void process(File file) {
process(file, Config.getInstance().getCoherent());
}
void process(File file, int depth) {
// TODO: Implement level crawl if coherence is not possible on user entered depth // TODO: Implement level crawl if coherence is not possible on user entered depth
// IMPL idea: recursive method call, cache needs to be implemented // IMPL idea: recursive method call, cache needs to be implemented
List<FileInfoDto> fileInfos = collector.loadFiles(file.getAbsolutePath()) List<FileInfoDto> fileInfos = collector.loadFiles(file.getAbsolutePath()).stream()
.stream().map(FileInfoDto::new) .map(FileInfoDto::new)
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<FileInfoDto, List<FileAttribute>> fileAttributeCache = new HashMap<>();
for (FileInfoDto fileInfo : fileInfos) {
if (!Config.getInstance().getIncludePattern().matcher(fileInfo.getFile().getAbsolutePath()).matches()) {
statistic.excluded();
continue;
}
fileAttributeCache.put(fileInfo, processor.loadAttributes(fileInfo.getFile()));
}
for (AttributeConfig config : Config.getInstance().getAttributeConfig()) { for (AttributeConfig config : Config.getInstance().getAttributeConfig()) {
for (FileInfoDto fileInfo : fileInfos) { for (FileInfoDto fileInfo : fileInfos) {
List<FileAttribute> attributes = fileAttributeCache.get(fileInfo); List<FileAttribute> attributes = processor.loadAttributes(fileInfo.getFile());
List<FileAttribute> nonForcedTracks = processor.retrieveNonForcedTracks(attributes); List<FileAttribute> nonForcedTracks = processor.retrieveNonForcedTracks(attributes);
List<FileAttribute> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes); List<FileAttribute> nonCommentaryTracks = processor.retrieveNonCommentaryTracks(attributes);
@@ -86,22 +83,23 @@ public class CoherentAttributeUpdaterKernel extends AttributeUpdaterKernel {
processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks, config); processor.detectDesiredTracks(fileInfo, nonForcedTracks, nonCommentaryTracks, config);
} }
if (fileInfos.stream().allMatch(elem -> elem.getDesiredSubtitleLane() != null && elem.getDesiredAudioLane() != null)) { if (fileInfos.stream().allMatch(elem -> ("OFF".equals(config.getSubtitleLanguage()) || elem.getDesiredDefaultSubtitleLane() != null)
&& elem.getDesiredDefaultAudioLane() != null)) {
log.info("Found {}/{} match for {}", config.getAudioLanguage(), config.getSubtitleLanguage(), file.getAbsolutePath()); log.info("Found {}/{} match for {}", config.getAudioLanguage(), config.getSubtitleLanguage(), file.getAbsolutePath());
statistic.increaseTotalBy(fileInfos.size());
fileInfos.forEach(this::updateFile); fileInfos.forEach(this::updateFile);
return; // match found, end process here return; // match found, end process here
} }
fileInfos.forEach(f -> { fileInfos.forEach(f -> {
f.setDesiredAudioLane(null); f.setDesiredDefaultAudioLane(null);
f.setDesiredSubtitleLane(null); f.setDesiredDefaultSubtitleLane(null);
}); });
} }
log.info("No coherent match found for {}", file.getAbsoluteFile());
for (FileInfoDto fileInfo : fileInfos) { for (FileInfoDto fileInfo : fileInfos) {
statistic.total(); if (!Config.getInstance().isForceCoherent()) {
if (Config.getInstance().isForceCoherent()) {
super.process(fileInfo.getFile()); super.process(fileInfo.getFile());
} else { } else {
statistic.excluded(); statistic.excluded();

View File

@@ -13,24 +13,39 @@ import java.util.Set;
@RequiredArgsConstructor @RequiredArgsConstructor
public class FileInfoDto { public class FileInfoDto {
private final File file; private final File file;
private Set<FileAttribute> defaultAudioLanes = new HashSet<>();
private Set<FileAttribute> defaultSubtitleLanes = new HashSet<>(); private Set<FileAttribute> existingDefaultAudioLanes = new HashSet<>();
private Set<FileAttribute> desiredForcedSubtitleLanes; private Set<FileAttribute> existingForcedAudioLanes = new HashSet<>();
private FileAttribute desiredAudioLane;
private FileAttribute desiredSubtitleLane; private Set<FileAttribute> existingDefaultSubtitleLanes = new HashSet<>();
private Set<FileAttribute> existingForcedSubtitleLanes = new HashSet<>();
private Set<FileAttribute> desiredForcedSubtitleLanes = new HashSet<>();
private FileAttribute desiredDefaultAudioLane;
private FileAttribute desiredDefaultSubtitleLane;
private AttributeConfig matchedConfig;
public boolean isAudioDifferent() { public boolean isAudioDifferent() {
return desiredAudioLane != null && return desiredDefaultAudioLane != null &&
(defaultAudioLanes == null || !defaultAudioLanes.contains(desiredAudioLane)); (existingDefaultAudioLanes == null || !existingDefaultAudioLanes.contains(desiredDefaultAudioLane) || existingDefaultAudioLanes.size() > 1);
} }
public boolean isSubtitleDifferent() { public boolean isSubtitleDifferent() {
return desiredSubtitleLane != null && return isSubtitleMatchDifferent() || isSubtitleOFF();
(defaultSubtitleLanes == null || !defaultSubtitleLanes.contains(desiredSubtitleLane)); }
private boolean isSubtitleMatchDifferent() {
return desiredDefaultSubtitleLane != null
&& (existingDefaultSubtitleLanes == null || !existingDefaultSubtitleLanes.contains(desiredDefaultSubtitleLane) || existingDefaultSubtitleLanes.size() > 1);
}
private boolean isSubtitleOFF() {
return desiredDefaultSubtitleLane == null && "OFF".equals(matchedConfig.getSubtitleLanguage()) &&
(existingDefaultSubtitleLanes != null && !existingDefaultSubtitleLanes.isEmpty());
} }
public boolean areForcedTracksDifferent() { public boolean areForcedTracksDifferent() {
return desiredForcedSubtitleLanes.size() > 0; return !desiredForcedSubtitleLanes.isEmpty();
} }
public FileStatus getStatus() { public FileStatus getStatus() {
@@ -41,24 +56,24 @@ public class FileInfoDto {
} }
private boolean isUnableToApplyConfig() { private boolean isUnableToApplyConfig() {
return desiredAudioLane == null && desiredSubtitleLane == null; return desiredDefaultAudioLane == null && desiredDefaultSubtitleLane == null;
} }
private boolean isAlreadySuitable() { private boolean isAlreadySuitable() {
return defaultAudioLanes.contains(desiredAudioLane) && defaultSubtitleLanes.contains(desiredSubtitleLane); return existingDefaultAudioLanes.contains(desiredDefaultAudioLane) && existingDefaultSubtitleLanes.contains(desiredDefaultSubtitleLane);
} }
private boolean isChangeNecessary() { private boolean isChangeNecessary() {
return isAudioDifferent() || isSubtitleDifferent() || areForcedTracksDifferent(); return isAudioDifferent() || isSubtitleDifferent() || areForcedTracksDifferent() || !existingForcedAudioLanes.isEmpty();
} }
@Override @Override
public String toString() { public String toString() {
return "[" + "defaultAudioLanes=" + defaultAudioLanes + return "[" + "defaultAudioLanes=" + existingDefaultAudioLanes +
", defaultSubtitleLanes=" + defaultSubtitleLanes + ", defaultSubtitleLanes=" + existingDefaultSubtitleLanes +
", desiredForcedSubtitleLanes=" + desiredForcedSubtitleLanes + ", desiredForcedSubtitleLanes=" + desiredForcedSubtitleLanes +
", desiredAudioLane=" + desiredAudioLane + ", desiredAudioLane=" + desiredDefaultAudioLane +
", desiredSubtitleLane=" + desiredSubtitleLane + ", desiredSubtitleLane=" + desiredDefaultSubtitleLane +
']'; ']';
} }
} }

View File

@@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
public enum MkvToolNix { public enum MkvToolNix {
MKV_MERGER("mkvmerge"), MKV_MERGE("mkvmerge"),
MKV_PROP_EDIT("mkvpropedit"); MKV_PROP_EDIT("mkvpropedit");
private final String file; private final String file;

View File

@@ -116,7 +116,7 @@ public class ResultStatistic {
@Override @Override
public String toString() { public String toString() {
String sb = "ResultStatistic[" + "filesTotal=" + filesTotal + return "ResultStatistic: " + "filesTotal=" + filesTotal +
", excluded=" + excluded + ", excluded=" + excluded +
", shouldChange=" + shouldChange + ", shouldChange=" + shouldChange +
" (failedChanging=" + failedChanging + " (failedChanging=" + failedChanging +
@@ -124,8 +124,6 @@ public class ResultStatistic {
"), noSuitableConfigFound=" + noSuitableConfigFound + "), noSuitableConfigFound=" + noSuitableConfigFound +
", alreadyFits=" + alreadyFits + ", alreadyFits=" + alreadyFits +
", failed=" + failed + ", failed=" + failed +
", runtime=" + formatTimer() + ", runtime=" + formatTimer();
']';
return sb;
} }
} }

View File

@@ -24,7 +24,7 @@ public class LanguageValidatorUtil {
} }
public static boolean isAudioLanguageValid(String language) { public static boolean isAudioLanguageValid(String language) {
return !language.equals("OFF") && ISO3_LANGUAGES.contains(language); return !language.equals("OFF") && isLanguageValid(language);
} }
public static boolean isLanguageValid(String language) { public static boolean isLanguageValid(String language) {

View File

@@ -1,10 +1,12 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import picocli.CommandLine;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Properties; import java.util.Properties;
public class ProjectUtil { public class ProjectUtil implements CommandLine.IVersionProvider {
private static final Properties PROJECT_PROPERTIES = new Properties(); private static final Properties PROJECT_PROPERTIES = new Properties();
static { static {
@@ -15,8 +17,8 @@ public class ProjectUtil {
} }
} }
public static String getVersion() { public String[] getVersion() {
return PROJECT_PROPERTIES.getProperty("version"); return new String[] {getProjectName() + " " + PROJECT_PROPERTIES.getProperty("version")};
} }
public static String getProjectName() { public static String getProjectName() {

View File

@@ -7,13 +7,17 @@ Configuration:
Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable"
ThresholdFilter: ThresholdFilter:
level: debug level: debug
File: RollingFile:
name: FileAppender name: FileAppender
fileName: default.log fileName: logs/application.log
filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log
PatternLayout: PatternLayout:
Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable"
ThresholdFilter: ThresholdFilter:
level: debug level: debug
Policies:
OnStartupTriggeringPolicy:
minSize: 0
Loggers: Loggers:
Root: Root:
level: debug level: debug

View File

@@ -0,0 +1,31 @@
Configuration:
name: DefaultLogger
Appenders:
File:
name: FileAppender
fileName: ${sys:user.home}/AppData/Roaming/MyApplication/MyApplication.log
PatternLayout:
Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable"
ThresholdFilter:
level: info
RollingFile:
name: FileAppender
fileName: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/application.log
filePattern: ${sys:user.home}/AppData/Roaming/MKVAudioSubtitleChanger/logs/archive/application-%d{yyyy-MM-dd}-%i.log
PatternLayout:
Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable"
ThresholdFilter:
level: info
Policies:
OnStartupTriggeringPolicy:
minSize: 0
Loggers:
Root:
level: info
AppenderRef:
- ref: FileAppender
Logger:
name: "com.zaxxer.hikari.HikariConfig"
level: info
AppenderRef:
- ref: FileAppender

View File

@@ -1,13 +1,17 @@
Configuration: Configuration:
name: DefaultLogger name: DefaultLogger
Appenders: Appenders:
File: RollingFile:
name: FileAppender name: FileAppender
fileName: default.log fileName: logs/application.log
filePattern: logs/archive/application-%d{yyyy-MM-dd}-%i.log
PatternLayout: PatternLayout:
Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable" Pattern: "%d{DEFAULT} | %-5level | %thread | %msg %n %throwable"
ThresholdFilter: ThresholdFilter:
level: info level: info
Policies:
OnStartupTriggeringPolicy:
minSize: 0
Loggers: Loggers:
Root: Root:
level: info level: info

144
src/main/resources/main.wxs Normal file
View File

@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<?ifdef JpIsSystemWide ?>
<?define JpInstallScope="perMachine"?>
<?else?>
<?define JpInstallScope="perUser"?>
<?endif?>
<?define JpProductLanguage=1033 ?>
<?define JpInstallerVersion=200 ?>
<?define JpCompressedMsi=yes ?>
<?ifdef JpAllowUpgrades ?>
<?define JpUpgradeVersionOnlyDetectUpgrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectUpgrade="yes"?>
<?endif?>
<?ifdef JpAllowDowngrades ?>
<?define JpUpgradeVersionOnlyDetectDowngrade="no"?>
<?else?>
<?define JpUpgradeVersionOnlyDetectDowngrade="yes"?>
<?endif?>
<?define JpProductCode="*"?>
<?define JpAppName="MKVAudioSubtitleChanger"?>
<?define JpAppVersion="4.0.0"?>
<?define JpAppVendor="RatzzFatzz"?>
<?define JpProductUpgradeCode="a9527300-d364-4cc3-a392-94035065d8c9"?>
<?define JpAppDescription="Change audio and subtitle tracks for .mkv files"?>
<?define JpHelpURL="github.com/RatzzFatzz"?>
<Product
Id="$(var.JpProductCode)"
Name="$(var.JpAppName)"
Language="$(var.JpProductLanguage)"
Version="$(var.JpAppVersion)"
Manufacturer="$(var.JpAppVendor)"
UpgradeCode="$(var.JpProductUpgradeCode)">
<Package
Description="$(var.JpAppDescription)"
Manufacturer="$(var.JpAppVendor)"
InstallerVersion="$(var.JpInstallerVersion)"
Compressed="$(var.JpCompressedMsi)"
InstallScope="$(var.JpInstallScope)" Platform="x64"
/>
<Media Id="1" Cabinet="Data.cab" EmbedCab="yes" />
<Upgrade Id="$(var.JpProductUpgradeCode)">
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectUpgrade)"
Property="JP_UPGRADABLE_FOUND"
Maximum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMaximum="$(var.JpUpgradeVersionOnlyDetectUpgrade)" />
<UpgradeVersion
OnlyDetect="$(var.JpUpgradeVersionOnlyDetectDowngrade)"
Property="JP_DOWNGRADABLE_FOUND"
Minimum="$(var.JpAppVersion)"
MigrateFeatures="yes"
IncludeMinimum="$(var.JpUpgradeVersionOnlyDetectDowngrade)" />
</Upgrade>
<?ifndef JpAllowUpgrades ?>
<CustomAction Id="JpDisallowUpgrade" Error="!(loc.DisallowUpgradeErrorMessage)" />
<?endif?>
<?ifndef JpAllowDowngrades ?>
<CustomAction Id="JpDisallowDowngrade" Error="!(loc.DowngradeErrorMessage)" />
<?endif?>
<Binary Id="JpCaDll" SourceFile="wixhelper.dll"/>
<CustomAction Id="JpFindRelatedProducts" BinaryKey="JpCaDll" DllEntry="FindRelatedProductsEx" />
<!-- Standard required root -->
<Directory Id="TARGETDIR" Name="SourceDir"/>
<Feature Id="DefaultFeature" Title="!(loc.MainFeatureTitle)" Level="1">
<ComponentGroupRef Id="Shortcuts"/>
<ComponentGroupRef Id="Files"/>
<ComponentGroupRef Id="FileAssociations"/>
<Component Id="pathEnvironmentVariable" Guid="$(var.JpProductUpgradeCode)" KeyPath="yes" Directory="TARGETDIR">
<Environment Id="MyPathVariable" Name="Path" Value="[INSTALLDIR]" Action="set" System="no" Permanent="no" Part="last" Separator=";" />
</Component>
</Feature>
<CustomAction Id="JpSetARPINSTALLLOCATION" Property="ARPINSTALLLOCATION" Value="[INSTALLDIR]" />
<CustomAction Id="JpSetARPCOMMENTS" Property="ARPCOMMENTS" Value="$(var.JpAppDescription)" />
<CustomAction Id="JpSetARPCONTACT" Property="ARPCONTACT" Value="$(var.JpAppVendor)" />
<!-- <CustomAction Id="JpSetARPSIZE" Property="ARPSIZE" Value="$(var.JpAppSizeKb)" /> -->
<?ifdef JpHelpURL ?>
<CustomAction Id="JpSetARPHELPLINK" Property="ARPHELPLINK" Value="$(var.JpHelpURL)" />
<?endif?>
<?ifdef JpAboutURL ?>
<CustomAction Id="JpSetARPURLINFOABOUT" Property="ARPURLINFOABOUT" Value="$(var.JpAboutURL)" />
<?endif?>
<?ifdef JpUpdateURL ?>
<CustomAction Id="JpSetARPURLUPDATEINFO" Property="ARPURLUPDATEINFO" Value="$(var.JpUpdateURL)" />
<?endif?>
<?ifdef JpIcon ?>
<Property Id="ARPPRODUCTICON" Value="JpARPPRODUCTICON"/>
<Icon Id="JpARPPRODUCTICON" SourceFile="$(var.JpIcon)"/>
<?endif?>
<UIRef Id="JpUI"/>
<InstallExecuteSequence>
<Custom Action="JpSetARPINSTALLLOCATION" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPCOMMENTS" After="CostFinalize">Not Installed</Custom>
<Custom Action="JpSetARPCONTACT" After="CostFinalize">Not Installed</Custom>
<!-- <Custom Action="JpSetARPSIZE" After="CostFinalize">Not Installed</Custom> -->
<?ifdef JpHelpURL ?>
<Custom Action="JpSetARPHELPLINK" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifdef JpAboutURL ?>
<Custom Action="JpSetARPURLINFOABOUT" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifdef JpUpdateURL ?>
<Custom Action="JpSetARPURLUPDATEINFO" After="CostFinalize">Not Installed</Custom>
<?endif?>
<?ifndef JpAllowUpgrades ?>
<Custom Action="JpDisallowUpgrade" After="JpFindRelatedProducts">JP_UPGRADABLE_FOUND</Custom>
<?endif?>
<?ifndef JpAllowDowngrades ?>
<Custom Action="JpDisallowDowngrade" After="JpFindRelatedProducts">JP_DOWNGRADABLE_FOUND</Custom>
<?endif?>
<RemoveExistingProducts Before="CostInitialize"/>
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
</InstallExecuteSequence>
<InstallUISequence>
<Custom Action="JpFindRelatedProducts" After="FindRelatedProducts"/>
</InstallUISequence>
</Product>
</Wix>

View File

@@ -0,0 +1,61 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.*;
class AttributeConfigTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-a", "jpn:ger"), attrConf("jpn", "ger")),
Arguments.of(args("-a", "jpn:ger", "jpn:eng"), attrConf("jpn", "ger", "jpn", "eng")),
Arguments.of(args("-a", "jpn:ger", "jpn:OFF"), attrConf("jpn", "ger", "jpn", "OFF"))
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, List<AttributeConfig> expectedConfig) {
Main underTest = new Main();
CommandLine.populateCommand(underTest, cmdArgs);
assertIterableEquals(expectedConfig, underTest.getConfig().getAttributeConfig());
}
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, new String[]{"-l", "/"}));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, new String[]{"-l", "/", "-a"}));
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, new String[]{"-l", "/", "-a", "ger:"}));
assertThrows(CommandLine.ParameterException.class,
() -> CommandLine.populateCommand(sut, new String[]{"-l", "/", "-a", "ger:qwf"})); // Invalid language code
}
private static String[] args(String... args) {
String[] staticArray = new String[]{"-l", "/"};
String[] result = new String[staticArray.length + args.length];
System.arraycopy(staticArray, 0, result, 0, staticArray.length);
System.arraycopy(args, 0, result, staticArray.length, args.length);
return result;
}
private static List<AttributeConfig> attrConf(String... languages) {
List<AttributeConfig> conf = new ArrayList<>();
for (int i = 0; i < languages.length; i += 2) {
conf.add(new AttributeConfig(languages[i], languages[i+1]));
}
return conf;
}
}

View File

@@ -0,0 +1,37 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.util.function.Function;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.assertEquals;
class BooleanConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-s"), true, (Function<Config, Boolean>) Config::isSafeMode),
Arguments.of(args("--safemode"), true, (Function<Config, Boolean>) Config::isSafeMode),
Arguments.of(args(), false, (Function<Config, Boolean>) Config::isSafeMode),
Arguments.of(args("-cf"), true, (Function<Config, Boolean>) Config::isForceCoherent),
Arguments.of(args("--force-coherent"), true, (Function<Config, Boolean>) Config::isForceCoherent),
Arguments.of(args(), false, (Function<Config, Boolean>) Config::isForceCoherent),
Arguments.of(args("-n"), true, (Function<Config, Boolean>) Config::isOnlyNewFiles),
Arguments.of(args(), false, (Function<Config, Boolean>) Config::isOnlyNewFiles)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, boolean expected, Function<Config, Boolean> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected, fieldUnderTest.apply(sut.getConfig()));
}
}

View File

@@ -0,0 +1,46 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import org.junit.jupiter.api.Test;
import picocli.CommandLine;
import java.util.List;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE;
import static org.junit.jupiter.api.Assertions.*;
class ConfigTest {
@Test
void initConfig() {
String[] sut = new String[]{"-a", "ger:ger", "eng:eng", "-l", TEST_FILE,
"-s", "-cf", "-n",
"-c", "2",
"-t", "4",
"-i", ".*[abc].*",
"-fk", "testForced",
"-ck", "testCommentary",
"-ps", "testPreferred"
};
CommandLine.populateCommand(Config.getInstance(), sut);
assertTrue(Config.getInstance().getLibraryPath().exists());
assertEquals(List.of(new AttributeConfig("ger", "ger"), new AttributeConfig("eng", "eng")),
Config.getInstance().getAttributeConfig());
assertTrue(Config.getInstance().isSafeMode());
assertTrue(Config.getInstance().isForceCoherent());
assertTrue(Config.getInstance().isOnlyNewFiles());
assertNull(Config.getInstance().getFilterDate());
assertEquals(2, Config.getInstance().getCoherent());
assertEquals(4, Config.getInstance().getThreads());
assertEquals(".*[abc].*", Config.getInstance().getIncludePattern().pattern());
assertTrue(Config.getInstance().getForcedKeywords().contains("testForced"));
assertTrue(Config.getInstance().getCommentaryKeywords().contains("testCommentary"));
assertTrue(Config.getInstance().getPreferredSubtitles().contains("testPreferred"));
assertNull(Config.getInstance().getConfigPath());
}
}

View File

@@ -0,0 +1,50 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.function.Function;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.*;
class IntegerConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args(), 2, (Function<Config, Integer>) Config::getThreads),
Arguments.of(args("-t", "5"), 5, (Function<Config, Integer>) Config::getThreads),
Arguments.of(args("--threads", "5"), 5, (Function<Config, Integer>) Config::getThreads)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, int expected, Function<Config, Integer> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected, fieldUnderTest.apply(sut.getConfig()));
}
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-t")));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("--threads")));
StringWriter writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
CommandLine underTest = new CommandLine(sut);
underTest = underTest.setErr(printWriter);
underTest.execute(args("-t", "0"));
printWriter.flush();
assertTrue(writer.toString().contains("ERROR: threads must be greater than or equal to 1"));
}
}

View File

@@ -0,0 +1,54 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import org.apache.commons.lang3.SystemUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.io.File;
import java.nio.file.Path;
import java.util.function.Function;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.*;
class MkvToolNixPathConfigParameterTest {
private static final String TEST_INVALID_DIR = "src/test/resources/test-dir";
private static final String TEST_MKVTOOLNIX_DIR = "src/test/resources/mkvtoolnix";
private static final String TEST_MKVTOOLNIX_EXE_DIR = "src/test/resources/mkvtoolnix_exe";
private static Stream<Arguments> provideTestCases() {
if (SystemUtils.IS_OS_WINDOWS) {
return Stream.of(
Arguments.of(args("-m", TEST_MKVTOOLNIX_EXE_DIR), TEST_MKVTOOLNIX_EXE_DIR, (Function<Config, File>) Config::getMkvToolNix),
Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_EXE_DIR), TEST_MKVTOOLNIX_EXE_DIR, (Function<Config, File>) Config::getMkvToolNix)
);
}
return Stream.of(
Arguments.of(args("-m", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function<Config, File>) Config::getMkvToolNix),
Arguments.of(args("--mkvtoolnix", TEST_MKVTOOLNIX_DIR), TEST_MKVTOOLNIX_DIR, (Function<Config, File>) Config::getMkvToolNix)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, String expected, Function<Config, File> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(Path.of(expected).toFile().getAbsolutePath(), fieldUnderTest.apply(sut.getConfig()).getAbsolutePath());
}
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m", TEST_INVALID_DIR)));
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-m")));
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("")));
}
}

View File

@@ -0,0 +1,53 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.io.File;
import java.nio.file.Path;
import java.util.function.Function;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_DIR;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.PathUtils.TEST_FILE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class PathConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-l", TEST_DIR), Path.of(TEST_DIR).toFile(), true, (Function<Config, File>) Config::getLibraryPath),
Arguments.of(args("-l", TEST_FILE), Path.of(TEST_FILE).toFile(), true, (Function<Config, File>) Config::getLibraryPath)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, File expected, boolean exists, Function<Config, File> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected.getAbsolutePath(), fieldUnderTest.apply(sut.getConfig()).getAbsolutePath());
assertEquals(exists, fieldUnderTest.apply(sut.getConfig()).exists());
}
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-l", "arst")));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-l")));
assertThrows(CommandLine.UnmatchedArgumentException.class, () -> CommandLine.populateCommand(sut, args("")));
}
private static String[] args(String... args) {
String[] staticArray = new String[]{"-a", "ger:ger"};
String[] result = new String[staticArray.length + args.length];
System.arraycopy(staticArray, 0, result, 0, staticArray.length);
System.arraycopy(args, 0, result, staticArray.length, args.length);
return result;
}
}

View File

@@ -0,0 +1,42 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class PatternConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-i", "[abd]?.*"), Pattern.compile("[abd]?.*"), (Function<Config, Pattern>) Config::getIncludePattern),
Arguments.of(args("-i", ".*"), Pattern.compile(".*"), (Function<Config, Pattern>) Config::getIncludePattern),
Arguments.of(args(), Pattern.compile(".*"), (Function<Config, Pattern>) Config::getIncludePattern)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, Pattern expected, Function<Config, Pattern> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expected.pattern(), fieldUnderTest.apply(sut.getConfig()).pattern());
}
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-i")));
assertThrows(CommandLine.ParameterException.class, () -> CommandLine.populateCommand(sut, args("-i", "[")));
}
}

View File

@@ -0,0 +1,50 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.Main;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import picocli.CommandLine;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.args;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class SetConfigParameterTest {
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(args("-ck", "test"), 1, (Function<Config, Set<String>>) Config::getCommentaryKeywords),
Arguments.of(args("-ck", "test", "test1", "test2", "test3", "test4"), 5, (Function<Config, Set<String>>) Config::getCommentaryKeywords),
Arguments.of(args(), 2, (Function<Config, Set<String>>) Config::getCommentaryKeywords),
Arguments.of(args("-fk", "test"), 1, (Function<Config, Set<String>>) Config::getForcedKeywords),
Arguments.of(args("-fk", "test", "test1", "test2", "test3", "test4"), 5, (Function<Config, Set<String>>) Config::getForcedKeywords),
Arguments.of(args(), 3, (Function<Config, Set<String>>) Config::getForcedKeywords),
Arguments.of(args("-ps", "test"), 1, (Function<Config, Set<String>>) Config::getPreferredSubtitles),
Arguments.of(args("-ps", "test", "test1", "test2", "test3", "test4"), 5, (Function<Config, Set<String>>) Config::getPreferredSubtitles),
Arguments.of(args(), 1, (Function<Config, Set<String>>) Config::getPreferredSubtitles)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String[] cmdArgs, int expectedSize, Function<Config, Set<String>> fieldUnderTest) {
Main sut = new Main();
CommandLine.populateCommand(sut, cmdArgs);
assertEquals(expectedSize, fieldUnderTest.apply(sut.getConfig()).size());
}
@Test
void validate() {
Main sut = new Main();
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-ck")));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-fk")));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-e")));
assertThrows(CommandLine.MissingParameterException.class, () -> CommandLine.populateCommand(sut, args("-ps")));
}
}

View File

@@ -1,85 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static org.junit.jupiter.api.Assertions.*;
class AttributeConfigValidatorTest {
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(ATTRIBUTE_CONFIG, ATTRIBUTE_CONFIG.abrv(), ATTRIBUTE_CONFIG.args()));
}
@BeforeEach
void beforeEach() {
Config.getInstance(true);
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(attrConfYaml("jpn", "ger"), new String[]{}, VALID, attrConf("jpn", "ger")),
Arguments.of("", new String[]{"-a", "jpn:ger"}, VALID, attrConf("jpn", "ger")),
Arguments.of(attrConfYaml("jpn", "ger", "jpn", "eng"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "eng")),
Arguments.of("", new String[]{"-a", "jpn:ger", "jpn:eng"}, VALID, attrConf("jpn", "ger", "jpn", "eng")),
Arguments.of(attrConfYaml("jpn", "ger", "jpn", "OFF"), new String[]{}, VALID, attrConf("jpn", "ger", "jpn", "OFF")),
Arguments.of("", new String[]{"-a", "jpn:ger", "jpn:OFF"}, VALID, attrConf("jpn", "ger", "jpn", "OFF")),
Arguments.of(attrConfYaml("jpn", "invalid"), new String[]{}, INVALID, null),
Arguments.of("", new String[]{}, MISSING, null)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(String yamlArgs, String[] cmdArgs, ValidationResult expectedResult, List<AttributeConfig> expectedConfig)
throws ParseException, YamlInvalidContentException {
AttributeConfigValidator underTest = new AttributeConfigValidator();
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
assertIterableEquals(expectedConfig, Config.getInstance().getAttributeConfig());
}
private static String attrConfYaml(String... languages) {
StringBuilder yaml = new StringBuilder("attribute-config: ");
int counter = 0;
for (int i = 0; i < languages.length; i += 2) {
counter++;
yaml.append(String.format("\n %s:\n audio: %s\n subtitle: %s", counter, languages[i], languages[i+1]));
}
return yaml.toString();
}
private static List<AttributeConfig> attrConf(String... languages) {
List<AttributeConfig> conf = new ArrayList<>();
for (int i = 0; i < languages.length; i += 2) {
conf.add(new AttributeConfig(languages[i], languages[i+1]));
}
return conf;
}
}

View File

@@ -1,58 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.yamlList;
import static org.junit.jupiter.api.Assertions.assertEquals;
class BooleanValidatorTest {
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(SAFE_MODE, SAFE_MODE.abrv(), SAFE_MODE.args()));
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(SAFE_MODE, false, "", new String[]{"-safe-mode"}, VALID),
Arguments.of(SAFE_MODE, true, "", new String[]{"-safe-mode"}, VALID),
Arguments.of(SAFE_MODE, false, "", new String[]{""}, NOT_PRESENT),
Arguments.of(SAFE_MODE, true, "", new String[]{""}, MISSING),
Arguments.of(SAFE_MODE, false, yamlList(ARGUMENTS, SAFE_MODE), new String[]{""}, VALID),
Arguments.of(SAFE_MODE, true, yamlList(ARGUMENTS, SAFE_MODE), new String[]{""}, VALID),
Arguments.of(SAFE_MODE, false, yamlList(ARGUMENTS, WINDOWS), new String[]{""}, NOT_PRESENT),
Arguments.of(SAFE_MODE, true, yamlList(ARGUMENTS, WINDOWS), new String[]{""}, MISSING)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
BooleanValidator underTest = new BooleanValidator(property, required);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
}
}

View File

@@ -1,65 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.File;
import java.nio.file.Path;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.MISSING;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static org.junit.jupiter.api.Assertions.*;
class MkvToolNixPathValidatorTest {
private static final String TEST_INVALID_DIR = "src/test/resources/test-dir";
private static final String TEST_MKVTOOLNIX_DIR = "src/test/resources/mkvtoolnix";
private static final String TEST_MKVTOOLNIX_EXE_DIR = "src/test/resources/mkvtoolnix_exe";
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(MKV_TOOL_NIX, MKV_TOOL_NIX.abrv(), MKV_TOOL_NIX.args()));
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
Arguments.of(MKV_TOOL_NIX, false, null, "", new String[]{"-m", TEST_MKVTOOLNIX_DIR}, VALID),
Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{"-m", TEST_MKVTOOLNIX_EXE_DIR}, VALID),
Arguments.of(MKV_TOOL_NIX, false, null, "mkvtoolnix: " + TEST_MKVTOOLNIX_EXE_DIR, new String[]{}, VALID),
Arguments.of(MKV_TOOL_NIX, true, null, "mkvtoolnix: " + TEST_MKVTOOLNIX_DIR, new String[]{}, VALID),
Arguments.of(MKV_TOOL_NIX, false, Path.of(TEST_MKVTOOLNIX_EXE_DIR).toFile(), "", new String[]{}, DEFAULT),
Arguments.of(MKV_TOOL_NIX, false, null, "", new String[]{}, NOT_PRESENT),
Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{}, MISSING),
Arguments.of(MKV_TOOL_NIX, true, null, "", new String[]{"-m", TEST_INVALID_DIR}, INVALID)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
MkvToolNixPathValidator underTest = new MkvToolNixPathValidator(property, required, defaultValue);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
}
}

View File

@@ -1,66 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.io.File;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.LIBRARY;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
import static org.junit.jupiter.api.Assertions.*;
class PathValidatorTest {
private static final String TEST_DIR = "src/test/resources/test-dir";
private static final String TEST_FILE = "src/test/resources/test-dir/test-file.mkv";
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(LIBRARY, LIBRARY.abrv(), LIBRARY.args()));
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
argumentsOf(LIBRARY, false, null, "library-path: " + TEST_DIR, new String[]{}, VALID),
argumentsOf(LIBRARY, true, null, "", new String[]{"-l", TEST_FILE}, VALID),
argumentsOf(LIBRARY, false, TEST_DIR, "", new String[]{}, DEFAULT),
argumentsOf(LIBRARY, true, TEST_FILE, "", new String[]{}, DEFAULT),
argumentsOf(LIBRARY, true, null, "", new String[]{}, MISSING),
argumentsOf(LIBRARY, false, null, "", new String[]{}, NOT_PRESENT),
argumentsOf(LIBRARY, true, null, "", new String[]{"-l", TEST_DIR + "/invalid"}, INVALID),
argumentsOf(LIBRARY, false, null, "library-path: " + TEST_DIR + "/invalid", new String[]{}, INVALID),
argumentsOf(LIBRARY, true, TEST_DIR, "", new String[]{"-l", TEST_DIR + "/invalid"}, INVALID)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, File defaultValue, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
PathValidator underTest = new PathValidator(property, required, defaultValue);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
}
}

View File

@@ -1,64 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.INVALID;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.INCLUDE_PATTERN;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
import static org.junit.jupiter.api.Assertions.*;
class PatternValidatorTest {
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(INCLUDE_PATTERN, INCLUDE_PATTERN.abrv(), INCLUDE_PATTERN.args()));
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
argumentsOf(INCLUDE_PATTERN, false, null, "include-pattern: \"[abd]?.*\"", new String[]{}, VALID),
argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{"-i", "[abd]?.*"}, VALID),
argumentsOf(INCLUDE_PATTERN, false, Pattern.compile(".*"), "", new String[]{}, DEFAULT),
argumentsOf(INCLUDE_PATTERN, true, Pattern.compile(".*"), "", new String[]{}, DEFAULT),
argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{}, MISSING),
argumentsOf(INCLUDE_PATTERN, false, null, "", new String[]{}, NOT_PRESENT),
argumentsOf(INCLUDE_PATTERN, true, null, "", new String[]{"-i", "?."}, INVALID),
argumentsOf(INCLUDE_PATTERN, false, null, "include-pattern: \"[arst*\"", new String[]{}, INVALID),
argumentsOf(INCLUDE_PATTERN, true, Pattern.compile(".?"), "", new String[]{"-i", "?."}, INVALID)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, Pattern defaultValue, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
PatternValidator underTest = new PatternValidator(property, required, defaultValue);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
}
}

View File

@@ -1,68 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.Config;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.COMMENTARY_KEYWORDS;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
class SetValidatorTest {
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(COMMENTARY_KEYWORDS, COMMENTARY_KEYWORDS.abrv(), COMMENTARY_KEYWORDS.args()));
}
@BeforeEach
void beforeEach() {
Config.getInstance(true);
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
argumentsOf(COMMENTARY_KEYWORDS, true, true, "", new String[]{"-ck", "test"}, VALID, 3),
argumentsOf(COMMENTARY_KEYWORDS, true, false, COMMENTARY_KEYWORDS.prop() + ": [test]", new String[]{}, VALID, 1),
argumentsOf(COMMENTARY_KEYWORDS, true, false, COMMENTARY_KEYWORDS.prop() + ":\n - test\n - test2", new String[]{}, VALID, 2),
argumentsOf(COMMENTARY_KEYWORDS, false, true, COMMENTARY_KEYWORDS.prop() + ": [test]", new String[]{}, VALID, 3),
argumentsOf(COMMENTARY_KEYWORDS, false, false, "", new String[]{"-ck", "test"}, VALID, 1),
argumentsOf(COMMENTARY_KEYWORDS, true, true, COMMENTARY_KEYWORDS.prop() + ": [commentary]", new String[]{}, VALID, 2),
argumentsOf(COMMENTARY_KEYWORDS, true, true, "", new String[]{}, MISSING, 2),
argumentsOf(COMMENTARY_KEYWORDS, false, true, "", new String[]{}, NOT_PRESENT, 2)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, boolean append, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult, int expectedSize) throws ParseException, YamlInvalidContentException {
SetValidator underTest = new SetValidator(property, required, append);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
assertEquals(expectedSize, Config.getInstance().getCommentaryKeywords().size());
}
}

View File

@@ -1,61 +0,0 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.config.validator;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.yaml.YAML;
import at.pcgamingfreaks.yaml.YamlInvalidContentException;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult.*;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty.THREADS;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.CommandLineOptionsUtil.optionOf;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.argumentsOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
class ThreadValidatorTest {
private static CommandLineParser parser;
private static Options options;
@BeforeAll
static void before() {
parser = new DefaultParser();
options = new Options();
options.addOption(optionOf(THREADS, "t", THREADS.args()));
}
private static Stream<Arguments> provideTestCases() {
return Stream.of(
argumentsOf(THREADS, false, null, "", new String[]{"-t", "10"}, VALID),
argumentsOf(THREADS, true, null, "", new String[]{"-t", "10"}, VALID),
argumentsOf(THREADS, false, null, "threads: 10", new String[]{}, VALID),
argumentsOf(THREADS, true, null, "threads: 10", new String[]{}, VALID),
argumentsOf(THREADS, false, 2, "", new String[]{}, DEFAULT),
argumentsOf(THREADS, true, null, "", new String[]{}, MISSING),
argumentsOf(THREADS, false, null, "", new String[]{}, NOT_PRESENT),
argumentsOf(THREADS, true, null, "", new String[]{"-t", "-1"}, INVALID),
argumentsOf(THREADS, true, null, "threads: 0", new String[]{}, INVALID),
argumentsOf(THREADS, true, 2, "", new String[]{"-t", "0"}, INVALID)
);
}
@ParameterizedTest
@MethodSource("provideTestCases")
void validate(ConfigProperty property, boolean required, Integer defaultValue, String yamlArgs, String[] cmdArgs,
ValidationResult expectedResult) throws ParseException, YamlInvalidContentException {
ThreadValidator underTest = new ThreadValidator(property, required, defaultValue);
ValidationResult result = underTest.validate(new YAML(yamlArgs), parser.parse(options, cmdArgs));
assertEquals(expectedResult, result);
}
}

View File

@@ -0,0 +1,59 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.model;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.Set;
import java.util.stream.Stream;
import static at.pcgamingfreaks.mkvaudiosubtitlechanger.util.TestUtil.createFileInfo;
import static org.junit.jupiter.api.Assertions.*;
class FileInfoDtoTest {
private static final FileAttribute AUDIO_GER_DEFAULT = new FileAttribute(0, "ger", "", true, false, LaneType.AUDIO);
private static final FileAttribute AUDIO_GER = new FileAttribute(0, "ger", "", false, false, LaneType.AUDIO);
private static final FileAttribute AUDIO_ENG_DEFAULT = new FileAttribute(1, "eng", "", true, false, LaneType.AUDIO);
private static final FileAttribute AUDIO_ENG = new FileAttribute(1, "eng", "", false, false, LaneType.AUDIO);
private static final FileAttribute SUB_GER_DEFAULT = new FileAttribute(0, "ger", "", true, false, LaneType.SUBTITLES);
private static final FileAttribute SUB_GER = new FileAttribute(0, "ger", "", false, false, LaneType.SUBTITLES);
private static final FileAttribute SUB_ENG_DEFAULT = new FileAttribute(1, "eng", "", true, false, LaneType.SUBTITLES);
private static final FileAttribute SUB_ENG = new FileAttribute(1, "eng", "", false, false, LaneType.SUBTITLES);
private static Stream<Arguments> isAudioDifferent() {
return Stream.of(
Arguments.of(createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_GER_DEFAULT), false),
Arguments.of(createFileInfo(Set.of(AUDIO_GER_DEFAULT), AUDIO_ENG), true),
Arguments.of(createFileInfo(Set.of(AUDIO_GER_DEFAULT, AUDIO_ENG_DEFAULT), AUDIO_GER_DEFAULT), true),
Arguments.of(createFileInfo(Set.of(), AUDIO_GER), true),
Arguments.of(createFileInfo(null, AUDIO_GER), true)
);
}
@ParameterizedTest
@MethodSource
void isAudioDifferent(FileInfoDto underTest, boolean expected) {
assertEquals(expected, underTest.isAudioDifferent());
}
private static Stream<Arguments> isSubtitleDifferent() {
return Stream.of(
Arguments.of(createFileInfo(Set.of(SUB_GER_DEFAULT), SUB_GER_DEFAULT, new AttributeConfig("", "ger")), false),
Arguments.of(createFileInfo(Set.of(SUB_GER_DEFAULT), SUB_ENG, new AttributeConfig("", "eng")), true),
Arguments.of(createFileInfo(Set.of(SUB_GER_DEFAULT, SUB_ENG_DEFAULT), SUB_ENG, new AttributeConfig("", "eng")), true),
Arguments.of(createFileInfo(Set.of(), SUB_ENG, new AttributeConfig("", "ger")), true),
Arguments.of(createFileInfo(null, SUB_GER, new AttributeConfig("", "ger")), true),
Arguments.of(createFileInfo(null, null, new AttributeConfig("", "OFF")), false),
Arguments.of(createFileInfo(Set.of(), null, new AttributeConfig("", "OFF")), false),
Arguments.of(createFileInfo(Set.of(SUB_GER_DEFAULT), null, new AttributeConfig("", "OFF")), true)
);
}
@ParameterizedTest
@MethodSource
void isSubtitleDifferent(FileInfoDto underTest, boolean expected) {
assertEquals(expected, underTest.isSubtitleDifferent());
}
}

View File

@@ -0,0 +1,23 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.util.Date;
import static org.junit.jupiter.api.Assertions.*;
@Disabled
class DateUtilsTest {
@Test
void convert() {
Date expectedDate = new Date(0);
String expectedString = "01.01.1970-01:00:00";
assertEquals(expectedDate, DateUtils.convert(0));
assertEquals(expectedDate, DateUtils.convert(expectedString, expectedDate));
assertEquals(expectedDate, DateUtils.convert("1234;15", expectedDate));
assertEquals(expectedString, DateUtils.convert(expectedDate));
}
}

View File

@@ -0,0 +1,6 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
public class PathUtils {
public static final String TEST_DIR = "src/test/resources/test-dir";
public static final String TEST_FILE = "src/test/resources/test-dir/test-file.mkv";
}

View File

@@ -0,0 +1,20 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.Set;
import static org.junit.jupiter.api.Assertions.*;
class SetUtilsTest {
@Test
void retainOf() {
List<Integer> list1 = List.of(1, 2, 3, 4, 5);
List<Integer> list2 = List.of(2, 4, 6, 8, 10);
Set<Integer> expected = Set.of(2, 4);
assertEquals(expected, SetUtils.retainOf(list1, list2));
}
}

View File

@@ -1,10 +1,14 @@
package at.pcgamingfreaks.mkvaudiosubtitlechanger.util; package at.pcgamingfreaks.mkvaudiosubtitlechanger.util;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult; import at.pcgamingfreaks.mkvaudiosubtitlechanger.config.ValidationResult;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.AttributeConfig;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty; import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.ConfigProperty;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileAttribute;
import at.pcgamingfreaks.mkvaudiosubtitlechanger.model.FileInfoDto;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
@@ -25,4 +29,26 @@ public class TestUtil {
return Arguments.of(property, required, append, yaml, cmd, result, expectedSize); return Arguments.of(property, required, append, yaml, cmd, result, expectedSize);
} }
public static FileInfoDto createFileInfo(Set<FileAttribute> defaultAudio, FileAttribute desiredAudio) {
FileInfoDto fileInfoDto = new FileInfoDto(null);
fileInfoDto.setExistingDefaultAudioLanes(defaultAudio);
fileInfoDto.setDesiredDefaultAudioLane(desiredAudio);
return fileInfoDto;
}
public static FileInfoDto createFileInfo(Set<FileAttribute> defaultSubtitle, FileAttribute desiredSubtitle, AttributeConfig config) {
FileInfoDto fileInfoDto = new FileInfoDto(null);
fileInfoDto.setExistingDefaultSubtitleLanes(defaultSubtitle);
fileInfoDto.setDesiredDefaultSubtitleLane(desiredSubtitle);
fileInfoDto.setMatchedConfig(config);
return fileInfoDto;
}
public static String[] args(String... args) {
String[] staticArray = new String[]{"-l", "/", "-a", "jpn:ger"};
String[] result = new String[staticArray.length + args.length];
System.arraycopy(staticArray, 0, result, 0, staticArray.length);
System.arraycopy(args, 0, result, staticArray.length, args.length);
return result;
}
} }