Support non-H@H archive download
This commit is contained in:
1 parent
3b5e56b049
commit
23acdb6492
6 files changed
+134
-31
No files matched your search
@@ -167,7 +167,7 @@ public class EhClient {
|
||||
case METHOD_ARCHIVE_LIST ->
|
||||
EhEngine.getArchiveList(this, mOkHttpClient, (String) params[0], (Long) params[1], (String) params[2]);
|
||||
case METHOD_DOWNLOAD_ARCHIVE ->
|
||||
EhEngine.downloadArchive(this, mOkHttpClient, (Long) params[0], (String) params[1], (String) params[2], (String) params[3]);
|
||||
EhEngine.downloadArchive(this, mOkHttpClient, (Long) params[0], (String) params[1], (String) params[2], (String) params[3], (Boolean) params[4]);
|
||||
case METHOD_VOTE_TAG ->
|
||||
EhEngine.voteTag(this, mOkHttpClient, (Long) params[0], (String) params[1], (Long) params[2], (String) params[3], (String) params[4], (Integer) params[5]);
|
||||
case METHOD_GET_UCONFIG -> EhEngine.getUConfig(this, mOkHttpClient);
|
||||
|
||||
@@ -33,7 +33,6 @@ import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.data.PreviewSet;
|
||||
import com.hippo.ehviewer.client.exception.CancelledException;
|
||||
import com.hippo.ehviewer.client.exception.EhException;
|
||||
import com.hippo.ehviewer.client.exception.NoHAtHClientException;
|
||||
import com.hippo.ehviewer.client.exception.ParseException;
|
||||
import com.hippo.ehviewer.client.parser.ArchiveParser;
|
||||
import com.hippo.ehviewer.client.parser.EventPaneParser;
|
||||
@@ -65,8 +64,6 @@ import org.jsoup.select.Elements;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import okhttp3.Call;
|
||||
import okhttp3.FormBody;
|
||||
@@ -88,8 +85,6 @@ public class EhEngine {
|
||||
private static final String KOKOMADE_URL = "https://exhentai.org/img/kokomade.jpg";
|
||||
private static final MediaType MEDIA_TYPE_JPEG = MediaType.parse("image/jpeg");
|
||||
|
||||
private static final Pattern PATTERN_NEED_HATH_CLIENT = Pattern.compile("(You must have a H@H client assigned to your account to use this feature\\.)");
|
||||
|
||||
public static EhFilter sEhFilter;
|
||||
|
||||
public static void initialize() {
|
||||
@@ -714,8 +709,8 @@ public class EhEngine {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Void downloadArchive(@Nullable EhClient.Task task, OkHttpClient okHttpClient,
|
||||
long gid, String token, String or, String res) throws Throwable {
|
||||
public static String downloadArchive(@Nullable EhClient.Task task, OkHttpClient okHttpClient,
|
||||
long gid, String token, String or, String res, boolean isHAtH) throws Throwable {
|
||||
if (or == null || or.length() == 0) {
|
||||
throw new EhException("Invalid form param or: " + or);
|
||||
}
|
||||
@@ -723,7 +718,16 @@ public class EhEngine {
|
||||
throw new EhException("Invalid res: " + res);
|
||||
}
|
||||
FormBody.Builder builder = new FormBody.Builder();
|
||||
builder.add("hathdl_xres", res);
|
||||
if (isHAtH) {
|
||||
builder.add("hathdl_xres", res);
|
||||
} else {
|
||||
builder.add("dltype", res);
|
||||
if (res.equals("org")) {
|
||||
builder.add("dlcheck", "Download Original Archive");
|
||||
} else {
|
||||
builder.add("dlcheck", "Download Resample Archive");
|
||||
}
|
||||
}
|
||||
String url = EhUrl.getDownloadArchive(gid, token, or);
|
||||
String referer = EhUrl.getGalleryDetailUrl(gid, token);
|
||||
String origin = EhUrl.getOrigin();
|
||||
@@ -752,11 +756,27 @@ public class EhEngine {
|
||||
throw e;
|
||||
}
|
||||
|
||||
Matcher m = PATTERN_NEED_HATH_CLIENT.matcher(body);
|
||||
if (m.find()) {
|
||||
throw new NoHAtHClientException("No H@H client");
|
||||
var result = ArchiveParser.parseArchiveUrl(body);
|
||||
if (!isHAtH) {
|
||||
if (result == null) {
|
||||
Thread.sleep(1000);
|
||||
try (var response = call.clone().execute()) {
|
||||
code = response.code();
|
||||
headers = response.headers();
|
||||
body = response.body().string();
|
||||
throwException(call, code, headers, body, null);
|
||||
} catch (Throwable e) {
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
throwException(call, code, headers, body, e);
|
||||
throw e;
|
||||
}
|
||||
result = ArchiveParser.parseArchiveUrl(body);
|
||||
if (result == null) {
|
||||
throw new EhException("Archive unavailable");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,51 +18,101 @@ package com.hippo.ehviewer.client.parser;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.exception.NoHAtHClientException;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ArchiveParser {
|
||||
|
||||
private static final Pattern PATTERN_FORM = Pattern.compile("<form id=\"hathdl_form\" action=\"[^\"]*?or=([^=\"]*?)\" method=\"post\">");
|
||||
private static final Pattern PATTERN_ARCHIVE = Pattern.compile("<p><a href=\"[^\"]*\" onclick=\"return do_hathdl\\('([0-9]+|org)'\\)\">([^<]+)</a></p>\\s*<p>([\\w. ]+)</p>\\s*<p>([\\w. ]+)</p>");
|
||||
private static final Pattern PATTERN_ARCHIVE_URL = Pattern.compile("<strong>(.*)</strong>.*<a href=\"([^\"]*)\">Click Here To Start Downloading</a>");
|
||||
private static final Pattern PATTERN_HATH_FORM = Pattern.compile("<form id=\"hathdl_form\" action=\"[^\"]*?or=([^=\"]*?)\" method=\"post\">");
|
||||
private static final Pattern PATTERN_HATH_ARCHIVE = Pattern.compile("<p><a href=\"[^\"]*\" onclick=\"return do_hathdl\\('([0-9]+|org)'\\)\">([^<]+)</a></p>\\s*<p>([\\w. ]+)</p>\\s*<p>([\\w. ]+)</p>");
|
||||
private static final Pattern PATTERN_NEED_HATH_CLIENT = Pattern.compile("You must have a H@H client assigned to your account to use this feature\\.");
|
||||
|
||||
public static Result parse(String body) {
|
||||
Matcher m = PATTERN_FORM.matcher(body);
|
||||
Matcher m = PATTERN_HATH_FORM.matcher(body);
|
||||
if (!m.find()) {
|
||||
return new Result(null, null);
|
||||
}
|
||||
String paramOr = m.group(1);
|
||||
|
||||
var archiveList = new ArrayList<Archive>();
|
||||
m = PATTERN_ARCHIVE.matcher(body);
|
||||
var d = Jsoup.parse(body);
|
||||
var es = d.select("#db>div>div");
|
||||
for (var e : es) {
|
||||
try {
|
||||
var res = e.selectFirst("form>input").attr("value");
|
||||
var name = e.selectFirst("form>div>input").attr("value");
|
||||
var size = e.selectFirst("p>strong").text();
|
||||
var cost = e.selectFirst("div>strong").text();
|
||||
var item = new Archive(res, name, size, cost, false);
|
||||
archiveList.add(item);
|
||||
} catch (NullPointerException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
m = PATTERN_HATH_ARCHIVE.matcher(body);
|
||||
while (m.find()) {
|
||||
String res = ParserUtils.trim(m.group(1));
|
||||
String name = ParserUtils.trim(m.group(2));
|
||||
String size = ParserUtils.trim(m.group(3));
|
||||
String cost = ParserUtils.trim(m.group(4));
|
||||
var item = new Archive(res, name, size, cost);
|
||||
var item = new Archive(res, name, size, cost, true);
|
||||
archiveList.add(item);
|
||||
}
|
||||
|
||||
return new Result(paramOr, archiveList);
|
||||
}
|
||||
|
||||
public static String parseArchiveUrl(String body) throws NoHAtHClientException {
|
||||
Matcher m = PATTERN_NEED_HATH_CLIENT.matcher(body);
|
||||
if (m.find()) {
|
||||
throw new NoHAtHClientException("No H@H client");
|
||||
}
|
||||
|
||||
var d = Jsoup.parse(body);
|
||||
var a = d.selectFirst("#continue>a[href]");
|
||||
if (a != null) {
|
||||
return a.attr("href") + "?start=1";
|
||||
}
|
||||
|
||||
// TODO: Check more errors
|
||||
return null;
|
||||
}
|
||||
|
||||
public static final class Archive {
|
||||
private final String res;
|
||||
private final String name;
|
||||
private final String size;
|
||||
private final String cost;
|
||||
private final boolean isHAtH;
|
||||
|
||||
public Archive(String res, String name, String size, String cost) {
|
||||
public Archive(String res, String name, String size, String cost, boolean isHAtH) {
|
||||
this.res = res;
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.cost = cost;
|
||||
this.isHAtH = isHAtH;
|
||||
}
|
||||
|
||||
public String format() {
|
||||
return String.format("%s [%s, %s]", name, size, cost);
|
||||
public String format(IntFunction<String> getString) {
|
||||
if (isHAtH) {
|
||||
var costStr = cost.equals("Free") ? getString.apply(R.string.archive_free) : cost;
|
||||
return String.format("[H@H] %s [%s] [%s]", name, size, costStr);
|
||||
} else {
|
||||
var nameStr = getString.apply(res.equals("org") ? R.string.archive_original : R.string.archive_resample);
|
||||
var costStr = cost.equals("Free!") ? getString.apply(R.string.archive_free) : cost;
|
||||
return String.format("%s [%s] [%s]", nameStr, size, costStr);
|
||||
}
|
||||
}
|
||||
|
||||
public String res() {
|
||||
@@ -81,6 +131,10 @@ public class ArchiveParser {
|
||||
return cost;
|
||||
}
|
||||
|
||||
public boolean isHAtH() {
|
||||
return isHAtH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
@@ -89,12 +143,13 @@ public class ArchiveParser {
|
||||
return Objects.equals(this.res, that.res) &&
|
||||
Objects.equals(this.name, that.name) &&
|
||||
Objects.equals(this.size, that.size) &&
|
||||
Objects.equals(this.cost, that.cost);
|
||||
Objects.equals(this.cost, that.cost) &&
|
||||
this.isHAtH == that.isHAtH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(res, name, size, cost);
|
||||
return Objects.hash(res, name, size, cost, isHAtH);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -104,7 +159,8 @@ public class ArchiveParser {
|
||||
"res=" + res + ", " +
|
||||
"name=" + name + ", " +
|
||||
"size=" + size + ", " +
|
||||
"cost=" + cost + ']';
|
||||
"cost=" + cost + ", " +
|
||||
"isHAtH=" + isHAtH + ']';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1177,7 +1177,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
}
|
||||
ArchiveListDialogHelper helper = new ArchiveListDialogHelper();
|
||||
Dialog dialog = new BaseDialogBuilder(context)
|
||||
.setTitle(R.string.dialog_archive_title)
|
||||
.setTitle(R.string.settings_download)
|
||||
.setView(R.layout.dialog_archive_list)
|
||||
.setOnDismissListener(helper)
|
||||
.show();
|
||||
@@ -1713,14 +1713,34 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
}
|
||||
}
|
||||
|
||||
private static class DownloadArchiveListener extends EhCallback<GalleryDetailScene, Void> {
|
||||
private static class DownloadArchiveListener extends EhCallback<GalleryDetailScene, String> {
|
||||
|
||||
public DownloadArchiveListener(Context context, int stageId, String sceneTag) {
|
||||
private final GalleryInfo mGalleryInfo;
|
||||
|
||||
public DownloadArchiveListener(Context context, int stageId, String sceneTag, GalleryInfo galleryInfo) {
|
||||
super(context, stageId, sceneTag);
|
||||
mGalleryInfo = galleryInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Void result) {
|
||||
public void onSuccess(String result) {
|
||||
if (result != null) {
|
||||
// TODO: Don't use buggy system download service
|
||||
DownloadManager.Request r = new DownloadManager.Request(Uri.parse(result));
|
||||
var name = mGalleryInfo.gid + "-" + EhUtils.getSuitableTitle(mGalleryInfo) + ".zip";
|
||||
r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,
|
||||
FileUtils.sanitizeFilename(name));
|
||||
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
|
||||
DownloadManager dm = (DownloadManager) getApplication().getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
if (dm != null) {
|
||||
try {
|
||||
dm.enqueue(r);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
ExceptionUtils.throwIfFatal(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
showTip(R.string.download_archive_started, LENGTH_SHORT);
|
||||
}
|
||||
|
||||
@@ -1790,7 +1810,7 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
mListView.setVisibility(View.GONE);
|
||||
mErrorText.setText(R.string.no_archives);
|
||||
} else {
|
||||
var nameArray = data.stream().map(ArchiveParser.Archive::format).toArray(String[]::new);
|
||||
var nameArray = data.stream().map(archive -> archive.format(getResources()::getString)).toArray(String[]::new);
|
||||
mProgressView.setVisibility(View.GONE);
|
||||
mErrorText.setVisibility(View.GONE);
|
||||
mListView.setVisibility(View.VISIBLE);
|
||||
@@ -1804,10 +1824,11 @@ public class GalleryDetailScene extends CollapsingToolbarScene implements View.O
|
||||
MainActivity activity = getMainActivity();
|
||||
if (null != context && null != activity && null != mArchiveList && position < mArchiveList.size()) {
|
||||
String res = mArchiveList.get(position).res();
|
||||
boolean isHAtH = mArchiveList.get(position).isHAtH();
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_DOWNLOAD_ARCHIVE);
|
||||
request.setArgs(mGalleryDetail.gid, mGalleryDetail.token, mArchiveFormParamOr, res);
|
||||
request.setCallback(new DownloadArchiveListener(context, activity.getStageId(), getTag()));
|
||||
request.setArgs(mGalleryDetail.gid, mGalleryDetail.token, mArchiveFormParamOr, res, isHAtH);
|
||||
request.setCallback(new DownloadArchiveListener(context, activity.getStageId(), getTag(), mGalleryDetail));
|
||||
EhApplication.getEhClient().execute(request);
|
||||
}
|
||||
|
||||
|
||||
@@ -531,6 +531,9 @@
|
||||
<string name="download_archive_started">开始下载压缩包</string>
|
||||
<string name="download_archive_failure">无法下载压缩包</string>
|
||||
<string name="archive">压缩包</string>
|
||||
<string name="archive_free">免费</string>
|
||||
<string name="archive_original">原始档案</string>
|
||||
<string name="archive_resample">重采样档案</string>
|
||||
<string name="download_archive_failure_no_hath">下载压缩包需要 H@H 客户端</string>
|
||||
<string name="settings_privacy">隐私</string>
|
||||
<string name="settings_privacy_secure">不允许屏幕抓取</string>
|
||||
|
||||
@@ -598,6 +598,9 @@
|
||||
<string name="download_archive_started">Archive download started</string>
|
||||
<string name="download_archive_failure">Failed to download archive</string>
|
||||
<string name="archive">Archive</string>
|
||||
<string name="archive_free">Free</string>
|
||||
<string name="archive_original">Original archive</string>
|
||||
<string name="archive_resample">Resample archive</string>
|
||||
<string name="download_archive_failure_no_hath">Need H@H client for archive download</string>
|
||||
<string name="settings_privacy">Privacy</string>
|
||||
<string name="settings_privacy_secure">Prevent screenshots</string>
|
||||
|
||||
Reference in new issue
Block a user