forked from j62/ctbrec
Improve MyFreeCamsClient
- Add watch dog to reestablish a broken connection - Implemented creation of stream urls properly - Add HD tab to display MFC HD streams
This commit is contained in:
parent
8e3d2fd565
commit
f4842fcf51
|
@ -56,7 +56,8 @@ public class FriendsUpdateService extends PaginatedScheduledService {
|
||||||
st.setUid(uid);
|
st.setUid(uid);
|
||||||
st.setLv(modelObject.getInt("lv"));
|
st.setLv(modelObject.getInt("lv"));
|
||||||
st.setVs(127);
|
st.setVs(127);
|
||||||
model.update(st);
|
|
||||||
|
model.update(st, myFreeCams.getClient().getStreamUrl(st));
|
||||||
}
|
}
|
||||||
models.add(model);
|
models.add(model);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package ctbrec.sites.mfc;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import ctbrec.Model;
|
||||||
|
import ctbrec.ui.PaginatedScheduledService;
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
|
||||||
|
public class HDCamsUpdateService extends PaginatedScheduledService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Task<List<Model>> createTask() {
|
||||||
|
return new Task<List<Model>>() {
|
||||||
|
@Override
|
||||||
|
public List<Model> call() throws IOException {
|
||||||
|
MyFreeCamsClient client = MyFreeCamsClient.getInstance();
|
||||||
|
int modelsPerPage = 50;
|
||||||
|
return client.getModels().stream()
|
||||||
|
.filter(m -> m.getPreview() != null)
|
||||||
|
.filter(m -> m.getStreamUrl() != null)
|
||||||
|
.filter(m -> m.getStreamUrl().contains("/x-hls/"))
|
||||||
|
.filter(m -> {
|
||||||
|
try {
|
||||||
|
return m.isOnline();
|
||||||
|
} catch(Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sorted((m1,m2) -> (int)(m2.getCamScore() - m1.getCamScore()))
|
||||||
|
.skip( (page-1) * modelsPerPage)
|
||||||
|
.limit(modelsPerPage)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,7 +36,6 @@ public class MessageTypes {
|
||||||
public static final int SERVERREFRESH = 27;
|
public static final int SERVERREFRESH = 27;
|
||||||
public static final int SETTING = 28;
|
public static final int SETTING = 28;
|
||||||
public static final int BWSTATS = 29;
|
public static final int BWSTATS = 29;
|
||||||
public static final int SETGUESTNAME = 30;
|
|
||||||
public static final int TKX = 30;
|
public static final int TKX = 30;
|
||||||
public static final int SETTEXTOPT = 31;
|
public static final int SETTEXTOPT = 31;
|
||||||
public static final int SERVERCONFIG = 32;
|
public static final int SERVERCONFIG = 32;
|
||||||
|
@ -61,7 +60,6 @@ public class MessageTypes {
|
||||||
public static final int JOINCHAN = 51;
|
public static final int JOINCHAN = 51;
|
||||||
public static final int CREATECHAN = 52;
|
public static final int CREATECHAN = 52;
|
||||||
public static final int INVITECHAN = 53;
|
public static final int INVITECHAN = 53;
|
||||||
public static final int KICKCHAN = 54;
|
|
||||||
public static final int QUIETCHAN = 55;
|
public static final int QUIETCHAN = 55;
|
||||||
public static final int BANCHAN = 56;
|
public static final int BANCHAN = 56;
|
||||||
public static final int PREVIEWCHAN = 57;
|
public static final int PREVIEWCHAN = 57;
|
||||||
|
@ -91,6 +89,9 @@ public class MessageTypes {
|
||||||
public static final int EXTDATA = 81;
|
public static final int EXTDATA = 81;
|
||||||
public static final int NOTIFY = 84;
|
public static final int NOTIFY = 84;
|
||||||
public static final int PUBLISH = 85;
|
public static final int PUBLISH = 85;
|
||||||
|
public static final int XREQUEST = 86;
|
||||||
|
public static final int XRESPONSE = 87;
|
||||||
|
public static final int EDGECON = 88;
|
||||||
public static final int ZGWINVALID = 95;
|
public static final int ZGWINVALID = 95;
|
||||||
public static final int CONNECTING = 96;
|
public static final int CONNECTING = 96;
|
||||||
public static final int CONNECTED = 97;
|
public static final int CONNECTED = 97;
|
||||||
|
|
|
@ -112,4 +112,8 @@ public class MyFreeCams implements Site {
|
||||||
public boolean isSiteForModel(Model m) {
|
public boolean isSiteForModel(Model m) {
|
||||||
return m instanceof MyFreeCamsModel;
|
return m instanceof MyFreeCamsModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MyFreeCamsClient getClient() {
|
||||||
|
return client;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,12 @@ public class MyFreeCamsClient {
|
||||||
private Map<Integer, MyFreeCamsModel> models = new HashMap<>();
|
private Map<Integer, MyFreeCamsModel> models = new HashMap<>();
|
||||||
private Lock lock = new ReentrantLock();
|
private Lock lock = new ReentrantLock();
|
||||||
private ExecutorService executor = Executors.newSingleThreadExecutor();
|
private ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
|
private ServerConfig serverConfig;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private String tkx;
|
||||||
|
private Integer cxid;
|
||||||
|
private int[] ctx;
|
||||||
|
private String ctxenc;
|
||||||
|
|
||||||
private MyFreeCamsClient() {
|
private MyFreeCamsClient() {
|
||||||
moshi = new Moshi.Builder().build();
|
moshi = new Moshi.Builder().build();
|
||||||
|
@ -62,20 +68,39 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
public void start() throws IOException {
|
public void start() throws IOException {
|
||||||
running = true;
|
running = true;
|
||||||
ServerConfig serverConfig = new ServerConfig(mfc.getHttpClient());
|
serverConfig = new ServerConfig(mfc.getHttpClient());
|
||||||
List<String> websocketServers = new ArrayList<String>(serverConfig.wsServers.keySet());
|
List<String> websocketServers = new ArrayList<String>(serverConfig.wsServers.keySet());
|
||||||
String server = websocketServers.get((int) (Math.random()*websocketServers.size()));
|
String server = websocketServers.get((int) (Math.random()*websocketServers.size()));
|
||||||
String wsUrl = "ws://" + server + ".myfreecams.com:8080/fcsl";
|
String wsUrl = "ws://" + server + ".myfreecams.com:8080/fcsl";
|
||||||
Request req = new Request.Builder()
|
|
||||||
.url(wsUrl)
|
Thread watchDog = new Thread(() -> {
|
||||||
.addHeader("Origin", "http://m.myfreecams.com")
|
while(running) {
|
||||||
.build();
|
if (ws == null) {
|
||||||
ws = createWebSocket(req);
|
Request req = new Request.Builder()
|
||||||
|
.url(wsUrl)
|
||||||
|
.addHeader("Origin", "http://m.myfreecams.com")
|
||||||
|
.build();
|
||||||
|
ws = createWebSocket(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Thread.sleep(1000);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
LOG.error("WatchDog couldn't sleep", e);
|
||||||
|
stop();
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
watchDog.setDaemon(true);
|
||||||
|
watchDog.setName("MFC WebSocket WatchDog");
|
||||||
|
watchDog.setPriority(Thread.MIN_PRIORITY);
|
||||||
|
watchDog.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void stop() {
|
public void stop() {
|
||||||
ws.close(1000, "Good Bye"); // terminate normally (1000)
|
|
||||||
running = false;
|
running = false;
|
||||||
|
ws.close(1000, "Good Bye"); // terminate normally (1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<MyFreeCamsModel> getModels() {
|
public List<MyFreeCamsModel> getModels() {
|
||||||
|
@ -115,12 +140,21 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClosed(WebSocket webSocket, int code, String reason) {
|
public void onClosed(WebSocket webSocket, int code, String reason) {
|
||||||
// TODO decide what todo: is this the end of the session
|
|
||||||
// or do we have to reconnect to keep things running?
|
|
||||||
super.onClosed(webSocket, code, reason);
|
super.onClosed(webSocket, code, reason);
|
||||||
LOG.trace("close: {} {}", code, reason);
|
LOG.info("MFC websocket closed: {} {}", code, reason);
|
||||||
running = false;
|
MyFreeCamsClient.this.ws = null;
|
||||||
mfc.getHttpClient().shutdown();
|
if(!running) {
|
||||||
|
mfc.getHttpClient().shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
||||||
|
super.onFailure(webSocket, t, response);
|
||||||
|
int code = response.code();
|
||||||
|
String message = response.message();
|
||||||
|
MyFreeCamsClient.this.ws = null;
|
||||||
|
LOG.error("MFC websocket failure: {} {}", code, message, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuilder msgBuffer = new StringBuilder();
|
private StringBuilder msgBuffer = new StringBuilder();
|
||||||
|
@ -137,13 +171,15 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (message.getType()) {
|
switch (message.getType()) {
|
||||||
|
case NULL:
|
||||||
|
break;
|
||||||
case LOGIN:
|
case LOGIN:
|
||||||
System.out.println("LOGIN");
|
// System.out.println("LOGIN");
|
||||||
System.out.println("Sender " + message.getSender());
|
// System.out.println("Sender " + message.getSender());
|
||||||
System.out.println("Receiver " + message.getReceiver());
|
// System.out.println("Receiver " + message.getReceiver());
|
||||||
System.out.println("Arg1 " + message.getArg1());
|
// System.out.println("Arg1 " + message.getArg1());
|
||||||
System.out.println("Arg2 " + message.getArg2());
|
// System.out.println("Arg2 " + message.getArg2());
|
||||||
System.out.println("Msg " + message.getMessage());
|
// System.out.println("Msg " + message.getMessage());
|
||||||
break;
|
break;
|
||||||
case DETAILS:
|
case DETAILS:
|
||||||
case ROOMHELPER:
|
case ROOMHELPER:
|
||||||
|
@ -158,6 +194,7 @@ public class MyFreeCamsClient {
|
||||||
case JOINCHAN:
|
case JOINCHAN:
|
||||||
case SESSIONSTATE:
|
case SESSIONSTATE:
|
||||||
if(!message.getMessage().isEmpty()) {
|
if(!message.getMessage().isEmpty()) {
|
||||||
|
//LOG.debug("SessionState: {}", message.getMessage());
|
||||||
JsonAdapter<SessionState> adapter = moshi.adapter(SessionState.class);
|
JsonAdapter<SessionState> adapter = moshi.adapter(SessionState.class);
|
||||||
try {
|
try {
|
||||||
SessionState sessionState = adapter.fromJson(message.getMessage());
|
SessionState sessionState = adapter.fromJson(message.getMessage());
|
||||||
|
@ -219,6 +256,21 @@ public class MyFreeCamsClient {
|
||||||
System.out.println("Arg2 " + message.getArg2());
|
System.out.println("Arg2 " + message.getArg2());
|
||||||
System.out.println("Msg " + message.getMessage());
|
System.out.println("Msg " + message.getMessage());
|
||||||
break;
|
break;
|
||||||
|
case SLAVEVSHARE:
|
||||||
|
// LOG.debug("SLAVEVSHARE {}", message);
|
||||||
|
// LOG.debug("SLAVEVSHARE MSG [{}]", message.getMessage());
|
||||||
|
break;
|
||||||
|
case TKX:
|
||||||
|
json = new JSONObject(message.getMessage());
|
||||||
|
tkx = json.getString("tkx");
|
||||||
|
cxid = json.getInt("cxid");
|
||||||
|
ctxenc = URLDecoder.decode(json.getString("ctxenc"), "utf-8");
|
||||||
|
JSONArray ctxArray = json.getJSONArray("ctx");
|
||||||
|
ctx = new int[ctxArray.length()];
|
||||||
|
for (int i = 0; i < ctxArray.length(); i++) {
|
||||||
|
ctx[i] = ctxArray.getInt(i);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
LOG.debug("Unknown message {}", message);
|
LOG.debug("Unknown message {}", message);
|
||||||
break;
|
break;
|
||||||
|
@ -240,7 +292,7 @@ public class MyFreeCamsClient {
|
||||||
String base = "http://www.myfreecams.com/php/FcwExtResp.php";
|
String base = "http://www.myfreecams.com/php/FcwExtResp.php";
|
||||||
String url = base + "?respkey="+respkey+"&opts="+opts+"&serv="+serv+"&type="+type;
|
String url = base + "?respkey="+respkey+"&opts="+opts+"&serv="+serv+"&type="+type;
|
||||||
Request req = new Request.Builder().url(url).build();
|
Request req = new Request.Builder().url(url).build();
|
||||||
LOG.debug("Requesting EXTDATA {}", url);
|
LOG.trace("Requesting EXTDATA {}", url);
|
||||||
Response resp = mfc.getHttpClient().execute(req);
|
Response resp = mfc.getHttpClient().execute(req);
|
||||||
|
|
||||||
if(resp.isSuccessful()) {
|
if(resp.isSuccessful()) {
|
||||||
|
@ -268,7 +320,7 @@ public class MyFreeCamsClient {
|
||||||
state.setLv(inner.getInt(idx++));
|
state.setLv(inner.getInt(idx++));
|
||||||
state.setU(new User());
|
state.setU(new User());
|
||||||
state.getU().setCamserv(inner.getInt(idx++));
|
state.getU().setCamserv(inner.getInt(idx++));
|
||||||
idx++;
|
state.getU().setPhase(inner.getString(idx++));
|
||||||
state.getU().setChatColor(inner.getString(idx++));
|
state.getU().setChatColor(inner.getString(idx++));
|
||||||
state.getU().setChatFont(inner.getInt(idx++));
|
state.getU().setChatFont(inner.getInt(idx++));
|
||||||
state.getU().setChatOpt(inner.getInt(idx++));
|
state.getU().setChatOpt(inner.getInt(idx++));
|
||||||
|
@ -334,7 +386,12 @@ public class MyFreeCamsClient {
|
||||||
|
|
||||||
private void updateModel(SessionState state) {
|
private void updateModel(SessionState state) {
|
||||||
// essential data not yet available
|
// essential data not yet available
|
||||||
if(state.getNm() == null || state.getM() == null || state.getU() == null || state.getU().getCamserv() == null) {
|
if(state.getNm() == null || state.getM() == null || state.getU() == null || state.getU().getCamserv() == null || state.getU().getCamserv() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// tokens not yet available
|
||||||
|
if(ctxenc == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -344,7 +401,7 @@ public class MyFreeCamsClient {
|
||||||
model.setUid(state.getUid());
|
model.setUid(state.getUid());
|
||||||
models.put(state.getUid(), model);
|
models.put(state.getUid(), model);
|
||||||
}
|
}
|
||||||
model.update(state);
|
model.update(state, getStreamUrl(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message parseMessage(StringBuilder msg) throws UnsupportedEncodingException {
|
private Message parseMessage(StringBuilder msg) throws UnsupportedEncodingException {
|
||||||
|
@ -406,7 +463,7 @@ public class MyFreeCamsClient {
|
||||||
try {
|
try {
|
||||||
for (SessionState state : sessionStates.values()) {
|
for (SessionState state : sessionStates.values()) {
|
||||||
if(Objects.equals(state.getNm(), model.getName())) {
|
if(Objects.equals(state.getNm(), model.getName())) {
|
||||||
model.update(state);
|
model.update(state, getStreamUrl(state));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,6 +472,34 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getStreamUrl(SessionState state) {
|
||||||
|
Integer camserv = state.getU().getCamserv();
|
||||||
|
if(camserv != null) {
|
||||||
|
int userChannel = 100000000 + state.getUid();
|
||||||
|
String streamUrl = "";
|
||||||
|
String phase = state.getU().getPhase() != null ? state.getU().getPhase() : "z";
|
||||||
|
if(serverConfig.isOnNgServer(state)) {
|
||||||
|
String server = serverConfig.ngVideoServers.get(camserv.toString());
|
||||||
|
streamUrl = "https://" + server + ".myfreecams.com:8444/x-hls/" + cxid + '/' + userChannel + '/' + ctxenc + "/mfc_" + phase + '_' + userChannel + ".m3u8";
|
||||||
|
//LOG.debug("{} {}", state.getNm(), streamUrl);
|
||||||
|
} else if(serverConfig.isOnWzObsVideoServer(state)) {
|
||||||
|
String server = serverConfig.wzobsServers.get(camserv.toString());
|
||||||
|
streamUrl = "https://"+ server + ".myfreecams.com/NxServer/ngrp:mfc_" + phase + '_' + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
LOG.debug("{} isOnWzObsvideo: {}", state.getNm(), streamUrl);
|
||||||
|
} else if(serverConfig.isOnHtml5VideoServer(state)) {
|
||||||
|
String server = serverConfig.h5Servers.get(camserv.toString());
|
||||||
|
streamUrl = "https://"+ server + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
} else {
|
||||||
|
if(camserv > 500) {
|
||||||
|
camserv -= 500;
|
||||||
|
}
|
||||||
|
streamUrl = "https://video" + camserv + ".myfreecams.com/NxServer/ngrp:mfc_" + userChannel + ".f4v_mobile/playlist.m3u8";
|
||||||
|
}
|
||||||
|
return streamUrl;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
public MyFreeCamsModel getModel(int uid) {
|
public MyFreeCamsModel getModel(int uid) {
|
||||||
return models.get(uid);
|
return models.get(uid);
|
||||||
}
|
}
|
||||||
|
@ -432,4 +517,8 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ServerConfig getServerConfig() {
|
||||||
|
return serverConfig;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,13 +80,16 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
if(playlist.getStreamInfo().getResolution() != null) {
|
if(playlist.getStreamInfo().getResolution() != null) {
|
||||||
src.width = playlist.getStreamInfo().getResolution().width;
|
src.width = playlist.getStreamInfo().getResolution().width;
|
||||||
src.height = playlist.getStreamInfo().getResolution().height;
|
src.height = playlist.getStreamInfo().getResolution().height;
|
||||||
String masterUrl = hlsUrl;
|
} else {
|
||||||
String baseUrl = masterUrl.substring(0, masterUrl.lastIndexOf('/') + 1);
|
src.width = Integer.MAX_VALUE;
|
||||||
String segmentUri = baseUrl + playlist.getUri();
|
src.height = Integer.MAX_VALUE;
|
||||||
src.mediaPlaylistUrl = segmentUri;
|
|
||||||
LOG.trace("Media playlist {}", src.mediaPlaylistUrl);
|
|
||||||
sources.add(src);
|
|
||||||
}
|
}
|
||||||
|
String masterUrl = hlsUrl;
|
||||||
|
String baseUrl = masterUrl.substring(0, masterUrl.lastIndexOf('/') + 1);
|
||||||
|
String segmentUri = baseUrl + playlist.getUri();
|
||||||
|
src.mediaPlaylistUrl = segmentUri;
|
||||||
|
LOG.trace("Media playlist {}", src.mediaPlaylistUrl);
|
||||||
|
sources.add(src);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sources;
|
return sources;
|
||||||
|
@ -100,11 +103,15 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
Request req = new Request.Builder().url(hlsUrl).build();
|
Request req = new Request.Builder().url(hlsUrl).build();
|
||||||
Response response = site.getHttpClient().execute(req);
|
Response response = site.getHttpClient().execute(req);
|
||||||
try {
|
try {
|
||||||
InputStream inputStream = response.body().byteStream();
|
if(response.isSuccessful()) {
|
||||||
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8);
|
InputStream inputStream = response.body().byteStream();
|
||||||
Playlist playlist = parser.parse();
|
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8);
|
||||||
MasterPlaylist master = playlist.getMasterPlaylist();
|
Playlist playlist = parser.parse();
|
||||||
return master;
|
MasterPlaylist master = playlist.getMasterPlaylist();
|
||||||
|
return master;
|
||||||
|
} else {
|
||||||
|
throw new IOException(response.code() + " " + response.message());
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
response.close();
|
response.close();
|
||||||
}
|
}
|
||||||
|
@ -199,9 +206,10 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
this.state = state;
|
this.state = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(SessionState state) {
|
public void update(SessionState state, String streamUrl) {
|
||||||
setCamScore(state.getM().getCamscore());
|
setCamScore(state.getM().getCamscore());
|
||||||
setState(State.of(state.getVs()));
|
setState(State.of(state.getVs()));
|
||||||
|
setStreamUrl(streamUrl);
|
||||||
|
|
||||||
// preview
|
// preview
|
||||||
String uid = state.getUid().toString();
|
String uid = state.getUid().toString();
|
||||||
|
@ -209,24 +217,6 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.300x300.jpg";
|
String previewUrl = "https://img.mfcimg.com/photos2/"+uidStart+'/'+uid+"/avatar.300x300.jpg";
|
||||||
setPreview(previewUrl);
|
setPreview(previewUrl);
|
||||||
|
|
||||||
// stream url
|
|
||||||
Integer camserv = state.getU().getCamserv();
|
|
||||||
if(camserv != null) {
|
|
||||||
if(state.getM() != null) {
|
|
||||||
if(state.getM().getFlags() != null) {
|
|
||||||
int flags = state.getM().getFlags();
|
|
||||||
int hd = flags >> 18 & 0x1;
|
|
||||||
if(hd == 1) {
|
|
||||||
String hlsUrl = "http://video" + (camserv - 500) + ".myfreecams.com:1935/NxServer/ngrp:mfc_a_" + (100000000 + state.getUid()) + ".f4v_mobile/playlist.m3u8";
|
|
||||||
setStreamUrl(hlsUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String hlsUrl = "http://video" + (camserv - 500) + ".myfreecams.com:1935/NxServer/ngrp:mfc_" + (100000000 + state.getUid()) + ".f4v_mobile/playlist.m3u8";
|
|
||||||
setStreamUrl(hlsUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
Optional.ofNullable(state.getM()).map((m) -> m.getTags()).ifPresent((tags) -> {
|
Optional.ofNullable(state.getM()).map((m) -> m.getTags()).ifPresent((tags) -> {
|
||||||
ArrayList<String> t = new ArrayList<>();
|
ArrayList<String> t = new ArrayList<>();
|
||||||
|
|
|
@ -37,6 +37,13 @@ public class MyFreeCamsTabProvider extends TabProvider {
|
||||||
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10)));
|
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10)));
|
||||||
tabs.add(friends);
|
tabs.add(friends);
|
||||||
|
|
||||||
|
updateService = new HDCamsUpdateService();
|
||||||
|
ThumbOverviewTab hd = new ThumbOverviewTab("HD", updateService, myFreeCams);
|
||||||
|
hd.setRecorder(recorder);
|
||||||
|
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10)));
|
||||||
|
tabs.add(hd);
|
||||||
|
|
||||||
|
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
@ -21,7 +22,7 @@ public class ServerConfig {
|
||||||
Map<String, String> h5Servers;
|
Map<String, String> h5Servers;
|
||||||
Map<String, String> wsServers;
|
Map<String, String> wsServers;
|
||||||
Map<String, String> wzobsServers;
|
Map<String, String> wzobsServers;
|
||||||
Map<String, String> ngVideo;
|
Map<String, String> ngVideoServers;
|
||||||
|
|
||||||
public ServerConfig(HttpClient client) throws IOException {
|
public ServerConfig(HttpClient client) throws IOException {
|
||||||
Request req = new Request.Builder().url("http://www.myfreecams.com/_js/serverconfig.js").build();
|
Request req = new Request.Builder().url("http://www.myfreecams.com/_js/serverconfig.js").build();
|
||||||
|
@ -35,7 +36,10 @@ public class ServerConfig {
|
||||||
h5Servers = parseMap(serverConfig, "h5video_servers");
|
h5Servers = parseMap(serverConfig, "h5video_servers");
|
||||||
wsServers = parseMap(serverConfig, "websocket_servers");
|
wsServers = parseMap(serverConfig, "websocket_servers");
|
||||||
wzobsServers = parseMap(serverConfig, "wzobs_servers");
|
wzobsServers = parseMap(serverConfig, "wzobs_servers");
|
||||||
ngVideo = parseMap(serverConfig, "ngvideo_servers");
|
ngVideoServers = parseMap(serverConfig, "ngvideo_servers");
|
||||||
|
// System.out.println("wz " + wzobsServers);
|
||||||
|
// System.out.println("ng " + ngVideoServers);
|
||||||
|
// System.out.println("h5 " + h5Servers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<String, String> parseMap(JSONObject serverConfig, String name) {
|
private static Map<String, String> parseMap(JSONObject serverConfig, String name) {
|
||||||
|
@ -56,4 +60,18 @@ public class ServerConfig {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOnNgServer(SessionState state) {
|
||||||
|
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
||||||
|
return ngVideoServers.containsKey(Integer.toString(camserv));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnWzObsVideoServer(SessionState state) {
|
||||||
|
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
||||||
|
return wzobsServers.containsKey(Integer.toString(camserv));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isOnHtml5VideoServer(SessionState state) {
|
||||||
|
int camserv = Objects.requireNonNull(Objects.requireNonNull(state.getU()).getCamserv());
|
||||||
|
return h5Servers.containsKey(Integer.toString(camserv)) || (camserv >= 904 && camserv <= 915 || camserv >= 940 && camserv <= 960);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ public class User {
|
||||||
private Integer photos;
|
private Integer photos;
|
||||||
private Integer profile;
|
private Integer profile;
|
||||||
private String status;
|
private String status;
|
||||||
|
private String phase;
|
||||||
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
|
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
|
||||||
|
|
||||||
public Integer getAvatar() {
|
public Integer getAvatar() {
|
||||||
|
@ -132,6 +133,14 @@ public class User {
|
||||||
this.additionalProperties.put(name, value);
|
this.additionalProperties.put(name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getPhase() {
|
||||||
|
return phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPhase(String phase) {
|
||||||
|
this.phase = phase;
|
||||||
|
}
|
||||||
|
|
||||||
public void merge(User u) {
|
public void merge(User u) {
|
||||||
if (u == null) {
|
if (u == null) {
|
||||||
return;
|
return;
|
||||||
|
@ -149,6 +158,7 @@ public class User {
|
||||||
photos = u.photos != null ? u.photos : photos;
|
photos = u.photos != null ? u.photos : photos;
|
||||||
profile = u.profile != null ? u.profile : profile;
|
profile = u.profile != null ? u.profile : profile;
|
||||||
status = u.status != null ? u.status : status;
|
status = u.status != null ? u.status : status;
|
||||||
|
phase = u.phase != null ? u.phase : phase;
|
||||||
additionalProperties.putAll(u.additionalProperties);
|
additionalProperties.putAll(u.additionalProperties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import com.squareup.moshi.Types;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Version;
|
import ctbrec.Version;
|
||||||
|
import ctbrec.io.HttpClient;
|
||||||
import ctbrec.recorder.LocalRecorder;
|
import ctbrec.recorder.LocalRecorder;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.recorder.RemoteRecorder;
|
import ctbrec.recorder.RemoteRecorder;
|
||||||
|
@ -51,25 +52,24 @@ public class CamrecApplication extends Application {
|
||||||
private SettingsTab settingsTab;
|
private SettingsTab settingsTab;
|
||||||
private TabPane rootPane = new TabPane();
|
private TabPane rootPane = new TabPane();
|
||||||
static EventBus bus;
|
static EventBus bus;
|
||||||
private Site site;
|
|
||||||
private List<Site> sites = new ArrayList<>();
|
private List<Site> sites = new ArrayList<>();
|
||||||
|
public static HttpClient httpClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception {
|
public void start(Stage primaryStage) throws Exception {
|
||||||
Chaturbate ctb = new Chaturbate();
|
sites.add(new Chaturbate());
|
||||||
sites.add(ctb);
|
sites.add(new MyFreeCams());
|
||||||
site = new MyFreeCams();
|
|
||||||
sites.add(site);
|
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
createHttpClient();
|
||||||
bus = new AsyncEventBus(Executors.newSingleThreadExecutor());
|
bus = new AsyncEventBus(Executors.newSingleThreadExecutor());
|
||||||
hostServices = getHostServices();
|
hostServices = getHostServices();
|
||||||
createRecorder();
|
createRecorder();
|
||||||
for (Site site : sites) {
|
for (Site site : sites) {
|
||||||
site.setRecorder(recorder);
|
site.setRecorder(recorder);
|
||||||
site.init();
|
site.init();
|
||||||
}
|
if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
||||||
if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
|
site.login();
|
||||||
site.login();
|
}
|
||||||
}
|
}
|
||||||
createGui(primaryStage);
|
createGui(primaryStage);
|
||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
|
@ -92,9 +92,9 @@ public class CamrecApplication extends Application {
|
||||||
}
|
}
|
||||||
((SiteTab)rootPane.getTabs().get(0)).selected();
|
((SiteTab)rootPane.getTabs().get(0)).selected();
|
||||||
|
|
||||||
RecordedModelsTab modelsTab = new RecordedModelsTab("Recording", recorder, site);
|
RecordedModelsTab modelsTab = new RecordedModelsTab("Recording", recorder, sites);
|
||||||
rootPane.getTabs().add(modelsTab);
|
rootPane.getTabs().add(modelsTab);
|
||||||
RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config, site);
|
RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config, sites);
|
||||||
rootPane.getTabs().add(recordingsTab);
|
rootPane.getTabs().add(recordingsTab);
|
||||||
settingsTab = new SettingsTab();
|
settingsTab = new SettingsTab();
|
||||||
rootPane.getTabs().add(settingsTab);
|
rootPane.getTabs().add(settingsTab);
|
||||||
|
@ -124,7 +124,9 @@ public class CamrecApplication extends Application {
|
||||||
public void run() {
|
public void run() {
|
||||||
settingsTab.saveConfig();
|
settingsTab.saveConfig();
|
||||||
recorder.shutdown();
|
recorder.shutdown();
|
||||||
site.shutdown();
|
for (Site site : sites) {
|
||||||
|
site.shutdown();
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
Config.getInstance().save();
|
Config.getInstance().save();
|
||||||
LOG.info("Shutdown complete. Goodbye!");
|
LOG.info("Shutdown complete. Goodbye!");
|
||||||
|
@ -162,7 +164,7 @@ public class CamrecApplication extends Application {
|
||||||
if (config.getSettings().localRecording) {
|
if (config.getSettings().localRecording) {
|
||||||
recorder = new LocalRecorder(config);
|
recorder = new LocalRecorder(config);
|
||||||
} else {
|
} else {
|
||||||
recorder = new RemoteRecorder(config, site.getHttpClient());
|
recorder = new RemoteRecorder(config, httpClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +182,15 @@ public class CamrecApplication extends Application {
|
||||||
config = Config.getInstance();
|
config = Config.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createHttpClient() {
|
||||||
|
httpClient = new HttpClient() {
|
||||||
|
@Override
|
||||||
|
public boolean login() throws IOException {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
launch(args);
|
launch(args);
|
||||||
}
|
}
|
||||||
|
@ -189,7 +200,7 @@ public class CamrecApplication extends Application {
|
||||||
try {
|
try {
|
||||||
String url = "https://api.github.com/repos/0xboobface/ctbrec/releases";
|
String url = "https://api.github.com/repos/0xboobface/ctbrec/releases";
|
||||||
Request request = new Request.Builder().url(url).build();
|
Request request = new Request.Builder().url(url).build();
|
||||||
Response response = site.getHttpClient().execute(request);
|
Response response = httpClient.execute(request);
|
||||||
if (response.isSuccessful()) {
|
if (response.isSuccessful()) {
|
||||||
Moshi moshi = new Moshi.Builder().build();
|
Moshi moshi = new Moshi.Builder().build();
|
||||||
Type type = Types.newParameterizedType(List.class, Release.class);
|
Type type = Types.newParameterizedType(List.class, Release.class);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import java.security.InvalidKeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.BlockingQueue;
|
import java.util.concurrent.BlockingQueue;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -26,6 +27,7 @@ import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
import javafx.concurrent.ScheduledService;
|
import javafx.concurrent.ScheduledService;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
|
import javafx.event.ActionEvent;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.scene.Cursor;
|
import javafx.scene.Cursor;
|
||||||
import javafx.scene.control.Alert;
|
import javafx.scene.control.Alert;
|
||||||
|
@ -59,7 +61,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
|
|
||||||
private ScheduledService<List<Model>> updateService;
|
private ScheduledService<List<Model>> updateService;
|
||||||
private Recorder recorder;
|
private Recorder recorder;
|
||||||
private Site site;
|
private List<Site> sites;
|
||||||
|
|
||||||
FlowPane grid = new FlowPane();
|
FlowPane grid = new FlowPane();
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
@ -71,10 +73,10 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
TextField model = new TextField();
|
TextField model = new TextField();
|
||||||
Button addModelButton = new Button("Record");
|
Button addModelButton = new Button("Record");
|
||||||
|
|
||||||
public RecordedModelsTab(String title, Recorder recorder, Site site) {
|
public RecordedModelsTab(String title, Recorder recorder, List<Site> sites) {
|
||||||
super(title);
|
super(title);
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
this.site = site;
|
this.sites = sites;
|
||||||
createGui();
|
createGui();
|
||||||
setClosable(false);
|
setClosable(false);
|
||||||
initializeUpdateService();
|
initializeUpdateService();
|
||||||
|
@ -126,18 +128,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
modelLabel.setPadding(new Insets(5, 0, 0, 0));
|
modelLabel.setPadding(new Insets(5, 0, 0, 0));
|
||||||
model.setPrefWidth(300);
|
model.setPrefWidth(300);
|
||||||
BorderPane.setMargin(addModelBox, new Insets(5));
|
BorderPane.setMargin(addModelBox, new Insets(5));
|
||||||
addModelButton.setOnAction((e) -> {
|
addModelButton.setOnAction((e) -> addModel(e));
|
||||||
Model m = site.createModel(model.getText());
|
|
||||||
try {
|
|
||||||
recorder.startRecording(m);
|
|
||||||
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
|
|
||||||
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
|
||||||
alert.setTitle("Error");
|
|
||||||
alert.setHeaderText("Couldn't add model");
|
|
||||||
alert.setContentText("The model " + m.getName() + " could not be added: " + e1.getLocalizedMessage());
|
|
||||||
alert.showAndWait();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
BorderPane root = new BorderPane();
|
BorderPane root = new BorderPane();
|
||||||
root.setPadding(new Insets(5));
|
root.setPadding(new Insets(5));
|
||||||
|
@ -146,6 +137,43 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
setContent(root);
|
setContent(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addModel(ActionEvent e) {
|
||||||
|
String[] parts = model.getText().trim().split(":");
|
||||||
|
if (parts.length != 2) {
|
||||||
|
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle("Wrong format");
|
||||||
|
alert.setHeaderText("Couldn't add model");
|
||||||
|
alert.setContentText("Use something like \"MyFreeCams:ModelName\"");
|
||||||
|
alert.showAndWait();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String siteName = parts[0];
|
||||||
|
String modelName = parts[1];
|
||||||
|
for (Site site : sites) {
|
||||||
|
if (Objects.equals(siteName.toLowerCase(), site.getClass().getSimpleName().toLowerCase())) {
|
||||||
|
try {
|
||||||
|
Model m = site.createModel(modelName);
|
||||||
|
recorder.startRecording(m);
|
||||||
|
} catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) {
|
||||||
|
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle("Error");
|
||||||
|
alert.setHeaderText("Couldn't add model");
|
||||||
|
alert.setContentText("The model " + modelName + " could not be added: " + e1.getLocalizedMessage());
|
||||||
|
alert.showAndWait();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);
|
||||||
|
alert.setTitle("Unknown site");
|
||||||
|
alert.setHeaderText("Couldn't add model");
|
||||||
|
alert.setContentText("The site you entered is unknown");
|
||||||
|
alert.showAndWait();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
void initializeUpdateService() {
|
void initializeUpdateService() {
|
||||||
updateService = createUpdateService();
|
updateService = createUpdateService();
|
||||||
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(2)));
|
updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(2)));
|
||||||
|
@ -189,7 +217,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
return new Task<List<Model>>() {
|
return new Task<List<Model>>() {
|
||||||
@Override
|
@Override
|
||||||
public List<Model> call() {
|
public List<Model> call() {
|
||||||
LOG.debug("Updating recorded models");
|
LOG.trace("Updating recorded models");
|
||||||
return recorder.getModelsRecording();
|
return recorder.getModelsRecording();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -279,7 +307,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener {
|
||||||
showStreamSwitchErrorDialog(t);
|
showStreamSwitchErrorDialog(t);
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
StreamSourceSelectionDialog.show(fxModel.getDelegate(), site.getHttpClient(), onSuccess, onFail);
|
StreamSourceSelectionDialog.show(fxModel.getDelegate(), onSuccess, onFail);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showStreamSwitchErrorDialog(Throwable throwable) {
|
private void showStreamSwitchErrorDialog(Throwable throwable) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ import com.iheartradio.m3u8.ParseException;
|
||||||
import com.iheartradio.m3u8.PlaylistException;
|
import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
|
||||||
import ctbrec.Recording;
|
import ctbrec.Recording;
|
||||||
import ctbrec.Recording.STATUS;
|
import ctbrec.Recording.STATUS;
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
|
@ -66,7 +65,8 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
private ScheduledService<List<JavaFxRecording>> updateService;
|
private ScheduledService<List<JavaFxRecording>> updateService;
|
||||||
private Config config;
|
private Config config;
|
||||||
private Recorder recorder;
|
private Recorder recorder;
|
||||||
private Site site;
|
@SuppressWarnings("unused")
|
||||||
|
private List<Site> sites;
|
||||||
|
|
||||||
FlowPane grid = new FlowPane();
|
FlowPane grid = new FlowPane();
|
||||||
ScrollPane scrollPane = new ScrollPane();
|
ScrollPane scrollPane = new ScrollPane();
|
||||||
|
@ -74,11 +74,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
ObservableList<JavaFxRecording> observableRecordings = FXCollections.observableArrayList();
|
ObservableList<JavaFxRecording> observableRecordings = FXCollections.observableArrayList();
|
||||||
ContextMenu popup;
|
ContextMenu popup;
|
||||||
|
|
||||||
public RecordingsTab(String title, Recorder recorder, Config config, Site site) {
|
public RecordingsTab(String title, Recorder recorder, Config config, List<Site> sites) {
|
||||||
super(title);
|
super(title);
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.site = site;
|
this.sites = sites;
|
||||||
createGui();
|
createGui();
|
||||||
setClosable(false);
|
setClosable(false);
|
||||||
initializeUpdateService();
|
initializeUpdateService();
|
||||||
|
@ -245,18 +245,19 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
contextMenu.getItems().add(openInPlayer);
|
contextMenu.getItems().add(openInPlayer);
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem stopRecording = new MenuItem("Stop recording");
|
// TODO find a way to reenable this
|
||||||
stopRecording.setOnAction((e) -> {
|
// MenuItem stopRecording = new MenuItem("Stop recording");
|
||||||
Model m = site.createModel(recording.getModelName());
|
// stopRecording.setOnAction((e) -> {
|
||||||
try {
|
// Model m = site.createModel(recording.getModelName());
|
||||||
recorder.stopRecording(m);
|
// try {
|
||||||
} catch (Exception e1) {
|
// recorder.stopRecording(m);
|
||||||
showErrorDialog("Stop recording", "Couldn't stop recording of model " + m.getName(), e1);
|
// } catch (Exception e1) {
|
||||||
}
|
// showErrorDialog("Stop recording", "Couldn't stop recording of model " + m.getName(), e1);
|
||||||
});
|
// }
|
||||||
if(recording.getStatus() == STATUS.RECORDING) {
|
// });
|
||||||
contextMenu.getItems().add(stopRecording);
|
// if(recording.getStatus() == STATUS.RECORDING) {
|
||||||
}
|
// contextMenu.getItems().add(stopRecording);
|
||||||
|
// }
|
||||||
|
|
||||||
MenuItem deleteRecording = new MenuItem("Delete");
|
MenuItem deleteRecording = new MenuItem("Delete");
|
||||||
deleteRecording.setOnAction((e) -> {
|
deleteRecording.setOnAction((e) -> {
|
||||||
|
@ -304,7 +305,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
MergedHlsDownload download = new MergedHlsDownload(site.getHttpClient());
|
MergedHlsDownload download = new MergedHlsDownload(CamrecApplication.httpClient);
|
||||||
download.start(url.toString(), target, (progress) -> {
|
download.start(url.toString(), target, (progress) -> {
|
||||||
Platform.runLater(() -> {
|
Platform.runLater(() -> {
|
||||||
if (progress == 100) {
|
if (progress == 100) {
|
||||||
|
|
|
@ -6,13 +6,12 @@ import java.util.concurrent.ExecutionException;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.io.HttpClient;
|
|
||||||
import ctbrec.recorder.download.StreamSource;
|
import ctbrec.recorder.download.StreamSource;
|
||||||
import javafx.concurrent.Task;
|
import javafx.concurrent.Task;
|
||||||
import javafx.scene.control.ChoiceDialog;
|
import javafx.scene.control.ChoiceDialog;
|
||||||
|
|
||||||
public class StreamSourceSelectionDialog {
|
public class StreamSourceSelectionDialog {
|
||||||
public static void show(Model model, HttpClient client, Function<Model,Void> onSuccess, Function<Throwable, Void> onFail) {
|
public static void show(Model model, Function<Model,Void> onSuccess, Function<Throwable, Void> onFail) {
|
||||||
Task<List<StreamSource>> selectStreamSource = new Task<List<StreamSource>>() {
|
Task<List<StreamSource>> selectStreamSource = new Task<List<StreamSource>>() {
|
||||||
@Override
|
@Override
|
||||||
protected List<StreamSource> call() throws Exception {
|
protected List<StreamSource> call() throws Exception {
|
||||||
|
|
|
@ -15,7 +15,6 @@ import com.iheartradio.m3u8.PlaylistException;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.io.HttpClient;
|
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.recorder.download.StreamSource;
|
import ctbrec.recorder.download.StreamSource;
|
||||||
import javafx.animation.FadeTransition;
|
import javafx.animation.FadeTransition;
|
||||||
|
@ -72,17 +71,14 @@ public class ThumbCell extends StackPane {
|
||||||
private SimpleBooleanProperty selectionProperty = new SimpleBooleanProperty(false);
|
private SimpleBooleanProperty selectionProperty = new SimpleBooleanProperty(false);
|
||||||
private double imgAspectRatio = 3.0 / 4.0;
|
private double imgAspectRatio = 3.0 / 4.0;
|
||||||
|
|
||||||
private HttpClient client;
|
|
||||||
|
|
||||||
private ObservableList<Node> thumbCellList;
|
private ObservableList<Node> thumbCellList;
|
||||||
private boolean mouseHovering = false;
|
private boolean mouseHovering = false;
|
||||||
private boolean recording = false;
|
private boolean recording = false;
|
||||||
|
|
||||||
public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder, HttpClient client) {
|
public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder) {
|
||||||
this.thumbCellList = parent.grid.getChildren();
|
this.thumbCellList = parent.grid.getChildren();
|
||||||
this.model = model;
|
this.model = model;
|
||||||
this.recorder = recorder;
|
this.recorder = recorder;
|
||||||
this.client = client;
|
|
||||||
recording = recorder.isRecording(model);
|
recording = recorder.isRecording(model);
|
||||||
|
|
||||||
iv = new ImageView();
|
iv = new ImageView();
|
||||||
|
@ -208,7 +204,7 @@ public class ThumbCell extends StackPane {
|
||||||
// when we first requested the stream info, so we remove this invalid value from the "cache"
|
// when we first requested the stream info, so we remove this invalid value from the "cache"
|
||||||
// so that it is requested again
|
// so that it is requested again
|
||||||
if (model.isOnline() && resolution[1] == 0) {
|
if (model.isOnline() && resolution[1] == 0) {
|
||||||
LOG.debug("Removing invalid resolution value for {}", model.getName());
|
LOG.trace("Removing invalid resolution value for {}", model.getName());
|
||||||
model.invalidateCacheEntries();
|
model.invalidateCacheEntries();
|
||||||
}
|
}
|
||||||
} catch (ExecutionException | IOException | InterruptedException e1) {
|
} catch (ExecutionException | IOException | InterruptedException e1) {
|
||||||
|
@ -227,7 +223,7 @@ public class ThumbCell extends StackPane {
|
||||||
LOG.trace("Model resolution {} {}x{}", model.getName(), resolution[0], resolution[1]);
|
LOG.trace("Model resolution {} {}x{}", model.getName(), resolution[0], resolution[1]);
|
||||||
LOG.trace("Resolution queue size: {}", ThumbOverviewTab.queue.size());
|
LOG.trace("Resolution queue size: {}", ThumbOverviewTab.queue.size());
|
||||||
final int w = resolution[1];
|
final int w = resolution[1];
|
||||||
_res = w > 0 ? Integer.toString(w) : state;
|
_res = w > 0 ? w != Integer.MAX_VALUE ? Integer.toString(w) : "HD" : state;
|
||||||
} else {
|
} else {
|
||||||
_res = model.getOnlineState(false);
|
_res = model.getOnlineState(false);
|
||||||
resolutionBackgroundColor = resolutionOfflineColor;
|
resolutionBackgroundColor = resolutionOfflineColor;
|
||||||
|
@ -336,7 +332,7 @@ public class ThumbCell extends StackPane {
|
||||||
alert.showAndWait();
|
alert.showAndWait();
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
StreamSourceSelectionDialog.show(model, client, onSuccess, onFail);
|
StreamSourceSelectionDialog.show(model, onSuccess, onFail);
|
||||||
} else {
|
} else {
|
||||||
_startStopAction(model, start);
|
_startStopAction(model, start);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@ import com.sun.javafx.collections.ObservableListWrapper;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.io.HttpClient;
|
|
||||||
import ctbrec.recorder.Recorder;
|
import ctbrec.recorder.Recorder;
|
||||||
import ctbrec.sites.Site;
|
import ctbrec.sites.Site;
|
||||||
import ctbrec.sites.mfc.MyFreeCamsClient;
|
import ctbrec.sites.mfc.MyFreeCamsClient;
|
||||||
|
@ -262,7 +261,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!found) {
|
if(!found) {
|
||||||
ThumbCell newCell = createThumbCell(this, model, recorder, site.getHttpClient());
|
ThumbCell newCell = createThumbCell(this, model, recorder);
|
||||||
newCell.setIndex(index);
|
newCell.setIndex(index);
|
||||||
positionChangedOrNew.add(newCell);
|
positionChangedOrNew.add(newCell);
|
||||||
}
|
}
|
||||||
|
@ -285,8 +284,8 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, Model model, Recorder recorder, HttpClient client2) {
|
ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, Model model, Recorder recorder) {
|
||||||
ThumbCell newCell = new ThumbCell(this, model, recorder, site.getHttpClient());
|
ThumbCell newCell = new ThumbCell(this, model, recorder);
|
||||||
newCell.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
|
newCell.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
|
||||||
suspendUpdates(true);
|
suspendUpdates(true);
|
||||||
popup = createContextMenu(newCell);
|
popup = createContextMenu(newCell);
|
||||||
|
|
Loading…
Reference in New Issue