From 8f5ee9d57a2a71b15023ab2e4527ef5a6c97210d Mon Sep 17 00:00:00 2001
From: Jafea7 <73450040+Jafea7@users.noreply.github.com>
Date: Fri, 26 Sep 2025 17:30:57 +1000
Subject: [PATCH] Implement PAC (Proxy Auto Config)
---
client/src/assembly/linux-jre.xml | 6 ++++
client/src/assembly/macos-jre.xml | 6 ++++
client/src/assembly/pac.js | 9 ++++++
client/src/assembly/win64-jre.xml | 6 ++++
.../java/ctbrec/ui/settings/SettingsTab.java | 7 +++--
common/pom.xml | 5 ++++
common/src/main/java/ctbrec/Settings.java | 4 ++-
.../src/main/java/ctbrec/io/HttpClient.java | 30 +++++++++++++++----
server/src/assembly/pac.js | 9 ++++++
server/src/assembly/server.xml | 6 ++++
10 files changed, 80 insertions(+), 8 deletions(-)
create mode 100644 client/src/assembly/pac.js
create mode 100644 server/src/assembly/pac.js
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 64bb98c4..90578bfb 100644
--- a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java
+++ b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java
@@ -83,6 +83,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;
@@ -160,11 +161,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)));
@@ -320,7 +322,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 29b5027b..6084edad 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -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 53a6566f..3b3687d2 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 {
@@ -139,6 +140,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 e90a6b79..e0c54c97 100644
--- a/common/src/main/java/ctbrec/io/HttpClient.java
+++ b/common/src/main/java/ctbrec/io/HttpClient.java
@@ -1,5 +1,8 @@
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 +23,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;
@@ -90,6 +94,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);
@@ -142,11 +158,11 @@ public abstract class HttpClient {
cacheSize = (long) config.getSettings().thumbCacheSize * 1024 * 1024;
Builder builder = new OkHttpClient.Builder()
- .cookieJar(cookieJar)
- .connectionPool(GLOBAL_HTTP_CONN_POOL)
- .connectTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
- .readTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
- .addNetworkInterceptor(new LoggingInterceptor());
+ .cookieJar(cookieJar)
+ .connectionPool(GLOBAL_HTTP_CONN_POOL)
+ .connectTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
+ .readTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
+ .addNetworkInterceptor(new LoggingInterceptor());
if (cacheSize > 0) {
cache = HttpClientCacheProvider.getCache(config);
@@ -155,6 +171,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 1f1ed6e4..35193878 100644
--- a/server/src/assembly/server.xml
+++ b/server/src/assembly/server.xml
@@ -26,6 +26,12 @@
ctbrec
true
+
+ ${project.basedir}/src/assembly/pac.js
+ ctbrec
+ true
+ pac.js
+
${project.basedir}/../CHANGELOG.md
ctbrec