diff --git a/src/main/java/ctbrec/Model.java b/src/main/java/ctbrec/Model.java index 7435aa19..2af0b540 100644 --- a/src/main/java/ctbrec/Model.java +++ b/src/main/java/ctbrec/Model.java @@ -144,6 +144,10 @@ public class Model { return Chaturbate.INSTANCE.getMasterPlaylist(getName()); } + public void receiveTip(int tokens) throws IOException { + Chaturbate.INSTANCE.sendTip(getName(), tokens); + } + @Override public int hashCode() { final int prime = 31; @@ -215,6 +219,25 @@ public class Model { this.client = client; } + public void sendTip(String name, int tokens) throws IOException { + RequestBody body = new FormBody.Builder() + .add("csrfmiddlewaretoken", client.getToken()) + .add("tip_amount", Integer.toString(tokens)) + .add("tip_room_type", "public") + .build(); + Request req = new Request.Builder() + .url("https://chaturbate.com/tipping/send_tip/"+name+"/") + .post(body) + .addHeader("Referer", "https://chaturbate.com/"+name+"/") + .addHeader("X-Requested-With", "XMLHttpRequest") + .build(); + try(Response response = client.execute(req, true)) { + if(!response.isSuccessful()) { + throw new IOException(response.code() + " " + response.message()); + } + } + } + private StreamInfo getStreamInfo(String modelName) throws IOException, ExecutionException { return streamInfoCache.get(modelName); } diff --git a/src/main/java/ctbrec/ui/ThumbOverviewTab.java b/src/main/java/ctbrec/ui/ThumbOverviewTab.java index 584bc702..708b373e 100644 --- a/src/main/java/ctbrec/ui/ThumbOverviewTab.java +++ b/src/main/java/ctbrec/ui/ThumbOverviewTab.java @@ -326,6 +326,35 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { clipboard.setContent(content); }); + MenuItem sendTip = new MenuItem("Send Tip"); + sendTip.setOnAction((e) -> { + TipDialog tipDialog = new TipDialog(cell.getModel()); + tipDialog.showAndWait(); + String tipText = tipDialog.getResult(); + if(tipText != null) { + if(tipText.matches("[1-9]\\d*")) { + int tokens = Integer.parseInt(tipText); + try { + cell.getModel().receiveTip(tokens); + } catch (IOException e1) { + Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); + alert.setTitle("Error"); + alert.setHeaderText("Couldn't send tip"); + alert.setContentText("An error occured while sending tip: " + e1.getLocalizedMessage()); + alert.showAndWait(); + } + } else { + Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); + alert.setTitle("Error"); + alert.setHeaderText("Couldn't send tip"); + alert.setContentText("You entered an invalid amount of tokens"); + alert.showAndWait(); + } + } + }); + String username = Config.getInstance().getSettings().username; + sendTip.setDisable(username == null || username.trim().isEmpty()); + // check, if other cells are selected, too. in that case, we have to disable menu item, which make sense only for // single selections. but only do that, if the popup has been triggered on a selected cell. otherwise remove the // selection and show the normal menu @@ -335,6 +364,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { openInPlayer.setDisable(true); } copyUrl.setDisable(true); + sendTip.setDisable(true); } else { removeSelection(); } @@ -345,7 +375,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener { contextMenu.setHideOnEscape(true); contextMenu.setAutoFix(true); MenuItem followOrUnFollow = this instanceof FollowedTab ? unfollow : follow; - contextMenu.getItems().addAll(openInPlayer, startStop , followOrUnFollow, copyUrl); + contextMenu.getItems().addAll(openInPlayer, startStop , followOrUnFollow, copyUrl, sendTip); return contextMenu; } diff --git a/src/main/java/ctbrec/ui/TipDialog.java b/src/main/java/ctbrec/ui/TipDialog.java new file mode 100644 index 00000000..09fc9ca4 --- /dev/null +++ b/src/main/java/ctbrec/ui/TipDialog.java @@ -0,0 +1,79 @@ +package ctbrec.ui; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ctbrec.Config; +import ctbrec.HttpClient; +import ctbrec.Model; +import javafx.application.Platform; +import javafx.concurrent.Task; +import javafx.scene.control.Alert; +import javafx.scene.control.TextInputDialog; +import okhttp3.Request; +import okhttp3.Response; + +public class TipDialog extends TextInputDialog { + + private static final transient Logger LOG = LoggerFactory.getLogger(TipDialog.class); + + public TipDialog(Model model) { + setTitle("Send Tip"); + loadTokenBalance(); + setHeaderText("Loading token balanceā€¦"); + setContentText("Amount of tokens to tip:"); + setResizable(true); + } + + private void loadTokenBalance() { + Task task = new Task() { + @Override + protected Integer call() throws Exception { + String username = Config.getInstance().getSettings().username; + if (username == null || username.trim().isEmpty()) { + throw new IOException("Not logged in"); + } + + String url = "https://chaturbate.com/p/" + username + "/"; + HttpClient client = HttpClient.getInstance(); + Request req = new Request.Builder().url(url).build(); + Response resp = client.execute(req, true); + if (resp.isSuccessful()) { + String profilePage = resp.body().string(); + String tokenText = HtmlParser.getText(profilePage, "span.tokencount"); + int tokens = Integer.parseInt(tokenText); + return tokens; + } else { + throw new IOException("HTTP response: " + resp.code() + " - " + resp.message()); + } + } + + @Override + protected void done() { + try { + int tokens = get(); + Platform.runLater(() -> setHeaderText("Current token balance: " + tokens)); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Couldn't retrieve account balance", e); + showErrorDialog(e); + } + } + }; + new Thread(task).start(); + } + + private void showErrorDialog(Throwable throwable) { + Platform.runLater(() -> { + Alert alert = new AutosizeAlert(Alert.AlertType.ERROR); + alert.setTitle("Error"); + alert.setHeaderText("Couldn't retrieve token balance"); + alert.setContentText("Error while loading your token balance: " + throwable.getLocalizedMessage()); + alert.showAndWait(); + TipDialog.this.close(); + }); + } + +}