From c364250440fbc3c413b6e4490d614bb55cfc3274 Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Sat, 22 Dec 2018 20:53:41 +0100 Subject: [PATCH] Add follow / unfollow for livejasmin --- .../sites/jasmin/LiveJasminFollowedTab.java | 76 ++++++++++++++++ .../LiveJasminFollowedUpdateService.java | 91 +++++++++++++++++++ .../sites/jasmin/LiveJasminTabProvider.java | 8 +- .../sites/jasmin/LiveJasminUpdateService.java | 5 +- .../java/ctbrec/sites/jasmin/LiveJasmin.java | 5 +- .../sites/jasmin/LiveJasminHttpClient.java | 10 ++ .../ctbrec/sites/jasmin/LiveJasminModel.java | 45 ++++++++- 7 files changed, 230 insertions(+), 10 deletions(-) create mode 100644 client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java create mode 100644 client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java diff --git a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java new file mode 100644 index 00000000..b04ac265 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java @@ -0,0 +1,76 @@ +package ctbrec.ui.sites.jasmin; + +import ctbrec.sites.jasmin.LiveJasmin; +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 LiveJasminFollowedTab extends ThumbOverviewTab implements FollowedTab { + private Label status; + + public LiveJasminFollowedTab(LiveJasmin liveJasmin) { + super("Followed", new LiveJasminFollowedUpdateService(liveJasmin), liveJasmin); + 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) -> { + ((LiveJasminFollowedUpdateService)updateService).setShowOnline(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/jasmin/LiveJasminFollowedUpdateService.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java new file mode 100644 index 00000000..90ada272 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java @@ -0,0 +1,91 @@ +package ctbrec.ui.sites.jasmin; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.json.JSONArray; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ctbrec.Config; +import ctbrec.Model; +import ctbrec.io.HttpException; +import ctbrec.sites.jasmin.LiveJasmin; +import ctbrec.sites.jasmin.LiveJasminModel; +import ctbrec.ui.PaginatedScheduledService; +import javafx.concurrent.Task; +import okhttp3.Request; +import okhttp3.Response; + +public class LiveJasminFollowedUpdateService extends PaginatedScheduledService { + + private static final transient Logger LOG = LoggerFactory.getLogger(LiveJasminFollowedUpdateService.class); + private LiveJasmin liveJasmin; + private String url; + private boolean showOnline = true; + + public LiveJasminFollowedUpdateService(LiveJasmin liveJasmin) { + this.liveJasmin = liveJasmin; + long ts = System.currentTimeMillis(); + this.url = liveJasmin.getBaseUrl() + "/en/free/favourite/get-favourite-list?_dc=" + ts; + } + + @Override + protected Task> createTask() { + return new Task>() { + @Override + public List call() throws IOException { + //String _url = url + ((page-1) * 36); // TODO find out how to switch pages + //LOG.debug("Fetching page {}", url); + Request request = new Request.Builder() + .url(url) + .header("User-Agent", Config.getInstance().getSettings().httpUserAgent) + .header("Accept", "*/*") + .header("Accept-Language", "en") + .header("Referer", liveJasmin.getBaseUrl() + "/en/free/favorite") + .header("X-Requested-With", "XMLHttpRequest") + .build(); + try (Response response = liveJasmin.getHttpClient().execute(request)) { + if (response.isSuccessful()) { + String body = response.body().string(); + List models = new ArrayList<>(); + JSONObject json = new JSONObject(body); + LOG.debug(json.toString(2)); + if(json.has("success")) { + JSONObject data = json.getJSONObject("data"); + JSONArray performers = data.getJSONArray("performers"); + for (int i = 0; i < performers.length(); i++) { + JSONObject m = performers.getJSONObject(i); + String name = m.optString("pid"); + if(name.isEmpty()) { + continue; + } + LiveJasminModel model = (LiveJasminModel) liveJasmin.createModel(name); + model.setId(m.getString("id")); + model.setPreview(m.getString("profilePictureUrl")); + Model.State onlineState = LiveJasminModel.mapStatus(m.getInt("status")); + boolean online = onlineState == Model.State.ONLINE; + model.setOnlineState(onlineState); + if(online == showOnline) { + models.add(model); + } + } + } else { + LOG.error("Request failed:\n{}", body); + throw new IOException("Response was not successful"); + } + return models; + } else { + throw new HttpException(response.code(), response.message()); + } + } + } + }; + } + + public void setShowOnline(boolean showOnline) { + this.showOnline = showOnline; + } +} diff --git a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminTabProvider.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminTabProvider.java index df06011a..f58f976a 100644 --- a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminTabProvider.java +++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminTabProvider.java @@ -12,6 +12,7 @@ import javafx.scene.control.Tab; public class LiveJasminTabProvider extends TabProvider { private LiveJasmin liveJasmin; + private LiveJasminFollowedTab followedTab; public LiveJasminTabProvider(LiveJasmin liveJasmin) { this.liveJasmin = liveJasmin; @@ -26,11 +27,16 @@ public class LiveJasminTabProvider extends TabProvider { ThumbOverviewTab tab = new ThumbOverviewTab("Girls", s, liveJasmin); tab.setRecorder(liveJasmin.getRecorder()); tabs.add(tab); + + followedTab = new LiveJasminFollowedTab(liveJasmin); + followedTab.setRecorder(liveJasmin.getRecorder()); + tabs.add(followedTab); + return tabs; } @Override public Tab getFollowedTab() { - return null; + return followedTab; } } diff --git a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminUpdateService.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminUpdateService.java index b4d0257f..6714cce3 100644 --- a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminUpdateService.java +++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminUpdateService.java @@ -35,7 +35,7 @@ public class LiveJasminUpdateService extends PaginatedScheduledService { return new Task>() { @Override public List call() throws IOException { - String _url = url + ((page-1) * 36); // TODO find out how to switch pages + //String _url = url + ((page-1) * 36); // TODO find out how to switch pages LOG.debug("Fetching page {}", url); Request request = new Request.Builder() .url(url) @@ -64,8 +64,7 @@ public class LiveJasminUpdateService extends PaginatedScheduledService { LiveJasminModel model = (LiveJasminModel) liveJasmin.createModel(name); model.setId(m.getString("id")); model.setPreview(m.getString("profilePictureUrl")); - model.setOnline(true); - model.setOnlineState(ctbrec.Model.State.ONLINE); + model.setOnlineState(LiveJasminModel.mapStatus(m.optInt("status"))); models.add(model); } } else { diff --git a/common/src/main/java/ctbrec/sites/jasmin/LiveJasmin.java b/common/src/main/java/ctbrec/sites/jasmin/LiveJasmin.java index fa3e8651..4f0dd311 100644 --- a/common/src/main/java/ctbrec/sites/jasmin/LiveJasmin.java +++ b/common/src/main/java/ctbrec/sites/jasmin/LiveJasmin.java @@ -2,6 +2,7 @@ package ctbrec.sites.jasmin; import java.io.IOException; +import ctbrec.Config; import ctbrec.Model; import ctbrec.io.HttpClient; import ctbrec.sites.AbstractSite; @@ -77,7 +78,7 @@ public class LiveJasmin extends AbstractSite { @Override public boolean supportsFollow() { - return false; + return true; } @Override @@ -87,7 +88,7 @@ public class LiveJasmin extends AbstractSite { @Override public boolean credentialsAvailable() { - return false; + return !Config.getInstance().getSettings().livejasminSession.isEmpty(); } } diff --git a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java index 7f09c93b..b979ee53 100644 --- a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java +++ b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminHttpClient.java @@ -2,6 +2,7 @@ package ctbrec.sites.jasmin; import java.io.IOException; import java.util.Collections; +import java.util.NoSuchElementException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -169,4 +170,13 @@ public class LiveJasminHttpClient extends HttpClient { } } } + + public String getSessionId() { + Cookie sessionCookie = getCookieJar().getCookie(HttpUrl.parse("https://www.livejasmin.com"), "session"); + if(sessionCookie != null) { + return sessionCookie.value(); + } else { + throw new NoSuchElementException("session cookie not found"); + } + } } diff --git a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java index 82eae5b0..64008189 100644 --- a/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java +++ b/common/src/main/java/ctbrec/sites/jasmin/LiveJasminModel.java @@ -89,7 +89,7 @@ public class LiveJasminModel extends AbstractModel { } } - private State mapStatus(int status) { + public static State mapStatus(int status) { switch(status) { case 0: return State.OFFLINE; @@ -99,11 +99,17 @@ public class LiveJasminModel extends AbstractModel { case 3: return State.PRIVATE; default: - LOG.debug("Unkown state {} {}", status, getUrl()); + LOG.debug("Unkown state {}", status); return State.UNKNOWN; } } + @Override + public void setOnlineState(State status) { + super.setOnlineState(status); + online = status == State.ONLINE; + } + @Override public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException { String masterUrl = getMasterPlaylistUrl(); @@ -195,12 +201,43 @@ public class LiveJasminModel extends AbstractModel { @Override public boolean follow() throws IOException { - return false; + return follow(true); } @Override public boolean unfollow() throws IOException { - return false; + return follow(false); + } + + private boolean follow(boolean follow) throws IOException { + if (id == null) { + loadModelInfo(); + } + + String sessionId = ((LiveJasminHttpClient) site.getHttpClient()).getSessionId(); + String url; + if (follow) { + url = site.getBaseUrl() + "/en/free/favourite/add-favourite?session=" + sessionId + "&performerId=" + id; + } else { + url = site.getBaseUrl() + "/en/free/favourite/delete-favourite?session=" + sessionId + "&performerId=" + id; + } + Request request = new Request.Builder() + .url(url) + .addHeader("User-Agent", Config.getInstance().getSettings().httpUserAgent) + .addHeader("Accept", "*/*") + .addHeader("Accept-Language", "en") + .addHeader("Referer", getUrl()) + .addHeader("X-Requested-With", "XMLHttpRequest") + .build(); + try (Response response = site.getHttpClient().execute(request)) { + if (response.isSuccessful()) { + String body = response.body().string(); + JSONObject json = new JSONObject(body); + return json.optString("status").equalsIgnoreCase("ok"); + } else { + throw new HttpException(response.code(), response.message()); + } + } } public String getId() {