diff --git a/src/main/java/ctbrec/Model.java b/src/main/java/ctbrec/Model.java index 1034b41f..63869b78 100644 --- a/src/main/java/ctbrec/Model.java +++ b/src/main/java/ctbrec/Model.java @@ -27,5 +27,8 @@ public interface Model { public String getOnlineState(boolean failFast) throws IOException, ExecutionException; public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException; public String getSegmentPlaylistUrl() throws IOException, ExecutionException, ParseException, PlaylistException; + public void invalidateCacheEntries(); + public void receiveTip(int tokens) throws IOException; + public int[] getStreamResolution(boolean failFast) throws ExecutionException; } \ No newline at end of file diff --git a/src/main/java/ctbrec/Site.java b/src/main/java/ctbrec/Site.java new file mode 100644 index 00000000..5565f7ce --- /dev/null +++ b/src/main/java/ctbrec/Site.java @@ -0,0 +1,13 @@ +package ctbrec; + +import ctbrec.recorder.Recorder; +import ctbrec.ui.TabProvider; + +public interface Site { + public String getName(); + public String getBaseUrl(); + public String getAffiliateLink(); + public void setRecorder(Recorder recorder); + public TabProvider getTabProvider(); + public Model createModel(String name); +} diff --git a/src/main/java/ctbrec/io/HttpClient.java b/src/main/java/ctbrec/io/HttpClient.java index b2ac5e09..7a3dd0ca 100644 --- a/src/main/java/ctbrec/io/HttpClient.java +++ b/src/main/java/ctbrec/io/HttpClient.java @@ -10,7 +10,7 @@ import org.slf4j.LoggerFactory; import ctbrec.Config; import ctbrec.Settings.ProxyType; import ctbrec.ui.CookieJarImpl; -import ctbrec.ui.CtbrecApplication; +import ctbrec.ui.CamrecApplication; import ctbrec.ui.HtmlParser; import okhttp3.ConnectionPool; import okhttp3.Cookie; @@ -122,7 +122,7 @@ public class HttpClient { public boolean login() throws IOException { try { Request login = new Request.Builder() - .url(CtbrecApplication.BASE_URI + "/auth/login/") + .url(CamrecApplication.BASE_URI + "/auth/login/") .build(); Response response = client.newCall(login).execute(); String content = response.body().string(); @@ -136,8 +136,8 @@ public class HttpClient { .add("csrfmiddlewaretoken", token) .build(); login = new Request.Builder() - .url(CtbrecApplication.BASE_URI + "/auth/login/") - .header("Referer", CtbrecApplication.BASE_URI + "/auth/login/") + .url(CamrecApplication.BASE_URI + "/auth/login/") + .header("Referer", CamrecApplication.BASE_URI + "/auth/login/") .post(body) .build(); diff --git a/src/main/java/ctbrec/recorder/LocalRecorder.java b/src/main/java/ctbrec/recorder/LocalRecorder.java index 6cb03866..ff9bfeda 100644 --- a/src/main/java/ctbrec/recorder/LocalRecorder.java +++ b/src/main/java/ctbrec/recorder/LocalRecorder.java @@ -35,8 +35,7 @@ import ctbrec.recorder.PlaylistGenerator.InvalidPlaylistException; import ctbrec.recorder.download.Download; import ctbrec.recorder.download.HlsDownload; import ctbrec.recorder.download.MergedHlsDownload; -import ctbrec.sites.chaturbate.ChaturbateModel; -import ctbrec.sites.chaturbate.ModelParser; +import ctbrec.sites.chaturbate.ChaturbateModelParser; import okhttp3.Request; import okhttp3.Response; @@ -270,10 +269,10 @@ public class LocalRecorder implements Recorder { Request request = new Request.Builder().url(url).build(); Response response = client.execute(request, true); if (response.isSuccessful()) { - List followed = ModelParser.parseModels(response.body().string()); + List followed = ChaturbateModelParser.parseModels(response.body().string()); response.close(); followedModels.clear(); - for (ChaturbateModel model : followed) { + for (Model model : followed) { if (!followedModels.contains(model) && !models.contains(model)) { LOG.info("Model {} added", model); followedModels.add(model); diff --git a/src/main/java/ctbrec/recorder/server/RecorderServlet.java b/src/main/java/ctbrec/recorder/server/RecorderServlet.java index 58d4e9cf..bb491126 100644 --- a/src/main/java/ctbrec/recorder/server/RecorderServlet.java +++ b/src/main/java/ctbrec/recorder/server/RecorderServlet.java @@ -25,7 +25,6 @@ import ctbrec.Recording; import ctbrec.io.InstantJsonAdapter; import ctbrec.io.ModelJsonAdapter; import ctbrec.recorder.Recorder; -import ctbrec.sites.chaturbate.ChaturbateModel; public class RecorderServlet extends AbstractCtbrecServlet { @@ -74,7 +73,7 @@ public class RecorderServlet extends AbstractCtbrecServlet { break; case "list": resp.getWriter().write("{\"status\": \"success\", \"msg\": \"List of models\", \"models\": ["); - JsonAdapter modelAdapter = moshi.adapter(Model.class); + JsonAdapter modelAdapter = new ModelJsonAdapter(); List models = recorder.getModelsRecording(); for (Iterator iterator = models.iterator(); iterator.hasNext();) { Model model = iterator.next(); @@ -133,7 +132,7 @@ public class RecorderServlet extends AbstractCtbrecServlet { private static class Request { public String action; - public ChaturbateModel model; + public Model model; public String recording; } } diff --git a/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java b/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java new file mode 100644 index 00000000..e97887e4 --- /dev/null +++ b/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java @@ -0,0 +1,44 @@ +package ctbrec.sites.chaturbate; + +import ctbrec.Model; +import ctbrec.Site; +import ctbrec.recorder.Recorder; +import ctbrec.ui.TabProvider; + +public class Chaturbate implements Site { + + private Recorder recorder; + + @Override + public String getName() { + return "Chaturbate"; + } + + @Override + public String getBaseUrl() { + return "https://chaturbate.com"; + } + + @Override + public String getAffiliateLink() { + return getBaseUrl() + "/in/?track=default&tour=LQps&campaign=55vTi&room=0xb00bface"; + } + + @Override + public TabProvider getTabProvider() { + return new ChaturbateTabProvider(this, recorder); + } + + @Override + public void setRecorder(Recorder recorder) { + this.recorder = recorder; + } + + @Override + public Model createModel(String name) { + ChaturbateModel m = new ChaturbateModel(); + m.setName(name); + m.setUrl(getBaseUrl() + '/' + name + '/'); + return m; + } +} diff --git a/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java b/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java index c4070143..311c9fbd 100644 --- a/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java +++ b/src/main/java/ctbrec/sites/chaturbate/ChaturbateModel.java @@ -55,23 +55,25 @@ public class ChaturbateModel extends AbstractModel { return Objects.equals("public", info.room_status); } + @Override public int[] getStreamResolution(boolean failFast) throws ExecutionException { int[] resolution = Chaturbate.INSTANCE.streamResolutionCache.getIfPresent(getName()); if(resolution != null) { return Chaturbate.INSTANCE.getResolution(getName()); } else { - return new int[2]; + if(failFast) { + return new int[2]; + } else { + return Chaturbate.INSTANCE.getResolution(getName()); + } } } - public int[] getStreamResolution() throws ExecutionException { - return Chaturbate.INSTANCE.getResolution(getName()); - } - /** * Invalidates the entries in StreamInfo and resolution cache for this model * and thus causes causes the LoadingCache to update them */ + @Override public void invalidateCacheEntries() { Chaturbate.INSTANCE.streamInfoCache.invalidate(getName()); Chaturbate.INSTANCE.streamResolutionCache.invalidate(getName()); @@ -94,6 +96,7 @@ public class ChaturbateModel extends AbstractModel { return Chaturbate.INSTANCE.getMasterPlaylist(getName()); } + @Override public void receiveTip(int tokens) throws IOException { Chaturbate.INSTANCE.sendTip(getName(), tokens); } diff --git a/src/main/java/ctbrec/sites/chaturbate/ModelParser.java b/src/main/java/ctbrec/sites/chaturbate/ChaturbateModelParser.java similarity index 80% rename from src/main/java/ctbrec/sites/chaturbate/ModelParser.java rename to src/main/java/ctbrec/sites/chaturbate/ChaturbateModelParser.java index f67726a0..a3fc0579 100644 --- a/src/main/java/ctbrec/sites/chaturbate/ModelParser.java +++ b/src/main/java/ctbrec/sites/chaturbate/ChaturbateModelParser.java @@ -1,6 +1,6 @@ package ctbrec.sites.chaturbate; -import static ctbrec.ui.CtbrecApplication.BASE_URI; +import static ctbrec.ui.CamrecApplication.BASE_URI; import java.util.ArrayList; import java.util.List; @@ -10,18 +10,19 @@ import org.jsoup.select.Elements; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import ctbrec.Model; import ctbrec.ui.HtmlParser; -public class ModelParser { - private static final transient Logger LOG = LoggerFactory.getLogger(ModelParser.class); +public class ChaturbateModelParser { + private static final transient Logger LOG = LoggerFactory.getLogger(ChaturbateModelParser.class); - public static List parseModels(String html) { - List models = new ArrayList<>(); + public static List parseModels(String html) { + List models = new ArrayList<>(); Elements cells = HtmlParser.getTags(html, "ul.list > li"); for (Element cell : cells) { String cellHtml = cell.html(); try { - ChaturbateModel model = new ChaturbateModel(); + Model model = new ChaturbateModel(); model.setName(HtmlParser.getText(cellHtml, "div.title > a").trim()); model.setPreview(HtmlParser.getTag(cellHtml, "a img").attr("src")); model.setUrl(BASE_URI + HtmlParser.getTag(cellHtml, "a").attr("href")); diff --git a/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java b/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java new file mode 100644 index 00000000..2aa5674e --- /dev/null +++ b/src/main/java/ctbrec/sites/chaturbate/ChaturbateTabProvider.java @@ -0,0 +1,45 @@ +package ctbrec.sites.chaturbate; + +import java.util.ArrayList; +import java.util.List; + +import ctbrec.recorder.Recorder; +import ctbrec.ui.FollowedTab; +import ctbrec.ui.TabProvider; +import ctbrec.ui.ThumbOverviewTab; +import javafx.scene.Scene; +import javafx.scene.control.Tab; + +public class ChaturbateTabProvider extends TabProvider { + + private Chaturbate chaturbate; + private Recorder recorder; + + public ChaturbateTabProvider(Chaturbate chaturbate, Recorder recorder) { + this.chaturbate = chaturbate; + this.recorder = recorder; + } + + @Override + public List getTabs(Scene scene) { + final String BASE_URI = chaturbate.getBaseUrl(); + List tabs = new ArrayList<>(); + tabs.add(createTab("Featured", BASE_URI + "/")); + tabs.add(createTab("Female", BASE_URI + "/female-cams/")); + tabs.add(createTab("Male", BASE_URI + "/male-cams/")); + tabs.add(createTab("Couples", BASE_URI + "/couple-cams/")); + tabs.add(createTab("Trans", BASE_URI + "/trans-cams/")); + FollowedTab followedTab = new FollowedTab("Followed", BASE_URI + "/followed-cams/"); + followedTab.setRecorder(recorder); + followedTab.setScene(scene); + tabs.add(followedTab); + return tabs; + } + + private Tab createTab(String title, String url) { + ChaturbateUpdateService updateService = new ChaturbateUpdateService(url, false); + ThumbOverviewTab tab = new ThumbOverviewTab(title, updateService); + tab.setRecorder(recorder); + return tab; + } +} diff --git a/src/main/java/ctbrec/sites/chaturbate/ChaturbateUpdateService.java b/src/main/java/ctbrec/sites/chaturbate/ChaturbateUpdateService.java new file mode 100644 index 00000000..b13d81f3 --- /dev/null +++ b/src/main/java/ctbrec/sites/chaturbate/ChaturbateUpdateService.java @@ -0,0 +1,67 @@ +package ctbrec.sites.chaturbate; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ctbrec.Model; +import ctbrec.io.HttpClient; +import ctbrec.ui.PaginatedScheduledService; +import javafx.concurrent.Task; +import okhttp3.Request; +import okhttp3.Response; + +public class ChaturbateUpdateService extends PaginatedScheduledService { + + private static final transient Logger LOG = LoggerFactory.getLogger(ChaturbateUpdateService.class); + private String url; + private boolean loginRequired; + + public ChaturbateUpdateService(String url, boolean loginRequired) { + this.url = url; + this.loginRequired = loginRequired; + + ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setDaemon(true); + t.setName("ThumbOverviewTab UpdateService"); + return t; + } + }); + setExecutor(executor); + } + + @Override + protected Task> createTask() { + return new Task>() { + @Override + public List call() throws IOException { + String url = ChaturbateUpdateService.this.url + "?page="+page+"&keywords=&_=" + System.currentTimeMillis(); + LOG.debug("Fetching page {}", url); + Request request = new Request.Builder().url(url).build(); + Response response = HttpClient.getInstance().execute(request, loginRequired); + if (response.isSuccessful()) { + List models = ChaturbateModelParser.parseModels(response.body().string()); + response.close(); + return models; + } else { + int code = response.code(); + response.close(); + throw new IOException("HTTP status " + code); + } + } + }; + } + + public void setUrl(String url) { + this.url = url; + } + +} diff --git a/src/main/java/ctbrec/ui/CtbrecApplication.java b/src/main/java/ctbrec/ui/CamrecApplication.java similarity index 93% rename from src/main/java/ctbrec/ui/CtbrecApplication.java rename to src/main/java/ctbrec/ui/CamrecApplication.java index a67ff856..3ffbe289 100644 --- a/src/main/java/ctbrec/ui/CtbrecApplication.java +++ b/src/main/java/ctbrec/ui/CamrecApplication.java @@ -20,11 +20,13 @@ import com.squareup.moshi.Moshi; import com.squareup.moshi.Types; import ctbrec.Config; +import ctbrec.Site; import ctbrec.Version; import ctbrec.io.HttpClient; import ctbrec.recorder.LocalRecorder; import ctbrec.recorder.Recorder; import ctbrec.recorder.RemoteRecorder; +import ctbrec.sites.chaturbate.Chaturbate; import javafx.application.Application; import javafx.application.HostServices; import javafx.application.Platform; @@ -49,9 +51,9 @@ import javafx.stage.Stage; import okhttp3.Request; import okhttp3.Response; -public class CtbrecApplication extends Application { +public class CamrecApplication extends Application { - static final transient Logger LOG = LoggerFactory.getLogger(CtbrecApplication.class); + static final transient Logger LOG = LoggerFactory.getLogger(CamrecApplication.class); public static final String BASE_URI = "https://chaturbate.com"; public static final String AFFILIATE_LINK = BASE_URI + "/in/?track=default&tour=LQps&campaign=55vTi&room=0xb00bface"; @@ -63,6 +65,7 @@ public class CtbrecApplication extends Application { private TabPane tabPane = new TabPane(); static EventBus bus; private HBox tokenPanel; + private Site site; @Override public void start(Stage primaryStage) throws Exception { @@ -71,6 +74,8 @@ public class CtbrecApplication extends Application { hostServices = getHostServices(); client = HttpClient.getInstance(); createRecorder(); + site = new Chaturbate(); + site.setRecorder(recorder); doInitialLogin(); createGui(primaryStage); checkForUpdates(); @@ -81,8 +86,12 @@ public class CtbrecApplication extends Application { primaryStage.setTitle("CTB Recorder " + getVersion()); InputStream icon = getClass().getResourceAsStream("/icon.png"); primaryStage.getIcons().add(new Image(icon)); - + int windowWidth = Config.getInstance().getSettings().windowWidth; + int windowHeight = Config.getInstance().getSettings().windowHeight; tabPane = new TabPane(); + Scene scene = new Scene(tabPane, windowWidth, windowHeight); + primaryStage.setScene(scene); + tabPane.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue ov, Tab from, Tab to) { @@ -95,26 +104,18 @@ public class CtbrecApplication extends Application { } }); tabPane.setTabClosingPolicy(TabClosingPolicy.SELECTED_TAB); - tabPane.getTabs().add(createTab("Featured", BASE_URI + "/")); - tabPane.getTabs().add(createTab("Female", BASE_URI + "/female-cams/")); - tabPane.getTabs().add(createTab("Male", BASE_URI + "/male-cams/")); - tabPane.getTabs().add(createTab("Couples", BASE_URI + "/couple-cams/")); - tabPane.getTabs().add(createTab("Trans", BASE_URI + "/trans-cams/")); - FollowedTab followedTab = new FollowedTab("Followed", BASE_URI + "/followed-cams/"); - followedTab.setRecorder(recorder); - tabPane.getTabs().add(followedTab); - RecordedModelsTab modelsTab = new RecordedModelsTab("Recording", recorder); + for (Tab tab : site.getTabProvider().getTabs(scene)) { + tabPane.getTabs().add(tab); + } + RecordedModelsTab modelsTab = new RecordedModelsTab("Recording", recorder, site); tabPane.getTabs().add(modelsTab); - RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config); + RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config, site); tabPane.getTabs().add(recordingsTab); settingsTab = new SettingsTab(); tabPane.getTabs().add(settingsTab); tabPane.getTabs().add(new DonateTabFx()); - int windowWidth = Config.getInstance().getSettings().windowWidth; - int windowHeight = Config.getInstance().getSettings().windowHeight; - primaryStage.setScene(new Scene(tabPane, windowWidth, windowHeight)); - followedTab.setScene(primaryStage.getScene()); + primaryStage.getScene().getStylesheets().add("/ctbrec/ui/ThumbCell.css"); primaryStage.getScene().widthProperty().addListener((observable, oldVal, newVal) -> Config.getInstance().getSettings().windowWidth = newVal.intValue()); primaryStage.getScene().heightProperty().addListener((observable, oldVal, newVal) -> Config.getInstance().getSettings().windowHeight = newVal.intValue()); @@ -270,12 +271,6 @@ public class CtbrecApplication extends Application { config = Config.getInstance(); } - Tab createTab(String title, String url) { - ThumbOverviewTab tab = new ThumbOverviewTab(title, url, false); - tab.setRecorder(recorder); - return tab; - } - public static void main(String[] args) { launch(args); } diff --git a/src/main/java/ctbrec/ui/DesktopIntergation.java b/src/main/java/ctbrec/ui/DesktopIntergation.java index b3c7d5f9..bb8eb565 100644 --- a/src/main/java/ctbrec/ui/DesktopIntergation.java +++ b/src/main/java/ctbrec/ui/DesktopIntergation.java @@ -19,7 +19,7 @@ public class DesktopIntergation { public static void open(String uri) { try { - CtbrecApplication.hostServices.showDocument(uri); + CamrecApplication.hostServices.showDocument(uri); return; } catch (Exception e) { LOG.debug("Couldn't open URL with host services {}", uri); diff --git a/src/main/java/ctbrec/ui/DonateTabFx.java b/src/main/java/ctbrec/ui/DonateTabFx.java index 6d8ca1e8..50125693 100644 --- a/src/main/java/ctbrec/ui/DonateTabFx.java +++ b/src/main/java/ctbrec/ui/DonateTabFx.java @@ -44,7 +44,7 @@ public class DonateTabFx extends Tab { ImageView tokenImage = new ImageView(getClass().getResource("/html/token.png").toString()); Button tokenButton = new Button("Buy tokens"); - tokenButton.setOnAction((e) -> { DesktopIntergation.open(CtbrecApplication.AFFILIATE_LINK); }); + tokenButton.setOnAction((e) -> { DesktopIntergation.open(CamrecApplication.AFFILIATE_LINK); }); VBox tokenBox = new VBox(5); tokenBox.setAlignment(Pos.TOP_CENTER); Label tokenDesc = new Label("If you buy tokens by using this button,\n" diff --git a/src/main/java/ctbrec/ui/FollowedTab.java b/src/main/java/ctbrec/ui/FollowedTab.java index f8b22214..446f6c28 100644 --- a/src/main/java/ctbrec/ui/FollowedTab.java +++ b/src/main/java/ctbrec/ui/FollowedTab.java @@ -1,5 +1,6 @@ package ctbrec.ui; +import ctbrec.sites.chaturbate.ChaturbateUpdateService; import javafx.concurrent.WorkerStateEvent; import javafx.geometry.Insets; import javafx.scene.Scene; @@ -16,7 +17,7 @@ public class FollowedTab extends ThumbOverviewTab { private String offlineUrl; public FollowedTab(String title, String url) { - super(title, url, true); + super(title, new ChaturbateUpdateService(url, true)); onlineUrl = url; offlineUrl = url + "offline/"; @@ -43,9 +44,9 @@ public class FollowedTab extends ThumbOverviewTab { online.setSelected(true); group.selectedToggleProperty().addListener((e) -> { if(online.isSelected()) { - super.url = onlineUrl; + ((ChaturbateUpdateService)updateService).setUrl(onlineUrl); } else { - super.url = offlineUrl; + ((ChaturbateUpdateService)updateService).setUrl(offlineUrl); } queue.clear(); updateService.restart(); diff --git a/src/main/java/ctbrec/ui/JavaFxModel.java b/src/main/java/ctbrec/ui/JavaFxModel.java index 7948bd1e..ef48491b 100644 --- a/src/main/java/ctbrec/ui/JavaFxModel.java +++ b/src/main/java/ctbrec/ui/JavaFxModel.java @@ -111,4 +111,19 @@ public class JavaFxModel extends AbstractModel { public List getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException { return delegate.getStreamSources(); } + + @Override + public void invalidateCacheEntries() { + delegate.invalidateCacheEntries(); + } + + @Override + public void receiveTip(int tokens) throws IOException { + delegate.receiveTip(tokens); + } + + @Override + public int[] getStreamResolution(boolean b) throws ExecutionException { + return delegate.getStreamResolution(b); + } } diff --git a/src/main/java/ctbrec/ui/Launcher.java b/src/main/java/ctbrec/ui/Launcher.java index 65643326..70e1bd34 100644 --- a/src/main/java/ctbrec/ui/Launcher.java +++ b/src/main/java/ctbrec/ui/Launcher.java @@ -13,7 +13,7 @@ public class Launcher { // check for OpenJFX try { Class.forName("javafx.application.Application"); - CtbrecApplication.main(args); + CamrecApplication.main(args); } catch (ClassNotFoundException e) { LOG.error("You are running ctbrec with OpenJDK, but OpenJFX can not be found.\n" + "Please either install OpenJFX or use the Oracle JRE, which you can download at\n" @@ -21,7 +21,7 @@ public class Launcher { System.exit(1); } } else { - CtbrecApplication.main(args); + CamrecApplication.main(args); } } } diff --git a/src/main/java/ctbrec/ui/PaginatedScheduledService.java b/src/main/java/ctbrec/ui/PaginatedScheduledService.java new file mode 100644 index 00000000..bba88ef5 --- /dev/null +++ b/src/main/java/ctbrec/ui/PaginatedScheduledService.java @@ -0,0 +1,19 @@ +package ctbrec.ui; + +import java.util.List; + +import ctbrec.Model; +import javafx.concurrent.ScheduledService; + +public abstract class PaginatedScheduledService extends ScheduledService> { + + protected int page = 1; + + public int getPage() { + return page; + } + + public void setPage(int page) { + this.page = page; + } +} diff --git a/src/main/java/ctbrec/ui/RecordedModelsTab.java b/src/main/java/ctbrec/ui/RecordedModelsTab.java index 245e9f2c..c8054536 100644 --- a/src/main/java/ctbrec/ui/RecordedModelsTab.java +++ b/src/main/java/ctbrec/ui/RecordedModelsTab.java @@ -19,9 +19,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ctbrec.Model; +import ctbrec.Site; import ctbrec.io.HttpClient; import ctbrec.recorder.Recorder; -import ctbrec.sites.chaturbate.ChaturbateModel; import javafx.application.Platform; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -60,6 +60,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { private ScheduledService> updateService; private Recorder recorder; + private Site site; FlowPane grid = new FlowPane(); ScrollPane scrollPane = new ScrollPane(); @@ -71,9 +72,10 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { TextField model = new TextField(); Button addModelButton = new Button("Record"); - public RecordedModelsTab(String title, Recorder recorder) { + public RecordedModelsTab(String title, Recorder recorder, Site site) { super(title); this.recorder = recorder; + this.site = site; createGui(); setClosable(false); initializeUpdateService(); @@ -126,9 +128,7 @@ public class RecordedModelsTab extends Tab implements TabSelectionListener { model.setPrefWidth(300); BorderPane.setMargin(addModelBox, new Insets(5)); addModelButton.setOnAction((e) -> { - ChaturbateModel m = new ChaturbateModel(); - m.setName(model.getText()); - m.setUrl("https://chaturbate.com/" + m.getName() + "/"); + Model m = site.createModel(model.getText()); try { recorder.startRecording(m); } catch (IOException | InvalidKeyException | NoSuchAlgorithmException | IllegalStateException e1) { diff --git a/src/main/java/ctbrec/ui/RecordingsTab.java b/src/main/java/ctbrec/ui/RecordingsTab.java index 44613752..2e490a6a 100644 --- a/src/main/java/ctbrec/ui/RecordingsTab.java +++ b/src/main/java/ctbrec/ui/RecordingsTab.java @@ -29,12 +29,13 @@ import com.iheartradio.m3u8.ParseException; import com.iheartradio.m3u8.PlaylistException; import ctbrec.Config; +import ctbrec.Model; import ctbrec.Recording; import ctbrec.Recording.STATUS; +import ctbrec.Site; import ctbrec.io.HttpClient; import ctbrec.recorder.Recorder; import ctbrec.recorder.download.MergedHlsDownload; -import ctbrec.sites.chaturbate.ChaturbateModel; import javafx.application.Platform; import javafx.beans.property.SimpleStringProperty; import javafx.collections.FXCollections; @@ -67,6 +68,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener { private ScheduledService> updateService; private Config config; private Recorder recorder; + private Site site; FlowPane grid = new FlowPane(); ScrollPane scrollPane = new ScrollPane(); @@ -74,10 +76,11 @@ public class RecordingsTab extends Tab implements TabSelectionListener { ObservableList observableRecordings = FXCollections.observableArrayList(); ContextMenu popup; - public RecordingsTab(String title, Recorder recorder, Config config) { + public RecordingsTab(String title, Recorder recorder, Config config, Site site) { super(title); this.recorder = recorder; this.config = config; + this.site = site; createGui(); setClosable(false); initializeUpdateService(); @@ -246,9 +249,7 @@ public class RecordingsTab extends Tab implements TabSelectionListener { MenuItem stopRecording = new MenuItem("Stop recording"); stopRecording.setOnAction((e) -> { - ChaturbateModel m = new ChaturbateModel(); - m.setName(recording.getModelName()); - m.setUrl(CtbrecApplication.BASE_URI + '/' + recording.getModelName() + '/'); + Model m = site.createModel(recording.getModelName()); try { recorder.stopRecording(m); } catch (Exception e1) { diff --git a/src/main/java/ctbrec/ui/SettingsTab.java b/src/main/java/ctbrec/ui/SettingsTab.java index e24ce9f1..4cfb8804 100644 --- a/src/main/java/ctbrec/ui/SettingsTab.java +++ b/src/main/java/ctbrec/ui/SettingsTab.java @@ -188,7 +188,7 @@ public class SettingsTab extends Tab implements TabSelectionListener { layout.add(password, 1, 1); Button createAccount = new Button("Create new Account"); - createAccount.setOnAction((e) -> DesktopIntergation.open(CtbrecApplication.AFFILIATE_LINK)); + createAccount.setOnAction((e) -> DesktopIntergation.open(CamrecApplication.AFFILIATE_LINK)); layout.add(createAccount, 1, 2); GridPane.setColumnSpan(createAccount, 2); diff --git a/src/main/java/ctbrec/ui/TabProvider.java b/src/main/java/ctbrec/ui/TabProvider.java new file mode 100644 index 00000000..1437a0e2 --- /dev/null +++ b/src/main/java/ctbrec/ui/TabProvider.java @@ -0,0 +1,14 @@ +package ctbrec.ui; + +import java.util.Collections; +import java.util.List; + +import javafx.scene.Scene; +import javafx.scene.control.Tab; + +public class TabProvider { + + public List getTabs(Scene scene) { + return Collections.emptyList(); + } +} diff --git a/src/main/java/ctbrec/ui/ThumbCell.java b/src/main/java/ctbrec/ui/ThumbCell.java index a18dae85..c5d00020 100644 --- a/src/main/java/ctbrec/ui/ThumbCell.java +++ b/src/main/java/ctbrec/ui/ThumbCell.java @@ -1,6 +1,8 @@ package ctbrec.ui; import java.io.IOException; +import java.util.Collections; +import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.function.Function; @@ -8,12 +10,14 @@ import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.iheartradio.m3u8.ParseException; +import com.iheartradio.m3u8.PlaylistException; + import ctbrec.Config; import ctbrec.Model; import ctbrec.io.HttpClient; import ctbrec.recorder.Recorder; -import ctbrec.sites.chaturbate.ChaturbateModel; -import ctbrec.sites.chaturbate.StreamInfo; +import ctbrec.recorder.download.StreamSource; import javafx.animation.FadeTransition; import javafx.animation.FillTransition; import javafx.animation.ParallelTransition; @@ -51,7 +55,7 @@ public class ThumbCell extends StackPane { public static int width = 180; private static final Duration ANIMATION_DURATION = new Duration(250); - private ChaturbateModel model; + private Model model; private ImageView iv; private Rectangle resolutionBackground; private final Paint resolutionOnlineColor = new Color(0.22, 0.8, 0.29, 1); @@ -77,7 +81,7 @@ public class ThumbCell extends StackPane { private boolean mouseHovering = false; private boolean recording = false; - public ThumbCell(ThumbOverviewTab parent, ChaturbateModel model, Recorder recorder, HttpClient client) { + public ThumbCell(ThumbOverviewTab parent, Model model, Recorder recorder, HttpClient client) { this.thumbCellList = parent.grid.getChildren(); this.model = model; this.recorder = recorder; @@ -198,7 +202,7 @@ public class ThumbCell extends StackPane { ThumbOverviewTab.threadPool.submit(() -> { try { ThumbOverviewTab.resolutionProcessing.add(model); - int[] resolution = model.getStreamResolution(); + int[] resolution = model.getStreamResolution(false); updateResolutionTag(resolution); // the model is online, but the resolution is 0. probably something went wrong @@ -225,14 +229,14 @@ public class ThumbCell extends StackPane { private void updateResolutionTag(int[] resolution) throws IOException, ExecutionException { String _res = "n/a"; Paint resolutionBackgroundColor = resolutionOnlineColor; - String state = model.getOnlineState(); + String state = model.getOnlineState(false); if ("public".equals(state)) { LOG.trace("Model resolution {} {}x{}", model.getName(), resolution[0], resolution[1]); LOG.trace("Resolution queue size: {}", ThumbOverviewTab.queue.size()); final int w = resolution[1]; _res = w > 0 ? Integer.toString(w) : state; } else { - _res = model.getOnlineState(); + _res = model.getOnlineState(false); resolutionBackgroundColor = resolutionOfflineColor; } final String resText = _res; @@ -281,16 +285,18 @@ public class ThumbCell extends StackPane { void startPlayer() { try { if(model.isOnline(true)) { - StreamInfo streamInfo = model.getStreamInfo(); - LOG.debug("Playing {}", streamInfo.url); - Player.play(streamInfo.url); + List sources = model.getStreamSources(); + Collections.sort(sources); + StreamSource best = sources.get(sources.size()-1); + LOG.debug("Playing {}", best.getMediaPlaylistUrl()); + Player.play(best.getMediaPlaylistUrl()); } else { Alert alert = new AutosizeAlert(Alert.AlertType.INFORMATION); alert.setTitle("Room not public"); alert.setHeaderText("Room is currently not public"); alert.showAndWait(); } - } catch (IOException | ExecutionException | InterruptedException e1) { + } catch (IOException | ExecutionException | InterruptedException | ParseException | PlaylistException e1) { LOG.error("Couldn't get stream information for model {}", model, e1); Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); alert.setTitle("Error"); @@ -374,9 +380,9 @@ public class ThumbCell extends StackPane { String url = null; if(follow) { - url = CtbrecApplication.BASE_URI + "/follow/follow/" + model.getName() + "/"; + url = CamrecApplication.BASE_URI + "/follow/follow/" + model.getName() + "/"; } else { - url = CtbrecApplication.BASE_URI + "/follow/unfollow/" + model.getName() + "/"; + url = CamrecApplication.BASE_URI + "/follow/unfollow/" + model.getName() + "/"; } RequestBody body = RequestBody.create(null, new byte[0]); @@ -422,7 +428,7 @@ public class ThumbCell extends StackPane { }.start(); } - public ChaturbateModel getModel() { + public Model getModel() { return model; } diff --git a/src/main/java/ctbrec/ui/ThumbOverviewTab.java b/src/main/java/ctbrec/ui/ThumbOverviewTab.java index 404b26fb..d043eb28 100644 --- a/src/main/java/ctbrec/ui/ThumbOverviewTab.java +++ b/src/main/java/ctbrec/ui/ThumbOverviewTab.java @@ -15,9 +15,7 @@ import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; @@ -28,13 +26,10 @@ import org.slf4j.LoggerFactory; import com.sun.javafx.collections.ObservableListWrapper; import ctbrec.Config; +import ctbrec.Model; import ctbrec.io.HttpClient; import ctbrec.recorder.Recorder; -import ctbrec.sites.chaturbate.ChaturbateModel; -import ctbrec.sites.chaturbate.ModelParser; import javafx.collections.ObservableList; -import javafx.concurrent.ScheduledService; -import javafx.concurrent.Task; import javafx.concurrent.Worker.State; import javafx.concurrent.WorkerStateEvent; import javafx.event.EventHandler; @@ -59,17 +54,15 @@ import javafx.scene.layout.BorderPane; import javafx.scene.layout.FlowPane; import javafx.scene.layout.HBox; import javafx.util.Duration; -import okhttp3.Request; -import okhttp3.Response; public class ThumbOverviewTab extends Tab implements TabSelectionListener { private static final transient Logger LOG = LoggerFactory.getLogger(ThumbOverviewTab.class); - static Set resolutionProcessing = Collections.synchronizedSet(new HashSet<>()); + static Set resolutionProcessing = Collections.synchronizedSet(new HashSet<>()); static BlockingQueue queue = new LinkedBlockingQueue<>(); static ExecutorService threadPool = new ThreadPoolExecutor(2, 2, 10, TimeUnit.MINUTES, queue); - ScheduledService> updateService; + PaginatedScheduledService updateService; Recorder recorder; List filteredThumbCells = Collections.synchronizedList(new ArrayList<>()); List selectedThumbCells = Collections.synchronizedList(new ArrayList<>()); @@ -77,12 +70,10 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { FlowPane grid = new FlowPane(); ReentrantLock gridLock = new ReentrantLock(); ScrollPane scrollPane = new ScrollPane(); - String url; boolean loginRequired; HttpClient client = HttpClient.getInstance(); HBox pagination; - int page = 1; - TextField pageInput = new TextField(Integer.toString(page)); + TextField pageInput = new TextField(Integer.toString(1)); Button pagePrev = new Button("◀"); Button pageNext = new Button("▶"); private volatile boolean updatesSuspended = false; @@ -90,10 +81,9 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { private ComboBox thumbWidth; - public ThumbOverviewTab(String title, String url, boolean loginRequired) { + public ThumbOverviewTab(String title, PaginatedScheduledService updateService) { super(title); - this.url = url; - this.loginRequired = loginRequired; + this.updateService = updateService; setClosable(false); createGui(); initializeUpdateService(); @@ -136,13 +126,17 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { pageInput.setPrefWidth(50); pageInput.setOnAction((e) -> handlePageNumberInput()); pagePrev.setOnAction((e) -> { + int page = updateService.getPage(); page = Math.max(1, --page); pageInput.setText(Integer.toString(page)); + updateService.setPage(page); restartUpdateService(); }); pageNext.setOnAction((e) -> { + int page = updateService.getPage(); page++; pageInput.setText(Integer.toString(page)); + updateService.setPage(page); restartUpdateService(); }); @@ -189,12 +183,13 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { private void handlePageNumberInput() { try { - page = Integer.parseInt(pageInput.getText()); + int page = Integer.parseInt(pageInput.getText()); page = Math.max(1, page); + updateService.setPage(page); restartUpdateService(); } catch(NumberFormatException e) { } finally { - pageInput.setText(Integer.toString(page)); + pageInput.setText(Integer.toString(updateService.getPage())); } } @@ -211,7 +206,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } void initializeUpdateService() { - updateService = createUpdateService(); updateService.setPeriod(new Duration(TimeUnit.SECONDS.toMillis(10))); updateService.setOnSucceeded((event) -> onSuccess()); updateService.setOnFailed((event) -> onFail(event)); @@ -223,7 +217,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } gridLock.lock(); try { - List models = updateService.getValue(); + List models = updateService.getValue(); ObservableList nodes = grid.getChildren(); // first remove models, which are not in the updated list @@ -238,7 +232,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { List positionChangedOrNew = new ArrayList<>(); int index = 0; - for (ChaturbateModel model : models) { + for (Model model : models) { boolean found = false; for (Iterator iterator = nodes.iterator(); iterator.hasNext();) { Node node = iterator.next(); @@ -278,7 +272,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } - ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, ChaturbateModel model, Recorder recorder2, HttpClient client2) { + ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, Model model, Recorder recorder2, HttpClient client2) { ThumbCell newCell = new ThumbCell(this, model, recorder, client); newCell.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> { suspendUpdates(true); @@ -341,7 +335,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { Map event = new HashMap<>(); event.put("event", "tokens.sent"); event.put("amount", tokens); - CtbrecApplication.bus.post(event); + CamrecApplication.bus.post(event); } catch (IOException e1) { Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); alert.setTitle("Error"); @@ -476,7 +470,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { for (Iterator iterator = grid.getChildren().iterator(); iterator.hasNext();) { Node node = iterator.next(); ThumbCell cell = (ThumbCell) node; - ChaturbateModel m = cell.getModel(); + Model m = cell.getModel(); if(!matches(m, filter)) { iterator.remove(); filteredThumbCells.add(cell); @@ -487,7 +481,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { // add the ones, which might have been filtered before, but now match for (Iterator iterator = filteredThumbCells.iterator(); iterator.hasNext();) { ThumbCell thumbCell = iterator.next(); - ChaturbateModel m = thumbCell.getModel(); + Model m = thumbCell.getModel(); if(matches(m, filter)) { iterator.remove(); insert(thumbCell); @@ -520,7 +514,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } } - private boolean matches(ChaturbateModel m, String filter) { + private boolean matches(Model m, String filter) { try { String[] tokens = filter.split(" "); StringBuilder searchTextBuilder = new StringBuilder(m.getName()); @@ -558,43 +552,6 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { } } - private ScheduledService> createUpdateService() { - ScheduledService> updateService = new ScheduledService>() { - @Override - protected Task> createTask() { - return new Task>() { - @Override - public List call() throws IOException { - String url = ThumbOverviewTab.this.url + "?page="+page+"&keywords=&_=" + System.currentTimeMillis(); - LOG.debug("Fetching page {}", url); - Request request = new Request.Builder().url(url).build(); - Response response = client.execute(request, loginRequired); - if (response.isSuccessful()) { - List models = ModelParser.parseModels(response.body().string()); - response.close(); - return models; - } else { - int code = response.code(); - response.close(); - throw new IOException("HTTP status " + code); - } - } - }; - } - }; - ExecutorService executor = Executors.newSingleThreadExecutor(new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setDaemon(true); - t.setName("ThumbOverviewTab UpdateService"); - return t; - } - }); - updateService.setExecutor(executor); - return updateService; - } - public void setRecorder(Recorder recorder) { this.recorder = recorder; } diff --git a/src/main/java/ctbrec/ui/TipDialog.java b/src/main/java/ctbrec/ui/TipDialog.java index f9533dce..8e01cf72 100644 --- a/src/main/java/ctbrec/ui/TipDialog.java +++ b/src/main/java/ctbrec/ui/TipDialog.java @@ -54,7 +54,7 @@ public class TipDialog extends TextInputDialog { Map event = new HashMap<>(); event.put("event", "tokens"); event.put("amount", tokens); - CtbrecApplication.bus.post(event); + CamrecApplication.bus.post(event); return tokens; } else { throw new IOException("HTTP response: " + resp.code() + " - " + resp.message()); @@ -78,7 +78,7 @@ public class TipDialog extends TextInputDialog { buyTokens.showAndWait(); TipDialog.this.close(); if(buyTokens.getResult() == ButtonType.YES) { - DesktopIntergation.open(CtbrecApplication.AFFILIATE_LINK); + DesktopIntergation.open(CamrecApplication.AFFILIATE_LINK); } } else { getEditor().setDisable(false); diff --git a/src/main/java/ctbrec/ui/TokenLabel.java b/src/main/java/ctbrec/ui/TokenLabel.java index b9d9a23b..073fb038 100644 --- a/src/main/java/ctbrec/ui/TokenLabel.java +++ b/src/main/java/ctbrec/ui/TokenLabel.java @@ -14,7 +14,7 @@ public class TokenLabel extends Label { public TokenLabel() { setText("Tokens: loading…"); - CtbrecApplication.bus.register(new Object() { + CamrecApplication.bus.register(new Object() { @Subscribe public void tokensUpdates(Map e) { if(Objects.equals("tokens", e.get("event"))) { diff --git a/src/main/java/ctbrec/ui/UpdateTab.java b/src/main/java/ctbrec/ui/UpdateTab.java index 4c82647e..7306b392 100644 --- a/src/main/java/ctbrec/ui/UpdateTab.java +++ b/src/main/java/ctbrec/ui/UpdateTab.java @@ -3,7 +3,7 @@ package ctbrec.ui; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ctbrec.ui.CtbrecApplication.Release; +import ctbrec.ui.CamrecApplication.Release; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.Button;