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/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsConfigUI.java b/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsConfigUI.java index bf64358b..0783a68a 100644 --- a/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsConfigUI.java +++ b/client/src/main/java/ctbrec/ui/sites/myfreecams/MyFreeCamsConfigUI.java @@ -8,6 +8,7 @@ import ctbrec.ui.sites.AbstractConfigUI; import javafx.geometry.Insets; import javafx.scene.Parent; import javafx.scene.control.Button; +import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.PasswordField; import javafx.scene.control.TextField; @@ -23,8 +24,9 @@ public class MyFreeCamsConfigUI extends AbstractConfigUI { @Override public Parent createConfigPanel() { + int row = 0; GridPane layout = SettingsTab.createGridLayout(); - layout.add(new Label("MyFreeCams User"), 0, 0); + layout.add(new Label("MyFreeCams User"), 0, row); TextField username = new TextField(Config.getInstance().getSettings().mfcUsername); username.setPrefWidth(300); username.textProperty().addListener((ob, o, n) -> { @@ -34,9 +36,9 @@ public class MyFreeCamsConfigUI extends AbstractConfigUI { GridPane.setFillWidth(username, true); GridPane.setHgrow(username, Priority.ALWAYS); GridPane.setColumnSpan(username, 2); - layout.add(username, 1, 0); + layout.add(username, 1, row++); - layout.add(new Label("MyFreeCams Password"), 0, 1); + layout.add(new Label("MyFreeCams Password"), 0, row); PasswordField password = new PasswordField(); password.setText(Config.getInstance().getSettings().mfcPassword); password.textProperty().addListener((ob, o, n) -> { @@ -46,9 +48,9 @@ public class MyFreeCamsConfigUI extends AbstractConfigUI { GridPane.setFillWidth(password, true); GridPane.setHgrow(password, Priority.ALWAYS); GridPane.setColumnSpan(password, 2); - layout.add(password, 1, 1); + layout.add(password, 1, row++); - layout.add(new Label("MyFreeCams Base URL"), 0, 2); + layout.add(new Label("MyFreeCams Base URL"), 0, row); TextField baseUrl = new TextField(); baseUrl.setText(Config.getInstance().getSettings().mfcBaseUrl); baseUrl.textProperty().addListener((ob, o, n) -> { @@ -58,15 +60,24 @@ public class MyFreeCamsConfigUI extends AbstractConfigUI { GridPane.setFillWidth(baseUrl, true); GridPane.setHgrow(baseUrl, Priority.ALWAYS); GridPane.setColumnSpan(baseUrl, 2); - layout.add(baseUrl, 1, 2); + layout.add(baseUrl, 1, row++); + + layout.add(new Label("Ignore upscaled stream (960p)"), 0, row); + CheckBox ignoreUpscaled = new CheckBox(); + ignoreUpscaled.setSelected(Config.getInstance().getSettings().mfcIgnoreUpscaled); + ignoreUpscaled.selectedProperty().addListener((obs, oldV, newV) -> { + Config.getInstance().getSettings().mfcIgnoreUpscaled = newV; + }); + layout.add(ignoreUpscaled, 1, row++); Button createAccount = new Button("Create new Account"); createAccount.setOnAction((e) -> DesktopIntegration.open(myFreeCams.getAffiliateLink())); - layout.add(createAccount, 1, 3); + layout.add(createAccount, 1, row); GridPane.setColumnSpan(createAccount, 2); GridPane.setMargin(username, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN)); GridPane.setMargin(password, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN)); GridPane.setMargin(baseUrl, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN)); + GridPane.setMargin(ignoreUpscaled, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN)); GridPane.setMargin(createAccount, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN)); return layout; diff --git a/common/src/main/java/ctbrec/Model.java b/common/src/main/java/ctbrec/Model.java index e13f2fcd..895f711e 100644 --- a/common/src/main/java/ctbrec/Model.java +++ b/common/src/main/java/ctbrec/Model.java @@ -14,33 +14,71 @@ import ctbrec.sites.Site; public interface Model { 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/Settings.java b/common/src/main/java/ctbrec/Settings.java index 64fc8e42..bb19eb34 100644 --- a/common/src/main/java/ctbrec/Settings.java +++ b/common/src/main/java/ctbrec/Settings.java @@ -49,6 +49,7 @@ public class Settings { public String mfcUsername = ""; public String mfcPassword = ""; public String mfcBaseUrl = "https://www.myfreecams.com"; + public boolean mfcIgnoreUpscaled = false; public String camsodaUsername = ""; public String camsodaPassword = ""; public String cam4Username; 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/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 6f167b77..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,9 +84,15 @@ 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); Thread watchDog = new Thread(() -> { while(running) { @@ -307,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); @@ -567,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..ec8301ef 100644 --- a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java +++ b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; +import java.util.stream.Collectors; import org.jsoup.nodes.Element; import org.slf4j.Logger; @@ -28,6 +29,7 @@ import com.squareup.moshi.JsonReader; import com.squareup.moshi.JsonWriter; import ctbrec.AbstractModel; +import ctbrec.Config; import ctbrec.io.HtmlParser; import ctbrec.io.HttpException; import ctbrec.recorder.download.StreamSource; @@ -45,7 +47,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 @@ -95,7 +97,13 @@ public class MyFreeCamsModel extends AbstractModel { sources.add(src); } } - return sources; + if(Config.getInstance().getSettings().mfcIgnoreUpscaled) { + return sources.stream() + .filter(src -> src.height != 960) + .collect(Collectors.toList()); + } else { + return sources; + } } private MasterPlaylist getMasterPlaylist() throws IOException, ParseException, PlaylistException { @@ -174,26 +182,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) {