forked from j62/ctbrec
Implement login and followed tab for cherry.tv
This commit is contained in:
parent
c4c5818496
commit
36cacda106
|
@ -1,7 +1,6 @@
|
||||||
package ctbrec.ui.sites.cherrytv;
|
package ctbrec.ui.sites.cherrytv;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.sites.cam4.Cam4;
|
|
||||||
import ctbrec.sites.cherrytv.CherryTv;
|
import ctbrec.sites.cherrytv.CherryTv;
|
||||||
import ctbrec.ui.DesktopIntegration;
|
import ctbrec.ui.DesktopIntegration;
|
||||||
import ctbrec.ui.settings.SettingsTab;
|
import ctbrec.ui.settings.SettingsTab;
|
||||||
|
@ -30,7 +29,7 @@ public class CherryTvConfigUI extends AbstractConfigUI {
|
||||||
var enabled = new CheckBox();
|
var enabled = new CheckBox();
|
||||||
enabled.setSelected(!settings.disabledSites.contains(site.getName()));
|
enabled.setSelected(!settings.disabledSites.contains(site.getName()));
|
||||||
enabled.setOnAction(e -> {
|
enabled.setOnAction(e -> {
|
||||||
if(enabled.isSelected()) {
|
if (enabled.isSelected()) {
|
||||||
settings.disabledSites.remove(site.getName());
|
settings.disabledSites.remove(site.getName());
|
||||||
} else {
|
} else {
|
||||||
settings.disabledSites.add(site.getName());
|
settings.disabledSites.add(site.getName());
|
||||||
|
@ -40,11 +39,11 @@ public class CherryTvConfigUI extends AbstractConfigUI {
|
||||||
GridPane.setMargin(enabled, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN));
|
GridPane.setMargin(enabled, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN));
|
||||||
layout.add(enabled, 1, row++);
|
layout.add(enabled, 1, row++);
|
||||||
|
|
||||||
layout.add(new Label("Cam4 User"), 0, row);
|
layout.add(new Label(site.getName() + " User"), 0, row);
|
||||||
var username = new TextField(Config.getInstance().getSettings().cam4Username);
|
var username = new TextField(Config.getInstance().getSettings().cherryTvUsername);
|
||||||
username.textProperty().addListener((ob, o, n) -> {
|
username.textProperty().addListener((ob, o, n) -> {
|
||||||
if(!n.equals(Config.getInstance().getSettings().cam4Username)) {
|
if (!n.equals(Config.getInstance().getSettings().cherryTvUsername)) {
|
||||||
Config.getInstance().getSettings().cam4Username = username.getText();
|
Config.getInstance().getSettings().cherryTvUsername = username.getText();
|
||||||
site.getHttpClient().logout();
|
site.getHttpClient().logout();
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
@ -54,12 +53,12 @@ public class CherryTvConfigUI extends AbstractConfigUI {
|
||||||
GridPane.setColumnSpan(username, 2);
|
GridPane.setColumnSpan(username, 2);
|
||||||
layout.add(username, 1, row++);
|
layout.add(username, 1, row++);
|
||||||
|
|
||||||
layout.add(new Label("Cam4 Password"), 0, row);
|
layout.add(new Label(site.getName() + " Password"), 0, row);
|
||||||
var password = new PasswordField();
|
var password = new PasswordField();
|
||||||
password.setText(Config.getInstance().getSettings().cam4Password);
|
password.setText(Config.getInstance().getSettings().cherryTvPassword);
|
||||||
password.textProperty().addListener((ob, o, n) -> {
|
password.textProperty().addListener((ob, o, n) -> {
|
||||||
if(!n.equals(Config.getInstance().getSettings().cam4Password)) {
|
if (!n.equals(Config.getInstance().getSettings().cherryTvPassword)) {
|
||||||
Config.getInstance().getSettings().cam4Password = password.getText();
|
Config.getInstance().getSettings().cherryTvPassword = password.getText();
|
||||||
site.getHttpClient().logout();
|
site.getHttpClient().logout();
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
@ -70,7 +69,7 @@ public class CherryTvConfigUI extends AbstractConfigUI {
|
||||||
layout.add(password, 1, row++);
|
layout.add(password, 1, row++);
|
||||||
|
|
||||||
var createAccount = new Button("Create new Account");
|
var createAccount = new Button("Create new Account");
|
||||||
createAccount.setOnAction(e -> DesktopIntegration.open(Cam4.AFFILIATE_LINK));
|
createAccount.setOnAction(e -> DesktopIntegration.open(site.getAffiliateLink()));
|
||||||
layout.add(createAccount, 1, row++);
|
layout.add(createAccount, 1, row++);
|
||||||
GridPane.setColumnSpan(createAccount, 2);
|
GridPane.setColumnSpan(createAccount, 2);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
|
||||||
|
package ctbrec.ui.sites.cherrytv;
|
||||||
|
|
||||||
|
import ctbrec.sites.cherrytv.CherryTv;
|
||||||
|
import ctbrec.ui.tabs.FollowedTab;
|
||||||
|
import ctbrec.ui.tabs.ThumbOverviewTab;
|
||||||
|
import javafx.concurrent.WorkerStateEvent;
|
||||||
|
import javafx.geometry.Insets;
|
||||||
|
import javafx.scene.Scene;
|
||||||
|
import javafx.scene.control.Label;
|
||||||
|
import javafx.scene.control.RadioButton;
|
||||||
|
import javafx.scene.control.ToggleGroup;
|
||||||
|
import javafx.scene.input.KeyCode;
|
||||||
|
import javafx.scene.input.KeyEvent;
|
||||||
|
import javafx.scene.layout.HBox;
|
||||||
|
|
||||||
|
public class CherryTvFollowedTab extends ThumbOverviewTab implements FollowedTab {
|
||||||
|
private final Label status;
|
||||||
|
private ToggleGroup group;
|
||||||
|
|
||||||
|
public CherryTvFollowedTab(String title, CherryTv site) {
|
||||||
|
super(title, new CherryTvFollowedUpdateService(site), site);
|
||||||
|
status = new Label("Logging in...");
|
||||||
|
grid.getChildren().add(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createGui() {
|
||||||
|
super.createGui();
|
||||||
|
group = new ToggleGroup();
|
||||||
|
addOnlineOfflineSelector();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addOnlineOfflineSelector() {
|
||||||
|
var online = new RadioButton("online");
|
||||||
|
online.setToggleGroup(group);
|
||||||
|
var offline = new RadioButton("offline");
|
||||||
|
offline.setToggleGroup(group);
|
||||||
|
pagination.getChildren().add(online);
|
||||||
|
pagination.getChildren().add(offline);
|
||||||
|
HBox.setMargin(online, new Insets(5, 5, 5, 40));
|
||||||
|
HBox.setMargin(offline, new Insets(5, 5, 5, 5));
|
||||||
|
online.setSelected(true);
|
||||||
|
group.selectedToggleProperty().addListener(e -> {
|
||||||
|
((CherryTvUpdateService) updateService).setFilter(m -> {
|
||||||
|
try {
|
||||||
|
return m.isOnline(false) == online.isSelected();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return false;
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
queue.clear();
|
||||||
|
updateService.restart();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onSuccess() {
|
||||||
|
grid.getChildren().remove(status);
|
||||||
|
super.onSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFail(WorkerStateEvent event) {
|
||||||
|
status.setText("Login failed");
|
||||||
|
super.onFail(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void selected() {
|
||||||
|
status.setText("Logging in...");
|
||||||
|
super.selected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScene(Scene scene) {
|
||||||
|
scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||||
|
if (this.isSelected() && event.getCode() == KeyCode.DELETE) {
|
||||||
|
follow(selectedThumbCells, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package ctbrec.ui.sites.cherrytv;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.sites.cherrytv.CherryTv;
|
||||||
|
import ctbrec.sites.cherrytv.CherryTvModel;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static ctbrec.Model.State.OFFLINE;
|
||||||
|
import static ctbrec.Model.State.ONLINE;
|
||||||
|
|
||||||
|
public class CherryTvFollowedUpdateService extends CherryTvUpdateService {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CherryTvFollowedUpdateService.class);
|
||||||
|
|
||||||
|
public CherryTvFollowedUpdateService(CherryTv site) {
|
||||||
|
super(site.getBaseUrl() + "/graphql?operationName=FindFollowings&variables={\"cursor\":${offset},\"limit\":${limit}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"7d2cf16b113dc1d57af02685e249e28df9649ea598717dc2c877294529ae0cb3\"}}",
|
||||||
|
site,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Model> parseModels(String body) throws IOException {
|
||||||
|
var json = new JSONObject(body);
|
||||||
|
if (json.has("errors")) {
|
||||||
|
JSONArray errors = json.getJSONArray("errors");
|
||||||
|
JSONObject first = errors.getJSONObject(0);
|
||||||
|
throw new IOException(first.getString("message"));
|
||||||
|
}
|
||||||
|
List<Model> models = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
JSONArray followings = json.getJSONObject("data").getJSONObject("followinglist").getJSONArray("followings");
|
||||||
|
for (int i = 0; i < followings.length(); i++) {
|
||||||
|
JSONObject following = followings.getJSONObject(i);
|
||||||
|
CherryTvModel model = site.createModel(following.optString("username"));
|
||||||
|
model.setId(following.getString("id"));
|
||||||
|
model.setPreview(following.optString("img"));
|
||||||
|
var online = following.optString("status").equalsIgnoreCase("Live");
|
||||||
|
model.setOnline(online);
|
||||||
|
model.setOnlineState(online ? ONLINE : OFFLINE);
|
||||||
|
models.add(model);
|
||||||
|
}
|
||||||
|
} catch (JSONException e) {
|
||||||
|
LOG.error("Couldn't parse JSON, the structure might have changed", e);
|
||||||
|
}
|
||||||
|
return models;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
package ctbrec.ui.sites.cherrytv;
|
package ctbrec.ui.sites.cherrytv;
|
||||||
|
|
||||||
import ctbrec.sites.cam4.Cam4;
|
|
||||||
import ctbrec.sites.cam4.Cam4HttpClient;
|
|
||||||
import ctbrec.sites.cherrytv.CherryTv;
|
import ctbrec.sites.cherrytv.CherryTv;
|
||||||
import ctbrec.ui.controls.Dialogs;
|
|
||||||
import ctbrec.ui.sites.AbstractSiteUi;
|
import ctbrec.ui.sites.AbstractSiteUi;
|
||||||
import ctbrec.ui.sites.ConfigUI;
|
import ctbrec.ui.sites.ConfigUI;
|
||||||
import ctbrec.ui.tabs.TabProvider;
|
import ctbrec.ui.tabs.TabProvider;
|
||||||
|
|
|
@ -14,28 +14,35 @@ public class CherryTvTabProvider implements TabProvider {
|
||||||
|
|
||||||
private final CherryTv site;
|
private final CherryTv site;
|
||||||
private final Recorder recorder;
|
private final Recorder recorder;
|
||||||
|
private final CherryTvFollowedTab followedTab;
|
||||||
|
|
||||||
public CherryTvTabProvider(CherryTv cherryTv) {
|
public CherryTvTabProvider(CherryTv cherryTv) {
|
||||||
this.site = cherryTv;
|
this.site = cherryTv;
|
||||||
this.recorder = cherryTv.getRecorder();
|
this.recorder = cherryTv.getRecorder();
|
||||||
|
|
||||||
|
followedTab = new CherryTvFollowedTab("Following", site);
|
||||||
|
followedTab.setImageAspectRatio(9.0 / 16.0);
|
||||||
|
followedTab.preserveAspectRatioProperty().set(false);
|
||||||
|
followedTab.setRecorder(recorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Tab> getTabs(Scene scene) {
|
public List<Tab> getTabs(Scene scene) {
|
||||||
List<Tab> tabs = new ArrayList<>();
|
List<Tab> tabs = new ArrayList<>();
|
||||||
tabs.add(createTab("Female", site.getBaseUrl() + "/graphql?operationName=findBroadcastsByPage&variables={\"slug\":\"female\",\"tag\":null,\"following\":null,\"limit\":${limit},\"cursor\":${offset}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f1e214ca901e525301fcc6966cf081ee95ef777974ec184897c4a2cf15e9ac6f\"}}"));
|
tabs.add(createTab("Female", site.getBaseUrl() + "/graphql?operationName=findBroadcastsByPage&variables={\"slug\":\"female\",\"tag\":null,\"following\":null,\"limit\":${limit},\"cursor\":${offset}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f1e214ca901e525301fcc6966cf081ee95ef777974ec184897c4a2cf15e9ac6f\"}}"));
|
||||||
tabs.add(createTab("Trans", site.getBaseUrl() + "/graphql?operationName=findBroadcastsByPage&variables={\"slug\":\"trans\",\"tag\":null,\"following\":null,\"limit\":${limit},\"cursor\":${offset}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f1e214ca901e525301fcc6966cf081ee95ef777974ec184897c4a2cf15e9ac6f\"}}"));
|
tabs.add(createTab("Trans", site.getBaseUrl() + "/graphql?operationName=findBroadcastsByPage&variables={\"slug\":\"trans\",\"tag\":null,\"following\":null,\"limit\":${limit},\"cursor\":${offset}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f1e214ca901e525301fcc6966cf081ee95ef777974ec184897c4a2cf15e9ac6f\"}}"));
|
||||||
tabs.add(createTab("Group Show", site.getBaseUrl() + "/graphql?operationName=findBroadcastsByPage&variables={\"slug\":\"groupshow\",\"tag\":null,\"following\":null,\"limit\":${limit},\"cursor\":${offset}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f1e214ca901e525301fcc6966cf081ee95ef777974ec184897c4a2cf15e9ac6f\"}}"));
|
tabs.add(createTab("Group Show", site.getBaseUrl() + "/graphql?operationName=findBroadcastsByPage&variables={\"slug\":\"groupshow\",\"tag\":null,\"following\":null,\"limit\":${limit},\"cursor\":${offset}}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"f1e214ca901e525301fcc6966cf081ee95ef777974ec184897c4a2cf15e9ac6f\"}}"));
|
||||||
|
tabs.add(followedTab);
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Tab getFollowedTab() {
|
public Tab getFollowedTab() {
|
||||||
return null;
|
return followedTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tab createTab(String name, String url) {
|
private Tab createTab(String name, String url) {
|
||||||
var updateService = new CherryTvUpdateService(url, site);
|
var updateService = new CherryTvUpdateService(url, site, false);
|
||||||
var tab = new ThumbOverviewTab(name, updateService, site);
|
var tab = new ThumbOverviewTab(name, updateService, site);
|
||||||
tab.setImageAspectRatio(9.0 / 16.0);
|
tab.setImageAspectRatio(9.0 / 16.0);
|
||||||
tab.preserveAspectRatioProperty().set(false);
|
tab.preserveAspectRatioProperty().set(false);
|
||||||
|
|
|
@ -21,6 +21,9 @@ import java.util.Locale;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static ctbrec.Model.State.OFFLINE;
|
import static ctbrec.Model.State.OFFLINE;
|
||||||
import static ctbrec.Model.State.ONLINE;
|
import static ctbrec.Model.State.ONLINE;
|
||||||
|
@ -31,12 +34,16 @@ public class CherryTvUpdateService extends PaginatedScheduledService {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(CherryTvUpdateService.class);
|
private static final Logger LOG = LoggerFactory.getLogger(CherryTvUpdateService.class);
|
||||||
private static final int MODELS_PER_PAGE = 100;
|
private static final int MODELS_PER_PAGE = 100;
|
||||||
private String url;
|
|
||||||
private final CherryTv site;
|
|
||||||
|
|
||||||
public CherryTvUpdateService(String url, CherryTv site) {
|
private final String url;
|
||||||
|
private final boolean loginRequired;
|
||||||
|
protected final CherryTv site;
|
||||||
|
private Predicate<Model> filter;
|
||||||
|
|
||||||
|
public CherryTvUpdateService(String url, CherryTv site, boolean loginRequired) {
|
||||||
this.site = site;
|
this.site = site;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
this.loginRequired = loginRequired;
|
||||||
|
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
|
ExecutorService executor = Executors.newSingleThreadExecutor(r -> {
|
||||||
var t = new Thread(r);
|
var t = new Thread(r);
|
||||||
|
@ -52,6 +59,10 @@ public class CherryTvUpdateService extends PaginatedScheduledService {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
@Override
|
@Override
|
||||||
public List<Model> call() throws IOException {
|
public List<Model> call() throws IOException {
|
||||||
|
if (loginRequired && !site.getHttpClient().login()) {
|
||||||
|
throw new IOException("Login failed");
|
||||||
|
}
|
||||||
|
|
||||||
String pageUrl = CherryTvUpdateService.this.url;
|
String pageUrl = CherryTvUpdateService.this.url;
|
||||||
pageUrl = pageUrl.replace("${limit}", String.valueOf(MODELS_PER_PAGE));
|
pageUrl = pageUrl.replace("${limit}", String.valueOf(MODELS_PER_PAGE));
|
||||||
pageUrl = pageUrl.replace("${offset}", String.valueOf((page - 1) * MODELS_PER_PAGE));
|
pageUrl = pageUrl.replace("${offset}", String.valueOf((page - 1) * MODELS_PER_PAGE));
|
||||||
|
@ -64,7 +75,13 @@ public class CherryTvUpdateService extends PaginatedScheduledService {
|
||||||
.build();
|
.build();
|
||||||
try (var response = site.getHttpClient().execute(request)) {
|
try (var response = site.getHttpClient().execute(request)) {
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
return parseModels(Objects.requireNonNull(response.body()).string());
|
String body = Objects.requireNonNull(response.body()).string();
|
||||||
|
LOG.debug(body);
|
||||||
|
Stream<Model> stream = parseModels(body).stream();
|
||||||
|
if (filter != null) {
|
||||||
|
stream = stream.filter(filter);
|
||||||
|
}
|
||||||
|
return stream.collect(Collectors.toList());
|
||||||
} else {
|
} else {
|
||||||
throw new HttpException(response.code(), response.message());
|
throw new HttpException(response.code(), response.message());
|
||||||
}
|
}
|
||||||
|
@ -73,8 +90,13 @@ public class CherryTvUpdateService extends PaginatedScheduledService {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Model> parseModels(String body) {
|
protected List<Model> parseModels(String body) throws IOException {
|
||||||
var json = new JSONObject(body);
|
var json = new JSONObject(body);
|
||||||
|
if (json.has("errors")) {
|
||||||
|
JSONArray errors = json.getJSONArray("errors");
|
||||||
|
JSONObject first = errors.getJSONObject(0);
|
||||||
|
throw new IOException(first.getString("message"));
|
||||||
|
}
|
||||||
List<Model> models = new ArrayList<>();
|
List<Model> models = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
JSONArray broadcasts = json.getJSONObject("data").getJSONObject("broadcasts").getJSONArray("broadcasts");
|
JSONArray broadcasts = json.getJSONObject("data").getJSONObject("broadcasts").getJSONArray("broadcasts");
|
||||||
|
@ -102,8 +124,7 @@ public class CherryTvUpdateService extends PaginatedScheduledService {
|
||||||
return models;
|
return models;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUrl(String url) {
|
public void setFilter(Predicate<Model> filter) {
|
||||||
this.url = url;
|
this.filter = filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ public class LoggingInterceptor implements Interceptor {
|
||||||
}
|
}
|
||||||
Response response = chain.proceed(request);
|
Response response = chain.proceed(request);
|
||||||
long t2 = System.nanoTime();
|
long t2 = System.nanoTime();
|
||||||
LOG.debug("OkHttp Received response for {} in {}\n{}", response.request().url(), (t2 - t1) / 1e6d, response.headers());
|
LOG.debug("OkHttp Received {} response for {} in {}ms\n{}", response.code(), response.request().url(), (t2 - t1) / 1e6d, response.headers());
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,8 @@ public class Settings {
|
||||||
public String chaturbateUsername = "";
|
public String chaturbateUsername = "";
|
||||||
public String chaturbateBaseUrl = "https://chaturbate.com";
|
public String chaturbateBaseUrl = "https://chaturbate.com";
|
||||||
public int chaturbateMsBetweenRequests = 1000;
|
public int chaturbateMsBetweenRequests = 1000;
|
||||||
|
public String cherryTvPassword = "";
|
||||||
|
public String cherryTvUsername = "";
|
||||||
public boolean chooseStreamQuality = false;
|
public boolean chooseStreamQuality = false;
|
||||||
public String colorAccent = "#FFFFFF";
|
public String colorAccent = "#FFFFFF";
|
||||||
public String colorBase = "#FFFFFF";
|
public String colorBase = "#FFFFFF";
|
||||||
|
|
|
@ -144,8 +144,9 @@ public abstract class HttpClient {
|
||||||
.cookieJar(cookieJar)
|
.cookieJar(cookieJar)
|
||||||
.connectionPool(GLOBAL_HTTP_CONN_POOL)
|
.connectionPool(GLOBAL_HTTP_CONN_POOL)
|
||||||
.connectTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
|
.connectTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
|
||||||
.readTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS);
|
.readTimeout(config.getSettings().httpTimeout, TimeUnit.MILLISECONDS)
|
||||||
//.addInterceptor(new LoggingInterceptor());
|
//.addNetworkInterceptor(new LoggingInterceptor())
|
||||||
|
;
|
||||||
|
|
||||||
ProxyType proxyType = config.getSettings().proxyType;
|
ProxyType proxyType = config.getSettings().proxyType;
|
||||||
if (proxyType == ProxyType.HTTP) {
|
if (proxyType == ProxyType.HTTP) {
|
||||||
|
|
|
@ -2,17 +2,122 @@ package ctbrec.sites.cherrytv;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
|
import ctbrec.io.HttpException;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static ctbrec.io.HttpConstants.*;
|
||||||
|
|
||||||
public class CherryTvHttpClient extends HttpClient {
|
public class CherryTvHttpClient extends HttpClient {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(CherryTvHttpClient.class);
|
||||||
|
|
||||||
public CherryTvHttpClient(Config config) {
|
public CherryTvHttpClient(Config config) {
|
||||||
super("cherrytv", config);
|
super("cherrytv", config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean login() throws IOException {
|
public synchronized boolean login() throws IOException {
|
||||||
return false;
|
if (loggedIn) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean cookiesWorked = checkLoginSuccess();
|
||||||
|
if (cookiesWorked) {
|
||||||
|
loggedIn = true;
|
||||||
|
LOG.debug("Logged in with cookies");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONObject body = new JSONObject()
|
||||||
|
.put("operationName", "authenticateUser")
|
||||||
|
.put("variables", new JSONObject()
|
||||||
|
.put("username", config.getSettings().cherryTvUsername)
|
||||||
|
.put("password", config.getSettings().cherryTvPassword)
|
||||||
|
)
|
||||||
|
.put("extensions", new JSONObject()
|
||||||
|
.put("persistedQuery", new JSONObject()
|
||||||
|
.put("version", 1)
|
||||||
|
.put("sha256Hash", "9c105878022f9a7d511c12527c70f125606dc25367a4dd56aa63a6af73579087")
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
RequestBody requestBody = RequestBody.create(body.toString(), MediaType.parse("application/json"));
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(CherryTv.BASE_URL + "/graphql")
|
||||||
|
.header(REFERER, CherryTv.BASE_URL)
|
||||||
|
.header(ORIGIN, CherryTv.BASE_URL)
|
||||||
|
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||||
|
.post(requestBody)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
LOG.debug("Logging in: {}\n{}", request.url(), body.toString(2));
|
||||||
|
try (Response response = execute(request)) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
JSONObject resp = new JSONObject(Objects.requireNonNull(response.body()).string());
|
||||||
|
LOG.info(resp.toString(2));
|
||||||
|
JSONObject data = resp.getJSONObject("data");
|
||||||
|
JSONObject login = data.getJSONObject("login");
|
||||||
|
loggedIn = login.optBoolean("success");
|
||||||
|
String jwt = login.optString("token");
|
||||||
|
saveAsSessionCookie(jwt);
|
||||||
|
LOG.debug("Login successful");
|
||||||
|
return loggedIn;
|
||||||
|
} else {
|
||||||
|
throw new HttpException(response.code(), response.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveAsSessionCookie(String jwt) {
|
||||||
|
HttpUrl url = HttpUrl.parse(CherryTv.BASE_URL);
|
||||||
|
Objects.requireNonNull(url);
|
||||||
|
long expiresAt = Instant.now().plus(1, ChronoUnit.DAYS).getEpochSecond();
|
||||||
|
Cookie sessionCookie = new Cookie.Builder()
|
||||||
|
.name("session")
|
||||||
|
.value(jwt)
|
||||||
|
.expiresAt(expiresAt)
|
||||||
|
.domain(Objects.requireNonNull(url.topPrivateDomain()))
|
||||||
|
.path("/")
|
||||||
|
.secure().httpOnly()
|
||||||
|
.build();
|
||||||
|
getCookieJar().saveFromResponse(url, Collections.singletonList(sessionCookie));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkLoginSuccess() {
|
||||||
|
String url = CherryTv.BASE_URL + "/graphql?operationName=FindFollowings&variables={\"cursor\":\"0\",\"limit\":20}&extensions={\"persistedQuery\":{\"version\":1,\"sha256Hash\":\"7d2cf16b113dc1d57af02685e249e28df9649ea598717dc2c877294529ae0cb3\"}}";
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.header(REFERER, CherryTv.BASE_URL)
|
||||||
|
.header(ORIGIN, CherryTv.BASE_URL)
|
||||||
|
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
try (Response response = execute(request)) {
|
||||||
|
String body = Objects.requireNonNull(response.body()).string();
|
||||||
|
LOG.debug("Login body: {}", body);
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
JSONObject json = new JSONObject(body);
|
||||||
|
if (json.has("errors")) {
|
||||||
|
LOG.error(json.toString(2));
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return json.optString("__typename").equals("FollowingList");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.error("Login check failed", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ import com.iheartradio.m3u8.*;
|
||||||
import com.iheartradio.m3u8.data.MasterPlaylist;
|
import com.iheartradio.m3u8.data.MasterPlaylist;
|
||||||
import com.iheartradio.m3u8.data.Playlist;
|
import com.iheartradio.m3u8.data.Playlist;
|
||||||
import com.iheartradio.m3u8.data.PlaylistData;
|
import com.iheartradio.m3u8.data.PlaylistData;
|
||||||
|
import com.squareup.moshi.JsonReader;
|
||||||
|
import com.squareup.moshi.JsonWriter;
|
||||||
import ctbrec.AbstractModel;
|
import ctbrec.AbstractModel;
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.NotImplementedExcetion;
|
import ctbrec.NotImplementedExcetion;
|
||||||
|
@ -39,6 +41,7 @@ public class CherryTvModel extends AbstractModel {
|
||||||
private boolean online = false;
|
private boolean online = false;
|
||||||
private int[] resolution;
|
private int[] resolution;
|
||||||
private String masterPlaylistUrl;
|
private String masterPlaylistUrl;
|
||||||
|
private String id;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||||
|
@ -198,6 +201,8 @@ public class CherryTvModel extends AbstractModel {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean follow() throws IOException {
|
public boolean follow() throws IOException {
|
||||||
|
// POST https://cherry.tv/graphql
|
||||||
|
// {"operationName":"follow","variables":{"userId":"1391"},"extensions":{"persistedQuery":{"version":1,"sha256Hash":"a7a8241014074f5c02ac83863a47f7579e5f03167a7ec424ff65ad045c7fcf6f"}}}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,4 +227,23 @@ public class CherryTvModel extends AbstractModel {
|
||||||
setOnlineState(OFFLINE);
|
setOnlineState(OFFLINE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSiteSpecificData(JsonReader reader) throws IOException {
|
||||||
|
reader.nextName();
|
||||||
|
id = reader.nextString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSiteSpecificData(JsonWriter writer) throws IOException {
|
||||||
|
writer.name("id").value(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue