Fix model loading

This commit is contained in:
0xboobface 2018-10-22 16:07:52 +02:00
parent bbd4f09d14
commit 8c45c45055
15 changed files with 141 additions and 38 deletions

View File

@ -1,14 +1,13 @@
package ctbrec;
import static java.nio.file.StandardOpenOption.CREATE;
import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
import static java.nio.file.StandardOpenOption.WRITE;
import static java.nio.file.StandardOpenOption.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Objects;
import org.slf4j.Logger;
@ -18,6 +17,7 @@ import com.squareup.moshi.JsonAdapter;
import com.squareup.moshi.Moshi;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.sites.Site;
import okio.Buffer;
import okio.BufferedSource;
@ -28,8 +28,10 @@ public class Config {
private static Config instance;
private Settings settings;
private String filename;
private List<Site> sites;
private Config() throws FileNotFoundException, IOException {
private Config(List<Site> sites) throws FileNotFoundException, IOException {
this.sites = sites;
if(System.getProperty("ctbrec.config") != null) {
filename = System.getProperty("ctbrec.config");
} else {
@ -40,7 +42,7 @@ public class Config {
private void load() throws FileNotFoundException, IOException {
Moshi moshi = new Moshi.Builder()
.add(Model.class, new ModelJsonAdapter())
.add(Model.class, new ModelJsonAdapter(sites))
.build();
JsonAdapter<Settings> adapter = moshi.adapter(Settings.class);
File configDir = OS.getConfigDir();
@ -57,9 +59,9 @@ public class Config {
}
}
public static synchronized void init() throws FileNotFoundException, IOException {
public static synchronized void init(List<Site> sites) throws FileNotFoundException, IOException {
if(instance == null) {
instance = new Config();
instance = new Config(sites);
}
}

View File

@ -8,6 +8,7 @@ import com.iheartradio.m3u8.ParseException;
import com.iheartradio.m3u8.PlaylistException;
import ctbrec.recorder.download.StreamSource;
import ctbrec.sites.Site;
public interface Model {
public String getUrl();
@ -32,4 +33,5 @@ public interface Model {
public int[] getStreamResolution(boolean failFast) throws ExecutionException;
public boolean follow() throws IOException;
public boolean unfollow() throws IOException;
public void setSite(Site site);
}

View File

@ -1,6 +1,7 @@
package ctbrec.io;
import java.io.IOException;
import java.util.List;
import java.util.Optional;
import com.squareup.moshi.JsonAdapter;
@ -9,10 +10,20 @@ import com.squareup.moshi.JsonReader.Token;
import com.squareup.moshi.JsonWriter;
import ctbrec.Model;
import ctbrec.sites.Site;
import ctbrec.sites.chaturbate.ChaturbateModel;
public class ModelJsonAdapter extends JsonAdapter<Model> {
private List<Site> sites;
public ModelJsonAdapter() {
}
public ModelJsonAdapter(List<Site> sites) {
this.sites = sites;
}
@Override
public Model fromJson(JsonReader reader) throws IOException {
reader.beginObject();
@ -49,6 +60,13 @@ public class ModelJsonAdapter extends JsonAdapter<Model> {
model.setDescription(description);
model.setUrl(url);
model.setStreamUrlIndex(streamUrlIndex);
if(sites != null) {
for (Site site : sites) {
if(site.isSiteForModel(model)) {
model.setSite(site);
}
}
}
return model;
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
throw new IOException("Couldn't instantiate mode class [" + type + "]", e);

View File

@ -13,7 +13,6 @@ import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
import java.util.concurrent.Callable;
import org.slf4j.Logger;
@ -45,7 +44,7 @@ public class HlsDownload extends AbstractHlsDownload {
Path modelDir = FileSystems.getDefault().getPath(config.getSettings().recordingsDir, model.getName());
downloadDir = FileSystems.getDefault().getPath(modelDir.toString(), startTime);
if(!Objects.equals(model.getOnlineState(false), "public")) {
if(!model.isOnline()) {
throw new IOException(model.getName() +"'s room is not public");
}

View File

@ -2,6 +2,8 @@ package ctbrec.recorder.server;
import java.io.IOException;
import java.net.BindException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
@ -17,6 +19,9 @@ import org.slf4j.LoggerFactory;
import ctbrec.Config;
import ctbrec.recorder.LocalRecorder;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import ctbrec.sites.chaturbate.Chaturbate;
import ctbrec.sites.mfc.MyFreeCams;
public class HttpServer {
@ -24,14 +29,16 @@ public class HttpServer {
private Recorder recorder;
private Config config;
private Server server = new Server();
private List<Site> sites = new ArrayList<>();
public HttpServer() throws Exception {
createSites();
System.setProperty("ctbrec.server.mode", "1");
if(System.getProperty("ctbrec.config") == null) {
System.setProperty("ctbrec.config", "server.json");
}
try {
Config.init();
Config.init(sites);
} catch (Exception e) {
LOG.error("Couldn't load config", e);
System.exit(1);
@ -44,9 +51,17 @@ public class HttpServer {
LOG.info("HMAC authentication is enabled");
}
recorder = new LocalRecorder(config);
for (Site site : sites) {
site.init();
}
startHttpServer();
}
private void createSites() {
sites.add(new Chaturbate());
sites.add(new MyFreeCams());
}
private void addShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
@ -86,7 +101,7 @@ public class HttpServer {
handlers.setHandlers(new Handler[] { handler });
server.setHandler(handlers);
RecorderServlet recorderServlet = new RecorderServlet(recorder);
RecorderServlet recorderServlet = new RecorderServlet(recorder, sites);
ServletHolder holder = new ServletHolder(recorderServlet);
handler.addServletWithMapping(holder, "/rec");

View File

@ -1,9 +1,6 @@
package ctbrec.recorder.server;
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
import static javax.servlet.http.HttpServletResponse.SC_OK;
import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import static javax.servlet.http.HttpServletResponse.*;
import java.io.IOException;
import java.time.Instant;
@ -25,6 +22,7 @@ import ctbrec.Recording;
import ctbrec.io.InstantJsonAdapter;
import ctbrec.io.ModelJsonAdapter;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
public class RecorderServlet extends AbstractCtbrecServlet {
@ -32,8 +30,11 @@ public class RecorderServlet extends AbstractCtbrecServlet {
private Recorder recorder;
public RecorderServlet(Recorder recorder) {
private List<Site> sites;
public RecorderServlet(Recorder recorder, List<Site> sites) {
this.recorder = recorder;
this.sites = sites;
}
@Override
@ -54,7 +55,7 @@ public class RecorderServlet extends AbstractCtbrecServlet {
LOG.debug("Request: {}", json);
Moshi moshi = new Moshi.Builder()
.add(Instant.class, new InstantJsonAdapter())
.add(Model.class, new ModelJsonAdapter())
.add(Model.class, new ModelJsonAdapter(sites))
.build();
JsonAdapter<Request> requestAdapter = moshi.adapter(Request.class);
Request request = requestAdapter.fromJson(json);

View File

@ -18,7 +18,9 @@ public interface Site {
public String getBuyTokensLink();
public void login() throws IOException;
public HttpClient getHttpClient();
public void init() throws IOException;
public void shutdown();
public boolean supportsTips();
public boolean supportsFollow();
public boolean isSiteForModel(Model m);
}

View File

@ -43,7 +43,12 @@ public class Chaturbate implements Site {
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";
private Recorder recorder;
private ChaturbateHttpClient httpClient = new ChaturbateHttpClient();
private ChaturbateHttpClient httpClient;
@Override
public void init() throws IOException {
}
@Override
public String getName() {
@ -87,7 +92,7 @@ public class Chaturbate implements Site {
String url = "https://chaturbate.com/p/" + username + "/";
Request req = new Request.Builder().url(url).build();
Response resp = httpClient.execute(req, true);
Response resp = getHttpClient().execute(req, true);
if (resp.isSuccessful()) {
String profilePage = resp.body().string();
String tokenText = HtmlParser.getText(profilePage, "span.tokencount");
@ -111,7 +116,7 @@ public class Chaturbate implements Site {
@Override
public void run() {
try {
httpClient.login();
getHttpClient().login();
} catch (IOException e1) {
LOG.warn("Initial login failed", e1);
}
@ -122,12 +127,15 @@ public class Chaturbate implements Site {
@Override
public HttpClient getHttpClient() {
if(httpClient == null) {
httpClient = new ChaturbateHttpClient();
}
return httpClient;
}
@Override
public void shutdown() {
httpClient.shutdown();
getHttpClient().shutdown();
}
@Override
@ -140,6 +148,11 @@ public class Chaturbate implements Site {
return true;
}
@Override
public boolean isSiteForModel(Model m) {
return m instanceof ChaturbateModel;
}
// #######################
private long lastRequest = System.currentTimeMillis();
@ -168,7 +181,7 @@ public class Chaturbate implements Site {
public void sendTip(String name, int tokens) throws IOException {
if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
RequestBody body = new FormBody.Builder()
.add("csrfmiddlewaretoken", httpClient.getToken())
.add("csrfmiddlewaretoken", ((ChaturbateHttpClient)getHttpClient()).getToken())
.add("tip_amount", Integer.toString(tokens))
.add("tip_room_type", "public")
.build();
@ -178,7 +191,7 @@ public class Chaturbate implements Site {
.addHeader("Referer", "https://chaturbate.com/"+name+"/")
.addHeader("X-Requested-With", "XMLHttpRequest")
.build();
try(Response response = httpClient.execute(req, true)) {
try(Response response = getHttpClient().execute(req, true)) {
if(!response.isSuccessful()) {
throw new IOException(response.code() + " " + response.message());
}
@ -201,7 +214,7 @@ public class Chaturbate implements Site {
.post(body)
.addHeader("X-Requested-With", "XMLHttpRequest")
.build();
Response response = httpClient.execute(req);
Response response = getHttpClient().execute(req);
try {
if(response.isSuccessful()) {
String content = response.body().string();
@ -281,7 +294,7 @@ public class Chaturbate implements Site {
public MasterPlaylist getMasterPlaylist(StreamInfo streamInfo) throws IOException, ParseException, PlaylistException {
LOG.trace("Loading master playlist {}", streamInfo.url);
Request req = new Request.Builder().url(streamInfo.url).build();
Response response = httpClient.execute(req);
Response response = getHttpClient().execute(req);
try {
InputStream inputStream = response.body().byteStream();
PlaylistParser parser = new PlaylistParser(inputStream, Format.EXT_M3U, Encoding.UTF_8);

View File

@ -18,6 +18,7 @@ import com.iheartradio.m3u8.data.PlaylistData;
import ctbrec.AbstractModel;
import ctbrec.recorder.download.StreamSource;
import ctbrec.sites.Site;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
@ -164,4 +165,13 @@ public class ChaturbateModel extends AbstractModel {
throw new IOException("HTTP status " + resp.code() + " " + resp.message());
}
}
@Override
public void setSite(Site site) {
if(site instanceof Chaturbate) {
this.site = (Chaturbate) site;
} else {
throw new IllegalArgumentException("Site has to be an instance of Chaturbate");
}
}
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import org.jsoup.select.Elements;
import ctbrec.Model;
import ctbrec.recorder.Recorder;
import ctbrec.sites.Site;
import ctbrec.ui.HtmlParser;
@ -17,9 +18,10 @@ public class MyFreeCams implements Site {
private Recorder recorder;
private MyFreeCamsClient client;
private MyFreeCamsHttpClient httpClient = new MyFreeCamsHttpClient();
private MyFreeCamsHttpClient httpClient;
public MyFreeCams() throws IOException {
@Override
public void init() throws IOException {
client = MyFreeCamsClient.getInstance();
client.setSite(this);
client.start();
@ -27,7 +29,7 @@ public class MyFreeCams implements Site {
@Override
public void login() throws IOException {
httpClient.login();
getHttpClient().login();
}
@Override
@ -66,7 +68,7 @@ public class MyFreeCams implements Site {
@Override
public Integer getTokenBalance() throws IOException {
Request req = new Request.Builder().url(BASE_URI + "/php/account.php?request=status").build();
Response resp = httpClient.execute(req, true);
Response resp = getHttpClient().execute(req, true);
if(resp.isSuccessful()) {
String content = resp.body().string();
Elements tags = HtmlParser.getTags(content, "div.content > p > b");
@ -85,6 +87,9 @@ public class MyFreeCams implements Site {
@Override
public MyFreeCamsHttpClient getHttpClient() {
if(httpClient == null) {
httpClient = new MyFreeCamsHttpClient();
}
return httpClient;
}
@ -100,6 +105,11 @@ public class MyFreeCams implements Site {
@Override
public boolean supportsTips() {
return true;
return false;
}
@Override
public boolean isSiteForModel(Model m) {
return m instanceof MyFreeCamsModel;
}
}

View File

@ -48,7 +48,6 @@ public class MyFreeCamsHttpClient extends HttpClient {
Response resp = execute(req);
if(resp.isSuccessful()) {
String page = resp.body().string();
System.out.println(page);
if(page.contains("Your username or password are incorrect")) {
return false;
} else {

View File

@ -26,6 +26,7 @@ import com.iheartradio.m3u8.data.PlaylistData;
import ctbrec.AbstractModel;
import ctbrec.recorder.download.StreamSource;
import ctbrec.sites.Site;
import ctbrec.ui.HtmlParser;
import okhttp3.FormBody;
import okhttp3.Request;
@ -43,6 +44,11 @@ public class MyFreeCamsModel extends AbstractModel {
private int resolution[];
private MyFreeCams site;
/**
* This constructor exists only for deserialization. Please don't call it directly
*/
public MyFreeCamsModel() {}
MyFreeCamsModel(MyFreeCams site) {
this.site = site;
}
@ -255,4 +261,13 @@ public class MyFreeCamsModel extends AbstractModel {
public void setUid(int uid) {
this.uid = uid;
}
@Override
public void setSite(Site site) {
if(site instanceof MyFreeCams) {
this.site = (MyFreeCams) site;
} else {
throw new IllegalArgumentException("Site has to be an instance of MyFreeCams");
}
}
}

View File

@ -5,6 +5,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executors;
@ -24,6 +25,7 @@ import ctbrec.recorder.LocalRecorder;
import ctbrec.recorder.Recorder;
import ctbrec.recorder.RemoteRecorder;
import ctbrec.sites.Site;
import ctbrec.sites.chaturbate.Chaturbate;
import ctbrec.sites.mfc.MyFreeCams;
import javafx.application.Application;
import javafx.application.HostServices;
@ -60,16 +62,22 @@ public class CamrecApplication extends Application {
static EventBus bus;
private HBox tokenPanel;
private Site site;
private List<Site> sites = new ArrayList<>();
@Override
public void start(Stage primaryStage) throws Exception {
site = new MyFreeCams();
sites.add(site);
Chaturbate ctb = new Chaturbate();
sites.add(ctb);
loadConfig();
bus = new AsyncEventBus(Executors.newSingleThreadExecutor());
hostServices = getHostServices();
createRecorder();
// site = new Chaturbate();
site = new MyFreeCams();
site.setRecorder(recorder);
for (Site site : sites) {
site.setRecorder(recorder);
site.init();
}
if (!Objects.equals(System.getenv("CTBREC_DEV"), "1")) {
site.login();
}
@ -155,7 +163,7 @@ public class CamrecApplication extends Application {
});
String username = Config.getInstance().getSettings().username;
if(username != null && !username.trim().isEmpty()) {
if(site.supportsTips() && username != null && !username.trim().isEmpty()) {
double fontSize = tabPane.getTabMaxHeight() / 2 - 1;
Button buyTokens = new Button("Buy Tokens");
buyTokens.setFont(Font.font(fontSize));
@ -196,7 +204,7 @@ public class CamrecApplication extends Application {
private void loadConfig() {
try {
Config.init();
Config.init(sites);
} catch (Exception e) {
LOG.error("Couldn't load settings", e);
Alert alert = new AutosizeAlert(Alert.AlertType.ERROR);

View File

@ -11,6 +11,7 @@ import com.iheartradio.m3u8.PlaylistException;
import ctbrec.AbstractModel;
import ctbrec.Model;
import ctbrec.recorder.download.StreamSource;
import ctbrec.sites.Site;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
@ -136,4 +137,9 @@ public class JavaFxModel extends AbstractModel {
public boolean unfollow() throws IOException {
return delegate.unfollow();
}
@Override
public void setSite(Site site) {
delegate.setSite(site);
}
}

View File

@ -279,7 +279,7 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
}
}
ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, Model model, Recorder recorder2, HttpClient client2) {
ThumbCell createThumbCell(ThumbOverviewTab thumbOverviewTab, Model model, Recorder recorder, HttpClient client2) {
ThumbCell newCell = new ThumbCell(this, model, recorder, site.getHttpClient());
newCell.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
suspendUpdates(true);
@ -391,7 +391,10 @@ public class ThumbOverviewTab extends Tab implements TabSelectionListener {
if(site.supportsFollow()) {
contextMenu.getItems().add(followOrUnFollow);
}
contextMenu.getItems().addAll(copyUrl, sendTip, debug);
if(site.supportsTips()) {
contextMenu.getItems().add(sendTip);
}
contextMenu.getItems().addAll(copyUrl, debug);
return contextMenu;
}