Add external login dialog for stripchat
This also enables us to support xhamsterlive
This commit is contained in:
parent
882742ce3b
commit
7462d68d7b
|
@ -1,8 +1,11 @@
|
||||||
3.8.3
|
3.8.3
|
||||||
========================
|
========================
|
||||||
* Fixed Streamate
|
* Fixed Streamate
|
||||||
* Fixed favorites tab for Cam4; kind of, because only the online tab works. I currently don't see
|
* Fixed favorites tab for Cam4; kind of, because only the online tab works.
|
||||||
a way to retrieve the offline favorites
|
I currently don't see a way to retrieve the offline favorites
|
||||||
|
* Fixed favorites tab for CamSoda
|
||||||
|
* Fixed CamSoda recordings
|
||||||
|
* Added external login dialog to Stripchat to support the captcha
|
||||||
|
|
||||||
|
|
||||||
3.8.2
|
3.8.2
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
package ctbrec.ui.sites.stripchat;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import ctbrec.Config;
|
||||||
|
import ctbrec.sites.stripchat.Stripchat;
|
||||||
|
import ctbrec.ui.ExternalBrowser;
|
||||||
|
import okhttp3.Cookie;
|
||||||
|
import okhttp3.Cookie.Builder;
|
||||||
|
import okhttp3.CookieJar;
|
||||||
|
import okhttp3.HttpUrl;
|
||||||
|
|
||||||
|
public class StripchatElectronLoginDialog {
|
||||||
|
|
||||||
|
private static final transient Logger LOG = LoggerFactory.getLogger(StripchatElectronLoginDialog.class);
|
||||||
|
public static final String DOMAIN = "stripchat.com";
|
||||||
|
public static final String URL = Stripchat.BASE_URI;
|
||||||
|
private CookieJar cookieJar;
|
||||||
|
private ExternalBrowser browser;
|
||||||
|
|
||||||
|
public StripchatElectronLoginDialog(CookieJar cookieJar) throws IOException {
|
||||||
|
this.cookieJar = cookieJar;
|
||||||
|
browser = ExternalBrowser.getInstance();
|
||||||
|
try {
|
||||||
|
JSONObject config = new JSONObject();
|
||||||
|
config.put("url", URL);
|
||||||
|
config.put("w", 640);
|
||||||
|
config.put("h", 640);
|
||||||
|
JSONObject msg = new JSONObject();
|
||||||
|
msg.put("config", config);
|
||||||
|
browser.run(msg, msgHandler);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw new IOException("Couldn't wait for login dialog", e);
|
||||||
|
} finally {
|
||||||
|
browser.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Consumer<String> msgHandler = (line) -> {
|
||||||
|
if(!line.startsWith("{")) {
|
||||||
|
System.err.println(line);
|
||||||
|
} else {
|
||||||
|
JSONObject json = new JSONObject(line);
|
||||||
|
if(json.has("url")) {
|
||||||
|
String url = json.getString("url");
|
||||||
|
|
||||||
|
if(url.endsWith(DOMAIN) || url.endsWith(DOMAIN + '/')) {
|
||||||
|
try {
|
||||||
|
browser.executeJavaScript("document.querySelector('button[class~=\"btn-visitors-agreement-accept\"]').click();");
|
||||||
|
browser.executeJavaScript("document.querySelector('div[class~=\"header-dropdown\"] a[class~=\"dropdown-link\"]').click();");
|
||||||
|
browser.executeJavaScript("document.querySelector('a[class~=\"btn\"][href*=\"login\"]').click();");
|
||||||
|
String username = Config.getInstance().getSettings().stripchatUsername;
|
||||||
|
if (username != null && !username.trim().isEmpty()) {
|
||||||
|
browser.executeJavaScript("document.querySelector('#login_login_or_email').value = '" + username + "';");
|
||||||
|
}
|
||||||
|
String password = Config.getInstance().getSettings().stripchatPassword;
|
||||||
|
if (password != null && !password.trim().isEmpty()) {
|
||||||
|
browser.executeJavaScript("document.querySelector('#login_password').value = '" + password + "';");
|
||||||
|
}
|
||||||
|
browser.executeJavaScript("document.querySelector('#recaptcha-checkbox-border').click();");
|
||||||
|
browser.executeJavaScript("document.querySelector('*[class~=btn-login]').addEventListener('click', function() {window.setTimeout(function() {location.reload()}, 2000)});");
|
||||||
|
} catch(Exception e) {
|
||||||
|
LOG.warn("Couldn't auto fill username and password for Stripchat", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.has("cookies")) {
|
||||||
|
JSONArray _cookies = json.getJSONArray("cookies");
|
||||||
|
boolean sessionCookieFound = false;
|
||||||
|
for (int i = 0; i < _cookies.length(); i++) {
|
||||||
|
JSONObject cookie = _cookies.getJSONObject(i);
|
||||||
|
if (cookie.getString("domain").contains(DOMAIN)) {
|
||||||
|
String domain = cookie.getString("domain");
|
||||||
|
if (domain.startsWith(".")) {
|
||||||
|
domain = domain.substring(1);
|
||||||
|
}
|
||||||
|
Cookie c = createCookie(domain, cookie);
|
||||||
|
cookieJar.saveFromResponse(HttpUrl.parse(url), Collections.singletonList(c));
|
||||||
|
c = createCookie(DOMAIN, cookie);
|
||||||
|
cookieJar.saveFromResponse(HttpUrl.parse(Stripchat.BASE_URI), Collections.singletonList(c));
|
||||||
|
if (c.name().equals("stripchat_com_sessionId")) {
|
||||||
|
sessionCookieFound = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sessionCookieFound) {
|
||||||
|
try {
|
||||||
|
browser.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
LOG.error("Couldn't send close request to browser", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private Cookie createCookie(String domain, JSONObject cookie) {
|
||||||
|
Builder b = new Cookie.Builder()
|
||||||
|
.path(cookie.getString("path"))
|
||||||
|
.domain(domain)
|
||||||
|
.name(cookie.getString("name"))
|
||||||
|
.value(cookie.getString("value"))
|
||||||
|
.expiresAt(Double.valueOf(cookie.optDouble("expirationDate")).longValue());
|
||||||
|
if(cookie.optBoolean("hostOnly")) {
|
||||||
|
b.hostOnlyDomain(domain);
|
||||||
|
}
|
||||||
|
if(cookie.optBoolean("httpOnly")) {
|
||||||
|
b.httpOnly();
|
||||||
|
}
|
||||||
|
if(cookie.optBoolean("secure")) {
|
||||||
|
b.secure();
|
||||||
|
}
|
||||||
|
return b.build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,6 +79,7 @@ public class StripchatFollowedUpdateService extends PaginatedScheduledService {
|
||||||
|
|
||||||
private JSONArray loadFavoriteModelIds() throws IOException {
|
private JSONArray loadFavoriteModelIds() throws IOException {
|
||||||
SiteUiFactory.getUi(stripchat).login();
|
SiteUiFactory.getUi(stripchat).login();
|
||||||
|
stripchat.getHttpClient().login();
|
||||||
long userId = ((StripchatHttpClient) stripchat.getHttpClient()).getUserId();
|
long userId = ((StripchatHttpClient) stripchat.getHttpClient()).getUserId();
|
||||||
String url = stripchat.getBaseUrl() + "/api/front/users/" + userId + "/favorites";
|
String url = stripchat.getBaseUrl() + "/api/front/users/" + userId + "/favorites";
|
||||||
Request request = new Request.Builder()
|
Request request = new Request.Builder()
|
||||||
|
|
|
@ -1,20 +1,30 @@
|
||||||
package ctbrec.ui.sites.stripchat;
|
package ctbrec.ui.sites.stripchat;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.sites.stripchat.Stripchat;
|
import ctbrec.sites.stripchat.Stripchat;
|
||||||
|
import ctbrec.sites.stripchat.StripchatHttpClient;
|
||||||
|
import ctbrec.ui.controls.Dialogs;
|
||||||
import ctbrec.ui.sites.AbstractSiteUi;
|
import ctbrec.ui.sites.AbstractSiteUi;
|
||||||
import ctbrec.ui.sites.ConfigUI;
|
import ctbrec.ui.sites.ConfigUI;
|
||||||
import ctbrec.ui.tabs.TabProvider;
|
import ctbrec.ui.tabs.TabProvider;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
|
||||||
public class StripchatSiteUi extends AbstractSiteUi {
|
public class StripchatSiteUi extends AbstractSiteUi {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(StripchatSiteUi.class);
|
||||||
|
|
||||||
private StripchatTabProvider tabProvider;
|
private StripchatTabProvider tabProvider;
|
||||||
private StripchatConfigUI configUi;
|
private StripchatConfigUI configUi;
|
||||||
private Stripchat stripchat;
|
private Stripchat site;
|
||||||
|
|
||||||
public StripchatSiteUi(Stripchat stripchat) {
|
public StripchatSiteUi(Stripchat stripchat) {
|
||||||
this.stripchat = stripchat;
|
this.site = stripchat;
|
||||||
tabProvider = new StripchatTabProvider(stripchat);
|
tabProvider = new StripchatTabProvider(stripchat);
|
||||||
configUi = new StripchatConfigUI(stripchat);
|
configUi = new StripchatConfigUI(stripchat);
|
||||||
}
|
}
|
||||||
|
@ -31,7 +41,40 @@ public class StripchatSiteUi extends AbstractSiteUi {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean login() throws IOException {
|
public synchronized boolean login() throws IOException {
|
||||||
boolean automaticLogin = stripchat.login();
|
boolean automaticLogin = site.login();
|
||||||
return automaticLogin;
|
if (automaticLogin) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
BlockingQueue<Boolean> queue = new LinkedBlockingQueue<>();
|
||||||
|
|
||||||
|
Runnable showDialog = () -> {
|
||||||
|
// login with external browser
|
||||||
|
try {
|
||||||
|
new StripchatElectronLoginDialog(site.getHttpClient().getCookieJar());
|
||||||
|
} catch (Exception e1) {
|
||||||
|
LOG.error("Error logging in with external browser", e1);
|
||||||
|
Dialogs.showError("Login error", "Couldn't login to " + site.getName(), e1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
queue.put(true);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.error("Error while signaling termination", e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Platform.runLater(showDialog);
|
||||||
|
try {
|
||||||
|
queue.take();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.error("Error while waiting for login dialog to close", e);
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
StripchatHttpClient httpClient = (StripchatHttpClient) site.getHttpClient();
|
||||||
|
boolean loggedIn = httpClient.checkLoginSuccess();
|
||||||
|
return loggedIn;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import static ctbrec.io.HttpConstants.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -36,7 +37,7 @@ public class StripchatHttpClient extends HttpClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
// persisted cookies might let us log in
|
// persisted cookies might let us log in
|
||||||
if(checkLoginSuccess()) {
|
if (checkLoginSuccess()) {
|
||||||
loggedIn = true;
|
loggedIn = true;
|
||||||
LOG.debug("Logged in with cookies");
|
LOG.debug("Logged in with cookies");
|
||||||
return true;
|
return true;
|
||||||
|
@ -75,7 +76,8 @@ public class StripchatHttpClient extends HttpClient {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new HttpException(response.code(), response.message());
|
LOG.info("Auto-Login failed: {} {} {}", response.code(), response.message(), url);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,11 +109,48 @@ public class StripchatHttpClient extends HttpClient {
|
||||||
* check, if the login worked
|
* check, if the login worked
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public boolean checkLoginSuccess() {
|
public boolean checkLoginSuccess() throws IOException {
|
||||||
return userId > 0;
|
long userId = getUserId();
|
||||||
|
String url = Stripchat.BASE_URI + "/api/front/users/" + userId + "/favorites";
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||||
|
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||||
|
.header(ORIGIN, Stripchat.BASE_URI)
|
||||||
|
.header(REFERER, Stripchat.BASE_URI + "/favorites")
|
||||||
|
.header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON)
|
||||||
|
.build();
|
||||||
|
try (Response response = execute(request)) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.info("Login check returned unsuccessful: {}", e.getLocalizedMessage());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getUserId() {
|
public long getUserId() throws JSONException, IOException {
|
||||||
|
if (userId == 0) {
|
||||||
|
String url = Stripchat.BASE_URI + "/api/front/users/username/" + Config.getInstance().getSettings().stripchatUsername;
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.header(ACCEPT, MIMETYPE_APPLICATION_JSON)
|
||||||
|
.header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
|
||||||
|
.header(ORIGIN, Stripchat.BASE_URI)
|
||||||
|
.header(REFERER, Stripchat.BASE_URI)
|
||||||
|
.header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON)
|
||||||
|
.build();
|
||||||
|
try (Response response = execute(request)) {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
JSONObject resp = new JSONObject(response.body().string());
|
||||||
|
JSONObject user = resp.getJSONObject("user");
|
||||||
|
userId = user.optLong("id");
|
||||||
|
} else {
|
||||||
|
throw new HttpException(url, response.code(), response.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return userId;
|
return userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue