diff --git a/client/src/assembly/linux-jre.xml b/client/src/assembly/linux-jre.xml
index 73a06723..21c6a1a1 100644
--- a/client/src/assembly/linux-jre.xml
+++ b/client/src/assembly/linux-jre.xml
@@ -26,6 +26,12 @@
true
ctbrec-no-splash.sh
+
+ ${project.basedir}/src/assembly/pac.js
+ ctbrec
+ true
+ pac.js
+
${project.build.directory}/${project.artifactId}-${project.version}.jar
ctbrec
diff --git a/client/src/assembly/macos-jre.xml b/client/src/assembly/macos-jre.xml
index e95f753c..72118aec 100644
--- a/client/src/assembly/macos-jre.xml
+++ b/client/src/assembly/macos-jre.xml
@@ -26,6 +26,12 @@
true
ctbrec-no-splash.sh
+
+ ${project.basedir}/src/assembly/pac.js
+ ctbrec
+ true
+ pac.js
+
${project.build.directory}/${project.artifactId}-${project.version}.jar
diff --git a/client/src/assembly/pac.js b/client/src/assembly/pac.js
new file mode 100644
index 00000000..13e660ea
--- /dev/null
+++ b/client/src/assembly/pac.js
@@ -0,0 +1,9 @@
+function FindProxyForURL(url, host) {
+ if (shExpMatch(host, "*stripchat.com")) {
+ return "SOCKS 127.0.0.1:1080";
+ } else if (shExpMatch(host, "*chaturbate.com")) {
+ return "PROXY 127.0.0.1:8080";
+ } else {
+ return "DIRECT";
+ }
+}
\ No newline at end of file
diff --git a/client/src/assembly/win64-jre.xml b/client/src/assembly/win64-jre.xml
index 055294d8..f27fe380 100644
--- a/client/src/assembly/win64-jre.xml
+++ b/client/src/assembly/win64-jre.xml
@@ -22,6 +22,12 @@
${project.build.directory}/ctbrec-no-splash.exe
ctbrec
+
+ ${project.basedir}/src/assembly/pac.js
+ ctbrec
+ true
+ pac.js
+
${project.build.directory}/${project.artifactId}-${project.version}.jar
ctbrec
diff --git a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java
index f3ef962b..91dd91b4 100644
--- a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java
+++ b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java
@@ -85,6 +85,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
private SimpleStringProperty proxyPort;
private SimpleStringProperty proxyUser;
private SimpleStringProperty proxyPassword;
+ private SimpleStringProperty pacUrl;
private SimpleDirectoryProperty recordingsDir;
private SimpleListProperty directoryStructure;
private SimpleListProperty splitAfter;
@@ -169,11 +170,12 @@ public class SettingsTab extends Tab implements TabSelectionListener {
maximumResolutionPlayer = new SimpleIntegerProperty(null, "maximumResolutionPlayer", settings.maximumResolutionPlayer);
showPlayerStarting = new SimpleBooleanProperty(null, "showPlayerStarting", settings.showPlayerStarting);
singlePlayer = new SimpleBooleanProperty(null, "singlePlayer", settings.singlePlayer);
- proxyType = new SimpleListProperty<>(null, "proxyType", FXCollections.observableList(List.of(DIRECT, HTTP, SOCKS4, SOCKS5)));
+ proxyType = new SimpleListProperty<>(null, "proxyType", FXCollections.observableList(List.of(DIRECT, HTTP, SOCKS4, SOCKS5, PAC)));
proxyHost = new SimpleStringProperty(null, "proxyHost", settings.proxyHost);
proxyPort = new SimpleStringProperty(null, "proxyPort", settings.proxyPort);
proxyUser = new SimpleStringProperty(null, "proxyUser", settings.proxyUser);
proxyPassword = new SimpleStringProperty(null, "proxyPassword", settings.proxyPassword);
+ pacUrl = new SimpleStringProperty(null, "pacUrl", settings.pacUrl);
recordingsDir = new SimpleDirectoryProperty(null, "recordingsDir", settings.recordingsDir);
directoryStructure = new SimpleListProperty<>(null, "recordingsDirStructure",
FXCollections.observableList(List.of(FLAT, ONE_PER_MODEL, ONE_PER_GROUP, ONE_PER_RECORDING)));
@@ -337,7 +339,8 @@ public class SettingsTab extends Tab implements TabSelectionListener {
Setting.of("Host", proxyHost).needsRestart(),
Setting.of("Port", proxyPort).needsRestart(),
Setting.of("Username", proxyUser).needsRestart(),
- Setting.of("Password", proxyPassword).needsRestart())),
+ Setting.of("Password", proxyPassword).needsRestart(),
+ Setting.of("PAC URL", pacUrl, "URL to your Proxy Auto-Config (PAC) file (e.g. http://example.com/pac.js or file:///G:/path/to/pac.js)").needsRestart())),
Category.of("Advanced / Devtools",
Group.of("Networking",
Setting.of("Playlist request timeout (ms)", playlistRequestTimeout, "Timeout in ms for playlist requests"),
diff --git a/common/pom.xml b/common/pom.xml
index 67ac4199..563b674c 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -8,7 +8,7 @@
ctbrec
master
- 25.9.22
+ 25.9.27
../master
@@ -41,6 +41,11 @@
com.fasterxml.jackson.datatype
jackson-datatype-jsr310
+
+ org.bidib.com.github.markusbernhardt
+ proxy-vole
+ 1.1.6
+
org.mapstruct
mapstruct
diff --git a/common/src/main/java/ctbrec/Settings.java b/common/src/main/java/ctbrec/Settings.java
index f25d2a71..dac30376 100644
--- a/common/src/main/java/ctbrec/Settings.java
+++ b/common/src/main/java/ctbrec/Settings.java
@@ -32,7 +32,8 @@ public class Settings {
DIRECT,
HTTP,
SOCKS4,
- SOCKS5
+ SOCKS5,
+ PAC
}
public enum SplitStrategy {
@@ -151,6 +152,7 @@ public class Settings {
public String proxyPort;
public ProxyType proxyType = ProxyType.DIRECT;
public String proxyUser;
+ public String pacUrl;
public boolean recentlyWatched = true;
public List recordLaterTableColumnOrder = new ArrayList<>();
public Map recordLaterTableColumnVisibility = new HashMap<>();
diff --git a/common/src/main/java/ctbrec/io/HttpClient.java b/common/src/main/java/ctbrec/io/HttpClient.java
index c80533ec..4177a0d3 100644
--- a/common/src/main/java/ctbrec/io/HttpClient.java
+++ b/common/src/main/java/ctbrec/io/HttpClient.java
@@ -1,5 +1,7 @@
package ctbrec.io;
+import com.github.markusbernhardt.proxy.selector.pac.PacProxySelector;
+import com.github.markusbernhardt.proxy.selector.pac.UrlPacScriptSource;
import com.fasterxml.jackson.core.type.TypeReference;
import ctbrec.Config;
import ctbrec.LoggingInterceptor;
@@ -20,6 +22,7 @@ import java.io.File;
import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
+import java.net.ProxySelector;
import java.nio.file.Files;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
@@ -116,6 +119,18 @@ public abstract class HttpClient {
Authenticator.setDefault(new SocksProxyAuth(username, password));
}
break;
+ case PAC:
+ String pacUrl = config.getSettings().pacUrl;
+ if (pacUrl != null && !pacUrl.isEmpty()) {
+ try {
+ UrlPacScriptSource pacSource = new UrlPacScriptSource(pacUrl);
+ ProxySelector pacSelector = new PacProxySelector(pacSource);
+ ProxySelector.setDefault(pacSelector);
+ } catch (Exception e) {
+ log.warn("Failed to load PAC file: {}", e.getMessage());
+ }
+ }
+ break;
case DIRECT:
default:
System.clearProperty(ProxyConstants.HTTP_PROXY_HOST);
@@ -248,6 +263,10 @@ public abstract class HttpClient {
}
}
+ if (config.getSettings().proxyType == ProxyType.PAC) {
+ builder.proxySelector(ProxySelector.getDefault());
+ }
+
ProxyType proxyType = config.getSettings().proxyType;
if (proxyType == ProxyType.HTTP) {
String username = config.getSettings().proxyUser;
diff --git a/server/src/assembly/pac.js b/server/src/assembly/pac.js
new file mode 100644
index 00000000..13e660ea
--- /dev/null
+++ b/server/src/assembly/pac.js
@@ -0,0 +1,9 @@
+function FindProxyForURL(url, host) {
+ if (shExpMatch(host, "*stripchat.com")) {
+ return "SOCKS 127.0.0.1:1080";
+ } else if (shExpMatch(host, "*chaturbate.com")) {
+ return "PROXY 127.0.0.1:8080";
+ } else {
+ return "DIRECT";
+ }
+}
\ No newline at end of file
diff --git a/server/src/assembly/server.xml b/server/src/assembly/server.xml
index 54e2f54d..8ac19dd5 100644
--- a/server/src/assembly/server.xml
+++ b/server/src/assembly/server.xml
@@ -30,6 +30,12 @@
${project.basedir}/LICENSE.txt
ctbrec
+
+ ${project.basedir}/src/assembly/pac.js
+ ctbrec
+ true
+ pac.js
+
${project.basedir}/../CHANGELOG.md
ctbrec