forked from j62/ctbrec
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:
parent
6c9bff56fc
commit
35c8378d88
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue