diff --git a/src/main/java/ctbrec/io/HttpClient.java b/src/main/java/ctbrec/io/HttpClient.java index 533db368..eb6fb409 100644 --- a/src/main/java/ctbrec/io/HttpClient.java +++ b/src/main/java/ctbrec/io/HttpClient.java @@ -76,8 +76,8 @@ public abstract class HttpClient { public Response execute(Request req, boolean requiresLogin) throws IOException { if(requiresLogin && !loggedIn) { - boolean loginSuccessful = login(); - if(!loginSuccessful) { + loggedIn = login(); + if(!loggedIn) { throw new IOException("403 Unauthorized"); } } diff --git a/src/main/java/ctbrec/sites/Site.java b/src/main/java/ctbrec/sites/Site.java index c10815dd..6265c8f3 100644 --- a/src/main/java/ctbrec/sites/Site.java +++ b/src/main/java/ctbrec/sites/Site.java @@ -19,4 +19,6 @@ public interface Site { public void login() throws IOException; public HttpClient getHttpClient(); public void shutdown(); + public boolean supportsTips(); + public boolean supportsFollow(); } diff --git a/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java b/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java index 6f31e5ac..c2f5cf56 100644 --- a/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java +++ b/src/main/java/ctbrec/sites/chaturbate/Chaturbate.java @@ -130,6 +130,16 @@ public class Chaturbate implements Site { httpClient.shutdown(); } + @Override + public boolean supportsFollow() { + return true; + } + + @Override + public boolean supportsTips() { + return true; + } + // ####################### private long lastRequest = System.currentTimeMillis(); diff --git a/src/main/java/ctbrec/sites/mfc/FriendsUpdateService.java b/src/main/java/ctbrec/sites/mfc/FriendsUpdateService.java index ec7d6763..34661797 100644 --- a/src/main/java/ctbrec/sites/mfc/FriendsUpdateService.java +++ b/src/main/java/ctbrec/sites/mfc/FriendsUpdateService.java @@ -40,24 +40,29 @@ public class FriendsUpdateService extends PaginatedScheduledService { Response resp = myFreeCams.getHttpClient().execute(req, true); if(resp.isSuccessful()) { String json = resp.body().string().substring(4); - JSONObject object = new JSONObject(json); - for (String key : object.keySet()) { - int uid = Integer.parseInt(key); - MyFreeCamsModel model = MyFreeCamsClient.getInstance().getModel(uid); - if(model == null) { - JSONObject modelObject = object.getJSONObject(key); - String name = modelObject.getString("u"); - model = myFreeCams.createModel(name); - SessionState st = new SessionState(); - st.setM(new ctbrec.sites.mfc.Model()); - st.getM().setCamscore(0.0); - st.setU(new User()); - st.setUid(uid); - st.setLv(modelObject.getInt("lv")); - st.setVs(127); - model.update(st); + try { + JSONObject object = new JSONObject(json); + for (String key : object.keySet()) { + int uid = Integer.parseInt(key); + MyFreeCamsModel model = MyFreeCamsClient.getInstance().getModel(uid); + if(model == null) { + JSONObject modelObject = object.getJSONObject(key); + String name = modelObject.getString("u"); + model = myFreeCams.createModel(name); + SessionState st = new SessionState(); + st.setM(new ctbrec.sites.mfc.Model()); + st.getM().setCamscore(0.0); + st.setU(new User()); + st.setUid(uid); + st.setLv(modelObject.getInt("lv")); + st.setVs(127); + model.update(st); + } + models.add(model); } - models.add(model); + } catch(Exception e) { + LOG.info("JSON: {}", json); + throw e; } } else { LOG.error("Couldn't load friends list {} {}", resp.code(), resp.message()); diff --git a/src/main/java/ctbrec/sites/mfc/MyFreeCams.java b/src/main/java/ctbrec/sites/mfc/MyFreeCams.java index dea59ff1..70414cbb 100644 --- a/src/main/java/ctbrec/sites/mfc/MyFreeCams.java +++ b/src/main/java/ctbrec/sites/mfc/MyFreeCams.java @@ -2,9 +2,14 @@ package ctbrec.sites.mfc; import java.io.IOException; +import org.jsoup.select.Elements; + import ctbrec.recorder.Recorder; import ctbrec.sites.Site; +import ctbrec.ui.HtmlParser; import ctbrec.ui.TabProvider; +import okhttp3.Request; +import okhttp3.Response; public class MyFreeCams implements Site { @@ -18,13 +23,11 @@ public class MyFreeCams implements Site { client = MyFreeCamsClient.getInstance(); client.setSite(this); client.start(); - - login(); } @Override public void login() throws IOException { - + httpClient.login(); } @Override @@ -62,7 +65,17 @@ public class MyFreeCams implements Site { @Override public Integer getTokenBalance() throws IOException { - throw new RuntimeException("Not implemented for MFC"); + Request req = new Request.Builder().url(BASE_URI + "/php/account.php?request=status").build(); + Response resp = httpClient.execute(req, true); + if(resp.isSuccessful()) { + String content = resp.body().string(); + Elements tags = HtmlParser.getTags(content, "div.content > p > b"); + String tokens = tags.get(2).text(); + return Integer.parseInt(tokens); + } else { + resp.close(); + throw new IOException(resp.code() + " " + resp.message()); + } } @Override @@ -79,4 +92,14 @@ public class MyFreeCams implements Site { public void shutdown() { httpClient.shutdown(); } + + @Override + public boolean supportsFollow() { + return false; + } + + @Override + public boolean supportsTips() { + return true; + } } diff --git a/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java b/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java index 88e3c2ab..3ad60ca9 100644 --- a/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java +++ b/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java @@ -96,8 +96,17 @@ public class MyFreeCamsClient { try { LOG.trace("open: [{}]", response.body().string()); webSocket.send("hello fcserver\n"); + // webSocket.send("fcsws_20180422\n"); + // webSocket.send("1 0 0 81 0 %7B%22err%22%3A0%2C%22start%22%3A1540159843072%2C%22stop%22%3A1540159844121%2C%22a%22%3A6392%2C%22time%22%3A1540159844%2C%22key%22%3A%228da80f985c9db390809713dac71df297%22%2C%22cid%22%3A%22c504d684%22%2C%22pid%22%3A1%2C%22site%22%3A%22www%22%7D\n"); // TxCmd Sending - nType: 1, nTo: 0, nArg1: 20080909, nArg2: 0, sMsg:guest:guest + // String username = Config.getInstance().getSettings().username; + // if(username != null && !username.trim().isEmpty()) { + // mfc.getHttpClient().login(); + // Cookie passcode = mfc.getHttpClient().getCookie("passcode"); + // webSocket.send("1 0 0 20080909 0 "+username+":"+passcode+"\n"); + // } else { webSocket.send("1 0 0 20080909 0 guest:guest\n"); + // } startKeepAlive(webSocket); } catch (IOException e) { e.printStackTrace(); @@ -129,7 +138,12 @@ public class MyFreeCamsClient { switch (message.getType()) { case LOGIN: - LOG.trace("login"); + System.out.println("LOGIN"); + System.out.println("Sender " + message.getSender()); + System.out.println("Receiver " + message.getReceiver()); + System.out.println("Arg1 " + message.getArg1()); + System.out.println("Arg2 " + message.getArg2()); + System.out.println("Msg " + message.getMessage()); break; case DETAILS: case ROOMHELPER: @@ -166,10 +180,47 @@ public class MyFreeCamsClient { } break; case EXTDATA: + // if(message.getReceiver() == 0) { + // String key = message.getMessage(); + // String username = Config.getInstance().getSettings().username; + // if(username != null && !username.trim().isEmpty()) { + // boolean login = mfc.getHttpClient().login(); + // if(login) { + // Cookie passcode = mfc.getHttpClient().getCookie("passcode"); + // System.out.println("1 0 0 20071025 0 "+key+"@1/"+username+":"+passcode+"\n"); + // webSocket.send("1 0 0 20071025 0 "+key+"@1/"+username+":"+passcode+"\n"); + // } else { + // LOG.error("Login failed"); + // } + // } else { + // webSocket.send("1 0 0 20080909 0 guest:guest\n"); + // } + // } + // System.out.println("EXTDATA"); + // System.out.println("Sender " + message.getSender()); + // System.out.println("Receiver " + message.getReceiver()); + // System.out.println("Arg1 " + message.getArg1()); + // System.out.println("Arg2 " + message.getArg2()); + // System.out.println("Msg " + message.getMessage()); requestExtData(message.getMessage()); break; + case ROOMDATA: + System.out.println("ROOMDATA"); + System.out.println("Sender " + message.getSender()); + System.out.println("Receiver " + message.getReceiver()); + System.out.println("Arg1 " + message.getArg1()); + System.out.println("Arg2 " + message.getArg2()); + System.out.println("Msg " + message.getMessage()); + case UEOPT: + System.out.println("UEOPT"); + System.out.println("Sender " + message.getSender()); + System.out.println("Receiver " + message.getReceiver()); + System.out.println("Arg1 " + message.getArg1()); + System.out.println("Arg2 " + message.getArg2()); + System.out.println("Msg " + message.getMessage()); + break; default: - LOG.trace("Unknown message {}", message); + LOG.debug("Unknown message {}", message); break; } } catch (UnsupportedEncodingException e) { @@ -290,6 +341,7 @@ public class MyFreeCamsClient { MyFreeCamsModel model = models.get(state.getUid()); if(model == null) { model = mfc.createModel(state.getNm()); + model.setUid(state.getUid()); models.put(state.getUid(), model); } model.update(state); diff --git a/src/main/java/ctbrec/sites/mfc/MyFreeCamsHttpClient.java b/src/main/java/ctbrec/sites/mfc/MyFreeCamsHttpClient.java index e72f591d..02fbc533 100644 --- a/src/main/java/ctbrec/sites/mfc/MyFreeCamsHttpClient.java +++ b/src/main/java/ctbrec/sites/mfc/MyFreeCamsHttpClient.java @@ -1,13 +1,19 @@ package ctbrec.sites.mfc; import java.io.IOException; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.Objects; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ctbrec.Config; import ctbrec.io.HttpClient; +import okhttp3.Cookie; +import okhttp3.CookieJar; import okhttp3.FormBody; +import okhttp3.HttpUrl; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; @@ -20,6 +26,10 @@ public class MyFreeCamsHttpClient extends HttpClient { @Override public boolean login() throws IOException { + if(loggedIn) { + return true; + } + String username = Config.getInstance().getSettings().username; String password = Config.getInstance().getSettings().password; RequestBody body = new FormBody.Builder() @@ -37,8 +47,14 @@ public class MyFreeCamsHttpClient extends HttpClient { .build(); Response resp = execute(req); if(resp.isSuccessful()) { - resp.close(); - return true; + String page = resp.body().string(); + System.out.println(page); + if(page.contains("Your username or password are incorrect")) { + return false; + } else { + loggedIn = true; + return true; + } } else { resp.close(); LOG.error("Login failed {} {}", resp.code(), resp.message()); @@ -49,4 +65,16 @@ public class MyFreeCamsHttpClient extends HttpClient { public WebSocket newWebSocket(Request req, WebSocketListener webSocketListener) { return client.newWebSocket(req, webSocketListener); } + + public Cookie getCookie(String name) { + CookieJar jar = client.cookieJar(); + HttpUrl url = HttpUrl.parse(MyFreeCams.BASE_URI); + List cookies = jar.loadForRequest(url); + for (Cookie cookie : cookies) { + if(Objects.equals(cookie.name(), name)) { + return cookie; + } + } + throw new NoSuchElementException("No cookie with name " + name); + } } diff --git a/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java b/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java index 4447f70a..6cd0880d 100644 --- a/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java +++ b/src/main/java/ctbrec/sites/mfc/MyFreeCamsModel.java @@ -7,9 +7,11 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutionException; +import org.jsoup.nodes.Element; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,13 +26,17 @@ import com.iheartradio.m3u8.data.PlaylistData; import ctbrec.AbstractModel; import ctbrec.recorder.download.StreamSource; +import ctbrec.ui.HtmlParser; +import okhttp3.FormBody; import okhttp3.Request; +import okhttp3.RequestBody; import okhttp3.Response; public class MyFreeCamsModel extends AbstractModel { private static final transient Logger LOG = LoggerFactory.getLogger(MyFreeCamsModel.class); + private int uid; private String hlsUrl; private double camScore; private State state; @@ -105,7 +111,44 @@ public class MyFreeCamsModel extends AbstractModel { @Override public void receiveTip(int tokens) throws IOException { - throw new RuntimeException("Not implemented for MFC"); + String tipUrl = MyFreeCams.BASE_URI + "/php/tip.php"; + String initUrl = tipUrl + "?request=tip&username="+getName()+"&broadcaster_id="+getUid(); + Request req = new Request.Builder().url(initUrl).build(); + Response resp = site.getHttpClient().execute(req); + if(resp.isSuccessful()) { + String page = resp.body().string(); + Element hiddenInput = HtmlParser.getTag(page, "input[name=token]"); + String token = hiddenInput.attr("value"); + if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) { + RequestBody body = new FormBody.Builder() + .add("token", token) + .add("broadcaster_id", Integer.toString(uid)) + .add("tip_value", Integer.toString(tokens)) + .add("submit_tip", "1") + .add("anonymous", "") + .add("public", "1") + .add("public_comment", "1") + .add("hide_amount", "0") + .add("silent", "") + .add("comment", "") + .add("mode", "") + .add("submit", " Confirm & Close Window") + .build(); + req = new Request.Builder() + .url(tipUrl) + .post(body) + .addHeader("Referer", initUrl) + .build(); + try(Response response = site.getHttpClient().execute(req, true)) { + if(!response.isSuccessful()) { + throw new IOException(response.code() + " " + response.message()); + } + } + } + } else { + resp.close(); + throw new IOException(resp.code() + " " + resp.message()); + } } @Override @@ -204,4 +247,12 @@ public class MyFreeCamsModel extends AbstractModel { public boolean unfollow() { return false; } + + public int getUid() { + return uid; + } + + public void setUid(int uid) { + this.uid = uid; + } } diff --git a/src/main/java/ctbrec/ui/ThumbOverviewTab.java b/src/main/java/ctbrec/ui/ThumbOverviewTab.java index 92ce556f..ce3d8164 100644 --- a/src/main/java/ctbrec/ui/ThumbOverviewTab.java +++ b/src/main/java/ctbrec/ui/ThumbOverviewTab.java @@ -387,7 +387,11 @@ 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, sendTip, debug); + contextMenu.getItems().addAll(openInPlayer, startStop); + if(site.supportsFollow()) { + contextMenu.getItems().add(followOrUnFollow); + } + contextMenu.getItems().addAll(copyUrl, sendTip, debug); return contextMenu; }