forked from j62/ctbrec
Implemt special player handling for fc2live
This commit is contained in:
parent
7b2f30474a
commit
fc6aeff94a
|
@ -75,7 +75,7 @@ public class Player {
|
|||
Collections.sort(sources);
|
||||
StreamSource best = sources.get(sources.size()-1);
|
||||
LOG.debug("Playing {}", best.getMediaPlaylistUrl());
|
||||
return Player.play(best.getMediaPlaylistUrl());
|
||||
return Player.play(best.getMediaPlaylistUrl(), async);
|
||||
} else {
|
||||
Platform.runLater(() -> {
|
||||
Alert alert = new AutosizeAlert(Alert.AlertType.INFORMATION);
|
||||
|
|
|
@ -2,15 +2,19 @@ package ctbrec.ui.sites.fc2live;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.sites.ConfigUI;
|
||||
import ctbrec.sites.fc2live.Fc2Live;
|
||||
import ctbrec.sites.fc2live.Fc2Model;
|
||||
import ctbrec.ui.Player;
|
||||
import ctbrec.ui.TabProvider;
|
||||
import ctbrec.ui.sites.AbstractSiteUi;
|
||||
|
||||
public class Fc2LiveSiteUi extends AbstractSiteUi {
|
||||
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2LiveSiteUi.class);
|
||||
private Fc2Live fc2live;
|
||||
private Fc2TabProvider tabProvider;
|
||||
|
||||
|
@ -37,11 +41,25 @@ public class Fc2LiveSiteUi extends AbstractSiteUi {
|
|||
@Override
|
||||
public boolean play(Model model) {
|
||||
new Thread(() -> {
|
||||
// create websocket
|
||||
|
||||
Player.play(model, false);
|
||||
|
||||
// close websocket
|
||||
Fc2Model m = (Fc2Model) model;
|
||||
try {
|
||||
boolean opened = m.openWebsocket();
|
||||
if(opened) {
|
||||
LOG.debug("Opened new websocket for player");
|
||||
} else {
|
||||
LOG.debug("Using existing websocket for player");
|
||||
}
|
||||
LOG.debug("Starting player");
|
||||
Player.play(model, false);
|
||||
if(opened) {
|
||||
LOG.debug("Closing websocket for player");
|
||||
m.closeWebsocket();
|
||||
} else {
|
||||
LOG.debug("Leaving websocket for player open");
|
||||
}
|
||||
} catch (InterruptedException | IOException e) {
|
||||
LOG.error("Error opening websocket connection", e);
|
||||
}
|
||||
}).start();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Objects;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -30,6 +31,9 @@ import okhttp3.FormBody;
|
|||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.WebSocket;
|
||||
import okhttp3.WebSocketListener;
|
||||
import okio.ByteString;
|
||||
|
||||
public class Fc2Model extends AbstractModel {
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2Model.class);
|
||||
|
@ -37,6 +41,8 @@ public class Fc2Model extends AbstractModel {
|
|||
private int viewerCount;
|
||||
private boolean online;
|
||||
private String version;
|
||||
private WebSocket ws;
|
||||
private String playlistUrl;
|
||||
|
||||
@Override
|
||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||
|
@ -91,22 +97,18 @@ public class Fc2Model extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||
loadModelInfo();
|
||||
List<StreamSource> sources = new ArrayList<>();
|
||||
getControlToken((token, url) -> {
|
||||
url = url + "?control_token=" + token;
|
||||
LOG.debug("Session token: {}", token);
|
||||
LOG.debug("Getting playlist token over websocket {}", url);
|
||||
Fc2WebSocketClient wsClient = new Fc2WebSocketClient(url, getSite().getHttpClient());
|
||||
try {
|
||||
String playlistUrl = wsClient.getPlaylistUrl();
|
||||
LOG.debug("Paylist url {}", playlistUrl);
|
||||
sources.addAll(parseMasterPlaylist(playlistUrl));
|
||||
} catch (InterruptedException | IOException | ParseException | PlaylistException e) {
|
||||
LOG.error("Couldn't fetch stream information", e);
|
||||
try {
|
||||
boolean opened = openWebsocket();
|
||||
List<StreamSource> sources = new ArrayList<>();
|
||||
LOG.debug("Paylist url {}", playlistUrl);
|
||||
sources.addAll(parseMasterPlaylist(playlistUrl));
|
||||
if(opened) {
|
||||
closeWebsocket();
|
||||
}
|
||||
});
|
||||
return sources;
|
||||
return sources;
|
||||
} catch (InterruptedException e1) {
|
||||
throw new ExecutionException(e1);
|
||||
}
|
||||
}
|
||||
|
||||
private List<StreamSource> parseMasterPlaylist(String playlistUrl) throws IOException, ParseException, PlaylistException {
|
||||
|
@ -221,4 +223,81 @@ public class Fc2Model extends AbstractModel {
|
|||
public void setViewerCount(int viewerCount) {
|
||||
this.viewerCount = viewerCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a chat websocket connection. This connection is used to retrieve the HLS playlist url. It also has to be kept open as long as the HLS stream is
|
||||
* "played"
|
||||
*
|
||||
* @return true, if a new websocket connection is opened. If the connection was already open, this method returns false
|
||||
* @throws IOException
|
||||
*/
|
||||
public boolean openWebsocket() throws InterruptedException, IOException {
|
||||
if(ws != null) {
|
||||
return false;
|
||||
} else {
|
||||
Object monitor = new Object();
|
||||
loadModelInfo();
|
||||
getControlToken((token, url) -> {
|
||||
url = url + "?control_token=" + token;
|
||||
LOG.debug("Session token: {}", token);
|
||||
LOG.debug("Getting playlist token over websocket {}", url);
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.header("User-Agent", Config.getInstance().getSettings().httpUserAgent)
|
||||
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||
.header("Accept-Language", "de,en-US;q=0.7,en;q=0.3")
|
||||
.build();
|
||||
ws = getSite().getHttpClient().newWebSocket(request, new WebSocketListener() {
|
||||
@Override
|
||||
public void onOpen(WebSocket webSocket, Response response) {
|
||||
response.close();
|
||||
webSocket.send("{\"name\":\"get_hls_information\",\"arguments\":{},\"id\":1}");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket webSocket, String text) {
|
||||
JSONObject json = new JSONObject(text);
|
||||
if(json.optString("name").equals("_response_") && json.optInt("id") == 1) {
|
||||
//LOG.debug(json.toString(2));
|
||||
JSONObject args = json.getJSONObject("arguments");
|
||||
JSONArray playlists = args.getJSONArray("playlists_high_latency");
|
||||
JSONObject playlist = playlists.getJSONObject(0);
|
||||
playlistUrl = playlist.getString("url");
|
||||
LOG.debug("Master Playlist: {}", playlistUrl);
|
||||
synchronized (monitor) {
|
||||
monitor.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessage(WebSocket webSocket, ByteString bytes) {
|
||||
LOG.debug("ws btxt {}", bytes.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(WebSocket webSocket, int code, String reason) {
|
||||
LOG.debug("ws closed {} - {}", code, reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
|
||||
LOG.debug("ws failure", t);
|
||||
response.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
synchronized (monitor) {
|
||||
monitor.wait();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean closeWebsocket() {
|
||||
ws.close(1000, "");
|
||||
ws = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue