package ctbrec.ui.sites.camsoda; import ctbrec.Model; import ctbrec.StringUtil; import ctbrec.io.HttpException; import ctbrec.sites.camsoda.Camsoda; import ctbrec.sites.camsoda.CamsodaModel; import ctbrec.ui.SiteUiFactory; import ctbrec.ui.tabs.PaginatedScheduledService; import javafx.concurrent.Task; 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.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; import static ctbrec.ErrorMessages.HTTP_RESPONSE_BODY_IS_NULL; import static ctbrec.Model.State.OFFLINE; import static ctbrec.Model.State.ONLINE; 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 Predicate filter; public CamsodaUpdateService(String url, boolean loginRequired, Camsoda camsoda, Predicate filter) { this.url = url; this.loginRequired = loginRequired; this.camsoda = camsoda; this.filter = filter; } @Override protected Task> createTask() { return new Task<>() { @Override public List call() throws IOException { return loadOnlineModels().stream() .sorted((m1, m2) -> (int) (m2.getSortOrder() - m1.getSortOrder())) .filter(filter) .skip((page - 1) * (long) modelsPerPage) .limit(modelsPerPage) .collect(Collectors.toList()); // NOSONAR } }; } protected List loadOnlineModels() throws IOException { if (loginRequired && StringUtil.isBlank(ctbrec.Config.getInstance().getSettings().camsodaUsername)) { return Collections.emptyList(); } else { LOG.debug("Fetching page {}", url); if (loginRequired) { SiteUiFactory.getUi(camsoda).login(); } var request = new Request.Builder().url(url).build(); try (var response = camsoda.getHttpClient().execute(request)) { if (response.isSuccessful()) { return parseModels(Objects.requireNonNull(response.body(), HTTP_RESPONSE_BODY_IS_NULL).string()); } else { throw new HttpException(response.code(), response.message()); } } } } protected List parseModels(String body) { List models = new ArrayList<>(); var json = new JSONObject(body); var template = json.getJSONArray("template"); var results = json.getJSONArray("results"); for (var i = 0; i < results.length(); i++) { var result = results.getJSONObject(i); var templateObject = result.get("tpl"); try { if (templateObject instanceof JSONObject) { parseModelFromObject(result, templateObject, template, models); } else if (templateObject instanceof JSONArray) { parseModelFromArray(templateObject, template, models); } } catch (Exception e) { LOG.warn("Couldn't parse one of the models: {}", result, e); } } return models; } private void parseModelFromArray(Object templateObject, JSONArray template, List 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"))); var preview = tpl.getString(getTemplateIndex(template, "thumb")); if (preview.startsWith("//")) { preview = "https:" + preview; } model.setPreview(preview); LOG.info("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]", "")); if (model.getDisplayName().isBlank()) { model.setDisplayName(name); } models.add(model); } private void parseModelFromObject(JSONObject result, Object templateObject, JSONArray template, List models) { var tpl = (JSONObject) templateObject; var name = tpl.getString(Integer.toString(getTemplateIndex(template, "username"))); CamsodaModel model = (CamsodaModel) camsoda.createModel(name); 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.setGender(tpl.getString(Integer.toString(getTemplateIndex(template, "gender")))); var preview = tpl.getString(Integer.toString(getTemplateIndex(template, "thumb"))); if (preview.startsWith("//")) { preview = "https:" + preview; } model.setPreview(preview); var displayName = tpl.getString(Integer.toString(getTemplateIndex(template, "display_name"))); model.setDisplayName(displayName.replaceAll("[^a-zA-Z0-9]", "")); if (model.getDisplayName().isBlank()) { model.setDisplayName(name); } model.setOnlineState(tpl.getString(Integer.toString(getTemplateIndex(template, "stream_name"))).isEmpty() ? OFFLINE : ONLINE); parseStatus(template, tpl, model); models.add(model); } private void parseStatus(JSONArray template, JSONObject tpl, CamsodaModel model) { try { var statusIndex = Integer.toString(getTemplateIndex(template, "status")); if (tpl.has(statusIndex)) { model.setOnlineStateByStatus(tpl.getString(statusIndex)); } } catch (NoSuchElementException e) { // that's ok } } private int getTemplateIndex(JSONArray template, String string) { for (var i = 0; i < template.length(); i++) { var s = template.getString(i); if (Objects.equals(s, string)) { return i; } } throw new NoSuchElementException(string + " not found in template: " + template); } public void setFilter(Predicate filter) { this.filter = filter; } }