Fix thumbnail caching

This commit is contained in:
0xb00bface 2023-12-30 17:13:57 +01:00
parent cc9a2c640e
commit 959b41e3b9
7 changed files with 131 additions and 58 deletions

View File

@ -3,6 +3,7 @@
* Added menu entry to force recording of models without changing the prio
* Added blacklist and whitelist settings to automatically filter out models
* Added setting to delete orphaned recording metadata (switched off by default)
* Fixed thumbnail caching
5.2.3
========================

View File

@ -14,10 +14,7 @@ import ctbrec.event.EventHandlerConfiguration;
import ctbrec.image.LocalPortraitStore;
import ctbrec.image.PortraitStore;
import ctbrec.image.RemotePortraitStore;
import ctbrec.io.BandwidthMeter;
import ctbrec.io.ByteUnitFormatter;
import ctbrec.io.HttpClient;
import ctbrec.io.HttpException;
import ctbrec.io.*;
import ctbrec.io.json.ObjectMapperFactory;
import ctbrec.notes.LocalModelNotesService;
import ctbrec.notes.ModelNotesService;
@ -434,6 +431,9 @@ public class CamrecApplication extends Application {
}
try {
ExternalBrowser.getInstance().close();
HttpClientCacheProvider.getCache(config).evictAll();
HttpClientCacheProvider.getCache(config).close();
IoUtils.deleteDirectory(new File(config.getConfigDir(), "cache"));
} catch (IOException e12) {
// noop
}

View File

@ -234,7 +234,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
Setting.of("Update overview interval (seconds)", overviewUpdateIntervalInSecs, "Update the thumbnail overviews every x seconds").needsRestart(),
Setting.of("Update thumbnails", updateThumbnails,
"The overviews will still be updated, but the thumbnails won't be changed. This is useful for less powerful systems."),
Setting.of("Cache size", new CacheSettingsPane(this, config)).needsRestart(),
Setting.of("Thumbnails cache size", new CacheSettingsPane(this, config)).needsRestart(),
Setting.of("Manually select stream quality", chooseStreamQuality, "Opens a dialog to select the video resolution before recording"),
Setting.of("Enable live previews (experimental)", livePreviews),
Setting.of("Enable recently watched tab", recentlyWatched).needsRestart(),

View File

@ -170,19 +170,20 @@ public class LiveJasminUpdateService extends PaginatedScheduledService {
}
listPageId = content.optString("listPageId");
JSONArray performers = content.getJSONArray("performers");
for (var i = 0; i < performers.length(); i++) {
var m = performers.getJSONObject(i);
var name = m.optString("pid");
if (name.isEmpty()) {
continue;
}
LiveJasminModel model = (LiveJasminModel) liveJasmin.createModel(name);
model.setId(m.getString("id"));
model.setPreview(m.optString("profilePictureUrl"));
for (var i = 0; i < performers.length(); i++) {
var m = performers.getJSONObject(i);
var name = m.optString("pid");
if (name.isEmpty()) {
continue;
}
LiveJasminModel model = (LiveJasminModel) liveJasmin.createModel(name);
model.setId(m.getString("id"));
model.setPreview(m.optString("profilePictureUrl"));
model.setOnlineState(LiveJasminModel.mapStatus(m.optInt("status")));
model.setDisplayName(m.optString("display_name", null));
models.add(model);
}} // if content
models.add(model);
}
} // if content
} // if data
}
}

View File

@ -429,7 +429,7 @@ public class ThumbCell extends StackPane {
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.header(REFERER, getModel().getSite().getBaseUrl())
.build();
try (Response resp = model.getSite().getHttpClient().execute(req)) {
try (Response resp = model.getSite().getHttpClient().executeWithCache(req)) {
if (resp.isSuccessful()) {
double width = 480;
double height = width * imgAspectRatio;
@ -500,9 +500,9 @@ public class ThumbCell extends StackPane {
} else {
modelRecordingState = ModelRecordingState.RECORDING;
if (model.isForcePriority()) {
recordingIndicator.setImage(imgForceRecordIndicator);
recordingIndicator.setImage(imgForceRecordIndicator);
} else {
recordingIndicator.setImage(imgRecordIndicator);
recordingIndicator.setImage(imgRecordIndicator);
}
recordingIndicatorTooltip.setText("Pause Recording");
}

View File

@ -8,6 +8,7 @@ import ctbrec.io.json.ObjectMapperFactory;
import ctbrec.io.json.dto.CookieDto;
import ctbrec.io.json.mapper.CookieMapper;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okhttp3.OkHttpClient.Builder;
@ -38,11 +39,14 @@ import static java.nio.charset.StandardCharsets.UTF_8;
public abstract class HttpClient {
private static final ConnectionPool GLOBAL_HTTP_CONN_POOL = new ConnectionPool(10, 2, TimeUnit.MINUTES);
@Getter
protected CookieJarImpl cookieJar;
protected OkHttpClient client;
protected Cache cache;
protected CookieJarImpl cookieJar;
protected Config config;
protected boolean loggedIn = false;
protected long cacheSize;
protected int cacheLifeTime = 600;
private final String name;
protected HttpClient(String name, Config config) {
@ -60,26 +64,26 @@ public abstract class HttpClient {
ProxyType proxyType = config.getSettings().proxyType;
switch (proxyType) {
case HTTP:
System.setProperty("http.proxyHost", config.getSettings().proxyHost);
System.setProperty("http.proxyPort", config.getSettings().proxyPort);
System.setProperty("https.proxyHost", config.getSettings().proxyHost);
System.setProperty("https.proxyPort", config.getSettings().proxyPort);
System.setProperty(ProxyConstants.HTTP_PROXY_HOST, config.getSettings().proxyHost);
System.setProperty(ProxyConstants.HTTP_PROXY_PORT, config.getSettings().proxyPort);
System.setProperty(ProxyConstants.HTTPS_PROXY_HOST, config.getSettings().proxyHost);
System.setProperty(ProxyConstants.HTTPS_PROXY_PORT, config.getSettings().proxyPort);
if (config.getSettings().proxyUser != null && !config.getSettings().proxyUser.isEmpty()) {
String username = config.getSettings().proxyUser;
String password = config.getSettings().proxyPassword;
System.setProperty("http.proxyUser", username);
System.setProperty("http.proxyPassword", password);
System.setProperty(ProxyConstants.HTTP_PROXY_USER, username);
System.setProperty(ProxyConstants.HTTP_PROXY_PASSWORD, password);
}
break;
case SOCKS4:
System.setProperty("socksProxyVersion", "4");
System.setProperty("socksProxyHost", config.getSettings().proxyHost);
System.setProperty("socksProxyPort", config.getSettings().proxyPort);
System.setProperty(ProxyConstants.SOCKS_PROXY_VERSION, "4");
System.setProperty(ProxyConstants.SOCKS_PROXY_HOST, config.getSettings().proxyHost);
System.setProperty(ProxyConstants.SOCKS_PROXY_PORT, config.getSettings().proxyPort);
break;
case SOCKS5:
System.setProperty("socksProxyVersion", "5");
System.setProperty("socksProxyHost", config.getSettings().proxyHost);
System.setProperty("socksProxyPort", config.getSettings().proxyPort);
System.setProperty(ProxyConstants.SOCKS_PROXY_VERSION, "5");
System.setProperty(ProxyConstants.SOCKS_PROXY_HOST, config.getSettings().proxyHost);
System.setProperty(ProxyConstants.SOCKS_PROXY_PORT, config.getSettings().proxyPort);
if (config.getSettings().proxyUser != null && !config.getSettings().proxyUser.isEmpty()) {
String username = config.getSettings().proxyUser;
String password = config.getSettings().proxyPassword;
@ -88,44 +92,55 @@ public abstract class HttpClient {
break;
case DIRECT:
default:
System.clearProperty("http.proxyHost");
System.clearProperty("http.proxyPort");
System.clearProperty("https.proxyHost");
System.clearProperty("https.proxyPort");
System.clearProperty("socksProxyVersion");
System.clearProperty("socksProxyHost");
System.clearProperty("socksProxyPort");
System.clearProperty("java.net.socks.username");
System.clearProperty("java.net.socks.password");
System.clearProperty("http.proxyUser");
System.clearProperty("http.proxyPassword");
System.clearProperty(ProxyConstants.HTTP_PROXY_HOST);
System.clearProperty(ProxyConstants.HTTP_PROXY_PORT);
System.clearProperty(ProxyConstants.HTTPS_PROXY_HOST);
System.clearProperty(ProxyConstants.HTTPS_PROXY_PORT);
System.clearProperty(ProxyConstants.SOCKS_PROXY_VERSION);
System.clearProperty(ProxyConstants.SOCKS_PROXY_HOST);
System.clearProperty(ProxyConstants.SOCKS_PROXY_PORT);
System.clearProperty(ProxyConstants.JAVA_NET_SOCKS_USERNAME);
System.clearProperty(ProxyConstants.JAVA_NET_SOCKS_PASSWORD);
System.clearProperty(ProxyConstants.HTTP_PROXY_USER);
System.clearProperty(ProxyConstants.HTTP_PROXY_PASSWORD);
break;
}
}
public Response execute(Request req) throws IOException {
if (cache != null) {
log.trace("Cache hit ratio {}/{} = {}", cache.hitCount(), cache.requestCount(), NumberFormat.getPercentInstance().format(cache.hitCount() / (double) cache.requestCount()));
}
Response resp = client.newCall(req).execute();
return resp;
}
public Response execute(Request request, int timeoutInMillis) throws IOException {
if (cache != null) {
log.trace("Cache hit ratio {}/{} = {}", cache.hitCount(), cache.requestCount(), NumberFormat.getPercentInstance().format(cache.hitCount() / (double) cache.requestCount()));
}
return client.newBuilder() //
.connectTimeout(timeoutInMillis, TimeUnit.MILLISECONDS) //
.readTimeout(timeoutInMillis, TimeUnit.MILLISECONDS).build() //
.newCall(request).execute();
}
public Response executeWithCache(Request req) throws IOException {
log.trace("Cached request for {}", req.url());
if (Objects.nonNull(cache)) {
log.trace("Cache hit ratio {}/{} = {}", cache.hitCount(), cache.requestCount(), NumberFormat.getPercentInstance().format(cache.hitCount() / (double) cache.requestCount()));
}
if (cacheSize > 0 && Objects.nonNull(cache)) {
Request r = req.newBuilder()
.cacheControl(new CacheControl.Builder().maxAge(cacheLifeTime, TimeUnit.SECONDS).build())
.build();
return execute(r);
} else {
return execute(req);
}
}
public abstract boolean login() throws IOException;
public void reconfigure() {
loadProxySettings();
loadCookies();
cacheSize = (long) config.getSettings().thumbCacheSize * 1024 * 1024;
Builder builder = new OkHttpClient.Builder()
.cookieJar(cookieJar)
.connectionPool(GLOBAL_HTTP_CONN_POOL)
@ -133,12 +148,11 @@ public abstract class HttpClient {
.readTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
.addNetworkInterceptor(new LoggingInterceptor());
long cacheSize = (long) config.getSettings().thumbCacheSize * 1024 * 1024;
if (cacheSize > 0) {
File configDir = config.getConfigDir();
File cacheDir = new File(configDir, "cache");
cache = new Cache(cacheDir, cacheSize);
builder.cache(cache);
cache = HttpClientCacheProvider.getCache(config);
if (cache != null) {
builder.cache(cache);
}
}
ProxyType proxyType = config.getSettings().proxyType;
@ -265,10 +279,6 @@ public abstract class HttpClient {
}
}
public CookieJarImpl getCookieJar() {
return cookieJar;
}
public void logout() {
getCookieJar().clear();
loggedIn = false;
@ -332,4 +342,19 @@ public abstract class HttpClient {
public void clearCookies() {
logout();
}
private static class ProxyConstants {
public static final String HTTP_PROXY_HOST = "http.proxyHost";
public static final String HTTP_PROXY_PORT = "http.proxyPort";
public static final String HTTPS_PROXY_HOST = "https.proxyHost";
public static final String HTTPS_PROXY_PORT = "https.proxyPort";
public static final String HTTP_PROXY_USER = "https.proxyUser";
public static final String HTTP_PROXY_PASSWORD = "https.proxyPassword";
public static final String SOCKS_PROXY_HOST = "socksProxyHost";
public static final String SOCKS_PROXY_PORT = "socksProxyPort";
public static final String SOCKS_PROXY_VERSION = "socksProxyVersion";
public static final String JAVA_NET_SOCKS_USERNAME = "java.net.socks.username";
public static final String JAVA_NET_SOCKS_PASSWORD = "java.net.socks.password";
}
}

View File

@ -0,0 +1,46 @@
package ctbrec.io;
import ctbrec.Config;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Cache;
import java.io.File;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@Slf4j
public class HttpClientCacheProvider {
private static final Lock lock = new ReentrantLock();
private static HttpClientCacheProvider provider;
private Cache cache;
private HttpClientCacheProvider(Config config) {
File configDir = config.getConfigDir();
File cacheDir = new File(configDir, "cache");
long cacheSize = (long) config.getSettings().thumbCacheSize * 1024 * 1024;
try {
cache = new Cache(cacheDir, cacheSize);
} catch (Exception ex) {
log.error("Could not create HTTP client cache", ex);
}
}
private Cache getCache() {
return cache;
}
public static Cache getCache(Config config) {
lock.lock();
try {
if (provider == null) {
provider = new HttpClientCacheProvider(config);
}
return provider.getCache();
} finally {
lock.unlock();
}
}
}