forked from j62/ctbrec
Improve online detection for MFC
This commit is contained in:
parent
08052bbd4e
commit
ea7f56c0fd
|
@ -5,6 +5,7 @@ import static ctbrec.io.HttpConstants.*;
|
|||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
|
@ -71,7 +72,7 @@ public class MyFreeCams extends AbstractSite {
|
|||
.build();
|
||||
try(Response response = getHttpClient().execute(req)) {
|
||||
if(response.isSuccessful()) {
|
||||
String content = response.body().string();
|
||||
String content = Objects.requireNonNull(response.body(), "HTTP response is null").string();
|
||||
Elements tags = HtmlParser.getTags(content, "div.content > p > b");
|
||||
String tokens = tags.get(2).text();
|
||||
return Double.parseDouble(tokens);
|
||||
|
|
|
@ -58,12 +58,12 @@ public class MyFreeCamsClient {
|
|||
private MyFreeCams mfc;
|
||||
private WebSocket ws;
|
||||
private Thread keepAlive;
|
||||
private Moshi moshi;
|
||||
private final Moshi moshi;
|
||||
private volatile boolean running = false;
|
||||
|
||||
private Cache<Integer, SessionState> sessionStates = CacheBuilder.newBuilder().maximumSize(4000).build();
|
||||
private Cache<Integer, MyFreeCamsModel> models = CacheBuilder.newBuilder().maximumSize(4000).build();
|
||||
private Lock lock = new ReentrantLock();
|
||||
private final Cache<Integer, SessionState> sessionStates = CacheBuilder.newBuilder().maximumSize(4000).build();
|
||||
private final Cache<Integer, MyFreeCamsModel> models = CacheBuilder.newBuilder().maximumSize(4000).build();
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private ServerConfig serverConfig;
|
||||
@SuppressWarnings("unused")
|
||||
private String tkx;
|
||||
|
@ -74,9 +74,10 @@ public class MyFreeCamsClient {
|
|||
private long heartBeat;
|
||||
private volatile boolean connecting = false;
|
||||
private static int messageId = 31415; // starting with 31415 just for fun
|
||||
private Map<Integer, Consumer<Message>> responseHandlers = new HashMap<>();
|
||||
private final Map<Integer, Consumer<Message>> responseHandlers = new HashMap<>();
|
||||
private final Random rng = new Random();
|
||||
|
||||
private Queue<String> receivedTextHistory = new LinkedList<>();
|
||||
private final Queue<String> receivedTextHistory = new LinkedList<>();
|
||||
|
||||
private MyFreeCamsClient() {
|
||||
moshi = new Moshi.Builder().build();
|
||||
|
@ -104,7 +105,7 @@ public class MyFreeCamsClient {
|
|||
}
|
||||
}
|
||||
|
||||
String server = websocketServers.get(new Random().nextInt(websocketServers.size() - 1));
|
||||
String server = websocketServers.get(rng.nextInt(websocketServers.size() - 1));
|
||||
String wsUrl = "wss://" + server + ".myfreecams.com/fcsl";
|
||||
LOG.debug("Connecting to random websocket server {}", wsUrl);
|
||||
|
||||
|
@ -636,7 +637,7 @@ public class MyFreeCamsClient {
|
|||
|
||||
public String getStreamUrl(SessionState state) {
|
||||
int userChannel = 100000000 + state.getUid();
|
||||
String phase = Optional.ofNullable(state).map(SessionState::getU).map(User::getPhase).orElse("z");
|
||||
String phase = Optional.of(state).map(SessionState::getU).map(User::getPhase).orElse("z");
|
||||
String phasePrefix = phase.equals("z") ? "" : '_' + phase;
|
||||
String server = "video" + getCamServ(state).replaceAll("^\\D+", "");
|
||||
String nonce = Double.toString(Math.random());
|
||||
|
@ -645,21 +646,21 @@ public class MyFreeCamsClient {
|
|||
}
|
||||
|
||||
private String getCamServ(SessionState state) {
|
||||
Integer camserv = Optional.ofNullable(state.getU()).map(User::getCamserv).orElse(-1);
|
||||
String camservString = camserv.toString();
|
||||
int camserv = Optional.ofNullable(state.getU()).map(User::getCamserv).orElse(-1);
|
||||
String camservString = Integer.toString(camserv);
|
||||
if (serverConfig.isOnWzObsVideoServer(state)) {
|
||||
camservString = serverConfig.wzobsServers.get(camserv.toString());
|
||||
camservString = serverConfig.wzobsServers.get(camservString);
|
||||
} else if (serverConfig.isOnObsServer(state)) {
|
||||
camservString = serverConfig.ngVideoServers.get(camserv.toString());
|
||||
camservString = serverConfig.ngVideoServers.get(camservString);
|
||||
} else if (serverConfig.isOnHtml5VideoServer(state)) {
|
||||
camservString = serverConfig.h5Servers.get(camserv.toString());
|
||||
camservString = serverConfig.h5Servers.get(camservString);
|
||||
} else if (camserv > 500) {
|
||||
if (camserv >= 3000) {
|
||||
camserv -= 1000;
|
||||
} else {
|
||||
camserv -= 500;
|
||||
}
|
||||
camservString = camserv.toString();
|
||||
camservString = Integer.toString(camserv);
|
||||
}
|
||||
return camservString;
|
||||
}
|
||||
|
@ -674,9 +675,12 @@ public class MyFreeCamsClient {
|
|||
}
|
||||
|
||||
public SessionState getSessionState(ctbrec.Model model) {
|
||||
for (SessionState state : sessionStates.asMap().values()) {
|
||||
if (Objects.equals(state.getNm(), model.getName())) {
|
||||
return state;
|
||||
if (model instanceof MyFreeCamsModel) {
|
||||
MyFreeCamsModel mfcModel = (MyFreeCamsModel) model;
|
||||
for (SessionState state : sessionStates.asMap().values()) {
|
||||
if (mfcModel.getUid() > 0 && state.getUid() != null && state.getUid() > 0 && mfcModel.getUid() == state.getUid()) {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -723,6 +727,37 @@ public class MyFreeCamsClient {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to look up the sessionId of a model
|
||||
*/
|
||||
public String getSessionId(String modelName) throws InterruptedException {
|
||||
if (ws == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
LOG.trace("Sending USERNAMELOOKUP for {}", modelName);
|
||||
int msgId = messageId++;
|
||||
Object monitor = new Object();
|
||||
|
||||
List<String> resultHolder = new ArrayList<>();
|
||||
responseHandlers.put(msgId, msg -> {
|
||||
LOG.trace("Search result: {}", msg);
|
||||
if (StringUtil.isNotBlank(msg.getMessage()) && !Objects.equals(msg.getMessage(), modelName)) {
|
||||
JSONObject json = new JSONObject(msg.getMessage());
|
||||
resultHolder.add(Integer.toString(json.optInt("sid")));
|
||||
}
|
||||
synchronized (monitor) {
|
||||
monitor.notifyAll();
|
||||
}
|
||||
});
|
||||
ws.send("10 " + sessionId + " 0 " + msgId + " 0 " + modelName + "\n");
|
||||
synchronized (monitor) {
|
||||
monitor.wait();
|
||||
}
|
||||
|
||||
return resultHolder.isEmpty() ? "" : resultHolder.get(0);
|
||||
}
|
||||
|
||||
public Collection<SessionState> getSessionStates() {
|
||||
return Collections.unmodifiableCollection(sessionStates.asMap().values());
|
||||
}
|
||||
|
|
|
@ -1,31 +1,9 @@
|
|||
package ctbrec.sites.mfc;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.util.Optional.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.iheartradio.m3u8.ParseException;
|
||||
import com.iheartradio.m3u8.PlaylistException;
|
||||
import com.squareup.moshi.JsonReader;
|
||||
import com.squareup.moshi.JsonWriter;
|
||||
|
||||
import ctbrec.AbstractModel;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.io.HtmlParser;
|
||||
|
@ -38,6 +16,19 @@ import okhttp3.FormBody;
|
|||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
public class MyFreeCamsModel extends AbstractModel {
|
||||
|
||||
|
@ -67,15 +58,38 @@ public class MyFreeCamsModel extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||
return isOnline();
|
||||
if (ignoreCache) {
|
||||
String sessionId = MyFreeCamsClient.getInstance().getSessionId(getName());
|
||||
boolean online = !(sessionId.isEmpty() || sessionId.equals("0"));
|
||||
SessionState sessionState = MyFreeCamsClient.getInstance().getSessionState(this);
|
||||
if (online) {
|
||||
if (sessionState == null) {
|
||||
LOG.warn("MFC model {} [{}] seems to be online but a SessionState could not be found", getName(), getUid());
|
||||
}
|
||||
} else {
|
||||
state = ctbrec.sites.mfc.State.OFFLINE;
|
||||
}
|
||||
return online;
|
||||
} else {
|
||||
return isOnline();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||
if(state == null) {
|
||||
if (state == null) {
|
||||
return State.UNKNOWN;
|
||||
}
|
||||
|
||||
if (!failFast) {
|
||||
MyFreeCamsClient.getInstance().update(this);
|
||||
try {
|
||||
isOnline(true);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
switch(state) {
|
||||
case ONLINE:
|
||||
case RECORDING:
|
||||
|
@ -106,7 +120,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
|||
}
|
||||
|
||||
private String updateStreamUrl() {
|
||||
if(streamUrl == null) {
|
||||
if (streamUrl == null) {
|
||||
MyFreeCams mfc = (MyFreeCams) getSite();
|
||||
mfc.getClient().update(this);
|
||||
}
|
||||
|
@ -129,9 +143,9 @@ public class MyFreeCamsModel extends AbstractModel {
|
|||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(CONNECTION, KEEP_ALIVE)
|
||||
.build();
|
||||
try(Response resp = site.getHttpClient().execute(req)) {
|
||||
if(resp.isSuccessful()) {
|
||||
String page = resp.body().string();
|
||||
try (Response resp = site.getHttpClient().execute(req)) {
|
||||
if (resp.isSuccessful()) {
|
||||
String page = Objects.requireNonNull(resp.body(), "HTTP response is null").string();
|
||||
Element hiddenInput = HtmlParser.getTag(page, "input[name=token]");
|
||||
String token = hiddenInput.attr("value");
|
||||
if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||
|
|
Loading…
Reference in New Issue