Fix Flirt4Free recordings
This commit is contained in:
parent
5cf45a87e3
commit
062a450e69
|
@ -14,8 +14,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -74,13 +72,13 @@ public class Flirt4FreeUpdateService extends PaginatedScheduledService {
|
|||
try {
|
||||
Flirt4FreeModel model = parseModel(modelJson);
|
||||
models.add(model);
|
||||
} catch(Exception e) {
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Couldn't parse model {}", modelJson);
|
||||
}
|
||||
}
|
||||
return models.stream()
|
||||
.filter(filter)
|
||||
.skip((page - 1) * (long)MODELS_PER_PAGE)
|
||||
.skip((page - 1) * (long) MODELS_PER_PAGE)
|
||||
.limit(MODELS_PER_PAGE)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
|
@ -112,6 +110,14 @@ public class Flirt4FreeUpdateService extends PaginatedScheduledService {
|
|||
if (modelData.has("category_id_3")) {
|
||||
model.getCategories().add(modelData.getString("category_id_3"));
|
||||
}
|
||||
if (modelData.has("video_width") && modelData.has("video_aspect_ratio")) {
|
||||
String[] aspectRatioParts = modelData.getString("video_aspect_ratio").split(":");
|
||||
double aspectWidth = Integer.parseInt(aspectRatioParts[0]);
|
||||
double aspectHeight = Integer.parseInt(aspectRatioParts[1]);
|
||||
int width = Integer.parseInt(modelData.getString("video_width"));
|
||||
int height = (int) Math.ceil(width * aspectHeight / aspectWidth);
|
||||
model.setStreamResolution(new int[]{width, height});
|
||||
}
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package ctbrec;
|
||||
|
||||
public class StringConstants {
|
||||
|
||||
public static final String MODEL_ID = "model_id";
|
||||
public static final String STATUS = "status";
|
||||
|
||||
private StringConstants() {
|
||||
}
|
||||
}
|
|
@ -1,6 +1,21 @@
|
|||
package ctbrec.sites.flirt4free;
|
||||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import com.iheartradio.m3u8.*;
|
||||
import com.iheartradio.m3u8.data.MasterPlaylist;
|
||||
import com.iheartradio.m3u8.data.Playlist;
|
||||
import com.iheartradio.m3u8.data.PlaylistData;
|
||||
import com.squareup.moshi.JsonReader;
|
||||
import com.squareup.moshi.JsonWriter;
|
||||
import ctbrec.AbstractModel;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.recorder.download.StreamSource;
|
||||
import okhttp3.*;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -12,35 +27,15 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.iheartradio.m3u8.Encoding;
|
||||
import com.iheartradio.m3u8.Format;
|
||||
import com.iheartradio.m3u8.ParseException;
|
||||
import com.iheartradio.m3u8.ParsingMode;
|
||||
import com.iheartradio.m3u8.PlaylistException;
|
||||
import com.iheartradio.m3u8.PlaylistParser;
|
||||
import com.iheartradio.m3u8.data.MasterPlaylist;
|
||||
import com.iheartradio.m3u8.data.Playlist;
|
||||
import com.iheartradio.m3u8.data.PlaylistData;
|
||||
import com.squareup.moshi.JsonReader;
|
||||
import com.squareup.moshi.JsonWriter;
|
||||
|
||||
import ctbrec.AbstractModel;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.recorder.download.StreamSource;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.WebSocket;
|
||||
import okhttp3.WebSocketListener;
|
||||
import static ctbrec.StringConstants.MODEL_ID;
|
||||
import static ctbrec.StringConstants.STATUS;
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Locale.ENGLISH;
|
||||
|
||||
public class Flirt4FreeModel extends AbstractModel {
|
||||
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(Flirt4FreeModel.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Flirt4FreeModel.class);
|
||||
private String id;
|
||||
private String chatHost;
|
||||
private String chatPort;
|
||||
|
@ -72,7 +67,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, "en-US,en;q=0.5")
|
||||
.header(ACCEPT_LANGUAGE, ENGLISH.getLanguage())
|
||||
.header(REFERER, getUrl())
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
|
@ -97,7 +92,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
return;
|
||||
}
|
||||
JSONObject json = new JSONObject(body);
|
||||
online = Objects.equals(json.optString("status"), "online"); // online is true, even if the model is in private or away
|
||||
online = Objects.equals(json.optString(STATUS), "online"); // online is true, even if the model is in private or away
|
||||
updateModelId(json);
|
||||
if (online) {
|
||||
try {
|
||||
|
@ -110,12 +105,11 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
}
|
||||
|
||||
private void updateModelId(JSONObject json) {
|
||||
if (json.has("model_id")) {
|
||||
Object modelId = json.get("model_id");
|
||||
if (modelId instanceof Number) {
|
||||
Number n = (Number) modelId;
|
||||
if (json.has(MODEL_ID)) {
|
||||
Object modelId = json.get(MODEL_ID);
|
||||
if (modelId instanceof Number n) {
|
||||
if (n.intValue() > 0) {
|
||||
id = String.valueOf(json.get("model_id"));
|
||||
id = String.valueOf(json.get(MODEL_ID));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +121,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, "en-US,en;q=0.5")
|
||||
.header(ACCEPT_LANGUAGE, ENGLISH.getLanguage())
|
||||
.header(REFERER, getUrl())
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
|
@ -135,7 +129,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
try (Response response = getSite().getHttpClient().execute(request)) {
|
||||
if (response.isSuccessful()) {
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if (json.optString("status").equals("success")) {
|
||||
if (json.optString(STATUS).equals("success")) {
|
||||
JSONObject config = json.getJSONObject("config");
|
||||
JSONObject performer = config.getJSONObject("performer");
|
||||
setUrl(getSite().getBaseUrl() + "/rooms/" + getName() + '/');
|
||||
|
@ -144,7 +138,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
chatHost = room.getString("host");
|
||||
chatPort = room.getString("port_to_be");
|
||||
chatToken = json.getString("token_enc");
|
||||
String status = room.optString("status");
|
||||
String status = room.optString(STATUS);
|
||||
setOnlineState(mapStatus(status));
|
||||
online = onlineState == State.ONLINE;
|
||||
JSONObject user = config.getJSONObject("user");
|
||||
|
@ -161,16 +155,12 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
}
|
||||
|
||||
private State mapStatus(String status) {
|
||||
switch (status) {
|
||||
case "P":
|
||||
case "F":
|
||||
return State.PRIVATE;
|
||||
case "A":
|
||||
return State.AWAY;
|
||||
case "O":
|
||||
default:
|
||||
return State.ONLINE;
|
||||
}
|
||||
return switch (status) {
|
||||
case "P", "F" -> State.PRIVATE;
|
||||
case "A" -> State.AWAY;
|
||||
case "O" -> State.ONLINE;
|
||||
default -> State.UNKNOWN;
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,7 +169,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
}
|
||||
|
||||
private List<StreamSource> getStreamSources(boolean withWebsocket) throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||
MasterPlaylist masterPlaylist = null;
|
||||
MasterPlaylist masterPlaylist;
|
||||
try {
|
||||
if (withWebsocket) {
|
||||
acquireSlot();
|
||||
|
@ -200,7 +190,8 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
StreamSource src = new StreamSource();
|
||||
src.bandwidth = playlist.getStreamInfo().getBandwidth();
|
||||
src.height = playlist.getStreamInfo().getResolution().height;
|
||||
src.mediaPlaylistUrl = "https://manifest.vscdns.com/" + playlist.getUri();
|
||||
HttpUrl masterPlaylistUrl = HttpUrl.parse(streamUrl);
|
||||
src.mediaPlaylistUrl = "https://" + masterPlaylistUrl.host() + '/' + playlist.getUri();
|
||||
LOG.trace("Media playlist {}", src.mediaPlaylistUrl);
|
||||
sources.add(src);
|
||||
}
|
||||
|
@ -213,7 +204,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
Request req = new Request.Builder()
|
||||
.url(streamUrl)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, "en-US,en;q=0.5")
|
||||
.header(ACCEPT_LANGUAGE, ENGLISH.getLanguage())
|
||||
.header(REFERER, getUrl())
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
|
@ -238,12 +229,12 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
loadModelInfo();
|
||||
Objects.requireNonNull(chatHost, "chatHost is null");
|
||||
String h = chatHost.replace("chat", "chat-vip");
|
||||
String url = "https://" + h + "/chat?token=" + URLEncoder.encode(chatToken, "utf-8") + "&port_to_be=" + chatPort;
|
||||
String url = "https://" + h + "/chat?token=" + URLEncoder.encode(chatToken, UTF_8) + "&port_to_be=" + chatPort;
|
||||
LOG.trace("Opening chat websocket {}", url);
|
||||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, "en-US,en;q=0.5")
|
||||
.header(ACCEPT_LANGUAGE, ENGLISH.getLanguage())
|
||||
.header(REFERER, getUrl())
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
|
@ -268,14 +259,14 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
String roomState = data.optString("room_state");
|
||||
onlineState = mapStatus(roomState);
|
||||
online = onlineState == State.ONLINE;
|
||||
if(data.optString("room_state").equals("0") && data.optString("login_group_id").equals("14")) {
|
||||
if (data.optString("room_state").equals("0") && data.optString("login_group_id").equals("14")) {
|
||||
onlineState = Model.State.GROUP;
|
||||
online = false;
|
||||
}
|
||||
try {
|
||||
resolution[0] = Integer.parseInt(data.getString("stream_width"));
|
||||
resolution[1] = Integer.parseInt(data.getString("stream_height"));
|
||||
} catch(Exception e) {
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Couldn't determine stream resolution", e);
|
||||
}
|
||||
webSocket.close(1000, "");
|
||||
|
@ -288,7 +279,9 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
synchronized (monitor) {
|
||||
monitor.notifyAll();
|
||||
}
|
||||
response.close();
|
||||
if (response != null) {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -305,8 +298,25 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
if (streamHost == null) {
|
||||
throw new RuntimeException("Couldn't determine streaming server for model " + getName());
|
||||
} else {
|
||||
streamUrl = "https://manifest.vscdns.com/manifest.m3u8.m3u8?key=nil&provider=highwinds&secure=true&host=" + streamHost + "&model_id=" + id;
|
||||
LOG.debug("Stream URL is {}", streamUrl);
|
||||
url = getSite().getBaseUrl() + "/ws/chat/get-stream-urls.php?"
|
||||
+ "model_id=" + id
|
||||
+ "&video_host=" + streamHost
|
||||
+ "&t=" + System.currentTimeMillis();
|
||||
LOG.debug("Loading master playlist information: {}", url);
|
||||
req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, ENGLISH.getLanguage())
|
||||
.header(REFERER, getUrl())
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(REFERER, getUrl())
|
||||
.build();
|
||||
try (Response response = getSite().getHttpClient().execute(req)) {
|
||||
JSONObject json = new JSONObject(Objects.requireNonNull(response.body(), "HTTP response body is null").string());
|
||||
JSONArray hls = json.getJSONObject("data").getJSONArray("hls");
|
||||
streamUrl = "https:" + hls.getJSONObject(0).getString("url");
|
||||
LOG.debug("Stream URL is {}", streamUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -339,7 +349,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, "en-US,en;q=0.5")
|
||||
.header(ACCEPT_LANGUAGE, ENGLISH.getLanguage())
|
||||
.header(REFERER, getUrl())
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(REFERER, getUrl())
|
||||
|
@ -412,21 +422,21 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public int[] getStreamResolution(boolean failFast) throws ExecutionException {
|
||||
if(failFast) {
|
||||
return resolution;
|
||||
} else {
|
||||
if(streamUrl != null) {
|
||||
try {
|
||||
List<StreamSource> streamSources = getStreamSources(false);
|
||||
Collections.sort(streamSources);
|
||||
StreamSource best = streamSources.get(streamSources.size()-1);
|
||||
resolution = new int[] {best.width, best.height};
|
||||
} catch (IOException | ParseException | PlaylistException e) {
|
||||
throw new ExecutionException("Couldn't determine stream resolution", e);
|
||||
}
|
||||
if (!failFast && streamUrl != null && resolution[0] == 0) {
|
||||
try {
|
||||
List<StreamSource> streamSources = getStreamSources(true);
|
||||
Collections.sort(streamSources);
|
||||
StreamSource best = streamSources.get(streamSources.size() - 1);
|
||||
resolution = new int[]{best.width, best.height};
|
||||
} catch (IOException | ParseException | PlaylistException e) {
|
||||
throw new ExecutionException("Couldn't determine stream resolution", e);
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
|
||||
public void setStreamResolution(int[] res) {
|
||||
this.resolution = res;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -521,7 +531,7 @@ public class Flirt4FreeModel extends AbstractModel {
|
|||
requestThrottle.acquire();
|
||||
long now = System.currentTimeMillis();
|
||||
long millisSinceLastRequest = now - lastRequest;
|
||||
if(millisSinceLastRequest < 500) {
|
||||
if (millisSinceLastRequest < 500) {
|
||||
Thread.sleep(500 - millisSinceLastRequest);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue