diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a40b0ca..2d1f6124 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ 5.2.3 ======================== * Fix one directory per group +* Add Stripchat tags thx to @winkru +* Fix follow / unfollow for Stripchat thx to @winkru +* Fix: Loading the config failed with model URLs, which contained spaces +* Fix recording size not properly being reported and transferred between + server and client 5.2.2 ======================== diff --git a/client/pom.xml b/client/pom.xml index 84a53779..d6db1183 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -8,7 +8,7 @@ ctbrec master - 5.2.2 + 5.2.3 ../master diff --git a/common/pom.xml b/common/pom.xml index c39f9a7a..6e5c16fb 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -8,7 +8,7 @@ ctbrec master - 5.2.2 + 5.2.3 ../master diff --git a/common/src/main/java/ctbrec/MigrateModel5_1_2.java b/common/src/main/java/ctbrec/MigrateModel5_1_2.java index 06d8197e..093b6c0e 100644 --- a/common/src/main/java/ctbrec/MigrateModel5_1_2.java +++ b/common/src/main/java/ctbrec/MigrateModel5_1_2.java @@ -8,8 +8,12 @@ public class MigrateModel5_1_2 { private static final String MARKED_FOR_LATER = "markedForLater"; private static final String ADDED_TIMESTAMP = "addedTimestamp"; + private static final String URL = "url"; public static void migrate(JSONObject model) { + if (model.has(URL)) { + model.put(URL, model.getString(URL).replace(" ", "%20")); + } if (model.has(MARKED_FOR_LATER)) { model.put("bookmarked", model.getBoolean(MARKED_FOR_LATER)); model.remove(MARKED_FOR_LATER); diff --git a/common/src/main/java/ctbrec/Recording.java b/common/src/main/java/ctbrec/Recording.java index 28525f24..4bc9fd8d 100644 --- a/common/src/main/java/ctbrec/Recording.java +++ b/common/src/main/java/ctbrec/Recording.java @@ -226,7 +226,7 @@ public class Recording implements Serializable { } else { long now = System.currentTimeMillis(); if (now - lastSizeUpdate > 2500) { - log.debug("full size update for {}", this); + log.trace("full size update for {}", this); sizeInByte = getSize(); lastSizeUpdate = now; } diff --git a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java index 68c0e9ec..0d3a4afd 100644 --- a/common/src/main/java/ctbrec/recorder/RemoteRecorder.java +++ b/common/src/main/java/ctbrec/recorder/RemoteRecorder.java @@ -402,7 +402,14 @@ public class RemoteRecorder implements Recorder { if (response.isSuccessful()) { RecordingListResponse resp = mapper.readValue(json, RecordingListResponse.class); if (resp.status.equals(SUCCESS)) { - List newRecordings = resp.recordings.stream().map(Mappers.getMapper(RecordingMapper.class)::toRecording).collect(Collectors.toList()); + List newRecordings = resp.recordings.stream() + .map(dto -> { + var rec = Mappers.getMapper(RecordingMapper.class).toRecording(dto); + rec.setSizeInByte(dto.getSizeInByte()); + rec.setLastSizeUpdate(Instant.now().toEpochMilli()); + return rec; + }) + .collect(Collectors.toList()); // fire changed events for (Recording recording : recordings) { if (newRecordings.contains(recording)) { diff --git a/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java b/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java index 6f248b99..356c66f2 100644 --- a/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/AbstractDownload.java @@ -12,12 +12,14 @@ import java.time.Instant; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; +import java.util.concurrent.atomic.AtomicLong; import static ctbrec.recorder.download.StreamSource.UNKNOWN; @Slf4j public abstract class AbstractDownload implements RecordingProcess { + protected AtomicLong downloadedBytes = new AtomicLong(); protected Instant startTime; protected Instant rescheduleTime = Instant.now(); protected Model model = new UnknownModel(); @@ -112,4 +114,9 @@ public abstract class AbstractDownload implements RecordingProcess { } } } + + @Override + public AtomicLong getDownloadedBytes() { + return downloadedBytes; + } } diff --git a/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java b/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java index f9cdd020..f502a6b9 100644 --- a/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java +++ b/common/src/main/java/ctbrec/recorder/download/RecordingProcess.java @@ -12,7 +12,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicLong; public interface RecordingProcess extends Callable { - AtomicLong downloadedBytes = new AtomicLong(); void init(Config config, Model model, Instant startTime, ExecutorService executorService) throws IOException; @@ -62,8 +61,5 @@ public interface RecordingProcess extends Callable { void awaitEnd(); - default AtomicLong getDownloadedBytes() { - return downloadedBytes; - } - + AtomicLong getDownloadedBytes(); } diff --git a/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java b/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java index e997c611..d2d76ec0 100644 --- a/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java +++ b/common/src/main/java/ctbrec/recorder/download/hls/AbstractHlsDownload.java @@ -44,7 +44,6 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicLong; import static ctbrec.io.HttpConstants.*; import static java.nio.charset.StandardCharsets.UTF_8; @@ -70,7 +69,6 @@ public abstract class AbstractHlsDownload extends AbstractDownload { private Instant beforeLastPlaylistRequest = Instant.EPOCH; private int consecutivePlaylistTimeouts = 0; private int consecutivePlaylistErrors = 0; - private final AtomicLong sizeInByte = new AtomicLong(); protected Instant lastSegmentDownload = Instant.MIN; private final List segmentErrorTimestamps = new LinkedList<>(); @@ -90,14 +88,13 @@ public abstract class AbstractHlsDownload extends AbstractDownload { @Override public long getSizeInByte() { - return sizeInByte.get(); + return getDownloadedBytes().get(); } protected abstract OutputStream getSegmentOutputStream(Segment segment) throws IOException; protected void segmentDownloadFinished(SegmentDownload segmentDownload) { // NOSONAR - long bytes = getDownloadedBytes().addAndGet(segmentDownload.size()); - sizeInByte.addAndGet(bytes); + getDownloadedBytes().addAndGet(segmentDownload.size()); lastSegmentDownload = Instant.now(); } diff --git a/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java b/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java index 0a0a9359..e5f6021a 100644 --- a/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java +++ b/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java @@ -211,7 +211,7 @@ public class CamsodaModel extends AbstractModel { } else { try { List sources = getStreamSources(); - LOG.debug("stream sources {}", sources); + LOG.debug("{}:{} stream sources {}", getSite().getName(), getName(), sources); if (sources.isEmpty()) { return new int[]{0, 0}; } else { diff --git a/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java b/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java index e15b3ed9..63b60ae4 100644 --- a/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java +++ b/common/src/main/java/ctbrec/sites/stripchat/StripchatHttpClient.java @@ -6,16 +6,15 @@ import ctbrec.io.HttpClient; import ctbrec.io.HttpException; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import okhttp3.MediaType; -import okhttp3.Request; -import okhttp3.RequestBody; -import okhttp3.Response; +import okhttp3.*; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; +import java.net.URLDecoder; import static ctbrec.io.HttpConstants.*; +import static java.nio.charset.StandardCharsets.UTF_8; @Slf4j public class StripchatHttpClient extends HttpClient { @@ -96,7 +95,7 @@ public class StripchatHttpClient extends HttpClient { } private void loadCsrfToken() throws IOException { - String url = Stripchat.baseUri + "/api/front/v2/config?requestPath=%2F&timezoneOffset=0"; + String url = Stripchat.baseUri + "/api/front/v2/config/data?requestPath=%2F&timezoneOffset=0"; Request request = new Request.Builder() .url(url) .header(ACCEPT, MIMETYPE_APPLICATION_JSON) @@ -112,6 +111,25 @@ public class StripchatHttpClient extends HttpClient { csrfToken = data.optString("csrfToken"); csrfTimestamp = data.optString("csrfTimestamp"); csrfNotifyTimestamp = data.optString("csrfNotifyTimestamp"); + } else { + throw new HttpException(response.code(), response.message()); + } + } + } + + private void loadJwtToken() throws IOException { + String url = Stripchat.baseUri + "/api/front/v2/config?requestPath=%2F&timezoneOffset=0"; + Request request = new Request.Builder() + .url(url) + .header(ACCEPT, MIMETYPE_APPLICATION_JSON) + .header(USER_AGENT, config.getSettings().httpUserAgent) + .header(ORIGIN, Stripchat.baseUri) + .header(REFERER, Stripchat.baseUri) + .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON) + .build(); + try (Response response = execute(request)) { + if (response.isSuccessful()) { + JSONObject resp = new JSONObject(response.body().string()); JSONObject config = resp.getJSONObject("config"); jwtToken = config.optString("jwtToken"); } else { @@ -127,7 +145,7 @@ public class StripchatHttpClient extends HttpClient { */ public boolean checkLoginSuccess() throws IOException { try { - loadCsrfToken(); + loadJwtToken(); } catch (Exception e) { log.info("Login check returned unsuccessful: {}", e.getLocalizedMessage()); return false; @@ -158,4 +176,15 @@ public class StripchatHttpClient extends HttpClient { } return userId; } + + public JSONObject getAmpl() { + try { + Cookie cookie = getCookieJar().getCookie(HttpUrl.parse(Stripchat.baseUri), "baseAmpl"); + String json = URLDecoder.decode(cookie.value(), UTF_8); + JSONObject ampl = new JSONObject(json); + return ampl; + } catch (Exception ex) { + return new JSONObject(); + } + } } diff --git a/common/src/main/java/ctbrec/sites/stripchat/StripchatModel.java b/common/src/main/java/ctbrec/sites/stripchat/StripchatModel.java index 73d319ee..5a481526 100644 --- a/common/src/main/java/ctbrec/sites/stripchat/StripchatModel.java +++ b/common/src/main/java/ctbrec/sites/stripchat/StripchatModel.java @@ -25,10 +25,7 @@ import java.io.InputStream; import java.text.MessageFormat; import java.time.Duration; import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Optional; +import java.util.*; import java.util.concurrent.ExecutionException; import static ctbrec.Model.State.*; @@ -42,7 +39,7 @@ public class StripchatModel extends AbstractModel { private int[] resolution = new int[]{0, 0}; private int modelId = 0; private boolean isVr = false; - private JSONObject modelInfo; + private transient JSONObject modelInfo; private transient Instant lastInfoRequest = Instant.EPOCH; @@ -85,8 +82,8 @@ public class StripchatModel extends AbstractModel { } private JSONObject getModelInfo() throws IOException { - if (Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) { - return Optional.ofNullable(modelInfo).orElse(new JSONObject()); + if (Objects.nonNull(modelInfo) && Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) { + return modelInfo; } lastInfoRequest = Instant.now(); modelInfo = loadModelInfo(); @@ -251,6 +248,8 @@ public class StripchatModel extends AbstractModel { requestParams.put("csrfToken", client.getCsrfToken()); requestParams.put("csrfTimestamp", client.getCsrfTimestamp()); requestParams.put("csrfNotifyTimestamp", client.getCsrfNotifyTimestamp()); + requestParams.put("uniq", getUniq()); + requestParams.put("ampl", client.getAmpl()); RequestBody body = RequestBody.Companion.create(requestParams.toString(), JSON); Request request = new Request.Builder() .url(url) @@ -286,6 +285,7 @@ public class StripchatModel extends AbstractModel { requestParams.put("csrfToken", client.getCsrfToken()); requestParams.put("csrfTimestamp", client.getCsrfTimestamp()); requestParams.put("csrfNotifyTimestamp", client.getCsrfNotifyTimestamp()); + requestParams.put("uniq", getUniq()); RequestBody body = RequestBody.Companion.create(requestParams.toString(), JSON); Request request = new Request.Builder() .url(url) @@ -335,4 +335,15 @@ public class StripchatModel extends AbstractModel { return new MergedFfmpegHlsDownload(getSite().getHttpClient()); } } + + protected String getUniq() { + Random r = new Random(); + String dict = "0123456789abcdefghijklmnopqarstvwxyz"; + char[] text = new char[16]; + for (int i = 0; i < 16; i++) { + text[i] = dict.charAt(r.nextInt(dict.length())); + } + return new String(text); + } + } diff --git a/master/pom.xml b/master/pom.xml index 1cc79036..88479bec 100644 --- a/master/pom.xml +++ b/master/pom.xml @@ -6,7 +6,7 @@ ctbrec master pom - 5.2.2 + 5.2.3 ../common diff --git a/server/pom.xml b/server/pom.xml index aa583a37..add9d8a0 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -8,7 +8,7 @@ ctbrec master - 5.2.2 + 5.2.3 ../master