Code cleanup
This commit is contained in:
parent
541fcf5bc7
commit
03dd723fb6
|
@ -0,0 +1,18 @@
|
|||
package ctbrec.ui.sites.streamray;
|
||||
|
||||
import ctbrec.sites.streamray.Streamray;
|
||||
import ctbrec.ui.tabs.PaginatedScheduledService;
|
||||
|
||||
abstract class AbstractStreamrayUpdateService extends PaginatedScheduledService {
|
||||
|
||||
protected int modelsPerPage = 48;
|
||||
protected final Streamray site;
|
||||
|
||||
AbstractStreamrayUpdateService(Streamray site) {
|
||||
this.site = site;
|
||||
}
|
||||
|
||||
boolean isLoggedIn() {
|
||||
return site.isLoggedIn();
|
||||
}
|
||||
}
|
|
@ -1,37 +1,31 @@
|
|||
package ctbrec.ui.sites.streamray;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.sites.streamray.Streamray;
|
||||
import ctbrec.ui.ExternalBrowser;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.Cookie.Builder;
|
||||
import okhttp3.CookieJar;
|
||||
import okhttp3.HttpUrl;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.sites.streamray.Streamray;
|
||||
import ctbrec.ui.ExternalBrowser;
|
||||
import okhttp3.Cookie;
|
||||
import okhttp3.Cookie.Builder;
|
||||
import okhttp3.CookieJar;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
@Slf4j
|
||||
public class StreamrayElectronLoginDialog {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StreamrayElectronLoginDialog.class);
|
||||
public static final String DOMAIN = "streamray.com";
|
||||
public static final String URL = "https://streamray.com/";
|
||||
private CookieJar cookieJar;
|
||||
private ExternalBrowser browser;
|
||||
private boolean firstCall = true;
|
||||
private final static Streamray site = new Streamray();
|
||||
|
||||
|
||||
public StreamrayElectronLoginDialog(CookieJar cookieJar) throws IOException {
|
||||
this.cookieJar = cookieJar;
|
||||
browser = ExternalBrowser.getInstance();
|
||||
try {
|
||||
try (ExternalBrowser browser = ExternalBrowser.getInstance()) {
|
||||
var config = new JSONObject();
|
||||
config.put("url", URL);
|
||||
config.put("url", Streamray.BASE_URI);
|
||||
config.put("w", 800);
|
||||
config.put("h", 600);
|
||||
config.put("userAgent", Config.getInstance().getSettings().httpUserAgent);
|
||||
|
@ -41,23 +35,17 @@ public class StreamrayElectronLoginDialog {
|
|||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new IOException("Couldn't wait for login dialog", e);
|
||||
} finally {
|
||||
browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Consumer<String> msgHandler = line -> {
|
||||
private final Consumer<String> msgHandler = line -> {
|
||||
if (!line.startsWith("{")) return;
|
||||
JSONObject json = new JSONObject(line);
|
||||
boolean loginCookie = false;
|
||||
if (json.has("cookies")) {
|
||||
var cookies = json.getJSONArray("cookies");
|
||||
for (var i = 0; i < cookies.length(); i++) {
|
||||
var cookie = cookies.getJSONObject(i);
|
||||
if (cookie.getString("domain").contains(DOMAIN)) {
|
||||
if (cookie.optString("name").equals("memberToken")) {
|
||||
loginCookie = true;
|
||||
}
|
||||
Builder b = new Cookie.Builder()
|
||||
.path(cookie.getString("path"))
|
||||
.domain(DOMAIN)
|
||||
|
@ -74,8 +62,8 @@ public class StreamrayElectronLoginDialog {
|
|||
b.secure();
|
||||
}
|
||||
Cookie c = b.build();
|
||||
LOG.trace("Adding cookie {}={}", c.name(), c.value());
|
||||
cookieJar.saveFromResponse(HttpUrl.parse(URL), Collections.singletonList(c));
|
||||
log.trace("Adding cookie {}={}", c.name(), c.value());
|
||||
cookieJar.saveFromResponse(HttpUrl.parse(Streamray.BASE_URI), Collections.singletonList(c));
|
||||
} // if
|
||||
} // for
|
||||
}
|
||||
|
|
|
@ -1,132 +1,41 @@
|
|||
package ctbrec.ui.sites.streamray;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.sites.streamray.*;
|
||||
import ctbrec.ui.SiteUiFactory;
|
||||
import ctbrec.ui.tabs.PaginatedScheduledService;
|
||||
import ctbrec.sites.streamray.Streamray;
|
||||
import ctbrec.sites.streamray.StreamrayModel;
|
||||
import javafx.concurrent.Task;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.concurrent.Task;
|
||||
import okhttp3.*;
|
||||
import org.json.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class StreamrayFavoritesService extends PaginatedScheduledService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StreamrayFavoritesService.class);
|
||||
private static final String API_URL = "https://beta-api.cams.com/won/compressed/";
|
||||
|
||||
private Streamray site;
|
||||
private static List<StreamrayModel> modelsList;
|
||||
private static JSONArray mapping;
|
||||
protected int modelsPerPage = 48;
|
||||
public boolean loggedIn = false;
|
||||
@Slf4j
|
||||
public class StreamrayFavoritesService extends AbstractStreamrayUpdateService {
|
||||
|
||||
public StreamrayFavoritesService(Streamray site) {
|
||||
this.site = site;
|
||||
super(site);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<List<Model>> createTask() {
|
||||
return new Task<List<Model>>() {
|
||||
return new Task<>() {
|
||||
@Override
|
||||
public List<Model> call() throws IOException {
|
||||
return getModelList().stream()
|
||||
.skip((page - 1) * (long) modelsPerPage)
|
||||
.limit(modelsPerPage)
|
||||
.collect(Collectors.toList()); // NOSONAR
|
||||
.map(Model.class::cast)
|
||||
.toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private List<StreamrayModel> getModelList() throws IOException {
|
||||
modelsList = loadModelList();
|
||||
if (modelsList == null) {
|
||||
modelsList = Collections.emptyList();
|
||||
List<StreamrayModel> models = site.loadModelList(true).stream().filter(StreamrayModel::isFavorite).toList();
|
||||
if (models == null) {
|
||||
models = Collections.emptyList();
|
||||
}
|
||||
return modelsList;
|
||||
}
|
||||
|
||||
private List<StreamrayModel> loadModelList() throws IOException {
|
||||
LOG.debug("Fetching page {}", API_URL);
|
||||
StreamrayHttpClient client = (StreamrayHttpClient) site.getHttpClient();
|
||||
String token = "";
|
||||
if (site.login()) {
|
||||
loggedIn = true;
|
||||
token = client.getUserToken();
|
||||
} else {
|
||||
loggedIn = false;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
Request req = new Request.Builder()
|
||||
.url(API_URL)
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.header(REFERER, site.getBaseUrl() + "/")
|
||||
.header(ORIGIN, site.getBaseUrl())
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
.header(AUTHORIZATION, "Bearer " + token)
|
||||
.build();
|
||||
try (Response response = client.execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
List<StreamrayModel> models = new ArrayList<>();
|
||||
String content = response.body().string();
|
||||
JSONObject json = new JSONObject(content);
|
||||
JSONArray modelNodes = json.getJSONArray("models");
|
||||
mapping = json.getJSONArray("mapping");
|
||||
parseModels(modelNodes, models);
|
||||
return models;
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseModels(JSONArray jsonModels, List<StreamrayModel> models) {
|
||||
int name_idx = mapping_index("stream_name");
|
||||
int fav_idx = mapping_index("is_favorite");
|
||||
for (int i = 0; i < jsonModels.length(); i++) {
|
||||
JSONArray m = jsonModels.getJSONArray(i);
|
||||
String name = m.optString(name_idx);
|
||||
boolean favorite = m.optBoolean(fav_idx);
|
||||
if (favorite) {
|
||||
StreamrayModel model = (StreamrayModel) site.createModel(name);
|
||||
String preview = getPreviewURL(name);
|
||||
model.setPreview(preview);
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getPreviewURL(String name) {
|
||||
String lname = name.toLowerCase();
|
||||
String url = MessageFormat.format("https://images4.streamray.com/images/streamray/won/jpg/{0}/{1}/{2}_640.jpg", lname.substring(0,1), lname.substring(lname.length()-1), lname);
|
||||
try {
|
||||
return MessageFormat.format("https://dynimages.securedataimages.com/unsigned/rs:fill:640::0/g:no/plain/{0}@jpg", URLEncoder.encode(url, "utf-8"));
|
||||
} catch (Exception ex) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
private int mapping_index(String s) {
|
||||
for (var i = 0; i < mapping.length(); i++) {
|
||||
if (Objects.equals(s, mapping.get(i))) return i;
|
||||
}
|
||||
return -1;
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,37 +4,34 @@ import ctbrec.sites.streamray.Streamray;
|
|||
import ctbrec.ui.tabs.FollowedTab;
|
||||
import ctbrec.ui.tabs.ThumbOverviewTab;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
|
||||
public class StreamrayFavoritesTab extends ThumbOverviewTab implements FollowedTab {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StreamrayFavoritesTab.class);
|
||||
private Label status;
|
||||
private Button loginButton;
|
||||
private Streamray site;
|
||||
private StreamrayFavoritesService updateService;
|
||||
private final Label status;
|
||||
private final Button loginButton;
|
||||
private final StreamrayFavoritesService streamrayFavoritesService;
|
||||
|
||||
public StreamrayFavoritesTab(String title, StreamrayFavoritesService updateService, Streamray site) {
|
||||
super(title, updateService, site);
|
||||
this.site = site;
|
||||
this.updateService = updateService;
|
||||
|
||||
this.streamrayFavoritesService = updateService;
|
||||
|
||||
status = new Label("Logging in...");
|
||||
grid.getChildren().addAll(status);
|
||||
|
||||
|
||||
loginButton = new Button("Login");
|
||||
loginButton.setPadding(new Insets(20));
|
||||
loginButton.setOnAction(e -> {
|
||||
try {
|
||||
new StreamrayElectronLoginDialog(site.getHttpClient().getCookieJar());
|
||||
updateService.restart();
|
||||
} catch (Exception ex) {}
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -48,8 +45,8 @@ public class StreamrayFavoritesTab extends ThumbOverviewTab implements FollowedT
|
|||
protected void onSuccess() {
|
||||
grid.getChildren().removeAll(status, loginButton);
|
||||
grid.setAlignment(Pos.TOP_LEFT);
|
||||
if (updateService.loggedIn == false) {
|
||||
addLoginButton();
|
||||
if (!((AbstractStreamrayUpdateService) updateService).isLoggedIn()) {
|
||||
addLoginButton();
|
||||
} else {
|
||||
super.onSuccess();
|
||||
}
|
||||
|
|
|
@ -37,8 +37,4 @@ public class StreamraySiteUi extends AbstractSiteUi {
|
|||
public boolean login() throws IOException {
|
||||
return site.login();
|
||||
}
|
||||
|
||||
public synchronized boolean checkLogin() throws IOException {
|
||||
return site.login();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package ctbrec.ui.sites.streamray;
|
|||
|
||||
import ctbrec.sites.streamray.Streamray;
|
||||
import ctbrec.sites.streamray.StreamrayModel;
|
||||
|
||||
import ctbrec.ui.sites.AbstractTabProvider;
|
||||
import ctbrec.ui.tabs.ThumbOverviewTab;
|
||||
import javafx.scene.Scene;
|
||||
|
@ -25,7 +24,7 @@ public class StreamrayTabProvider extends AbstractTabProvider {
|
|||
tabs.add(createTab("Girls", m -> Objects.equals("F", m.getGender())));
|
||||
tabs.add(createTab("Boys", m -> Objects.equals("M", m.getGender())));
|
||||
tabs.add(createTab("Trans", m -> Objects.equals("TS", m.getGender())));
|
||||
tabs.add(createTab("New", m -> m.isNew()));
|
||||
tabs.add(createTab("New", StreamrayModel::isNew));
|
||||
tabs.add(favoritesTab());
|
||||
return tabs;
|
||||
}
|
||||
|
|
|
@ -1,146 +1,52 @@
|
|||
package ctbrec.ui.sites.streamray;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.sites.streamray.*;
|
||||
import ctbrec.ui.SiteUiFactory;
|
||||
import ctbrec.ui.tabs.PaginatedScheduledService;
|
||||
import ctbrec.sites.streamray.Streamray;
|
||||
import ctbrec.sites.streamray.StreamrayModel;
|
||||
import javafx.concurrent.Task;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import javafx.concurrent.Task;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class StreamrayUpdateService extends PaginatedScheduledService {
|
||||
@Slf4j
|
||||
public class StreamrayUpdateService extends AbstractStreamrayUpdateService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StreamrayUpdateService.class);
|
||||
private static final String API_URL = "https://beta-api.cams.com/won/compressed/";
|
||||
private List<StreamrayModel> models;
|
||||
private Instant lastListInfoRequest = Instant.EPOCH;
|
||||
|
||||
private Streamray site;
|
||||
private static List<StreamrayModel> modelsList;
|
||||
private static Instant lastListInfoRequest = Instant.EPOCH;
|
||||
private static JSONArray mapping;
|
||||
protected int modelsPerPage = 48;
|
||||
@Setter
|
||||
protected Predicate<StreamrayModel> filter;
|
||||
|
||||
public StreamrayUpdateService(Streamray site, Predicate<StreamrayModel> filter) {
|
||||
this.site = site;
|
||||
super(site);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<List<Model>> createTask() {
|
||||
return new Task<List<Model>>() {
|
||||
return new Task<>() {
|
||||
@Override
|
||||
public List<Model> call() throws IOException {
|
||||
return getModelList().stream()
|
||||
return getModels().stream()
|
||||
.filter(filter)
|
||||
.skip((page - 1) * (long) modelsPerPage)
|
||||
.limit(modelsPerPage)
|
||||
.collect(Collectors.toList()); // NOSONAR
|
||||
.map(Model.class::cast)
|
||||
.toList();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private List<StreamrayModel> getModelList() throws IOException {
|
||||
if (Duration.between(lastListInfoRequest, Instant.now()).getSeconds() < 30) {
|
||||
return Optional.ofNullable(modelsList).orElse(loadModelList());
|
||||
private List<StreamrayModel> getModels() throws IOException {
|
||||
if (models == null || Duration.between(lastListInfoRequest, Instant.now()).getSeconds() >= 10) {
|
||||
models = site.loadModelList();
|
||||
lastListInfoRequest = Instant.now();
|
||||
}
|
||||
modelsList = loadModelList();
|
||||
return Optional.ofNullable(modelsList).orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
private List<StreamrayModel> loadModelList() throws IOException {
|
||||
LOG.debug("Fetching page {}", API_URL);
|
||||
lastListInfoRequest = Instant.now();
|
||||
StreamrayHttpClient client = (StreamrayHttpClient) site.getHttpClient();
|
||||
Request req = new Request.Builder()
|
||||
.url(API_URL)
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.header(REFERER, site.getBaseUrl() + "/")
|
||||
.header(ORIGIN, site.getBaseUrl())
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
.build();
|
||||
try (Response response = client.execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
List<StreamrayModel> models = new ArrayList<>();
|
||||
String content = response.body().string();
|
||||
JSONObject json = new JSONObject(content);
|
||||
JSONArray modelNodes = json.getJSONArray("models");
|
||||
mapping = json.getJSONArray("mapping");
|
||||
parseModels(modelNodes, models);
|
||||
return models;
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseModels(JSONArray jsonModels, List<StreamrayModel> models) {
|
||||
int name_idx = mapping_index("stream_name");
|
||||
int date_idx = mapping_index("create_date");
|
||||
int gen_idx = mapping_index("gender");
|
||||
for (var i = 0; i < jsonModels.length(); i++) {
|
||||
var m = jsonModels.getJSONArray(i);
|
||||
String name = m.optString(name_idx);
|
||||
String gender = m.optString(gen_idx);
|
||||
String reg = m.optString(date_idx);
|
||||
StreamrayModel model = (StreamrayModel) site.createModel(name);
|
||||
try {
|
||||
LocalDate regDate = LocalDate.parse(reg, DateTimeFormatter.BASIC_ISO_DATE);
|
||||
model.setRegDate(regDate);
|
||||
} catch (DateTimeParseException e) {
|
||||
model.setRegDate(LocalDate.EPOCH);
|
||||
}
|
||||
String preview = getPreviewURL(name);
|
||||
model.setPreview(preview);
|
||||
model.setGender(gender);
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
|
||||
private String getPreviewURL(String name) {
|
||||
String lname = name.toLowerCase();
|
||||
String url = MessageFormat.format("https://images4.streamray.com/images/streamray/won/jpg/{0}/{1}/{2}_640.jpg", lname.substring(0,1), lname.substring(lname.length()-1), lname);
|
||||
try {
|
||||
return MessageFormat.format("https://dynimages.securedataimages.com/unsigned/rs:fill:640::0/g:no/plain/{0}@jpg", URLEncoder.encode(url, "utf-8"));
|
||||
} catch (Exception ex) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
public void setFilter(Predicate<StreamrayModel> filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
private int mapping_index(String s) {
|
||||
for (var i = 0; i < mapping.length(); i++) {
|
||||
if (Objects.equals(s, mapping.get(i))) return i;
|
||||
}
|
||||
return -1;
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ public interface Site {
|
|||
|
||||
HttpClient getHttpClient();
|
||||
|
||||
void init() throws IOException;
|
||||
default void init() throws IOException {
|
||||
// do nothing per default
|
||||
}
|
||||
|
||||
void shutdown();
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import static ctbrec.io.HttpConstants.*;
|
|||
public class AmateurTvModel extends AbstractModel {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AmateurTvModel.class);
|
||||
private JSONArray qualities = new JSONArray();
|
||||
private transient JSONArray qualities = new JSONArray();
|
||||
private int[] resolution = new int[2];
|
||||
|
||||
@Override
|
||||
|
@ -55,9 +55,7 @@ public class AmateurTvModel extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||
if (failFast && onlineState != UNKNOWN) {
|
||||
return onlineState;
|
||||
} else {
|
||||
if (!failFast || onlineState == UNKNOWN) {
|
||||
try {
|
||||
onlineState = isOnline(true) ? ONLINE : OFFLINE;
|
||||
} catch (InterruptedException e) {
|
||||
|
@ -66,8 +64,8 @@ public class AmateurTvModel extends AbstractModel {
|
|||
} catch (IOException | ExecutionException e) {
|
||||
onlineState = OFFLINE;
|
||||
}
|
||||
return onlineState;
|
||||
}
|
||||
return onlineState;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -31,7 +31,7 @@ import static ctbrec.Model.State.*;
|
|||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
public class ChaturbateModel extends AbstractModel { // NOSONAR
|
||||
public class ChaturbateModel extends AbstractModel {
|
||||
|
||||
private static final String PUBLIC = "public";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ChaturbateModel.class);
|
||||
|
|
|
@ -108,11 +108,6 @@ public class CherryTvModel extends AbstractModel {
|
|||
return onlineState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnlineState(State onlineState) {
|
||||
this.onlineState = onlineState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||
try {
|
||||
|
|
|
@ -1,40 +1,43 @@
|
|||
package ctbrec.sites.streamray;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.Model.State;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.sites.AbstractSite;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static ctbrec.io.HttpConstants.USER_AGENT;
|
||||
import static ctbrec.Model.State.*;
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
|
||||
@Slf4j
|
||||
public class Streamray extends AbstractSite {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Streamray.class);
|
||||
public static final String BASE_URI = "https://streamray.com";
|
||||
public static final String API_URL = "https://beta-api.cams.com";
|
||||
@Getter
|
||||
private boolean loggedIn = false;
|
||||
|
||||
private StreamrayHttpClient httpClient;
|
||||
public static String domain = "streamray.com";
|
||||
public static String baseUri = "https://streamray.com";
|
||||
public static String apiURL = "https://beta-api.cams.com";
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -43,11 +46,11 @@ public class Streamray extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
return baseUri;
|
||||
return BASE_URI;
|
||||
}
|
||||
|
||||
public String getApiUrl() {
|
||||
return apiURL;
|
||||
return API_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -72,9 +75,14 @@ public class Streamray extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public synchronized boolean login() throws IOException {
|
||||
boolean result = getHttpClient().login();
|
||||
LOG.debug("Streamray site login call result: {}", result);
|
||||
return result;
|
||||
if (!loggedIn) {
|
||||
boolean result = getHttpClient().login();
|
||||
log.debug("Streamray site login call result: {}", result);
|
||||
loggedIn = result;
|
||||
return result;
|
||||
} else {
|
||||
return loggedIn;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,17 +115,12 @@ public class Streamray extends AbstractSite {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean searchRequiresLogin() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Model> search(String q) throws IOException, InterruptedException {
|
||||
if (StringUtil.isBlank(q)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String url = getApiUrl() + "/models/new/?limit=30&search=" + URLEncoder.encode(q, "utf-8") + "&order=is_online";
|
||||
String url = getApiUrl() + "/models/new/?limit=30&search=" + URLEncoder.encode(q, UTF_8) + "&order=is_online";
|
||||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(USER_AGENT, getConfig().getSettings().httpUserAgent)
|
||||
|
@ -128,15 +131,12 @@ public class Streamray extends AbstractSite {
|
|||
if (json.has("results")) {
|
||||
List<Model> models = new ArrayList<>();
|
||||
JSONArray results = json.getJSONArray("results");
|
||||
if (results.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (int i = 0; i < results.length(); i++) {
|
||||
JSONObject result = results.getJSONObject(i);
|
||||
StreamrayModel model = createModel(result.getString("stream_name"));
|
||||
String image = result.optString("profile_image");
|
||||
if (StringUtil.isBlank(image)) {
|
||||
image = model.getPreviewURL();
|
||||
image = getPreviewURL(model.getName());
|
||||
}
|
||||
model.setPreview(image);
|
||||
models.add(model);
|
||||
|
@ -163,7 +163,7 @@ public class Streamray extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public Model createModelFromUrl(String url) {
|
||||
Matcher m = Pattern.compile("https://(streamray|cams).com/([_a-zA-Z0-9]+)").matcher(url);
|
||||
Matcher m = Pattern.compile("https://(streamray|cams).com/(\\w+)").matcher(url);
|
||||
if (m.matches()) {
|
||||
String modelName = m.group(2);
|
||||
return createModel(modelName);
|
||||
|
@ -176,4 +176,98 @@ public class Streamray extends AbstractSite {
|
|||
public String getAffiliateLink() {
|
||||
return getBaseUrl();
|
||||
}
|
||||
|
||||
|
||||
public List<StreamrayModel> loadModelList() throws IOException {
|
||||
return loadModelList(false);
|
||||
}
|
||||
|
||||
public List<StreamrayModel> loadModelList(boolean withLogin) throws IOException {
|
||||
String url = API_URL + "/won/compressed/";
|
||||
log.debug("Fetching page {}", url);
|
||||
StreamrayHttpClient client = (StreamrayHttpClient) getHttpClient();
|
||||
String token;
|
||||
Request.Builder builder = new Request.Builder().url(url);
|
||||
if (withLogin) {
|
||||
if (login()) {
|
||||
token = client.getUserToken();
|
||||
builder.header(AUTHORIZATION, "Bearer " + token);
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
builder.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.header(REFERER, getBaseUrl() + "/")
|
||||
.header(ORIGIN, getBaseUrl())
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST);
|
||||
Request req = builder.build();
|
||||
try (Response response = client.execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
List<StreamrayModel> models = new ArrayList<>();
|
||||
String content = response.body().string();
|
||||
JSONObject json = new JSONObject(content);
|
||||
parseModels(json, models);
|
||||
return models;
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void parseModels(JSONObject json, List<StreamrayModel> models) {
|
||||
JSONArray mapping = json.getJSONArray("mapping");
|
||||
JSONArray jsonModels = json.getJSONArray("models");
|
||||
int nameIdx = indexOfProperty(mapping, "stream_name");
|
||||
int dateIdx = indexOfProperty(mapping, "create_date");
|
||||
int genIdx = indexOfProperty(mapping, "gender");
|
||||
int chatTypeIdx = indexOfProperty(mapping, "chat_type");
|
||||
int favIdx = indexOfProperty(mapping, "is_favorite");
|
||||
for (var i = 0; i < jsonModels.length(); i++) {
|
||||
var m = jsonModels.getJSONArray(i);
|
||||
String name = m.optString(nameIdx);
|
||||
StreamrayModel model = createModel(name);
|
||||
try {
|
||||
LocalDate regDate = LocalDate.parse(m.optString(dateIdx), DateTimeFormatter.BASIC_ISO_DATE);
|
||||
model.setRegDate(regDate);
|
||||
} catch (DateTimeParseException e) {
|
||||
model.setRegDate(LocalDate.EPOCH);
|
||||
}
|
||||
model.setOnlineState(mapOnlineState(m.optString(chatTypeIdx)));
|
||||
String preview = getPreviewURL(name);
|
||||
model.setPreview(preview);
|
||||
model.setGender(m.optString(genIdx));
|
||||
model.setFavorite(m.optBoolean(favIdx));
|
||||
models.add(model);
|
||||
}
|
||||
}
|
||||
|
||||
public State mapOnlineState(String status) {
|
||||
boolean goalShows = Config.getInstance().getSettings().streamrayRecordGoalShows;
|
||||
return switch (status) {
|
||||
case "0" -> OFFLINE;
|
||||
case "1" -> ONLINE;
|
||||
case "6" -> goalShows ? ONLINE : PRIVATE;
|
||||
case "2", "3", "4", "7", "10", "11", "12", "13", "14" -> PRIVATE;
|
||||
default -> UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
private int indexOfProperty(JSONArray mapping, String key) {
|
||||
for (var i = 0; i < mapping.length(); i++) {
|
||||
if (Objects.equals(key, mapping.get(i))) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private String getPreviewURL(String name) {
|
||||
String lname = name.toLowerCase();
|
||||
String url = MessageFormat.format("https://images4.streamray.com/images/streamray/won/jpg/{0}/{1}/{2}_640.jpg", lname.substring(0, 1), lname.substring(lname.length() - 1), lname);
|
||||
try {
|
||||
return MessageFormat.format("https://dynimages.securedataimages.com/unsigned/rs:fill:640::0/g:no/plain/{0}@jpg", URLEncoder.encode(url, UTF_8));
|
||||
} catch (Exception ex) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,26 +39,28 @@ public class StreamrayHttpClient extends HttpClient {
|
|||
|
||||
private void updateToken() {
|
||||
Request req = new Request.Builder()
|
||||
.url(Streamray.baseUri)
|
||||
.url(Streamray.BASE_URI)
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.build();
|
||||
try (Response response = execute(req)) {
|
||||
// nothing to do, we just call the base URI to get the cookie
|
||||
} catch (Exception ex) {
|
||||
// fail silently
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkLoginSuccess() {
|
||||
String token = getUserToken();
|
||||
Request req = new Request.Builder()
|
||||
.url(Streamray.apiURL + "/members/me/balance/")
|
||||
.url(Streamray.API_URL + "/members/me/balance/")
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.header(AUTHORIZATION, "Bearer " + token)
|
||||
.header(REFERER, Streamray.baseUri + "/")
|
||||
.header(ORIGIN, Streamray.baseUri)
|
||||
.header(REFERER, Streamray.BASE_URI + "/")
|
||||
.header(ORIGIN, Streamray.BASE_URI)
|
||||
.build();
|
||||
try (Response response = execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
|
@ -75,7 +77,7 @@ public class StreamrayHttpClient extends HttpClient {
|
|||
|
||||
public String getUserToken() {
|
||||
try {
|
||||
Cookie cookie = getCookieJar().getCookie(HttpUrl.parse(Streamray.baseUri), "memberToken");
|
||||
Cookie cookie = getCookieJar().getCookie(HttpUrl.parse(Streamray.BASE_URI), "memberToken");
|
||||
String token = cookie.value();
|
||||
return token;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -8,15 +8,15 @@ import ctbrec.io.HttpException;
|
|||
import ctbrec.recorder.download.RecordingProcess;
|
||||
import ctbrec.recorder.download.StreamSource;
|
||||
import ctbrec.recorder.download.hls.FfmpegHlsDownload;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.IOException;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
|
@ -24,21 +24,28 @@ import java.time.LocalDate;
|
|||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static ctbrec.Model.State.*;
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@Slf4j
|
||||
public class StreamrayModel extends AbstractModel {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(StreamrayModel.class);
|
||||
private String status = null;
|
||||
private String gender = null;
|
||||
private LocalDate regDate = LocalDate.EPOCH;
|
||||
private JSONObject modelInfo;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String gender = null;
|
||||
|
||||
@Setter
|
||||
private LocalDate regDate = LocalDate.EPOCH;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean favorite = false;
|
||||
|
||||
private transient JSONObject modelInfo;
|
||||
private transient Instant lastInfoRequest = Instant.EPOCH;
|
||||
|
||||
@Override
|
||||
|
@ -48,7 +55,7 @@ public class StreamrayModel extends AbstractModel {
|
|||
JSONObject json = getModelInfo();
|
||||
if (json.has("online")) {
|
||||
status = json.optString("online");
|
||||
mapOnlineState(status);
|
||||
setOnlineState(((Streamray) site).mapOnlineState(status));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
setOnlineState(UNKNOWN);
|
||||
|
@ -57,22 +64,9 @@ public class StreamrayModel extends AbstractModel {
|
|||
return onlineState == ONLINE;
|
||||
}
|
||||
|
||||
private void mapOnlineState(String status) {
|
||||
boolean goalShows = Config.getInstance().getSettings().streamrayRecordGoalShows;
|
||||
switch (status) {
|
||||
case "0" -> setOnlineState(OFFLINE);
|
||||
case "1" -> setOnlineState(ONLINE);
|
||||
case "6" -> setOnlineState(goalShows ? ONLINE : PRIVATE);
|
||||
case "2", "3", "4", "7", "10", "11", "12", "13", "14" -> setOnlineState(PRIVATE);
|
||||
default -> setOnlineState(OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||
if (failFast && onlineState != UNKNOWN) {
|
||||
return onlineState;
|
||||
} else {
|
||||
if (!failFast || onlineState == UNKNOWN) {
|
||||
try {
|
||||
onlineState = isOnline(true) ? ONLINE : OFFLINE;
|
||||
} catch (InterruptedException e) {
|
||||
|
@ -81,8 +75,8 @@ public class StreamrayModel extends AbstractModel {
|
|||
} catch (IOException | ExecutionException e) {
|
||||
onlineState = OFFLINE;
|
||||
}
|
||||
return onlineState;
|
||||
}
|
||||
return onlineState;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -97,7 +91,7 @@ public class StreamrayModel extends AbstractModel {
|
|||
src.bandwidth = 0;
|
||||
sources.add(src);
|
||||
} catch (IOException e) {
|
||||
LOG.error("Can not get stream sources for {}", getName());
|
||||
log.error("Can not get stream sources for {}", getName());
|
||||
}
|
||||
return sources;
|
||||
}
|
||||
|
@ -115,9 +109,7 @@ public class StreamrayModel extends AbstractModel {
|
|||
}
|
||||
|
||||
private JSONObject getModelInfo() throws IOException {
|
||||
if (Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) {
|
||||
modelInfo = Optional.ofNullable(modelInfo).orElse(loadModelInfo());
|
||||
} else {
|
||||
if (modelInfo == null || Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) {
|
||||
modelInfo = loadModelInfo();
|
||||
}
|
||||
return modelInfo;
|
||||
|
@ -134,24 +126,13 @@ public class StreamrayModel extends AbstractModel {
|
|||
.build();
|
||||
try (Response response = site.getHttpClient().execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
JSONObject jsonResponse = new JSONObject(response.body().string());
|
||||
return jsonResponse;
|
||||
return new JSONObject(response.body().string());
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getPreviewURL() {
|
||||
String lname = getName().toLowerCase();
|
||||
String url = MessageFormat.format("https://images4.streamray.com/images/streamray/won/jpg/{0}/{1}/{2}_640.jpg", lname.substring(0, 1), lname.substring(lname.length() - 1), lname);
|
||||
try {
|
||||
return MessageFormat.format("https://dynimages.securedataimages.com/unsigned/rs:fill:320::0/g:no/plain/{0}@jpg", URLEncoder.encode(url, UTF_8));
|
||||
} catch (Exception ex) {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecordingProcess createDownload() {
|
||||
return new FfmpegHlsDownload(getSite().getHttpClient());
|
||||
|
@ -179,18 +160,6 @@ public class StreamrayModel extends AbstractModel {
|
|||
modelInfo = null;
|
||||
}
|
||||
|
||||
public String getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(String gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public void setRegDate(LocalDate reg) {
|
||||
this.regDate = reg;
|
||||
}
|
||||
|
||||
public boolean isNew() {
|
||||
return ChronoUnit.DAYS.between(this.regDate, LocalDate.now()) < 30;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue