diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java index c59708fe..bbac61ce 100644 --- a/client/src/main/java/ctbrec/ui/CamrecApplication.java +++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java @@ -1,5 +1,8 @@ package ctbrec.ui; +import static ctbrec.EventBusHolder.*; +import static ctbrec.EventBusHolder.EVENT_TYPE.*; + import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; @@ -69,6 +72,7 @@ public class CamrecApplication extends Application { public void start(Stage primaryStage) throws Exception { this.primaryStage = primaryStage; logEnvironment(); + registerAlertSystem(); sites.add(new BongaCams()); sites.add(new Cam4()); sites.add(new Camsoda()); @@ -91,7 +95,6 @@ public class CamrecApplication extends Application { createGui(primaryStage); checkForUpdates(); - registerAlertSystem(); } private void logEnvironment() { @@ -203,15 +206,14 @@ public class CamrecApplication extends Application { private void registerAlertSystem() { new Thread(() -> { - try { - // don't register before 1 minute has passed, because directly after - // the start of ctbrec, an event for every online model would be fired, - // which is annoying as f - //Thread.sleep(TimeUnit.MINUTES.toMillis(1)); - Thread.sleep(1); - } catch (InterruptedException e) { - e.printStackTrace(); - } + // try { + // // don't register before 1 minute has passed, because directly after + // // the start of ctbrec, an event for every online model would be fired, + // // which is annoying as f + // Thread.sleep(TimeUnit.MINUTES.toMillis(1)); + // } catch (InterruptedException e) { + // e.printStackTrace(); + // } LOG.debug("Alert System registered"); Platform.runLater(() -> { EventBusHolder.BUS.register(new Object() { @@ -219,10 +221,10 @@ public class CamrecApplication extends Application { public void modelEvent(Map e) { LOG.debug("Alert: {}", e); try { - if (Objects.equals("model.status", e.get("event"))) { - String status = (String) e.get("status"); - Model model = (Model) e.get("model"); - if (Objects.equals("online", status)) { + if (Objects.equals(e.get(EVENT), MODEL_STATUS_CHANGED)) { + Model.STATUS status = (Model.STATUS) e.get(STATUS); + Model model = (Model) e.get(MODEL); + if (Objects.equals(Model.STATUS.ONLINE, status)) { Platform.runLater(() -> { String header = "Model Online"; String msg = model.getDisplayName() + " is now online"; diff --git a/client/src/main/java/ctbrec/ui/JavaFxRecording.java b/client/src/main/java/ctbrec/ui/JavaFxRecording.java index e44f36c0..74926de8 100644 --- a/client/src/main/java/ctbrec/ui/JavaFxRecording.java +++ b/client/src/main/java/ctbrec/ui/JavaFxRecording.java @@ -67,8 +67,14 @@ public class JavaFxRecording extends Recording { case DOWNLOADING: statusProperty.set("downloading"); break; - case MERGING: - statusProperty.set("merging"); + case POST_PROCESSING: + statusProperty.set("post-processing"); + break; + case STOPPED: + statusProperty.set("stopped"); + break; + case UNKNOWN: + statusProperty.set("unknown"); break; } } diff --git a/client/src/main/java/ctbrec/ui/RecordedModelsTab.java b/client/src/main/java/ctbrec/ui/RecordedModelsTab.java index f636b424..878c8d00 100644 --- a/client/src/main/java/ctbrec/ui/RecordedModelsTab.java +++ b/client/src/main/java/ctbrec/ui/RecordedModelsTab.java @@ -3,6 +3,7 @@ package ctbrec.ui; import java.io.IOException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -296,13 +297,13 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { massEdit(models, action); } - private void massEdit(List models, Consumer action) { - getTabPane().setCursor(Cursor.WAIT); + private void massEdit(List models, Consumer action) { + table.setCursor(Cursor.WAIT); threadPool.submit(() -> { for (Model model : models) { action.accept(model); } - Platform.runLater(() -> getTabPane().setCursor(Cursor.DEFAULT)); + Platform.runLater(() -> table.setCursor(Cursor.DEFAULT)); }); } @@ -443,6 +444,8 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { openInPlayer.setOnAction((e) -> openInPlayer(selectedModels.get(0))); MenuItem switchStreamSource = new MenuItem("Switch resolution"); switchStreamSource.setOnAction((e) -> switchStreamSource(selectedModels.get(0))); + MenuItem follow = new MenuItem("Follow"); + follow.setOnAction((e) -> follow(selectedModels)); ContextMenu menu = new ContextMenu(stop); if (selectedModels.size() == 1) { @@ -450,7 +453,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { } else { menu.getItems().addAll(resumeRecording, pauseRecording); } - menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, switchStreamSource); + menu.getItems().addAll(copyUrl, openInPlayer, openInBrowser, switchStreamSource, follow); if (selectedModels.size() > 1) { copyUrl.setDisable(true); @@ -462,6 +465,19 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { return menu; } + private void follow(ObservableList selectedModels) { + Consumer action = (m) -> { + try { + m.follow(); + } catch(Throwable e) { + LOG.error("Couldn't follow model {}", m, e); + Platform.runLater(() -> + showErrorDialog(e, "Couldn't follow model", "Following " + m.getName() + " failed: " + e.getMessage())); + } + }; + massEdit(new ArrayList(selectedModels), action); + } + private void openInPlayer(JavaFxModel selectedModel) { table.setCursor(Cursor.WAIT); new Thread(() -> { diff --git a/client/src/main/java/ctbrec/ui/StreamSourceSelectionDialog.java b/client/src/main/java/ctbrec/ui/StreamSourceSelectionDialog.java index 2347493b..2ff98c50 100644 --- a/client/src/main/java/ctbrec/ui/StreamSourceSelectionDialog.java +++ b/client/src/main/java/ctbrec/ui/StreamSourceSelectionDialog.java @@ -25,7 +25,8 @@ public class StreamSourceSelectionDialog { List sources; try { sources = selectStreamSource.get(); - ChoiceDialog choiceDialog = new ChoiceDialog(sources.get(sources.size()-1), sources); + int selectedIndex = model.getStreamUrlIndex() > -1 ? Math.min(model.getStreamUrlIndex(), sources.size()-1) : sources.size()-1; + ChoiceDialog choiceDialog = new ChoiceDialog(sources.get(selectedIndex), sources); choiceDialog.setTitle("Stream Quality"); choiceDialog.setHeaderText("Select your preferred stream quality"); choiceDialog.setResizable(true); diff --git a/client/src/main/java/ctbrec/ui/ThumbCell.java b/client/src/main/java/ctbrec/ui/ThumbCell.java index ece9efce..5e9bdb16 100644 --- a/client/src/main/java/ctbrec/ui/ThumbCell.java +++ b/client/src/main/java/ctbrec/ui/ThumbCell.java @@ -7,11 +7,14 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import com.iheartradio.m3u8.ParseException; import ctbrec.Config; @@ -80,6 +83,10 @@ public class ThumbCell extends StackPane { private boolean mouseHovering = false; private boolean recording = false; private static ExecutorService imageLoadingThreadPool = Executors.newFixedThreadPool(30); + private static Cache resolutionCache = CacheBuilder.newBuilder() + .expireAfterAccess(4, TimeUnit.HOURS) + .maximumSize(1000) + .build(); public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder) { this.thumbCellList = parent.grid.getChildren(); @@ -212,35 +219,45 @@ public class ThumbCell extends StackPane { return; } - ThumbOverviewTab.threadPool.submit(() -> { + int[] resolution = resolutionCache.getIfPresent(model); + if(resolution != null) { try { - ThumbOverviewTab.resolutionProcessing.add(model); - int[] resolution = model.getStreamResolution(false); updateResolutionTag(resolution); - - // the model is online, but the resolution is 0. probably something went wrong - // when we first requested the stream info, so we remove this invalid value from the "cache" - // so that it is requested again - if (model.isOnline() && resolution[1] == 0) { - LOG.trace("Removing invalid resolution value for {}", model.getName()); - model.invalidateCacheEntries(); - } - - Thread.sleep(500); - } catch (IOException | InterruptedException e1) { - LOG.warn("Couldn't update resolution tag for model {}", model.getName(), e1); - } catch(ExecutionException e) { - if(e.getCause() instanceof EOFException) { - LOG.warn("Couldn't update resolution tag for model {}. Playlist empty", model.getName()); - } else if(e.getCause() instanceof ParseException) { - LOG.warn("Couldn't update resolution tag for model {} - {}", model.getName(), e.getMessage()); - } else { - LOG.warn("Couldn't update resolution tag for model {}", model.getName(), e); - } - } finally { - ThumbOverviewTab.resolutionProcessing.remove(model); + } catch(Exception e) { + LOG.warn("Couldn't update resolution tag for model {}", model.getName(), e); } - }); + } else { + ThumbOverviewTab.threadPool.submit(() -> { + try { + ThumbOverviewTab.resolutionProcessing.add(model); + int[] _resolution = model.getStreamResolution(false); + resolutionCache.put(model, _resolution); + updateResolutionTag(_resolution); + + // the model is online, but the resolution is 0. probably something went wrong + // when we first requested the stream info, so we remove this invalid value from the "cache" + // so that it is requested again + if (model.isOnline() && _resolution[1] == 0) { + LOG.trace("Removing invalid resolution value for {}", model.getName()); + model.invalidateCacheEntries(); + } + + Thread.sleep(100); + } catch (IOException | InterruptedException e1) { + LOG.warn("Couldn't update resolution tag for model {}", model.getName(), e1); + } catch(ExecutionException e) { + if(e.getCause() instanceof EOFException) { + LOG.warn("Couldn't update resolution tag for model {}. Playlist empty", model.getName()); + } else if(e.getCause() instanceof ParseException) { + LOG.warn("Couldn't update resolution tag for model {} - {}", model.getName(), e.getMessage()); + } else { + LOG.warn("Couldn't update resolution tag for model {}", model.getName(), e); + } + } finally { + ThumbOverviewTab.resolutionProcessing.remove(model); + } + }); + } } private void updateResolutionTag(int[] resolution) throws IOException, ExecutionException, InterruptedException { @@ -492,7 +509,7 @@ public class ThumbCell extends StackPane { this.model.setPreview(model.getPreview()); this.model.setTags(model.getTags()); this.model.setUrl(model.getUrl()); - this.model.setSuspended(model.isSuspended()); + this.model.setSuspended(recorder.isSuspended(model)); update(); } diff --git a/common/src/main/java/ctbrec/EventBusHolder.java b/common/src/main/java/ctbrec/EventBusHolder.java index aefe499b..d1435407 100644 --- a/common/src/main/java/ctbrec/EventBusHolder.java +++ b/common/src/main/java/ctbrec/EventBusHolder.java @@ -6,5 +6,15 @@ import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; public class EventBusHolder { + + public static final String EVENT = "event"; + public static final String STATUS = "status"; + public static final String MODEL = "model"; + + public static enum EVENT_TYPE { + MODEL_STATUS_CHANGED, + RECORDING_STATUS_CHANGED + } + public static final EventBus BUS = new AsyncEventBus(Executors.newSingleThreadExecutor()); } diff --git a/common/src/main/java/ctbrec/Model.java b/common/src/main/java/ctbrec/Model.java index e13f2fcd..81cf2497 100644 --- a/common/src/main/java/ctbrec/Model.java +++ b/common/src/main/java/ctbrec/Model.java @@ -13,34 +13,92 @@ import ctbrec.recorder.download.StreamSource; import ctbrec.sites.Site; public interface Model { + + public static enum STATUS { + ONLINE("online"), + OFFLINE("offline"), + AWAY("away"), + PRIVATE("private"), + GROUP("group"), + UNKNOWN("unknown"); + + String display; + STATUS(String display) { + this.display = display; + } + + @Override + public String toString() { + return display; + } + } + public String getUrl(); + public void setUrl(String url); + public String getDisplayName(); + public void setDisplayName(String name); + public String getName(); + public void setName(String name); + public String getPreview(); + public void setPreview(String preview); + public List getTags(); + public void setTags(List tags); + public String getDescription(); + public void setDescription(String description); + public int getStreamUrlIndex(); + public void setStreamUrlIndex(int streamUrlIndex); + public boolean isOnline() throws IOException, ExecutionException, InterruptedException; + public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException; + public String getOnlineState(boolean failFast) throws IOException, ExecutionException; + public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException; + public void invalidateCacheEntries(); + public void receiveTip(int tokens) throws IOException; + + /** + * Determines the stream resolution for this model + * + * @param failFast + * If set to true, the method returns emmediately, even if the resolution is unknown. If + * the resolution is unknown, the array contains 0,0 + * + * @return a tupel of width and height represented by an int[2] + * @throws ExecutionException + */ public int[] getStreamResolution(boolean failFast) throws ExecutionException; + public boolean follow() throws IOException; + public boolean unfollow() throws IOException; + public void setSite(Site site); + public Site getSite(); + public void writeSiteSpecificData(JsonWriter writer) throws IOException; + public void readSiteSpecificData(JsonReader reader) throws IOException; + public boolean isSuspended(); + public void setSuspended(boolean suspended); } \ No newline at end of file diff --git a/common/src/main/java/ctbrec/Recording.java b/common/src/main/java/ctbrec/Recording.java index 1c9d43b6..cd41386d 100644 --- a/common/src/main/java/ctbrec/Recording.java +++ b/common/src/main/java/ctbrec/Recording.java @@ -10,16 +10,18 @@ public class Recording { private Instant startDate; private String path; private boolean hasPlaylist; - private STATUS status; + private STATUS status = STATUS.UNKNOWN; private int progress = -1; private long sizeInByte; public static enum STATUS { RECORDING, GENERATING_PLAYLIST, + STOPPED, FINISHED, DOWNLOADING, - MERGING + POST_PROCESSING, + UNKNOWN } public Recording() {} diff --git a/common/src/main/java/ctbrec/recorder/LocalRecorder.java b/common/src/main/java/ctbrec/recorder/LocalRecorder.java index c7f5b897..1efdb1b1 100644 --- a/common/src/main/java/ctbrec/recorder/LocalRecorder.java +++ b/common/src/main/java/ctbrec/recorder/LocalRecorder.java @@ -1,5 +1,7 @@ package ctbrec.recorder; +import static ctbrec.EventBusHolder.*; +import static ctbrec.EventBusHolder.EVENT_TYPE.*; import static ctbrec.Recording.STATUS.*; import java.io.File; @@ -180,7 +182,7 @@ public class LocalRecorder implements Recorder { } } }.start(); - fireRecordingStateChanged(model, true); + fireRecordingStateChanged(model, RECORDING); } private void stopRecordingProcess(Model model) { @@ -190,7 +192,7 @@ public class LocalRecorder implements Recorder { if(!Config.isServerMode()) { postprocess(download); } - fireRecordingStateChanged(model, false); + fireRecordingStateChanged(model, FINISHED); } private void postprocess(Download download) { @@ -371,7 +373,7 @@ public class LocalRecorder implements Recorder { } else { postprocess(d); } - fireRecordingStateChanged(m, false); + fireRecordingStateChanged(m, FINISHED); // TODO fire all the events } } for (Model m : restart) { @@ -438,11 +440,7 @@ public class LocalRecorder implements Recorder { List models = getModelsRecording(); for (Model model : models) { try { - boolean wasOnline = model.isOnline(); boolean isOnline = model.isOnline(IGNORE_CACHE); - if(wasOnline != isOnline) { - fireModelOnlineStateChanged(model, isOnline); - } LOG.trace("Checking online state for {}: {}", model, (isOnline ? "online" : "offline")); if (isOnline && !isSuspended(model) && !recordingProcesses.containsKey(model)) { LOG.info("Model {}'s room back to public", model); @@ -476,23 +474,22 @@ public class LocalRecorder implements Recorder { } LOG.debug(getName() + " terminated"); } - } - private void fireModelOnlineStateChanged(Model model, boolean online) { + private void fireModelOnlineStateChanged(Model model, Model.STATUS status) { Map evt = new HashMap<>(); - evt.put("event", "model.status"); - evt.put("status", online ? "online" : "offline"); - evt.put("model", model); + evt.put(EVENT, MODEL_STATUS_CHANGED); + evt.put(STATUS, status); + evt.put(MODEL, model); EventBusHolder.BUS.post(evt); LOG.debug("Event fired {}", evt); } - private void fireRecordingStateChanged(Model model, boolean recording) { + private void fireRecordingStateChanged(Model model, Recording.STATUS status) { Map evt = new HashMap<>(); - evt.put("event", "recording.status"); - evt.put("status", recording ? "started" : "stopped"); - evt.put("model", model); + evt.put(EVENT, RECORDING_STATUS_CHANGED); + evt.put(STATUS, status); + evt.put(MODEL, model); EventBusHolder.BUS.post(evt); LOG.debug("Event fired {}", evt); } diff --git a/common/src/main/java/ctbrec/recorder/download/StreamSource.java b/common/src/main/java/ctbrec/recorder/download/StreamSource.java index dbb86f03..6044716b 100644 --- a/common/src/main/java/ctbrec/recorder/download/StreamSource.java +++ b/common/src/main/java/ctbrec/recorder/download/StreamSource.java @@ -44,7 +44,11 @@ public class StreamSource implements Comparable { public String toString() { DecimalFormat df = new DecimalFormat("0.00"); float mbit = bandwidth / 1024.0f / 1024.0f; - return height + "p (" + df.format(mbit) + " Mbit/s)"; + if(height == Integer.MAX_VALUE) { + return "unknown resolution (" + df.format(mbit) + " Mbit/s)"; + } else { + return height + "p (" + df.format(mbit) + " Mbit/s)"; + } } /** diff --git a/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java b/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java index 95686b19..9381b9ad 100644 --- a/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java +++ b/common/src/main/java/ctbrec/sites/cam4/Cam4Model.java @@ -43,11 +43,6 @@ public class Cam4Model extends AbstractModel { private int[] resolution = null; private boolean privateRoom = false; - @Override - public boolean isOnline() throws IOException, ExecutionException, InterruptedException { - return isOnline(false); - } - @Override public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException { if(ignoreCache || onlineState == null) { diff --git a/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java b/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java index b3d03d94..3c938eb4 100644 --- a/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java +++ b/common/src/main/java/ctbrec/sites/camsoda/CamsodaModel.java @@ -6,14 +6,11 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import com.iheartradio.m3u8.Encoding; import com.iheartradio.m3u8.Format; import com.iheartradio.m3u8.ParseException; @@ -41,12 +38,7 @@ public class CamsodaModel extends AbstractModel { private List streamSources = null; private String status = "n/a"; private float sortOrder = 0; - - private static Cache streamResolutionCache = CacheBuilder.newBuilder() - .initialCapacity(10_000) - .maximumSize(10_000) - .expireAfterWrite(30, TimeUnit.MINUTES) - .build(); + int[] resolution = new int[2]; public String getStreamUrl() throws IOException { if(streamUrl == null) { @@ -139,13 +131,11 @@ public class CamsodaModel extends AbstractModel { @Override public void invalidateCacheEntries() { streamSources = null; - streamResolutionCache.invalidate(getName()); } @Override public int[] getStreamResolution(boolean failFast) throws ExecutionException { - int[] resolution = streamResolutionCache.getIfPresent(getName()); - if(resolution != null) { + if(failFast) { return resolution; } else { if(failFast) { @@ -158,7 +148,6 @@ public class CamsodaModel extends AbstractModel { } else { StreamSource src = streamSources.get(0); resolution = new int[] {src.width, src.height}; - streamResolutionCache.put(getName(), resolution); return resolution; } } catch (IOException | ParseException | PlaylistException e) { diff --git a/common/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java b/common/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java index bd96ad96..56dffb1b 100644 --- a/common/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java +++ b/common/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java @@ -189,17 +189,6 @@ public class Chaturbate extends AbstractSite { } }); - LoadingCache streamResolutionCache = CacheBuilder.newBuilder() - .initialCapacity(10_000) - .maximumSize(10_000) - .expireAfterWrite(5, TimeUnit.MINUTES) - .build(new CacheLoader () { - @Override - public int[] load(String model) throws Exception { - return loadResolution(model); - } - }); - public void sendTip(String name, int tokens) throws IOException { if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) { RequestBody body = new FormBody.Builder() @@ -264,11 +253,9 @@ public class Chaturbate extends AbstractSite { } } - public int[] getResolution(String modelName) throws ExecutionException { - return streamResolutionCache.get(modelName); - } + public int[] getResolution(String modelName) throws ExecutionException, IOException, ParseException, PlaylistException, InterruptedException { + throttleRequests(); - private int[] loadResolution(String modelName) throws IOException, ParseException, PlaylistException, ExecutionException, InterruptedException { int[] res = new int[2]; StreamInfo streamInfo = getStreamInfo(modelName); if(!streamInfo.url.startsWith("http")) { @@ -303,7 +290,6 @@ public class Chaturbate extends AbstractSite { throw ex; } - streamResolutionCache.put(modelName, res); return res; } diff --git a/common/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java b/common/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java index 5ca806c1..5a6acce3 100644 --- a/common/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java +++ b/common/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java @@ -25,6 +25,7 @@ import okhttp3.Response; public class ChaturbateModel extends AbstractModel { private static final transient Logger LOG = LoggerFactory.getLogger(ChaturbateModel.class); + private int[] resolution = new int[2]; /** * This constructor exists only for deserialization. Please don't call it directly @@ -52,16 +53,16 @@ public class ChaturbateModel extends AbstractModel { @Override public int[] getStreamResolution(boolean failFast) throws ExecutionException { - int[] resolution = getChaturbate().streamResolutionCache.getIfPresent(getName()); - if(resolution != null) { - return getChaturbate().getResolution(getName()); - } else { - if(failFast) { - return new int[2]; - } else { - return getChaturbate().getResolution(getName()); - } + if(failFast) { + return resolution; } + + try { + resolution = getChaturbate().getResolution(getName()); + } catch(Exception e) { + throw new ExecutionException(e); + } + return resolution; } /** @@ -71,7 +72,6 @@ public class ChaturbateModel extends AbstractModel { @Override public void invalidateCacheEntries() { getChaturbate().streamInfoCache.invalidate(getName()); - getChaturbate().streamResolutionCache.invalidate(getName()); } public String getOnlineState() throws IOException, ExecutionException { diff --git a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java index b7b20df3..c9317abf 100644 --- a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java +++ b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java @@ -10,10 +10,9 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -52,7 +51,6 @@ public class MyFreeCamsClient { private Cache sessionStates = CacheBuilder.newBuilder().maximumSize(4000).build(); private Cache models = CacheBuilder.newBuilder().maximumSize(4000).build(); private Lock lock = new ReentrantLock(); - private ExecutorService executor = Executors.newSingleThreadExecutor(); private ServerConfig serverConfig; @SuppressWarnings("unused") private String tkx; @@ -86,8 +84,13 @@ public class MyFreeCamsClient { public void start() throws IOException { running = true; serverConfig = new ServerConfig(mfc); - List websocketServers = new ArrayList(serverConfig.wsServers.keySet()); - String server = websocketServers.get((int) (Math.random()*websocketServers.size())); + List websocketServers = new ArrayList(serverConfig.wsServers.size()); + for (Entry entry : serverConfig.wsServers.entrySet()) { + if (entry.getValue().equals("rfc6455")) { + websocketServers.add(entry.getKey()); + } + } + String server = websocketServers.get((int) (Math.random() * websocketServers.size() - 1)); String wsUrl = "ws://" + server + ".myfreecams.com:8080/fcsl"; LOG.debug("Connecting to random websocket server {}", wsUrl); @@ -308,7 +311,7 @@ public class MyFreeCamsClient { long opts = json.getInt("opts"); long serv = json.getInt("serv"); long type = json.getInt("type"); - String base = "http://www.myfreecams.com/php/FcwExtResp.php"; + String base = mfc.getBaseUrl() + "/php/FcwExtResp.php"; String url = base + "?respkey="+respkey+"&opts="+opts+"&serv="+serv+"&type="+type; Request req = new Request.Builder().url(url).build(); LOG.trace("Requesting EXTDATA {}", url); @@ -568,10 +571,6 @@ public class MyFreeCamsClient { return models.getIfPresent(uid); } - public void execute(Runnable r) { - executor.execute(r); - } - public void getSessionState(ctbrec.Model model) { for (SessionState state : sessionStates.asMap().values()) { if(Objects.equals(state.getNm(), model.getName())) { diff --git a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java index d79afa01..5bb3d998 100644 --- a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java +++ b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java @@ -45,7 +45,7 @@ public class MyFreeCamsModel extends AbstractModel { private double camScore; private int viewerCount; private State state; - private int resolution[]; + private int resolution[] = new int[2]; /** * This constructor exists only for deserialization. Please don't call it directly @@ -72,6 +72,24 @@ public class MyFreeCamsModel extends AbstractModel { return state != null ? state.toString() : "offline"; } + // @Override + // public STATUS getOnlineState() { + // switch(this.state) { + // case ONLINE: + // case RECORDING: + // return ctbrec.Model.STATUS.ONLINE; + // case AWAY: + // return ctbrec.Model.STATUS.AWAY; + // case PRIVATE: + // return ctbrec.Model.STATUS.PRIVATE; + // case GROUP_SHOW: + // return ctbrec.Model.STATUS.GROUP; + // default: + // LOG.debug("State {} is not mapped", this.state); + // return ctbrec.Model.STATUS.UNKNOWN; + // } + // } + @Override public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException { MasterPlaylist masterPlaylist = getMasterPlaylist(); @@ -174,26 +192,19 @@ public class MyFreeCamsModel extends AbstractModel { @Override public int[] getStreamResolution(boolean failFast) throws ExecutionException { - if(resolution == null) { - if(failFast || hlsUrl == null) { - return new int[2]; + if (!failFast && hlsUrl != null) { + try { + List streamSources = getStreamSources(); + Collections.sort(streamSources); + StreamSource best = streamSources.get(streamSources.size() - 1); + resolution = new int[] { best.width, best.height }; + } catch (ParseException | PlaylistException e) { + LOG.warn("Couldn't determine stream resolution - {}", e.getMessage()); + } catch (ExecutionException | IOException e) { + LOG.error("Couldn't determine stream resolution", e); } - MyFreeCamsClient.getInstance().execute(()->{ - try { - List streamSources = getStreamSources(); - Collections.sort(streamSources); - StreamSource best = streamSources.get(streamSources.size()-1); - resolution = new int[] {best.width, best.height}; - } catch (ParseException | PlaylistException e) { - LOG.warn("Couldn't determine stream resolution - {}", e.getMessage()); - } catch (ExecutionException | IOException e) { - LOG.error("Couldn't determine stream resolution", e); - } - }); - return new int[2]; - } else { - return resolution; } + return resolution; } public void setStreamUrl(String hlsUrl) {