Fix WinkTV browsing

This commit is contained in:
0xb00bface 2023-11-05 13:53:30 +01:00
parent 03dd723fb6
commit 970b2ab14e
3 changed files with 48 additions and 86 deletions

View File

@ -2,7 +2,6 @@ package ctbrec.ui.sites.winktv;
import ctbrec.sites.winktv.WinkTv;
import ctbrec.sites.winktv.WinkTvModel;
import ctbrec.ui.sites.AbstractTabProvider;
import ctbrec.ui.tabs.ThumbOverviewTab;
import javafx.scene.Scene;
@ -10,7 +9,6 @@ import javafx.scene.control.Tab;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
public class WinkTvTabProvider extends AbstractTabProvider {
@ -22,7 +20,9 @@ public class WinkTvTabProvider extends AbstractTabProvider {
@Override
protected List<Tab> getSiteTabs(Scene scene) {
List<Tab> tabs = new ArrayList<>();
tabs.add(createTab("Live", m -> !m.isAdult()));
tabs.add(createTab("Live", Predicate.not(WinkTvModel::isAdult)));
// adult streams are only available with korean age verification, you have to be logged in
//tabs.add(createTab("Adult", WinkTvModel::isAdult));
return tabs;
}

View File

@ -1,43 +1,32 @@
package ctbrec.ui.sites.winktv;
import static ctbrec.io.HttpConstants.*;
import ctbrec.Config;
import ctbrec.Model;
import ctbrec.io.HttpException;
import ctbrec.sites.winktv.WinkTv;
import ctbrec.sites.winktv.WinkTvModel;
import ctbrec.ui.SiteUiFactory;
import ctbrec.ui.tabs.PaginatedScheduledService;
import java.io.IOException;
import java.text.MessageFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javafx.concurrent.Task;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.function.Predicate;
import static ctbrec.io.HttpConstants.*;
@Slf4j
public class WinkTvUpdateService extends PaginatedScheduledService {
private static final Logger LOG = LoggerFactory.getLogger(WinkTvUpdateService.class);
private static final String API_URL = "https://api.winktv.co.kr/v1/live";
private WinkTv site;
private String url;
private static List<WinkTvModel> modelsList;
private static Instant lastListInfoRequest = Instant.EPOCH;
private final WinkTv site;
protected int modelsPerPage = 48;
protected Predicate<WinkTvModel> filter;
@ -48,54 +37,46 @@ public class WinkTvUpdateService extends PaginatedScheduledService {
@Override
protected Task<List<Model>> createTask() {
return new Task<List<Model>>() {
return new Task<>() {
@Override
public List<Model> call() throws IOException {
return getModelList().stream()
return loadModelList()
.stream()
.filter(filter)
.skip((page - 1) * (long) modelsPerPage)
.limit(modelsPerPage)
.collect(Collectors.toList()); // NOSONAR
.map(Model.class::cast)
.toList();
}
};
}
private List<WinkTvModel> getModelList() throws IOException {
if (Duration.between(lastListInfoRequest, Instant.now()).getSeconds() < 30) {
return Optional.ofNullable(modelsList).orElse(loadModelList());
}
modelsList = loadModelList();
return Optional.ofNullable(modelsList).orElse(Collections.emptyList());
}
private List<WinkTvModel> loadModelList() throws IOException {
LOG.debug("Fetching page {}", API_URL);
lastListInfoRequest = Instant.now();
int offset = (page - 1) * modelsPerPage;
log.debug("Fetching page {} offset:{}, limit:{}", API_URL, offset, modelsPerPage);
FormBody body = new FormBody.Builder()
.add("offset", "0")
.add("limit", "500")
.add("offset", String.valueOf(offset))
.add("limit", String.valueOf(modelsPerPage))
.add("orderBy", "hot")
.add("onlyNewBj", "N")
.build();
Request req = new Request.Builder()
.url(API_URL)
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
.header(ACCEPT, "*/*")
.header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
.header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
.header(REFERER, site.getBaseUrl() + "/")
.header(ORIGIN, site.getBaseUrl())
.post(body)
.build();
try (var response = site.getHttpClient().execute(req)) {
if (response.isSuccessful()) {
List<WinkTvModel> models = new ArrayList<>();
List<WinkTvModel> result = new ArrayList<>();
var content = response.body().string();
var json = new JSONObject(content);
if (json.optBoolean("result")) {
var modelNodes = json.getJSONArray("list");
parseModels(modelNodes, models);
parseModels(modelNodes, result);
}
return models;
return result;
} else {
throw new HttpException(response.code(), response.message());
}
@ -106,9 +87,9 @@ public class WinkTvUpdateService extends PaginatedScheduledService {
for (var i = 0; i < jsonModels.length(); i++) {
var m = jsonModels.getJSONObject(i);
String name = m.optString("userId");
WinkTvModel model = (WinkTvModel) site.createModel(name);
WinkTvModel model = site.createModel(name);
model.setDisplayName(m.getString("userNick"));
boolean isAdult = m.optBoolean("isAdult");
boolean isAdult = m.optBoolean("isAdult");
model.setAdult(isAdult);
if (isAdult && m.has("ivsThumbnail")) {
model.setPreview(m.optString("ivsThumbnail"));
@ -119,9 +100,9 @@ public class WinkTvUpdateService extends PaginatedScheduledService {
if (isLive) models.add(model);
}
}
public void setFilter(Predicate<WinkTvModel> filter) {
this.filter = filter;
}
}

View File

@ -10,12 +10,13 @@ import ctbrec.io.HttpException;
import ctbrec.recorder.download.RecordingProcess;
import ctbrec.recorder.download.StreamSource;
import ctbrec.recorder.download.hls.MergedFfmpegHlsDownload;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.Request;
import okhttp3.Response;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@ -25,19 +26,21 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
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;
@Slf4j
public class WinkTvModel extends AbstractModel {
private static final Logger LOG = LoggerFactory.getLogger(WinkTvModel.class);
private int[] resolution = new int[]{0, 0};
@Getter
@Setter
private boolean adult = false;
private JSONObject modelInfo;
private transient JSONObject modelInfo;
private transient Instant lastInfoRequest = Instant.EPOCH;
@ -98,7 +101,7 @@ public class WinkTvModel extends AbstractModel {
src.bandwidth = playlist.getStreamInfo().getBandwidth();
src.height = playlist.getStreamInfo().getResolution().height;
src.mediaPlaylistUrl = playlist.getUri();
LOG.trace("Media playlist {}", src.mediaPlaylistUrl);
log.trace("Media playlist {}", src.mediaPlaylistUrl);
sources.add(src);
}
}
@ -106,7 +109,7 @@ public class WinkTvModel extends AbstractModel {
}
private MasterPlaylist getMasterPlaylist(String url) throws IOException, ParseException, PlaylistException {
LOG.trace("Loading master playlist {}", url);
log.trace("Loading master playlist {}", url);
Request req = new Request.Builder()
.url(url)
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
@ -153,7 +156,7 @@ public class WinkTvModel extends AbstractModel {
String hlsUrl = hls.optString("url");
return hlsUrl;
} else {
LOG.debug("Error while get master playlist url for {}: {}", getName(), response.body().string());
log.debug("Error while get master playlist url for {}: {}", getName(), response.body().string());
throw new HttpException(response.code(), response.message());
}
}
@ -176,11 +179,10 @@ public class WinkTvModel extends AbstractModel {
}
private JSONObject getModelInfo() throws IOException {
if (Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) {
return Optional.ofNullable(modelInfo).orElse(new JSONObject());
if (modelInfo == null || Duration.between(lastInfoRequest, Instant.now()).getSeconds() < 5) {
lastInfoRequest = Instant.now();
modelInfo = loadModelInfo();
}
lastInfoRequest = Instant.now();
modelInfo = loadModelInfo();
return modelInfo;
}
@ -210,19 +212,6 @@ public class WinkTvModel extends AbstractModel {
}
}
public String getPreviewURL() throws IOException {
JSONObject json = 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;
@ -233,14 +222,6 @@ public class WinkTvModel extends AbstractModel {
return false;
}
public boolean isAdult() {
return adult;
}
public void setAdult(boolean a) {
this.adult = a;
}
@Override
public void receiveTip(Double tokens) throws IOException {
// not implemented