Implement follow/unfollow for Flirt4Free

This commit is contained in:
0xboobface 2019-04-16 19:51:57 +02:00
parent 8f5c7ac9c4
commit 204eb99b29
6 changed files with 235 additions and 10 deletions

View File

@ -495,7 +495,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
LOG.error("An error occured while sending tip", ex);
showError("Couldn't send tip", "An error occured while sending tip:", ex);
} catch (Exception ex) {
showError("Couldn't send tip", "You entered an invalid amount of tokens", null);
showError("Couldn't send tip", "You entered an invalid amount of tokens", ex);
}
}
});

View File

@ -0,0 +1,25 @@
package ctbrec.ui.sites.flirt4free;
import ctbrec.sites.flirt4free.Flirt4Free;
import ctbrec.ui.FollowedTab;
import ctbrec.ui.ThumbOverviewTab;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public class Flirt4FreeFavoritesTab extends ThumbOverviewTab implements FollowedTab {
public Flirt4FreeFavoritesTab(Flirt4Free flirt4free) {
super("Favorites", new Flirt4FreeFavoritesUpdateService(flirt4free), flirt4free);
}
public void setScene(Scene scene) {
scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
if(this.isSelected()) {
if(event.getCode() == KeyCode.DELETE) {
follow(selectedThumbCells, false);
}
}
});
}
}

View File

@ -0,0 +1,72 @@
package ctbrec.ui.sites.flirt4free;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.io.HtmlParser;
import ctbrec.io.HttpException;
import ctbrec.sites.flirt4free.Flirt4Free;
import ctbrec.sites.flirt4free.Flirt4FreeModel;
import ctbrec.ui.PaginatedScheduledService;
import ctbrec.ui.SiteUiFactory;
import javafx.concurrent.Task;
import okhttp3.Request;
import okhttp3.Response;
public class Flirt4FreeFavoritesUpdateService extends PaginatedScheduledService {
private Flirt4Free flirt4free;
public Flirt4FreeFavoritesUpdateService(Flirt4Free flirt4free) {
this.flirt4free = flirt4free;
}
@Override
protected Task<List<Model>> createTask() {
return new Task<List<Model>>() {
@Override
public List<Model> call() throws IOException {
List<Model> models = new ArrayList<>();
String url = flirt4free.getBaseUrl() + "/my-account/secure/favorites.php?a=models&sort=online&pg=" + page;
SiteUiFactory.getUi(flirt4free).login();
Request request = new Request.Builder()
.url(url)
.header("Accept", "*/*")
.header("Accept-Language", "en-US,en;q=0.5")
.header("Referer", flirt4free.getBaseUrl())
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.build();
try(Response response = flirt4free.getHttpClient().execute(request)) {
if (response.isSuccessful()) {
String body = response.body().string();
Elements modelContainers = HtmlParser.getTags(body, "div.model-container");
for (Element modelContainer : modelContainers) {
String modelHtml = modelContainer.html();
Element bioLink = HtmlParser.getTag(modelHtml, "a.common-link");
bioLink.setBaseUri(flirt4free.getBaseUrl());
Flirt4FreeModel model = (Flirt4FreeModel) flirt4free.createModelFromUrl(bioLink.absUrl("href"));
Element img = HtmlParser.getTag(modelHtml, "a > img[alt]");
model.setDisplayName(img.attr("alt"));
model.setPreview(img.attr("src"));
model.setDescription("");
model.setOnline(modelHtml.contains("I'm Online"));
try {
model.setOnlineState(model.isOnline() ? Model.State.ONLINE : Model.State.OFFLINE);
} catch (ExecutionException | InterruptedException e) {}
models.add(model);
}
return models;
} else {
throw new HttpException(response.code(), response.message());
}
}
}
};
}
}

View File

@ -13,9 +13,12 @@ import javafx.util.Duration;
public class Flirt4FreeTabProvider extends TabProvider {
private Flirt4Free flirt4Free;
private ThumbOverviewTab followedTab;
public Flirt4FreeTabProvider(Flirt4Free flirt4Free) {
this.flirt4Free = flirt4Free;
followedTab = new Flirt4FreeFavoritesTab(flirt4Free);
followedTab.setRecorder(flirt4Free.getRecorder());
}
@Override
@ -24,12 +27,13 @@ public class Flirt4FreeTabProvider extends TabProvider {
tabs.add(createTab("Girls", flirt4Free.getBaseUrl() + "/live/girls/"));
tabs.add(createTab("Boys", flirt4Free.getBaseUrl() + "/live/guys/"));
tabs.add(createTab("Trans", flirt4Free.getBaseUrl() + "/live/trans/"));
tabs.add(followedTab);
return tabs;
}
@Override
public Tab getFollowedTab() {
return null;
return followedTab;
}
private ThumbOverviewTab createTab(String title, String url) {

View File

@ -9,8 +9,6 @@ import java.util.regex.Pattern;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.Model;
@ -23,7 +21,6 @@ import okhttp3.Response;
public class Flirt4Free extends AbstractSite {
private static final transient Logger LOG = LoggerFactory.getLogger(Flirt4Free.class);
public static final String BASE_URI = "https://www.flirt4free.com";
private HttpClient httpClient;
@ -106,12 +103,12 @@ public class Flirt4Free extends AbstractSite {
@Override
public boolean supportsTips() {
return true;
return false;
}
@Override
public boolean supportsFollow() {
return false;
return true;
}
@Override

View File

@ -8,6 +8,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONObject;
import org.slf4j.Logger;
@ -47,6 +49,9 @@ public class Flirt4FreeModel extends AbstractModel {
int[] resolution = new int[2];
private Object monitor = new Object();
private boolean online = false;
private boolean isInteractiveShow = false;
private String userIdt = "";
private String userIp = "0.0.0.0";
@Override
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
@ -63,6 +68,7 @@ public class Flirt4FreeModel extends AbstractModel {
try(Response response = getSite().getHttpClient().execute(request)) {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
//LOG.debug("check model status: {}", json.toString(2));
online = Objects.equals(json.optString("status"), "online");
id = json.getString("model_id");
if(online) {
@ -96,6 +102,7 @@ public class Flirt4FreeModel extends AbstractModel {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
if(json.optString("status").equals("success")) {
//LOG.debug("chat-room-interface {}", json.toString(2));
JSONObject config = json.getJSONObject("config");
JSONObject performer = config.getJSONObject("performer");
setName(performer.optString("name_seo", "n/a"));
@ -105,6 +112,8 @@ public class Flirt4FreeModel extends AbstractModel {
chatHost = room.getString("host");
chatPort = room.getString("port_to_be");
chatToken = json.getString("token_enc");
JSONObject user = config.getJSONObject("user");
userIp = user.getString("ip");
} else {
LOG.trace("Loading model info failed. Assuming model {} is offline", getName());
online = false;
@ -193,10 +202,20 @@ public class Flirt4FreeModel extends AbstractModel {
public void onMessage(WebSocket webSocket, String text) {
LOG.trace("Chat wbesocket for {}: {}", getName(), text);
JSONObject json = new JSONObject(text);
//LOG.debug("WS {}", text);
if (json.optString("command").equals("8011")) {
JSONObject data = json.getJSONObject("data");
streamHost = data.getString("stream_host");
streamHost = data.getString("stream_host"); // TODO look, if the stream_host is equal to the one encoded in base64 in some of the ajax requests (parameters)
online = true;
isInteractiveShow = data.optString("devices").equals("1");
if(data.optString("room_state").equals("P")) {
onlineState = Model.State.PRIVATE;
online = false;
}
if(data.optString("room_state").equals("0") && data.optString("login_group_id").equals("14")) {
onlineState = Model.State.GROUP;
online = false;
}
try {
resolution[0] = Integer.parseInt(data.getString("stream_width"));
resolution[1] = Integer.parseInt(data.getString("stream_height"));
@ -239,6 +258,82 @@ public class Flirt4FreeModel extends AbstractModel {
@Override
public void receiveTip(Double tokens) throws IOException {
// if(tokens < 50 || tokens > 750000) {
// throw new RuntimeException("Tip amount has to be between 50 and 750000");
// }
// make sure we are logged in and all necessary model data is available
getSite().login();
try {
loadStreamUrl();
} catch (InterruptedException e) {
throw new IOException("Couldn't send tip", e);
}
// send the tip
int giftId = isInteractiveShow ? 775 : 171;
int amount = tokens.intValue();
LOG.debug("Sending tip of {} to {}", amount, getName());
String url = "https://ws.vs3.com/rooms/send-tip.php?" +
"gift_id=" + giftId +
"&num_credits=" + amount +
"&userId=" + getUserIdt() +
"&username=" + Config.getInstance().getSettings().flirt4freeUsername +
"&userIP=" + userIp +
"&anonymous=N&response_type=json" +
"&t=" + System.currentTimeMillis();
LOG.debug("Trying to send tip: {}", url);
Request req = new Request.Builder()
.url(url)
.header("Accept", "*/*")
.header("Accept-Language", "en-US,en;q=0.5")
.header("Referer", getUrl())
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.header("Referer", getUrl())
.header("X-Requested-With", "XMLHttpRequest")
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if(response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
if(json.optInt("success") != 1) {
String msg = json.optString("message");
if(json.has("error_message")) {
msg = json.getString("error_message");
}
LOG.error("Sending tip failed: {}", msg);
LOG.debug("Response: {}", json.toString(2));
throw new IOException(msg);
}
} else {
throw new HttpException(response.code(), response.message());
}
}
}
private String getUserIdt() throws IOException {
if(userIdt.isEmpty()) {
Request req = new Request.Builder()
.url(getUrl())
.header("Accept", "*/*")
.header("Accept-Language", "en-US,en;q=0.5")
.header("Referer", getUrl())
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if(response.isSuccessful()) {
String body = response.body().string();
Matcher m = Pattern.compile("idt\\s*:\\s*'(.*?)',").matcher(body);
if(m.find()) {
userIdt = m.group(1);
} else {
throw new IOException("userIdt not found on HTML page");
}
} else {
throw new HttpException(response.code(), response.message());
}
}
}
return userIdt;
}
@Override
@ -262,12 +357,44 @@ public class Flirt4FreeModel extends AbstractModel {
@Override
public boolean follow() throws IOException {
return false;
return changeFavoriteStatus(true);
}
@Override
public boolean unfollow() throws IOException {
return false;
try {
isOnline(true);
} catch (ExecutionException | InterruptedException e) {
throw new IOException("Couldn't rectrieve model id", e);
}
return changeFavoriteStatus(false);
}
private boolean changeFavoriteStatus(boolean add) throws IOException {
getSite().login();
loadModelInfo();
String url = getSite().getBaseUrl() + "/external.php?a=" +
(add ? "add_favorite" : "delete_favorite") +
"&id=" + id +
"&name=" + getDisplayName() +
"&t=" + System.currentTimeMillis();
LOG.debug("Sending follow/unfollow request: {}", url);
Request req = new Request.Builder()
.url(url)
.header("Accept", "*/*")
.header("Accept-Language", "en-US,en;q=0.5")
.header("Referer", getUrl())
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if(response.isSuccessful()) {
String body = response.body().string();
LOG.debug("Follow/Unfollow response: {}", body);
return Objects.equals(body, "1");
} else {
throw new HttpException(response.code(), response.message());
}
}
}
public void setId(String id) {