Fix WinkTv capture
This commit is contained in:
parent
1c1a767046
commit
ba44257a84
|
@ -5,6 +5,7 @@ import ctbrec.StringUtil;
|
|||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.sites.AbstractSite;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
@ -22,14 +23,15 @@ import java.util.regex.Pattern;
|
|||
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
|
||||
@Slf4j
|
||||
public class WinkTv extends AbstractSite {
|
||||
|
||||
public static String domain = "www.winktv.co.kr";
|
||||
public static String baseUri = "https://www.winktv.co.kr";
|
||||
private HttpClient httpClient;
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
// Initialization logic if needed
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -63,7 +65,7 @@ public class WinkTv extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public Double getTokenBalance() throws IOException {
|
||||
return 0d;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,6 +113,7 @@ public class WinkTv extends AbstractSite {
|
|||
if (StringUtil.isBlank(q)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String url = "https://api.winktv.co.kr/v1/live";
|
||||
FormBody body = new FormBody.Builder()
|
||||
.add("offset", "0")
|
||||
|
@ -118,6 +121,7 @@ public class WinkTv extends AbstractSite {
|
|||
.add("orderBy", "user")
|
||||
.add("searchVal", URLEncoder.encode(q, "utf-8"))
|
||||
.build();
|
||||
|
||||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(USER_AGENT, getConfig().getSettings().httpUserAgent)
|
||||
|
@ -128,28 +132,32 @@ public class WinkTv extends AbstractSite {
|
|||
.header(ORIGIN, getBaseUrl())
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
try (Response response = getHttpClient().execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if (json.optBoolean("result") && json.has("list")) {
|
||||
List<Model> models = new ArrayList<>();
|
||||
JSONArray results = json.getJSONArray("list");
|
||||
if (results.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
for (int i = 0; i < results.length(); i++) {
|
||||
JSONObject result = results.getJSONObject(i);
|
||||
WinkTvModel model = createModel(result.optString("userId"));
|
||||
model.setPreview(result.optString("thumbUrl"));
|
||||
models.add(model);
|
||||
}
|
||||
return models;
|
||||
} else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
if (!response.isSuccessful()) {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
log.debug("WinkTv: Parsed JSON: {}", json.toString());
|
||||
if (!json.optBoolean("result") || !json.has("list")) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
JSONArray results = json.getJSONArray("list");
|
||||
if (results.length() == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Model> models = new ArrayList<>();
|
||||
for (int i = 0; i < results.length(); i++) {
|
||||
JSONObject result = results.getJSONObject(i);
|
||||
WinkTvModel model = createModel(result.optString("userId"));
|
||||
model.setPreview(result.optString("thumbUrl"));
|
||||
models.add(model);
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,19 +173,21 @@ public class WinkTv extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public Model createModelFromUrl(String url) {
|
||||
String[] patterns = {
|
||||
String[] patterns = new String[]{
|
||||
"https://.*?winktv.co.kr/live/play/([_a-zA-Z0-9]+)",
|
||||
"https://.*?winktv.co.kr/channel/([_a-zA-Z0-9]+)",
|
||||
"https://.*?pandalive.co.kr/live/play/([_a-zA-Z0-9]+)",
|
||||
"https://.*?pandalive.co.kr/channel/([_a-zA-Z0-9]+)"
|
||||
};
|
||||
for (String p : patterns) {
|
||||
Matcher m = Pattern.compile(p).matcher(url);
|
||||
|
||||
for (String pattern : patterns) {
|
||||
Matcher m = Pattern.compile(pattern).matcher(url);
|
||||
if (m.matches()) {
|
||||
String modelName = m.group(1);
|
||||
return createModel(modelName);
|
||||
}
|
||||
}
|
||||
|
||||
return super.createModelFromUrl(url);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,9 +9,10 @@ import ctbrec.Config;
|
|||
import ctbrec.io.HttpException;
|
||||
import ctbrec.recorder.download.RecordingProcess;
|
||||
import ctbrec.recorder.download.StreamSource;
|
||||
import ctbrec.recorder.download.hls.HlsdlDownload;
|
||||
import ctbrec.recorder.download.hls.MergedFfmpegHlsDownload;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
// import lombok.Getter;
|
||||
// import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.Request;
|
||||
|
@ -26,11 +27,13 @@ import java.time.Instant;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import static ctbrec.Model.State.*;
|
||||
import static ctbrec.io.HttpConstants.*;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Slf4j
|
||||
public class WinkTvModel extends AbstractModel {
|
||||
|
@ -38,11 +41,8 @@ public class WinkTvModel extends AbstractModel {
|
|||
private static final String KEY_MEDIA = "media";
|
||||
private int[] resolution = new int[]{0, 0};
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private boolean adult = false;
|
||||
private transient JSONObject modelInfo;
|
||||
|
||||
private transient Instant lastInfoRequest = Instant.EPOCH;
|
||||
|
||||
@Override
|
||||
|
@ -50,6 +50,7 @@ public class WinkTvModel extends AbstractModel {
|
|||
if (ignoreCache) {
|
||||
try {
|
||||
JSONObject json = getModelInfo();
|
||||
log.debug("WinkTvModel-isOnline: {}", json.toString());
|
||||
if (json.has(KEY_MEDIA)) {
|
||||
JSONObject media = json.getJSONObject(KEY_MEDIA);
|
||||
boolean isLive = media.optBoolean("isLive");
|
||||
|
@ -71,15 +72,16 @@ public class WinkTvModel extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public State getOnlineState(boolean failFast) throws IOException, ExecutionException {
|
||||
if (!failFast || onlineState == UNKNOWN || onlineState == UNCHECKED) {
|
||||
try {
|
||||
onlineState = isOnline(true) ? ONLINE : OFFLINE;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
onlineState = OFFLINE;
|
||||
} catch (IOException | ExecutionException e) {
|
||||
onlineState = OFFLINE;
|
||||
}
|
||||
if (failFast && onlineState != UNKNOWN) {
|
||||
return onlineState;
|
||||
}
|
||||
try {
|
||||
onlineState = isOnline(true) ? ONLINE : OFFLINE;
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
onlineState = OFFLINE;
|
||||
} catch (IOException | ExecutionException e) {
|
||||
onlineState = OFFLINE;
|
||||
}
|
||||
return onlineState;
|
||||
}
|
||||
|
@ -98,8 +100,12 @@ public class WinkTvModel extends AbstractModel {
|
|||
if (playlist.hasStreamInfo()) {
|
||||
StreamSource src = new StreamSource();
|
||||
src.setBandwidth(playlist.getStreamInfo().getBandwidth());
|
||||
src.setHeight(playlist.getStreamInfo().getResolution().height);
|
||||
src.setWidth(playlist.getStreamInfo().getResolution().width);
|
||||
src.setHeight(Optional.ofNullable(playlist.getStreamInfo().getResolution())
|
||||
.map(res -> res.height)
|
||||
.orElse(0));
|
||||
src.setWidth(Optional.ofNullable(playlist.getStreamInfo().getResolution())
|
||||
.map(res -> res.width)
|
||||
.orElse(0));
|
||||
src.setMediaPlaylistUrl(playlist.getUri());
|
||||
log.trace("Media playlist {}", src.getMediaPlaylistUrl());
|
||||
sources.add(src);
|
||||
|
@ -113,11 +119,17 @@ public class WinkTvModel extends AbstractModel {
|
|||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, "*/*")
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
.header(REFERER, this.getUrl())
|
||||
.header(ORIGIN, this.getSite().getBaseUrl())
|
||||
.build();
|
||||
|
||||
try (Response response = getSite().getHttpClient().execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
String body = response.body().string();
|
||||
InputStream inputStream = new ByteArrayInputStream(body.getBytes(UTF_8));
|
||||
InputStream inputStream = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
|
||||
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8, ParsingMode.LENIENT);
|
||||
Playlist playlist = parser.parse();
|
||||
MasterPlaylist master = playlist.getMasterPlaylist();
|
||||
|
@ -130,36 +142,13 @@ public class WinkTvModel extends AbstractModel {
|
|||
|
||||
private String getMasterPlaylistUrl() throws IOException {
|
||||
JSONObject json = getModelInfo();
|
||||
JSONObject info = json.getJSONObject("bjInfo");
|
||||
long userIdx = info.optLong("idx");
|
||||
String url = "https://api.winktv.co.kr/v1/live/play";
|
||||
FormBody body = new FormBody.Builder()
|
||||
.add("action", "watch")
|
||||
.add("userIdx", String.valueOf(userIdx))
|
||||
.add("password", "")
|
||||
.build();
|
||||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
|
||||
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
|
||||
.header(REFERER, getUrl())
|
||||
.header(ORIGIN, getSite().getBaseUrl())
|
||||
.post(body)
|
||||
.build();
|
||||
try (Response response = getSite().getHttpClient().execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
JSONObject jsonResponse = new JSONObject(response.body().string());
|
||||
JSONObject playlist = jsonResponse.getJSONObject("PlayList");
|
||||
JSONObject hls = playlist.getJSONArray("hls").getJSONObject(0);
|
||||
String hlsUrl = hls.optString("url");
|
||||
return hlsUrl;
|
||||
} else {
|
||||
log.debug("Error while get master playlist url for {}: {}", getName(), response.body().string());
|
||||
throw new HttpException(response.code(), response.message());
|
||||
}
|
||||
if (json.has("PlayList")) {
|
||||
JSONObject playlist = json.getJSONObject("PlayList");
|
||||
JSONObject hls = playlist.getJSONArray("hls").getJSONObject(0);
|
||||
String hlsUrl = hls.optString("url") + "&player_version=1.20.0";
|
||||
return hlsUrl;
|
||||
}
|
||||
throw new IOException("Master playlist URL not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -179,18 +168,21 @@ public class WinkTvModel extends AbstractModel {
|
|||
}
|
||||
|
||||
private JSONObject getModelInfo() throws IOException {
|
||||
if (modelInfo == null || Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) {
|
||||
lastInfoRequest = Instant.now();
|
||||
modelInfo = loadModelInfo();
|
||||
if (Objects.nonNull(modelInfo) && Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5L) {
|
||||
return modelInfo;
|
||||
}
|
||||
lastInfoRequest = Instant.now();
|
||||
modelInfo = loadModelInfo();
|
||||
return modelInfo;
|
||||
}
|
||||
|
||||
private JSONObject loadModelInfo() throws IOException {
|
||||
String url = "https://api.winktv.co.kr/v1/member/bj";
|
||||
String url = "https://api.winktv.co.kr/v1/live/play";
|
||||
FormBody body = new FormBody.Builder()
|
||||
.add("userId", getName())
|
||||
.add("info", KEY_MEDIA)
|
||||
.add("action", "watch")
|
||||
.add("password", "")
|
||||
.add("shareLinkType", "")
|
||||
.build();
|
||||
Request req = new Request.Builder()
|
||||
.url(url)
|
||||
|
@ -205,6 +197,7 @@ public class WinkTvModel extends AbstractModel {
|
|||
try (Response response = getSite().getHttpClient().execute(req)) {
|
||||
if (response.isSuccessful()) {
|
||||
JSONObject jsonResponse = new JSONObject(response.body().string());
|
||||
log.debug("WinkTvModel-loadModelInfo: {}", jsonResponse.toString());
|
||||
return jsonResponse;
|
||||
} else {
|
||||
throw new HttpException(response.code(), response.message());
|
||||
|
@ -212,6 +205,19 @@ public class WinkTvModel extends AbstractModel {
|
|||
}
|
||||
}
|
||||
|
||||
public String getPreviewURL() throws IOException {
|
||||
JSONObject json = this.getModelInfo();
|
||||
if (json.has("media")) {
|
||||
JSONObject media = json.getJSONObject("media");
|
||||
return media.optString("ivsThumbnail");
|
||||
}
|
||||
if (json.has("bjInfo")) {
|
||||
JSONObject info = json.getJSONObject("bjInfo");
|
||||
return info.optString("thumbUrl");
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean follow() throws IOException {
|
||||
return false;
|
||||
|
@ -222,6 +228,14 @@ public class WinkTvModel extends AbstractModel {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean isAdult() {
|
||||
return adult;
|
||||
}
|
||||
|
||||
public void setAdult(boolean a) {
|
||||
adult = a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveTip(Double tokens) throws IOException {
|
||||
// not implemented
|
||||
|
@ -236,6 +250,9 @@ public class WinkTvModel extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public RecordingProcess createDownload() {
|
||||
return new MergedFfmpegHlsDownload(getSite().getHttpClient());
|
||||
if (Config.getInstance().getSettings().useHlsdl) {
|
||||
return new HlsdlDownload();
|
||||
}
|
||||
return new MergedFfmpegHlsDownload(new WinkTvHttpClient(Config.getInstance()));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue