From c7e07b4b261cf0e793a99d39d77755539880c95d Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Fri, 14 Dec 2018 17:36:24 +0100 Subject: [PATCH] Implement login and favorites tab --- .../streamate/StreamateFollowedService.java | 94 +++++++++++++++++++ .../sites/streamate/StreamateFollowedTab.java | 77 +++++++++++++++ .../ui/sites/streamate/StreamateSiteUi.java | 4 +- .../sites/streamate/StreamateTabProvider.java | 7 +- .../ctbrec/sites/streamate/Streamate.java | 5 +- .../sites/streamate/StreamateHttpClient.java | 51 +++++++++- 6 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedService.java create mode 100644 client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedTab.java diff --git a/client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedService.java b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedService.java new file mode 100644 index 00000000..6aab7d5b --- /dev/null +++ b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedService.java @@ -0,0 +1,94 @@ +package ctbrec.ui.sites.streamate; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathExpressionException; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +import ctbrec.Config; +import ctbrec.Model; +import ctbrec.io.HttpException; +import ctbrec.sites.streamate.Streamate; +import ctbrec.sites.streamate.StreamateHttpClient; +import ctbrec.sites.streamate.StreamateModel; +import ctbrec.ui.PaginatedScheduledService; +import javafx.concurrent.Task; +import okhttp3.Request; +import okhttp3.Response; + +public class StreamateFollowedService extends PaginatedScheduledService { + + private static final transient Logger LOG = LoggerFactory.getLogger(StreamateFollowedService.class); + + private static final int MODELS_PER_PAGE = 48; + private Streamate streamate; + private StreamateHttpClient httpClient; + private String url; + private boolean showOnline = true; + + public StreamateFollowedService(Streamate streamate) { + this.streamate = streamate; + this.httpClient = (StreamateHttpClient) streamate.getHttpClient(); + this.url = streamate.getBaseUrl() + "/api/search/v1/favorites?host=streamate.com&domain=streamate.com"; + } + + @Override + protected Task> createTask() { + return new Task>() { + @Override + public List call() throws IOException, SAXException, ParserConfigurationException, XPathExpressionException { + httpClient.login(); + String saKey = httpClient.getSaKey(); + String userId = httpClient.getUserId(); + String _url = url + "&page_number=" + page + "&results_per_page=" + MODELS_PER_PAGE + "&sakey=" + saKey + "&userid=" + userId; + LOG.debug("Fetching page {}", _url); + Request request = new Request.Builder() + .url(_url) + .addHeader("User-Agent", Config.getInstance().getSettings().httpUserAgent) + .addHeader("Accept", "application/json, */*") + .addHeader("Accept-Language", "en") + .addHeader("Referer", streamate.getBaseUrl()) + .build(); + try(Response response = streamate.getHttpClient().execute(request)) { + if (response.isSuccessful()) { + List models = new ArrayList<>(); + String content = response.body().string(); + JSONObject json = new JSONObject(content); + if(json.optString("status").equals("SM_OK")) { + JSONArray performers = json.getJSONArray("Results"); + for (int i = 0; i < performers.length(); i++) { + JSONObject p = performers.getJSONObject(i); + String nickname = p.getString("Nickname"); + StreamateModel model = (StreamateModel) streamate.createModel(nickname); + model.setId(Long.toString(p.getLong("PerformerId"))); + model.setPreview("https://m1.nsimg.net/biopic/320x240/" + model.getId()); + boolean online = p.optString("LiveStatus").equals("live"); + model.setOnline(online); + if(online == showOnline) { + models.add(model); + } + } + } else { + throw new IOException("Status: " + json.optString("status")); + } + return models; + } else { + throw new HttpException(response.code(), response.message()); + } + } + } + }; + } + + public void setOnline(boolean online) { + this.showOnline = online; + } +} diff --git a/client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedTab.java b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedTab.java new file mode 100644 index 00000000..f79cc30f --- /dev/null +++ b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateFollowedTab.java @@ -0,0 +1,77 @@ +package ctbrec.ui.sites.streamate; + +import ctbrec.sites.streamate.Streamate; +import ctbrec.ui.FollowedTab; +import ctbrec.ui.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 StreamateFollowedTab extends ThumbOverviewTab implements FollowedTab { + private Label status; + + public StreamateFollowedTab(Streamate streamate) { + super("Favorites", new StreamateFollowedService(streamate), streamate); + + status = new Label("Logging in..."); + grid.getChildren().add(status); + } + + @Override + protected void createGui() { + super.createGui(); + addOnlineOfflineSelector(); + } + + private void addOnlineOfflineSelector() { + ToggleGroup group = new ToggleGroup(); + RadioButton online = new RadioButton("online"); + online.setToggleGroup(group); + RadioButton 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) -> { + ((StreamateFollowedService)updateService).setOnline(online.isSelected()); + 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()) { + if(event.getCode() == KeyCode.DELETE) { + follow(selectedThumbCells, false); + } + } + }); + } +} diff --git a/client/src/main/java/ctbrec/ui/sites/streamate/StreamateSiteUi.java b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateSiteUi.java index bd29af2b..c7348a1f 100644 --- a/client/src/main/java/ctbrec/ui/sites/streamate/StreamateSiteUi.java +++ b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateSiteUi.java @@ -11,8 +11,10 @@ public class StreamateSiteUi implements SiteUI { private StreamateTabProvider tabProvider; private StreamateConfigUI configUi; + private Streamate streamate; public StreamateSiteUi(Streamate streamate) { + this.streamate = streamate; tabProvider = new StreamateTabProvider(streamate); configUi = new StreamateConfigUI(streamate); } @@ -29,7 +31,7 @@ public class StreamateSiteUi implements SiteUI { @Override public boolean login() throws IOException { - return false; + return streamate.login(); } } diff --git a/client/src/main/java/ctbrec/ui/sites/streamate/StreamateTabProvider.java b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateTabProvider.java index 137854a5..d43ec25f 100644 --- a/client/src/main/java/ctbrec/ui/sites/streamate/StreamateTabProvider.java +++ b/client/src/main/java/ctbrec/ui/sites/streamate/StreamateTabProvider.java @@ -18,6 +18,7 @@ public class StreamateTabProvider extends TabProvider { private static final transient Logger LOG = LoggerFactory.getLogger(StreamateTabProvider.class); private Streamate streamate; private Recorder recorder; + private ThumbOverviewTab followedTab; public StreamateTabProvider(Streamate streamate) { this.streamate = streamate; @@ -37,6 +38,10 @@ public class StreamateTabProvider extends TabProvider { tabs.add(createTab("Trans female", Streamate.BASE_URL + "/api/search/list?domain=streamate.com&index=availperf&filters=gender:tm2f")); tabs.add(createTab("Trans male", Streamate.BASE_URL + "/api/search/list?domain=streamate.com&index=availperf&filters=gender:tf2m")); tabs.add(createTab("New", Streamate.BASE_URL + "/api/search/list?domain=streamate.com&index=availperf&filters=new:true")); + + followedTab = new StreamateFollowedTab(streamate); + followedTab.setRecorder(recorder); + tabs.add(followedTab); } catch (IOException e) { LOG.error("Couldn't create streamate tab", e); } @@ -45,7 +50,7 @@ public class StreamateTabProvider extends TabProvider { @Override public Tab getFollowedTab() { - return null; + return followedTab; } private Tab createTab(String title, String url) throws IOException { diff --git a/common/src/main/java/ctbrec/sites/streamate/Streamate.java b/common/src/main/java/ctbrec/sites/streamate/Streamate.java index 12cf63c7..390767f0 100644 --- a/common/src/main/java/ctbrec/sites/streamate/Streamate.java +++ b/common/src/main/java/ctbrec/sites/streamate/Streamate.java @@ -15,6 +15,7 @@ import org.slf4j.LoggerFactory; import ctbrec.Config; import ctbrec.Model; +import ctbrec.StringUtil; import ctbrec.io.HttpClient; import ctbrec.io.HttpException; import ctbrec.sites.AbstractSite; @@ -150,6 +151,7 @@ public class Streamate extends AbstractSite { if (response.isSuccessful()) { String body = response.body().string(); JSONObject json = new JSONObject(body); + LOG.debug(json.toString(2)); if (json.optString("status").equals("SM_OK")) { List models = new ArrayList<>(); JSONObject results = json.getJSONObject("results"); @@ -183,7 +185,8 @@ public class Streamate extends AbstractSite { @Override public boolean credentialsAvailable() { - return false; + String username = Config.getInstance().getSettings().username; + return StringUtil.isNotBlank(username); } @Override diff --git a/common/src/main/java/ctbrec/sites/streamate/StreamateHttpClient.java b/common/src/main/java/ctbrec/sites/streamate/StreamateHttpClient.java index aa64b61f..d1242dac 100644 --- a/common/src/main/java/ctbrec/sites/streamate/StreamateHttpClient.java +++ b/common/src/main/java/ctbrec/sites/streamate/StreamateHttpClient.java @@ -3,17 +3,26 @@ package ctbrec.sites.streamate; import java.io.IOException; import java.util.Collections; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ctbrec.Config; import ctbrec.io.HttpClient; import okhttp3.Cookie; import okhttp3.HttpUrl; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; public class StreamateHttpClient extends HttpClient { private static final transient Logger LOG = LoggerFactory.getLogger(StreamateHttpClient.class); + private String userId = ""; + private String saKey = ""; + public StreamateHttpClient() { super("streamate"); @@ -39,7 +48,38 @@ public class StreamateHttpClient extends HttpClient { return true; } - return false; + JSONObject loginRequest = new JSONObject(); + loginRequest.put("email", Config.getInstance().getSettings().streamateUsername); + loginRequest.put("password", Config.getInstance().getSettings().streamatePassword); + loginRequest.put("referrerId", 0); + loginRequest.put("siteId", 1); + RequestBody body = RequestBody.create(MediaType.parse("application/json"), loginRequest.toString()); + Request login = new Request.Builder() + .url(Streamate.BASE_URL + "/api/member/login") + .addHeader("User-Agent", Config.getInstance().getSettings().httpUserAgent) + .addHeader("Accept", "application/json, text/javascript, */*") + .addHeader("Accept-Language", "en") + .addHeader("Referer", Streamate.BASE_URL) + .addHeader("X-Requested-With", "XMLHttpRequest") + .post(body) + .build(); + try (Response response = client.newCall(login).execute()) { + String content = response.body().string(); + //LOG.debug(content); + if(response.isSuccessful()) { + JSONObject json = new JSONObject(content); + LOG.debug(json.toString()); + loggedIn = json.has("sakey"); + saKey = json.optString("sakey"); + JSONObject account = json.getJSONObject("account"); + userId = Long.toString(account.getLong("userid")); + } else { + throw new IOException("Login failed: " + response.code() + " " + response.message()); + } + response.close(); + } + + return loggedIn; } /** @@ -47,6 +87,7 @@ public class StreamateHttpClient extends HttpClient { * @throws IOException */ public boolean checkLoginSuccess() throws IOException { + //https://www.streamate.com/api/search/v1/favorites?host=streamate.com&domain=streamate.com&page_number=1&results_per_page=48&sakey=62857cfd1908cd28 return false; // String modelName = getAnyModelName(); // // we request the roomData of a random model, because it contains @@ -83,4 +124,12 @@ public class StreamateHttpClient extends HttpClient { // } // } } + + public String getSaKey() { + return saKey; + } + + public String getUserId() { + return userId; + } }