Implemented followed tab for CamSoda
This commit is contained in:
parent
7442ddd3e4
commit
8fd09fd521
|
@ -24,6 +24,8 @@ public class Settings {
|
|||
public String password = ""; // chaturbate password TODO maybe rename this onetime
|
||||
public String mfcUsername = "";
|
||||
public String mfcPassword = "";
|
||||
public String camsodaUsername = "";
|
||||
public String camsodaPassword = "";
|
||||
public String lastDownloadDir = "";
|
||||
|
||||
public List<Model> models = new ArrayList<Model>();
|
||||
|
|
|
@ -2,12 +2,26 @@ package ctbrec.sites.camsoda;
|
|||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.AbstractSite;
|
||||
import ctbrec.ui.DesktopIntergation;
|
||||
import ctbrec.ui.SettingsTab;
|
||||
import ctbrec.ui.TabProvider;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.PasswordField;
|
||||
import javafx.scene.control.TextField;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class Camsoda extends AbstractSite {
|
||||
|
||||
|
@ -27,7 +41,7 @@ public class Camsoda extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public String getAffiliateLink() {
|
||||
return "";
|
||||
return BASE_URI;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -51,7 +65,26 @@ public class Camsoda extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public Integer getTokenBalance() throws IOException {
|
||||
return 0;
|
||||
String username = Config.getInstance().getSettings().camsodaUsername;
|
||||
if (username == null || username.trim().isEmpty()) {
|
||||
throw new IOException("Not logged in");
|
||||
}
|
||||
|
||||
String url = BASE_URI + "/api/v1/user/" + username;
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
Response response = getHttpClient().execute(request, true);
|
||||
if(response.isSuccessful()) {
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if(json.has("user")) {
|
||||
JSONObject user = json.getJSONObject("user");
|
||||
if(user.has("tokens")) {
|
||||
return user.getInt("tokens");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new IOException(response.code() + " " + response.message());
|
||||
}
|
||||
throw new RuntimeException("Tokens not found in response");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,23 +94,19 @@ public class Camsoda extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public void login() throws IOException {
|
||||
httpClient.login();
|
||||
getHttpClient().login();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpClient getHttpClient() {
|
||||
if(httpClient == null) {
|
||||
httpClient = new CamsodaHttpClient();
|
||||
}
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws IOException {
|
||||
httpClient = new HttpClient() {
|
||||
@Override
|
||||
public boolean login() throws IOException {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -87,12 +116,12 @@ public class Camsoda extends AbstractSite {
|
|||
|
||||
@Override
|
||||
public boolean supportsTips() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFollow() {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,12 +130,38 @@ public class Camsoda extends AbstractSite {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Node getConfigurationGui() {
|
||||
return null;
|
||||
public boolean credentialsAvailable() {
|
||||
String username = Config.getInstance().getSettings().camsodaUsername;
|
||||
return username != null && !username.trim().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean credentialsAvailable() {
|
||||
return false;
|
||||
public Node getConfigurationGui() {
|
||||
GridPane layout = SettingsTab.createGridLayout();
|
||||
layout.add(new Label("CamSoda User"), 0, 0);
|
||||
TextField username = new TextField(Config.getInstance().getSettings().camsodaUsername);
|
||||
username.focusedProperty().addListener((e) -> Config.getInstance().getSettings().camsodaUsername = username.getText());
|
||||
GridPane.setFillWidth(username, true);
|
||||
GridPane.setHgrow(username, Priority.ALWAYS);
|
||||
GridPane.setColumnSpan(username, 2);
|
||||
layout.add(username, 1, 0);
|
||||
|
||||
layout.add(new Label("CamSoda Password"), 0, 1);
|
||||
PasswordField password = new PasswordField();
|
||||
password.setText(Config.getInstance().getSettings().camsodaPassword);
|
||||
password.focusedProperty().addListener((e) -> Config.getInstance().getSettings().camsodaPassword = password.getText());
|
||||
GridPane.setFillWidth(password, true);
|
||||
GridPane.setHgrow(password, Priority.ALWAYS);
|
||||
GridPane.setColumnSpan(password, 2);
|
||||
layout.add(password, 1, 1);
|
||||
|
||||
Button createAccount = new Button("Create new Account");
|
||||
createAccount.setOnAction((e) -> DesktopIntergation.open(getAffiliateLink()));
|
||||
layout.add(createAccount, 1, 2);
|
||||
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(createAccount, new Insets(0, 0, 0, SettingsTab.CHECKBOX_MARGIN));
|
||||
return layout;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package ctbrec.sites.camsoda;
|
||||
|
||||
import ctbrec.ui.FollowedTab;
|
||||
import ctbrec.ui.ThumbOverviewTab;
|
||||
import javafx.concurrent.WorkerStateEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.RadioButton;
|
||||
import javafx.scene.control.ToggleGroup;
|
||||
import javafx.scene.input.KeyCode;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.HBox;
|
||||
|
||||
public class CamsodaFollowedTab extends ThumbOverviewTab implements FollowedTab {
|
||||
private Label status;
|
||||
boolean showOnline = true;
|
||||
|
||||
public CamsodaFollowedTab(String title, Camsoda camsoda) {
|
||||
super(title, new CamsodaFollowedUpdateService(camsoda), camsoda);
|
||||
status = new Label("Logging in...");
|
||||
grid.getChildren().add(status);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createGui() {
|
||||
super.createGui();
|
||||
addOnlineOfflineSelector();
|
||||
}
|
||||
|
||||
private void addOnlineOfflineSelector() {
|
||||
ToggleGroup group = new ToggleGroup();
|
||||
RadioButton online = new RadioButton("online");
|
||||
online.setToggleGroup(group);
|
||||
RadioButton offline = new RadioButton("offline");
|
||||
offline.setToggleGroup(group);
|
||||
pagination.getChildren().add(online);
|
||||
pagination.getChildren().add(offline);
|
||||
HBox.setMargin(online, new Insets(5, 5, 5, 40));
|
||||
HBox.setMargin(offline, new Insets(5, 5, 5, 5));
|
||||
online.setSelected(true);
|
||||
group.selectedToggleProperty().addListener((e) -> {
|
||||
queue.clear();
|
||||
((CamsodaFollowedUpdateService)updateService).showOnline(online.isSelected());
|
||||
updateService.restart();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSuccess() {
|
||||
grid.getChildren().remove(status);
|
||||
super.onSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFail(WorkerStateEvent event) {
|
||||
status.setText("Login failed");
|
||||
super.onFail(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected() {
|
||||
status.setText("Logging in...");
|
||||
super.selected();
|
||||
}
|
||||
|
||||
public void setScene(Scene scene) {
|
||||
scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
|
||||
if (this.isSelected()) {
|
||||
if (event.getCode() == KeyCode.DELETE) {
|
||||
follow(selectedThumbCells, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package ctbrec.sites.camsoda;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.ui.PaginatedScheduledService;
|
||||
import javafx.concurrent.Task;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class CamsodaFollowedUpdateService extends PaginatedScheduledService {
|
||||
private Camsoda camsoda;
|
||||
private boolean showOnline = true;
|
||||
|
||||
public CamsodaFollowedUpdateService(Camsoda camsoda) {
|
||||
this.camsoda = camsoda;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Task<List<Model>> createTask() {
|
||||
return new Task<List<Model>>() {
|
||||
@Override
|
||||
public List<Model> call() throws IOException {
|
||||
List<Model> models = new ArrayList<>();
|
||||
String url = camsoda.getBaseUrl() + "/api/v1/user/current";
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
Response response = camsoda.getHttpClient().execute(request, true);
|
||||
if (response.isSuccessful()) {
|
||||
JSONObject json = new JSONObject(response.body().string());
|
||||
if(json.has("status") && json.getBoolean("status")) {
|
||||
JSONObject user = json.getJSONObject("user");
|
||||
JSONArray following = user.getJSONArray("following");
|
||||
for (int i = 0; i < following.length(); i++) {
|
||||
JSONObject m = following.getJSONObject(i);
|
||||
CamsodaModel model = (CamsodaModel) camsoda.createModel(m.getString("followname"));
|
||||
boolean online = m.getInt("online") == 1;
|
||||
model.setOnlineState(online ? "offline" : "online");
|
||||
model.setPreview("https://md.camsoda.com/thumbs/" + model.getName() + ".jpg");
|
||||
models.add(model);
|
||||
}
|
||||
return models.stream()
|
||||
.filter((m) -> {
|
||||
try {
|
||||
return m.isOnline() == showOnline;
|
||||
} catch (IOException | ExecutionException | InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
} else {
|
||||
response.close();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
} else {
|
||||
int code = response.code();
|
||||
response.close();
|
||||
throw new IOException("HTTP status " + code);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void showOnline(boolean online) {
|
||||
this.showOnline = online;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package ctbrec.sites.camsoda;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.io.HttpClient;
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class CamsodaHttpClient extends HttpClient {
|
||||
|
||||
@Override
|
||||
public boolean login() throws IOException {
|
||||
String url = Camsoda.BASE_URI + "/api/v1/auth/login";
|
||||
FormBody body = new FormBody.Builder()
|
||||
.add("username", Config.getInstance().getSettings().camsodaUsername)
|
||||
.add("password", Config.getInstance().getSettings().camsodaPassword)
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(body)
|
||||
.build();
|
||||
Response response = execute(request);
|
||||
if(response.isSuccessful()) {
|
||||
JSONObject resp = new JSONObject(response.body().string());
|
||||
if(resp.has("error")) {
|
||||
throw new IOException(resp.getString("error"));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
throw new IOException(response.code() + " " + response.message());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import ctbrec.AbstractModel;
|
|||
import ctbrec.recorder.download.StreamSource;
|
||||
import ctbrec.sites.Site;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class CamsodaModel extends AbstractModel {
|
||||
|
@ -94,8 +95,7 @@ public class CamsodaModel extends AbstractModel {
|
|||
|
||||
@Override
|
||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||
LOG.trace("Loading master playlist {}", streamUrl);
|
||||
if(streamSources == null) {
|
||||
LOG.debug("Loading master playlist {}", streamUrl);
|
||||
Request req = new Request.Builder().url(streamUrl).build();
|
||||
Response response = site.getHttpClient().execute(req);
|
||||
try {
|
||||
|
@ -120,7 +120,6 @@ public class CamsodaModel extends AbstractModel {
|
|||
} finally {
|
||||
response.close();
|
||||
}
|
||||
}
|
||||
return streamSources;
|
||||
}
|
||||
|
||||
|
@ -153,18 +152,47 @@ public class CamsodaModel extends AbstractModel {
|
|||
@Override
|
||||
public void receiveTip(int tokens) throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
/*
|
||||
sendTip: function(i, a, r, o, c, d) {
|
||||
if (!s.isAuthenticated()) return s.showRegister(), t.when(!1);
|
||||
var u = t.defer();
|
||||
return e.post("/api/v1/tip/" + i, {
|
||||
amount: a,
|
||||
comment: o,
|
||||
type: r,
|
||||
app_data: c,
|
||||
source_id: d
|
||||
}).then(function(e) {
|
||||
1 == e.data.status ? (s.currentUser.tokens = e.data.total, void 0 != e.data.tipped_performer_last_24hrs && e.data.tipped_performer_last_24hrs >= 25 && (n.$emit("local.allowed_to_rate"), 0 == n.allowedToRate && (n.allowedToRate = !0, l.pop("info", "Voting Unlocked", "You tipped " + i + " 25 tokens in the past 24 hours, you may now vote!"))), u.resolve(e.data)) : (l.pop("error", e.data.error, e.data.message), u.reject(e.data))
|
||||
}), u.promise
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean follow() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
String url = Camsoda.BASE_URI + "/api/v1/follow/" + getName();
|
||||
//RequestBody body = new FormBody.Builder().build();
|
||||
LOG.debug("Sending follow request {}", url);
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.post(RequestBody.create(null, ""))
|
||||
.addHeader("Content-Lentgh", "0")
|
||||
.addHeader("Referer", Camsoda.BASE_URI + '/' + getName())
|
||||
.build();
|
||||
Response resp = site.getHttpClient().execute(request, true);
|
||||
if (resp.isSuccessful()) {
|
||||
System.out.println(resp.body().string());
|
||||
return true;
|
||||
} else {
|
||||
resp.close();
|
||||
throw new IOException("HTTP status " + resp.code() + " " + resp.message());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unfollow() throws IOException {
|
||||
// TODO Auto-generated method stub
|
||||
// TODO /api/v1/unfollow/" + n.slug
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,13 +33,13 @@ import javafx.scene.control.Alert;
|
|||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ProgressIndicator;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TitledPane;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.VBox;
|
||||
import javafx.scene.text.Font;
|
||||
import javafx.scene.text.FontWeight;
|
||||
import okhttp3.Request;
|
||||
|
@ -51,7 +51,7 @@ public class CamsodaShowsTab extends Tab implements TabSelectionListener {
|
|||
|
||||
private Camsoda camsoda;
|
||||
private Recorder recorder;
|
||||
private VBox showList;
|
||||
private GridPane showList;
|
||||
private ProgressIndicator progressIndicator;
|
||||
|
||||
public CamsodaShowsTab(Camsoda camsoda, Recorder recorder) {
|
||||
|
@ -61,7 +61,10 @@ public class CamsodaShowsTab extends Tab implements TabSelectionListener {
|
|||
}
|
||||
|
||||
private void createGui() {
|
||||
showList = new VBox();
|
||||
showList = new GridPane();
|
||||
showList.setPadding(new Insets(5));
|
||||
showList.setHgap(5);
|
||||
showList.setVgap(5);
|
||||
progressIndicator = new ProgressIndicator();
|
||||
progressIndicator.setPrefSize(100, 100);
|
||||
setContent(progressIndicator);
|
||||
|
@ -118,14 +121,15 @@ public class CamsodaShowsTab extends Tab implements TabSelectionListener {
|
|||
try {
|
||||
List<ShowBox> boxes = get();
|
||||
showList.getChildren().clear();
|
||||
int index = 0;
|
||||
for (ShowBox showBox : boxes) {
|
||||
showList.getChildren().add(showBox);
|
||||
VBox.setMargin(showBox, new Insets(20, 20, 0, 20));
|
||||
showList.add(showBox, index%2, index++/2);
|
||||
GridPane.setMargin(showBox, new Insets(20, 20, 0, 20));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Couldn't load upcoming camsoda shows", e);
|
||||
}
|
||||
setContent(showList);
|
||||
setContent(new ScrollPane(showList));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -25,11 +25,11 @@ public class CamsodaTabProvider extends TabProvider {
|
|||
public List<Tab> getTabs(Scene scene) {
|
||||
List<Tab> tabs = new ArrayList<>();
|
||||
tabs.add(createTab("Online", BASE_URI + "/api/v1/browse/online"));
|
||||
CamsodaFollowedTab followedTab = new CamsodaFollowedTab("Followed", camsoda);
|
||||
followedTab.setRecorder(recorder);
|
||||
followedTab.setScene(scene);
|
||||
tabs.add(followedTab);
|
||||
tabs.add(new CamsodaShowsTab(camsoda, recorder));
|
||||
// ChaturbateFollowedTab followedTab = new ChaturbateFollowedTab("Followed", BASE_URI + "/followed-cams/", chaturbate);
|
||||
// followedTab.setRecorder(recorder);
|
||||
// followedTab.setScene(scene);
|
||||
// tabs.add(followedTab);
|
||||
return tabs;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package ctbrec.ui;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.iheartradio.m3u8.ParseException;
|
||||
|
@ -20,14 +19,13 @@ import javafx.beans.property.SimpleBooleanProperty;
|
|||
*/
|
||||
public class JavaFxModel extends AbstractModel {
|
||||
private transient BooleanProperty onlineProperty = new SimpleBooleanProperty();
|
||||
|
||||
private Model delegate;
|
||||
|
||||
public JavaFxModel(Model delegate) {
|
||||
this.delegate = delegate;
|
||||
try {
|
||||
onlineProperty.set(Objects.equals("public", delegate.getOnlineState(true)));
|
||||
} catch (IOException | ExecutionException e) {}
|
||||
onlineProperty.set(delegate.isOnline());
|
||||
} catch (IOException | ExecutionException | InterruptedException e) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,6 +13,7 @@ import ctbrec.sites.Site;
|
|||
import javafx.application.Platform;
|
||||
import javafx.concurrent.Task;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.Tooltip;
|
||||
|
||||
public class TokenLabel extends Label {
|
||||
|
||||
|
@ -26,10 +27,10 @@ public class TokenLabel extends Label {
|
|||
CamrecApplication.bus.register(new Object() {
|
||||
@Subscribe
|
||||
public void tokensUpdates(Map<String, Object> e) {
|
||||
if(Objects.equals("tokens", e.get("event"))) {
|
||||
if (Objects.equals("tokens", e.get("event"))) {
|
||||
tokens = (int) e.get("amount");
|
||||
updateText();
|
||||
} else if(Objects.equals("tokens.sent", e.get("event"))) {
|
||||
} else if (Objects.equals("tokens.sent", e.get("event"))) {
|
||||
int _tokens = (int) e.get("amount");
|
||||
tokens -= _tokens;
|
||||
updateText();
|
||||
|
@ -70,7 +71,10 @@ public class TokenLabel extends Label {
|
|||
update(tokens);
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
LOG.error("Couldn't retrieve account balance", e);
|
||||
Platform.runLater(() -> setText("Tokens: error"));
|
||||
Platform.runLater(() -> {
|
||||
setText("Tokens: error");
|
||||
setTooltip(new Tooltip(e.getMessage()));
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue