Added Voyeur tab for Camsoda
This commit is contained in:
parent
9da5eb2eb4
commit
81f641b777
|
@ -12,6 +12,8 @@
|
|||
* Changes by @WinkRU
|
||||
* Added setting to restrict recording by bit rate
|
||||
* Added setting to use the shortest side to restrict the resolution
|
||||
* Cam4: Fixed stream URLs search. Slightly increased chances to find good one.
|
||||
* Camsoda: Added "Voyeur" tab
|
||||
* Chaturbate: Added "Gaming" tab
|
||||
* Streamate:
|
||||
- Fixed "Couldn't load model ID" error while adding models by URL or by
|
||||
|
@ -19,7 +21,6 @@
|
|||
- Online/Offline switch on all tabs. Up to 10 000 offline models in each
|
||||
category. How do you like it, Elon Musk?
|
||||
- Added "New Girls" tab and adjusted others. All same models on less tabs.
|
||||
* Cam4: Fixed stream URLs search. Slightly increased chances to find good one.
|
||||
|
||||
5.2.3
|
||||
========================
|
||||
|
|
|
@ -33,6 +33,7 @@ public class CamsodaTabProvider extends AbstractTabProvider {
|
|||
tabs.add(createTab("Male", API_URL, m -> Objects.equals("m", m.getGender())));
|
||||
tabs.add(createTab("Couples", API_URL, m -> Objects.equals("c", m.getGender())));
|
||||
tabs.add(createTab("Trans", API_URL, m -> Objects.equals("t", m.getGender())));
|
||||
tabs.add(createTab("Voyeur", API_URL, CamsodaModel::isVoyeur));
|
||||
followedTab.setRecorder(recorder);
|
||||
followedTab.setScene(scene);
|
||||
tabs.add(followedTab);
|
||||
|
|
|
@ -8,13 +8,15 @@ import ctbrec.sites.camsoda.CamsodaModel;
|
|||
import ctbrec.ui.SiteUiFactory;
|
||||
import ctbrec.ui.tabs.PaginatedScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import okhttp3.Request;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -23,15 +25,16 @@ import static ctbrec.ErrorMessages.HTTP_RESPONSE_BODY_IS_NULL;
|
|||
import static ctbrec.Model.State.OFFLINE;
|
||||
import static ctbrec.Model.State.ONLINE;
|
||||
|
||||
@Slf4j
|
||||
public class CamsodaUpdateService extends PaginatedScheduledService {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CamsodaUpdateService.class);
|
||||
|
||||
protected final String url;
|
||||
protected final boolean loginRequired;
|
||||
protected final Camsoda camsoda;
|
||||
protected int modelsPerPage = 50;
|
||||
|
||||
protected int modelsPerPage = 60;
|
||||
private static List<CamsodaModel> modelsList;
|
||||
private static Instant lastListInfoRequest = Instant.EPOCH;
|
||||
@Setter
|
||||
protected Predicate<CamsodaModel> filter;
|
||||
|
||||
public CamsodaUpdateService(String url, boolean loginRequired, Camsoda camsoda, Predicate<CamsodaModel> filter) {
|
||||
|
@ -46,7 +49,7 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
|||
return new Task<>() {
|
||||
@Override
|
||||
public List<Model> call() throws IOException {
|
||||
return loadOnlineModels().stream()
|
||||
return getModelList().stream()
|
||||
.sorted((m1, m2) -> (int) (m2.getSortOrder() - m1.getSortOrder()))
|
||||
.filter(filter)
|
||||
.skip((page - 1) * (long) modelsPerPage)
|
||||
|
@ -56,11 +59,20 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
|||
};
|
||||
}
|
||||
|
||||
private List<CamsodaModel> getModelList() throws IOException {
|
||||
if (Objects.nonNull(modelsList) && Duration.between(lastListInfoRequest, Instant.now()).getSeconds() < 30) {
|
||||
return modelsList;
|
||||
}
|
||||
lastListInfoRequest = Instant.now();
|
||||
modelsList = loadOnlineModels();
|
||||
return Optional.ofNullable(modelsList).orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
protected List<CamsodaModel> loadOnlineModels() throws IOException {
|
||||
if (loginRequired && StringUtil.isBlank(ctbrec.Config.getInstance().getSettings().camsodaUsername)) {
|
||||
return Collections.emptyList();
|
||||
} else {
|
||||
LOG.debug("Fetching page {}", url);
|
||||
log.debug("Fetching page {}", url);
|
||||
if (loginRequired) {
|
||||
SiteUiFactory.getUi(camsoda).login();
|
||||
}
|
||||
|
@ -87,27 +99,29 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
|||
if (templateObject instanceof JSONObject) {
|
||||
parseModelFromObject(result, templateObject, template, models);
|
||||
} else if (templateObject instanceof JSONArray) {
|
||||
parseModelFromArray(templateObject, template, models);
|
||||
parseModelFromArray(result, templateObject, template, models);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Couldn't parse one of the models: {}", result, e);
|
||||
log.warn("Couldn't parse one of the models: {}", result, e);
|
||||
}
|
||||
}
|
||||
return models;
|
||||
}
|
||||
|
||||
private void parseModelFromArray(Object templateObject, JSONArray template, List<CamsodaModel> models) {
|
||||
private void parseModelFromArray(JSONObject result, Object templateObject, JSONArray template, List<CamsodaModel> models) {
|
||||
var tpl = (JSONArray) templateObject;
|
||||
var name = tpl.getString(getTemplateIndex(template, "username"));
|
||||
CamsodaModel model = (CamsodaModel) camsoda.createModel(name);
|
||||
model.setSortOrder(tpl.getFloat(getTemplateIndex(template, "sort_value")));
|
||||
model.setDescription(tpl.getString(getTemplateIndex(template, "subject_html")));
|
||||
model.setNew(result.optBoolean("new"));
|
||||
model.setVoyeur(result.optBoolean("voyeur"));
|
||||
var preview = tpl.getString(getTemplateIndex(template, "thumb"));
|
||||
if (preview.startsWith("//")) {
|
||||
preview = "https:" + preview;
|
||||
}
|
||||
model.setPreview(preview);
|
||||
LOG.trace("Preview: {}", preview);
|
||||
log.trace("Preview: {}", preview);
|
||||
model.setOnlineStateByStatus(tpl.getString(getTemplateIndex(template, "status")));
|
||||
var displayName = tpl.getString(getTemplateIndex(template, "display_name"));
|
||||
model.setDisplayName(displayName.replaceAll("[^a-zA-Z0-9]", ""));
|
||||
|
@ -124,6 +138,7 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
|||
model.setDescription(tpl.getString(Integer.toString(getTemplateIndex(template, "subject_html"))));
|
||||
model.setSortOrder(tpl.getFloat(Integer.toString(getTemplateIndex(template, "sort_value"))));
|
||||
model.setNew(result.optBoolean("new"));
|
||||
model.setVoyeur(result.optBoolean("voyeur"));
|
||||
model.setGender(tpl.getString(Integer.toString(getTemplateIndex(template, "gender"))));
|
||||
var preview = tpl.getString(Integer.toString(getTemplateIndex(template, "thumb")));
|
||||
if (preview.startsWith("//")) {
|
||||
|
@ -160,8 +175,4 @@ public class CamsodaUpdateService extends PaginatedScheduledService {
|
|||
}
|
||||
throw new NoSuchElementException(string + " not found in template: " + template);
|
||||
}
|
||||
|
||||
public void setFilter(Predicate<CamsodaModel> filter) {
|
||||
this.filter = filter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.iheartradio.m3u8.data.PlaylistData;
|
|||
import com.iheartradio.m3u8.data.StreamInfo;
|
||||
import ctbrec.AbstractModel;
|
||||
import ctbrec.Config;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.io.HttpException;
|
||||
import ctbrec.recorder.download.StreamSource;
|
||||
import lombok.Getter;
|
||||
|
@ -21,6 +22,7 @@ import org.json.JSONObject;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
|
@ -40,6 +42,9 @@ public class CamsodaModel extends AbstractModel {
|
|||
private transient String gender;
|
||||
@Getter
|
||||
@Setter
|
||||
private transient boolean isVoyeur;
|
||||
@Getter
|
||||
@Setter
|
||||
private float sortOrder = 0;
|
||||
private final Random random = new Random();
|
||||
int[] resolution = new int[2];
|
||||
|
@ -166,6 +171,9 @@ public class CamsodaModel extends AbstractModel {
|
|||
JSONObject chat = result.getJSONObject("chat");
|
||||
String status = chat.getString(STATUS);
|
||||
setOnlineStateByStatus(status);
|
||||
if (onlineState == OFFLINE) {
|
||||
setLastSeen(chat.optString("lastOnlineAt"));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
throw new IOException("Couldn't parse body as JSON:\n" + body, e);
|
||||
}
|
||||
|
@ -203,6 +211,16 @@ public class CamsodaModel extends AbstractModel {
|
|||
return onlineState;
|
||||
}
|
||||
|
||||
private void setLastSeen(String date) {
|
||||
try {
|
||||
if (StringUtil.isNotBlank(date)) {
|
||||
setLastSeen(Instant.parse(date.replace("+0000", ".00Z")));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// fail silently
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCacheEntries() {
|
||||
streamSources = null;
|
||||
|
@ -219,7 +237,7 @@ public class CamsodaModel extends AbstractModel {
|
|||
if (sources.isEmpty()) {
|
||||
return new int[]{0, 0};
|
||||
} else {
|
||||
StreamSource src = sources.get(sources.size() - 1);
|
||||
StreamSource src = sources.getLast();
|
||||
resolution = new int[]{src.getWidth(), src.getHeight()};
|
||||
return resolution;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue