forked from j62/ctbrec
1
0
Fork 0

Add mechanism to restrict the number of requests

Flirt4Free is finnicky with the amount of requests you can do. So we use
a mechanism to only allow 2 requests at a time and a cooldown of 500 ms
between requests.
This commit is contained in:
0xboobface 2019-05-11 15:03:15 +02:00
parent 6c9bff56fc
commit 35c8378d88
1 changed files with 161 additions and 99 deletions

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.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -53,45 +55,58 @@ public class Flirt4FreeModel extends AbstractModel {
private String userIdt = "";
private String userIp = "0.0.0.0";
private static Semaphore requestThrottle = new Semaphore(2, true);
private static volatile long lastRequest = 0;
private long lastOnlineRequest = 0;
@Override
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
if(ignoreCache) {
long now = System.currentTimeMillis();
long timeSinceLastCheck = now - lastOnlineRequest;
if (ignoreCache && timeSinceLastCheck > TimeUnit.MINUTES.toMillis(1)) {
String url = "https://ws.vs3.com/rooms/check-model-status.php?model_name=" + getName();
Request request = 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("X-Requested-With", "XMLHttpRequest")
.build();
try(Response response = getSite().getHttpClient().execute(request)) {
if(response.isSuccessful()) {
String body = response.body().string();
if(body.trim().isEmpty()) {
return false;
}
JSONObject json = new JSONObject(body);
//LOG.debug("check model status: ", json.toString(2));
online = Objects.equals(json.optString("status"), "online");
id = json.getString("model_id");
if(online) {
try {
loadStreamUrl();
} catch(Exception e) {
online = false;
onlineState = Model.State.OFFLINE;
acquireSlot();
try {
Request request = 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("X-Requested-With", "XMLHttpRequest")
.build();
try (Response response = getSite().getHttpClient().execute(request)) {
if (response.isSuccessful()) {
String body = response.body().string();
if (body.trim().isEmpty()) {
return false;
}
JSONObject json = new JSONObject(body);
// LOG.debug("check model status: {}", json.toString(2));
online = Objects.equals(json.optString("status"), "online");
id = String.valueOf(json.get("model_id"));
if (online) {
try {
loadStreamUrl();
} catch (Exception e) {
online = false;
onlineState = Model.State.OFFLINE;
}
}
} else {
throw new HttpException(response.code(), response.message());
}
} else {
throw new HttpException(response.code(), response.message());
}
} finally {
lastOnlineRequest = System.currentTimeMillis();
releaseSlot();
}
}
return online;
}
private void loadModelInfo() throws IOException {
private void loadModelInfo() throws IOException, InterruptedException {
String url = getSite().getBaseUrl() + "/webservices/chat-room-interface.php?a=login_room&model_id=" + id;
LOG.trace("Loading url {}", url);
Request request = new Request.Builder()
@ -102,11 +117,11 @@ public class Flirt4FreeModel extends AbstractModel {
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.header("X-Requested-With", "XMLHttpRequest")
.build();
try(Response response = getSite().getHttpClient().execute(request)) {
if(response.isSuccessful()) {
try (Response response = getSite().getHttpClient().execute(request)) {
if (response.isSuccessful()) {
JSONObject json = new JSONObject(response.body().string());
if(json.optString("status").equals("success")) {
//LOG.debug("chat-room-interface {}", json.toString(2));
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"));
@ -137,8 +152,13 @@ public class Flirt4FreeModel extends AbstractModel {
private List<StreamSource> getStreamSources(boolean withWebsocket) throws IOException, ExecutionException, ParseException, PlaylistException {
MasterPlaylist masterPlaylist = null;
try {
if(withWebsocket) {
loadStreamUrl();
if (withWebsocket) {
acquireSlot();
try {
loadStreamUrl();
} finally {
releaseSlot();
}
}
masterPlaylist = getMasterPlaylist();
} catch (InterruptedException e) {
@ -168,8 +188,9 @@ public class Flirt4FreeModel extends AbstractModel {
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.header("X-Requested-With", "XMLHttpRequest")
.build();
acquireSlot();
try (Response response = getSite().getHttpClient().execute(req)) {
if(response.isSuccessful()) {
if (response.isSuccessful()) {
InputStream inputStream = response.body().byteStream();
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT);
Playlist playlist = parser.parse();
@ -178,6 +199,8 @@ public class Flirt4FreeModel extends AbstractModel {
} else {
throw new HttpException(response.code(), response.message());
}
} finally {
releaseSlot();
}
}
@ -246,6 +269,7 @@ public class Flirt4FreeModel extends AbstractModel {
}
}
});
synchronized (monitor) {
monitor.wait(10_000);
if (streamHost == null) {
@ -262,80 +286,92 @@ 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);
}
// if(tokens < 50 || tokens > 750000) {
// throw new RuntimeException("Tip amount has to be between 50 and 750000");
// }
// 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());
// make sure we are logged in and all necessary model data is available
getSite().login();
acquireSlot();
try {
loadStreamUrl();
} catch (InterruptedException e) {
throw new IOException("Couldn't send tip", e);
} finally {
releaseSlot();
}
}
}
private String getUserIdt() throws IOException {
if(userIdt.isEmpty()) {
// 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(getUrl())
.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()) {
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");
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());
}
}
} catch (InterruptedException e) {
throw new IOException("Couldn't acquire request slot", e);
}
}
private String getUserIdt() throws IOException, InterruptedException {
if (userIdt.isEmpty()) {
acquireSlot();
try {
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());
}
}
} finally {
releaseSlot();
}
}
return userIdt;
}
@ -361,22 +397,31 @@ public class Flirt4FreeModel extends AbstractModel {
@Override
public boolean follow() throws IOException {
return changeFavoriteStatus(true);
try {
return changeFavoriteStatus(true);
} catch (InterruptedException e) {
throw new IOException("Couldn't change follow status for model " + getName(), e);
}
}
@Override
public boolean unfollow() throws IOException {
try {
isOnline(true);
return changeFavoriteStatus(false);
} catch (ExecutionException | InterruptedException e) {
throw new IOException("Couldn't rectrieve model id", e);
throw new IOException("Couldn't change follow status for model " + getName(), e);
}
return changeFavoriteStatus(false);
}
private boolean changeFavoriteStatus(boolean add) throws IOException {
private boolean changeFavoriteStatus(boolean add) throws IOException, InterruptedException {
getSite().login();
loadModelInfo();
acquireSlot();
try {
loadModelInfo();
} finally {
releaseSlot();
}
String url = getSite().getBaseUrl() + "/external.php?a=" +
(add ? "add_favorite" : "delete_favorite") +
"&id=" + id +
@ -391,7 +436,7 @@ public class Flirt4FreeModel extends AbstractModel {
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
.build();
try (Response response = getSite().getHttpClient().execute(req)) {
if(response.isSuccessful()) {
if (response.isSuccessful()) {
String body = response.body().string();
LOG.debug("Follow/Unfollow response: {}", body);
return Objects.equals(body, "1");
@ -423,4 +468,21 @@ public class Flirt4FreeModel extends AbstractModel {
public void setOnline(boolean b) {
online = b;
}
private void acquireSlot() throws InterruptedException {
LOG.debug("Acquire: {}", requestThrottle.availablePermits());
requestThrottle.acquire();
long now = System.currentTimeMillis();
long millisSinceLastRequest = now - lastRequest;
if(millisSinceLastRequest < 500) {
LOG.debug("Sleeping: {}", (500-millisSinceLastRequest));
Thread.sleep(500 - millisSinceLastRequest);
}
}
private void releaseSlot() {
lastRequest = System.currentTimeMillis();
requestThrottle.release();
LOG.debug("Release: {}", requestThrottle.availablePermits());
}
}