Compare commits

..

No commits in common. "cb44a320795030f125182d522199a833ee14b217" and "c91b410307839a50df84eaef71a7c530f766af2e" have entirely different histories.

17 changed files with 58 additions and 115 deletions

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<version>5.3.3</version>
<version>5.3.2</version>
<relativePath>../master</relativePath>
</parent>

View File

@ -15,7 +15,6 @@ import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONObject;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@ -36,7 +35,7 @@ public class ChaturbateApiUpdateService extends PaginatedScheduledService {
protected List<Model> call() throws Exception {
var request = new Request.Builder()
.url(url)
.header(USER_AGENT, chaturbate.getHttpClient().getEffectiveUserAgent(URI.create(url).getHost()))
.header(USER_AGENT, chaturbate.getHttpClient().getEffectiveUserAgent())
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
.build();
try (var response = chaturbate.getHttpClient().execute(request)) {

View File

@ -13,7 +13,6 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Collections;
import java.util.Objects;
@ -36,7 +35,7 @@ public class ChaturbateElectronLoginDialog {
config.put("url", site.getBaseUrl() + "/auth/login/");
config.put("w", 640);
config.put("h", 480);
config.put("userAgent", site.getHttpClient().getEffectiveUserAgent(URI.create(site.getBaseUrl()).getHost()));
config.put("userAgent", site.getHttpClient().getEffectiveUserAgent());
var msg = new JSONObject();
msg.put("config", config);
browser.run(msg, msgHandler);

View File

@ -14,7 +14,6 @@ import org.json.JSONObject;
import org.jsoup.Jsoup;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -55,7 +54,7 @@ public class ChaturbateUpdateService extends PaginatedScheduledService {
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.header(USER_AGENT, chaturbate.getHttpClient().getEffectiveUserAgent(URI.create(pageUrl).getHost()))
.header(USER_AGENT, chaturbate.getHttpClient().getEffectiveUserAgent())
.build();
try (var response = chaturbate.getHttpClient().execute(request)) {
if (response.isSuccessful()) {

View File

@ -19,7 +19,7 @@ public abstract class AbstractStripchatUpdateService extends PaginatedScheduledS
if (timestamp == 0) {
return model.optString("previewUrlThumbBig");
}
return MessageFormat.format("https://img.doppiocdn.net/thumbs/{0}/{1}", String.valueOf(timestamp), String.valueOf(id));
return MessageFormat.format("https://img.strpst.com/thumbs/{0}/{1}", String.valueOf(timestamp), String.valueOf(id));
}
protected List<String> createTags(JSONObject model) {

View File

@ -3,7 +3,6 @@ package ctbrec.ui.tabs.recorded;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.Recording;
import ctbrec.Model.State;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import ctbrec.ui.JavaFxModel;
@ -328,7 +327,7 @@ public class RecordedModelsTab extends AbstractRecordedModelsTab implements TabS
if (Objects.equals(onlineModel, fxm)) {
fxm.setOnlineProperty(true);
try {
fxm.setOnlineStateProperty(Model.State.ONLINE);
fxm.setOnlineStateProperty(onlineModel.getOnlineState(true));
} catch (Exception e) {}
break;
}

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<version>5.3.3</version>
<version>5.3.2</version>
<relativePath>../master</relativePath>
</parent>
@ -93,11 +93,6 @@
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>1.7</version>
</dependency>
</dependencies>

View File

@ -26,6 +26,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.NumberFormat;
import java.time.Instant;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@ -33,6 +34,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.time.*;
import java.util.Optional;
import static ctbrec.io.HttpConstants.ACCEPT_ENCODING_GZIP;
import static ctbrec.io.HttpConstants.CONTENT_ENCODING;
@ -49,7 +51,6 @@ public abstract class HttpClient {
protected OkHttpClient client;
protected Cache cache;
protected Config config;
@Getter
protected boolean loggedIn = false;
protected long cacheSize;
protected int cacheLifeTime = 600;
@ -453,11 +454,7 @@ public abstract class HttpClient {
}
// overridable default user agent (used for Flaresolverr)
public String getEffectiveUserAgent(String host) {
if (config.getSettings().flaresolverr.useForDomains.contains(host)) {
return config.getSettings().flaresolverr.userAgent;
} else {
return config.getSettings().httpUserAgent;
}
public String getEffectiveUserAgent() {
return config.getSettings().httpUserAgent;
}
}

View File

@ -20,8 +20,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import java.util.List;
public class RecordingPreconditions {
@ -201,16 +199,13 @@ public class RecordingPreconditions {
// go through each model in group in descendind priority order, checking this model last amongst same-prio models
// this is to make sure that we only stop lower priority recordings in favor of this one. I.e. if same-prio model is recordnig, let it run
var models = modelGroup.get().getModelUrls().stream()
.map(modelUrl -> getModelForUrl(modelUrl))
.filter(x -> x.isPresent())
.map(x -> x.get())
.toList();
for (var groupModel : IntStream.range(0, models.size()).boxed()
for (var groupModel : modelGroup.get().getModelUrls().stream()
.map(modelUrl -> getModelForUrl(modelUrl))
.filter(x -> x.isPresent())
.map(x -> x.get())
.sorted(Comparator
.comparing((Integer i) -> models.get(i).getPriority()).reversed() // high to low
.thenComparing((Integer i) -> i)) // in group's order
.map((Integer i) -> models.get(i))
.comparing((Model m) -> m.getPriority()).reversed() // high to low
.thenComparing((Model m) -> m.getUrl().equals(model.getUrl()))) // this model last (false -> true)
.toList()) {
if (model.getUrl().equals(groupModel.getUrl())) {
// no other model with higher prio is online, start recording

View File

@ -11,7 +11,6 @@ import org.json.JSONArray;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.time.Duration;
import java.time.Instant;
@ -56,7 +55,7 @@ public class Chaturbate extends AbstractSite {
ChaturbateModel m = new ChaturbateModel(this);
m.setName(normalizedName);
m.setUrl(getBaseUrl() + '/' + normalizedName + '/');
m.setPreview("https://thumb.live.mmcdn.com/riw/" + normalizedName + ".jpg?" + Instant.now().getEpochSecond());
m.setPreview("https://roomimg.stream.highwebmedia.com/ri/" + normalizedName + ".jpg?" + Instant.now().getEpochSecond());
return m;
}
@ -70,7 +69,7 @@ public class Chaturbate extends AbstractSite {
String url = "https://chaturbate.com/p/" + username + "/";
Request req = new Request.Builder()
.url(url)
.header(USER_AGENT, getHttpClient().getEffectiveUserAgent(URI.create(url).getHost()))
.header(USER_AGENT, getHttpClient().getEffectiveUserAgent())
.build();
try (Response resp = getHttpClient().execute(req)) {
if (resp.isSuccessful()) {
@ -132,7 +131,7 @@ public class Chaturbate extends AbstractSite {
// search online models
Request req = new Request.Builder()
.url(url)
.header(USER_AGENT, getHttpClient().getEffectiveUserAgent(URI.create(url).getHost()))
.header(USER_AGENT, getHttpClient().getEffectiveUserAgent())
.header(ACCEPT, "*/*")
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.header(REFERER, getBaseUrl())

View File

@ -8,7 +8,6 @@ import okhttp3.*;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.URI;
import java.util.NoSuchElementException;
import java.util.concurrent.Semaphore;
@ -29,6 +28,15 @@ public class ChaturbateHttpClient extends HttpClient {
super("chaturbate", config);
}
@Override
public String getEffectiveUserAgent() {
if (flaresolverr != null) {
return config.getSettings().flaresolverr.userAgent;
} else {
return config.getSettings().httpUserAgent;
}
}
private void extractCsrfToken(Request request) {
try {
Cookie csrfToken = cookieJar.getCookie(request.url(), "csrftoken");
@ -57,7 +65,7 @@ public class ChaturbateHttpClient extends HttpClient {
}
Request login = new Request.Builder()
.url(Chaturbate.baseUrl + PATH)
.header(USER_AGENT, getEffectiveUserAgent(URI.create(Chaturbate.baseUrl).getHost()))
.header(USER_AGENT, getEffectiveUserAgent())
.build();
try (var initResponse = client.newCall(login).execute()) {
String content = initResponse.body().string();
@ -73,7 +81,7 @@ public class ChaturbateHttpClient extends HttpClient {
login = new Request.Builder()
.url(Chaturbate.baseUrl + PATH)
.header(REFERER, Chaturbate.baseUrl + PATH)
.header(USER_AGENT, getEffectiveUserAgent(URI.create(Chaturbate.baseUrl).getHost()))
.header(USER_AGENT, getEffectiveUserAgent())
.post(body)
.build();
@ -98,7 +106,7 @@ public class ChaturbateHttpClient extends HttpClient {
String url = "https://chaturbate.com/api/ts/chatmessages/pm_users/?offset=0";
Request req = new Request.Builder()
.url(url)
.header(USER_AGENT, getEffectiveUserAgent(URI.create(url).getHost()))
.header(USER_AGENT, getEffectiveUserAgent())
.build();
try (Response response = execute(req)) {
boolean result = false;

View File

@ -22,7 +22,6 @@ import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.*;
@ -31,14 +30,11 @@ import java.util.concurrent.ExecutionException;
import static ctbrec.Model.State.*;
import static ctbrec.io.HttpConstants.*;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.util.regex.Pattern;
@Slf4j
public class ChaturbateModel extends AbstractModel {
private static final String PUBLIC = "public";
private static final Pattern serverPattern = Pattern.compile("live-.+amlst");
private int[] resolution = new int[2];
private transient StreamInfo streamInfo;
private transient Instant lastStreamInfoRequest = Instant.EPOCH;
@ -79,7 +75,7 @@ public class ChaturbateModel extends AbstractModel {
private boolean isOffline() {
String normalizedName = getName().toLowerCase().trim();
String previewUrl = "https://thumb.live.mmcdn.com/riw/" + normalizedName + ".jpg?" + Instant.now().getEpochSecond();
String previewUrl = "https://roomimg.stream.highwebmedia.com/ri/" + normalizedName + ".jpg?" + Instant.now().getEpochSecond();
if (offlineImageSize == 0) {
offlineImageSize = getOfflineImageSize(); // NOSONAR
}
@ -89,7 +85,7 @@ public class ChaturbateModel extends AbstractModel {
private int getOfflineImageSize() {
String[] names = {"Sophia", "Helena", "Olivia", "Natasha", "Emmy", "Jenny", "Diana", "Teresa", "Julia", "Polly", "Amanda"};
String randomName = names[RNG.nextInt(names.length)] + RNG.nextInt(99);
String previewUrl = "https://thumb.live.mmcdn.com/riw/" + randomName + ".jpg?" + Instant.now().getEpochSecond();
String previewUrl = "https://roomimg.stream.highwebmedia.com/ri/" + randomName + ".jpg?" + Instant.now().getEpochSecond();
int imageSize = getImageSize(previewUrl);
if (imageSize == 0) {
imageSize = 21971;
@ -101,7 +97,7 @@ public class ChaturbateModel extends AbstractModel {
int imageSize = 0;
Request req = new Request.Builder()
.url(url)
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent(URI.create(url).getHost()))
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.head()
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
@ -194,7 +190,7 @@ public class ChaturbateModel extends AbstractModel {
.post(body)
.header(REFERER, "https://chaturbate.com/" + getName() + "/")
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent("chaturbate.com"))
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if (!response.isSuccessful()) {
@ -215,7 +211,7 @@ public class ChaturbateModel extends AbstractModel {
src.setBandwidth(playlist.getStreamInfo().getBandwidth());
src.setHeight(playlist.getStreamInfo().getResolution().height);
src.setWidth(playlist.getStreamInfo().getResolution().width);
String masterUrl = streamInfo.hls_source;
String masterUrl = streamInfo.url;
String baseUrl = masterUrl.substring(0, masterUrl.lastIndexOf('/') + 1);
String segmentUri = baseUrl + playlist.getUri();
src.setMediaPlaylistUrl(segmentUri);
@ -243,7 +239,7 @@ public class ChaturbateModel extends AbstractModel {
// do an initial request to get cookies
Request req = new Request.Builder()
.url(getUrl())
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent(URI.create(getUrl()).getHost()))
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.build();
Response resp = site.getHttpClient().execute(req);
resp.close();
@ -262,7 +258,7 @@ public class ChaturbateModel extends AbstractModel {
.header(ACCEPT, "*/*")
.header(ACCEPT_LANGUAGE, "en-US,en;q=0.5")
.header(REFERER, getUrl())
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent(URI.create(url).getHost()))
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.header("X-CSRFToken", ((ChaturbateHttpClient) site.getHttpClient()).getToken())
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.build();
@ -299,9 +295,14 @@ public class ChaturbateModel extends AbstractModel {
if (streamInfo != null && Duration.between(lastStreamInfoRequest, Instant.now()).getSeconds() < 5) {
return streamInfo;
}
RequestBody body = new FormBody.Builder()
.add("room_slug", getName())
.add("bandwidth", "high")
.build();
Request req = new Request.Builder()
.url(getSite().getBaseUrl() + "/api/chatvideocontext/" + getName() + '/')
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent(URI.create(getSite().getBaseUrl()).getHost()))
.url(getSite().getBaseUrl() + "/get_edge_hls_url_ajax/")
.post(body)
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
@ -310,23 +311,6 @@ public class ChaturbateModel extends AbstractModel {
String content = response.body().string();
log.trace("Raw stream info for model {}: {}", getName(), content);
streamInfo = mapper.readValue(content, StreamInfo.class);
if (streamInfo.cmaf_edge) {
if (streamInfo.hls_source.contains("playlist.m3u8")) {
streamInfo.hls_source = streamInfo.hls_source.replace("playlist.m3u8", "playlist_sfm4s.m3u8");
} else if (streamInfo.hls_source.contains("playlist_sfm4s.m3u8")) {
streamInfo.hls_source = streamInfo.hls_source.replace("playlist_sfm4s.m3u8", "playlist.m3u8");
}
var match = serverPattern.matcher(streamInfo.hls_source);
if (getSite().getHttpClient().isLoggedIn()) {
streamInfo.hls_source = match.replaceFirst("live-fhls/amlst");
} else {
streamInfo.hls_source = match.replaceFirst("live-c-fhls/amlst");
}
}
return streamInfo;
} else {
int code = response.code();
@ -338,7 +322,7 @@ public class ChaturbateModel extends AbstractModel {
private int[] getResolution() throws IOException, ParseException, PlaylistException {
int[] res = new int[2];
if (!getStreamInfo().hls_source.startsWith("http")) {
if (!getStreamInfo().url.startsWith("http")) {
return res;
}
@ -377,10 +361,10 @@ public class ChaturbateModel extends AbstractModel {
}
private MasterPlaylist getMasterPlaylist(StreamInfo streamInfo) throws IOException, ParseException, PlaylistException {
log.trace("Loading master playlist {}", streamInfo.hls_source);
log.trace("Loading master playlist {}", streamInfo.url);
Request req = new Request.Builder()
.url(streamInfo.hls_source)
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent(URI.create(streamInfo.hls_source).getHost()))
.url(streamInfo.url)
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if (response.isSuccessful()) {
@ -401,7 +385,7 @@ public class ChaturbateModel extends AbstractModel {
public boolean exists() throws IOException {
Request req = new Request.Builder() // @formatter:off
.url(getUrl())
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent(URI.create(getUrl()).getHost()))
.header(USER_AGENT, site.getHttpClient().getEffectiveUserAgent())
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.build(); // @formatter:on
try (Response response = getSite().getHttpClient().execute(req)) {

View File

@ -1,8 +1,8 @@
package ctbrec.sites.chaturbate;
public class StreamInfo {
public String hls_source;
public String url;
public String room_status;
public String hidden_message;
public boolean cmaf_edge;
public boolean success;
}

View File

@ -16,8 +16,6 @@ import lombok.extern.slf4j.Slf4j;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.apache.commons.text.StringSubstitutor;
import org.json.JSONArray;
import org.json.JSONObject;
@ -32,8 +30,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.HashMap;
import java.util.Map;
import static ctbrec.Model.State.*;
import static ctbrec.io.HttpConstants.*;
@ -200,26 +196,6 @@ public class StripchatModel extends AbstractModel {
}
}
}
private String getHlsUrlTemplate() throws IOException {
log.trace("Loading URL template for {}", getName());
Request req = new Request.Builder()
.url(getSite().getBaseUrl() + "/api/front/v3/config/initial?requestPath=%2F" + getName() + "&timezoneOffset=0")
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if (response.isSuccessful()) {
JSONObject jsonResponse = new JSONObject(response.body().string());
var common = jsonResponse.getJSONObject("initial").getJSONObject("common");
var urlTemplate = common.getString("hlsStreamUrlTemplate");
var host = common.getString("hlsStreamHost");
return urlTemplate.replace("{cdnHost}", host);
} else {
throw new HttpException(response.code(), response.message());
}
}
}
private String getMasterPlaylistUrl() throws IOException {
JSONObject info = getModelInfo();
@ -239,15 +215,8 @@ public class StripchatModel extends AbstractModel {
log.debug("Spy start for {}", getName());
}
}
// the master playlist host can vary per model
String hlsUrlTemplate = getHlsUrlTemplate();
Map<String, Object> params = new HashMap<>();
params.put("streamName", String.valueOf(id) + vrSuffix);
params.put("suffix", "_auto");
var result = StringSubstitutor.replace(hlsUrlTemplate, params, "{", "}") + "?playlistType=Standart" + token;
return result;
String hlsUrlTemplate = "https://edge-hls.doppiocdn.com/hls/{0}{1}/master/{0}{1}_auto.m3u8?playlistType=Standart{2}";
return MessageFormat.format(hlsUrlTemplate, String.valueOf(id), vrSuffix, token);
} else {
throw new IOException("Playlist URL not found");
}

View File

@ -6,7 +6,7 @@
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<packaging>pom</packaging>
<version>5.3.3</version>
<version>5.3.2</version>
<modules>
<module>../common</module>

View File

@ -8,7 +8,7 @@
<parent>
<groupId>ctbrec</groupId>
<artifactId>master</artifactId>
<version>5.3.3</version>
<version>5.3.2</version>
<relativePath>../master</relativePath>
</parent>

View File

@ -34,7 +34,7 @@ function loadConfig() {
return this.value.join('\n');
},
write: function (value) {
this.value = value === '' ? [] : value.split('\n')
this.value = value.split('\n')
},
owner: param
});