2020-11-12 21:19:45 +00:00
|
|
|
package me.kavin.piped.utils;
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
|
|
|
import com.github.benmanes.caffeine.cache.LoadingCache;
|
2022-01-26 04:00:56 +00:00
|
|
|
import com.github.benmanes.caffeine.cache.Scheduler;
|
2022-02-02 21:05:22 +00:00
|
|
|
import com.grack.nanojson.JsonParserException;
|
|
|
|
import me.kavin.piped.consts.Constants;
|
|
|
|
import me.kavin.piped.utils.obj.SolvedCaptcha;
|
|
|
|
import okhttp3.FormBody;
|
|
|
|
import okhttp3.RequestBody;
|
2021-03-04 14:14:52 +00:00
|
|
|
import org.apache.commons.lang3.StringUtils;
|
2022-01-26 04:00:56 +00:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
2021-03-04 14:14:52 +00:00
|
|
|
import org.jsoup.Jsoup;
|
|
|
|
import org.jsoup.nodes.Element;
|
2020-11-12 21:19:45 +00:00
|
|
|
import org.schabi.newpipe.extractor.downloader.Downloader;
|
|
|
|
import org.schabi.newpipe.extractor.downloader.Request;
|
|
|
|
import org.schabi.newpipe.extractor.downloader.Response;
|
|
|
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.net.HttpCookie;
|
|
|
|
import java.util.concurrent.TimeUnit;
|
2020-11-12 21:19:45 +00:00
|
|
|
|
|
|
|
public class DownloaderImpl extends Downloader {
|
|
|
|
|
2021-03-04 14:14:52 +00:00
|
|
|
private static HttpCookie saved_cookie;
|
2021-05-28 15:17:25 +00:00
|
|
|
private static long cookie_received;
|
2021-03-04 14:14:52 +00:00
|
|
|
private static final Object cookie_lock = new Object();
|
|
|
|
|
2022-01-26 04:00:56 +00:00
|
|
|
final LoadingCache<Request, Response> responseCache = Caffeine.newBuilder()
|
|
|
|
.expireAfterWrite(1, TimeUnit.MINUTES)
|
|
|
|
.scheduler(Scheduler.systemScheduler())
|
|
|
|
.maximumSize(1000).build(this::executeRequest);
|
2021-11-17 09:54:46 +00:00
|
|
|
|
|
|
|
@Override
|
2022-01-26 04:00:56 +00:00
|
|
|
public Response execute(@NotNull Request request) {
|
2021-11-17 09:54:46 +00:00
|
|
|
return responseCache.get(request);
|
|
|
|
}
|
|
|
|
|
2020-11-12 21:19:45 +00:00
|
|
|
/**
|
|
|
|
* Executes a request with HTTP/2.
|
|
|
|
*/
|
2021-11-17 09:54:46 +00:00
|
|
|
public Response executeRequest(Request request) throws IOException, ReCaptchaException {
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2021-02-24 09:52:29 +00:00
|
|
|
// TODO: HTTP/3 aka QUIC
|
2022-02-02 21:05:22 +00:00
|
|
|
var bytes = request.dataToSend();
|
|
|
|
RequestBody body = null;
|
|
|
|
if (bytes != null)
|
|
|
|
body = RequestBody.create(bytes);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
var builder = new okhttp3.Request.Builder()
|
|
|
|
.url(request.url())
|
|
|
|
.method(request.httpMethod(), body)
|
|
|
|
.header("User-Agent", Constants.USER_AGENT);
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2021-03-04 14:14:52 +00:00
|
|
|
if (saved_cookie != null && !saved_cookie.hasExpired())
|
2022-02-02 21:05:22 +00:00
|
|
|
builder.header("Cookie", saved_cookie.getName() + "=" + saved_cookie.getValue());
|
2021-03-04 14:14:52 +00:00
|
|
|
|
|
|
|
request.headers().forEach((name, values) -> values.forEach(value -> builder.header(name, value)));
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
var response = Constants.h2client.newCall(builder.build()).execute();
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
if (response.code() == 429) {
|
2021-03-04 14:14:52 +00:00
|
|
|
|
|
|
|
synchronized (cookie_lock) {
|
|
|
|
|
2021-05-28 15:17:25 +00:00
|
|
|
if (saved_cookie != null && saved_cookie.hasExpired()
|
|
|
|
|| (System.currentTimeMillis() - cookie_received > TimeUnit.MINUTES.toMillis(30)))
|
2021-03-04 14:14:52 +00:00
|
|
|
saved_cookie = null;
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
String redir_url = String.valueOf(response.request().url());
|
2021-03-04 14:14:52 +00:00
|
|
|
|
|
|
|
if (saved_cookie == null && redir_url.startsWith("https://www.google.com/sorry")) {
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
var formBuilder = new FormBody.Builder();
|
2021-03-04 14:14:52 +00:00
|
|
|
String sitekey = null, data_s = null;
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
for (Element el : Jsoup.parse(response.body().string()).selectFirst("form").children()) {
|
2021-03-04 14:14:52 +00:00
|
|
|
String name;
|
|
|
|
if (!(name = el.tagName()).equals("script")) {
|
|
|
|
if (name.equals("input"))
|
2022-02-02 21:05:22 +00:00
|
|
|
formBuilder.add(el.attr("name"), el.attr("value"));
|
2021-03-04 14:14:52 +00:00
|
|
|
else if (name.equals("div") && el.attr("id").equals("recaptcha")) {
|
|
|
|
sitekey = el.attr("data-sitekey");
|
|
|
|
data_s = el.attr("data-s");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-02-02 21:05:22 +00:00
|
|
|
if (StringUtils.isEmpty(sitekey) || StringUtils.isEmpty(data_s))
|
2021-03-04 14:14:52 +00:00
|
|
|
throw new ReCaptchaException("Could not get recaptcha", redir_url);
|
|
|
|
|
|
|
|
SolvedCaptcha solved = null;
|
|
|
|
|
|
|
|
try {
|
|
|
|
solved = CaptchaSolver.solve(redir_url, sitekey, data_s);
|
|
|
|
} catch (JsonParserException | InterruptedException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
formBuilder.add("g-recaptcha-response", solved.getRecaptchaResponse());
|
2021-03-04 14:14:52 +00:00
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
var formReqBuilder = new okhttp3.Request.Builder()
|
|
|
|
.url("https://www.google.com/sorry/index")
|
|
|
|
.header("User-Agent", Constants.USER_AGENT)
|
|
|
|
.post(formBuilder.build());
|
2021-03-04 14:14:52 +00:00
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
var formResponse = Constants.h2_no_redir_client.newCall(formReqBuilder.build()).execute();
|
2021-03-04 14:14:52 +00:00
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
saved_cookie = HttpCookie.parse(URLUtils.silentDecode(StringUtils
|
|
|
|
.substringAfter(formResponse.headers().get("Location"), "google_abuse=")))
|
|
|
|
.get(0);
|
|
|
|
cookie_received = System.currentTimeMillis();
|
2021-03-04 14:14:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (saved_cookie != null) // call again as captcha has been solved or cookie has not expired.
|
|
|
|
execute(request);
|
|
|
|
}
|
|
|
|
|
2021-02-24 09:52:29 +00:00
|
|
|
}
|
2020-11-12 21:19:45 +00:00
|
|
|
|
2022-02-02 21:05:22 +00:00
|
|
|
return new Response(response.code(), response.message(), response.headers().toMultimap(), response.body().string(),
|
|
|
|
String.valueOf(response.request().url()));
|
2020-11-12 21:19:45 +00:00
|
|
|
}
|
|
|
|
}
|