From b5cae76de5c4016e2ade6804ffe1f7dfd3ced3cb Mon Sep 17 00:00:00 2001 From: "Lin, Yi-Li" Date: Sun, 29 Jan 2017 02:00:02 +0900 Subject: [PATCH] able to request archive download --- .../com/hippo/ehviewer/client/EhClient.java | 6 + .../com/hippo/ehviewer/client/EhEngine.java | 69 ++++++++ .../java/com/hippo/ehviewer/client/EhUrl.java | 4 + .../ehviewer/client/data/GalleryDetail.java | 3 + .../ehviewer/client/parser/ArchiveParser.java | 48 +++++ .../client/parser/GalleryDetailParser.java | 8 + .../ehviewer/ui/scene/GalleryDetailScene.java | 166 ++++++++++++++++++ .../res/drawable/v_archive_primary_x48.xml | 29 +++ .../main/res/layout/dialog_archive_list.xml | 44 +++++ .../res/layout/gallery_detail_actions.xml | 9 + app/src/main/res/values-zh-rCN/strings.xml | 5 + app/src/main/res/values-zh-rHK/strings.xml | 5 + app/src/main/res/values-zh-rTW/strings.xml | 5 + app/src/main/res/values/pathdata.xml | 1 + app/src/main/res/values/strings.xml | 5 + 15 files changed, 407 insertions(+) create mode 100644 app/src/main/java/com/hippo/ehviewer/client/parser/ArchiveParser.java create mode 100644 app/src/main/res/drawable/v_archive_primary_x48.xml create mode 100644 app/src/main/res/layout/dialog_archive_list.xml diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhClient.java b/app/src/main/java/com/hippo/ehviewer/client/EhClient.java index dd331fbf2..056ae8395 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhClient.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhClient.java @@ -59,6 +59,8 @@ public class EhClient { public static final int METHOD_GET_PROFILE = 14; public static final int METHOD_VOTE_COMMENT = 15; public static final int METHOD_IMAGE_SEARCH = 16; + public static final int METHOD_ARCHIVE_LIST = 17; + public static final int METHOD_DOWNLOAD_ARCHIVE = 18; private final ThreadPoolExecutor mRequestThreadPool; private final OkHttpClient mOkHttpClient; @@ -184,6 +186,10 @@ public class EhClient { return EhEngine.voteComment(this, mOkHttpClient, (Long) params[0], (String) params[1], (Long) params[2], (String) params[3], (Long) params[4], (Integer) params[5]); case METHOD_IMAGE_SEARCH: return EhEngine.imageSearch(this, mOkHttpClient, (File) params[0], (Boolean) params[1], (Boolean) params[2], (Boolean) params[3]); + case METHOD_ARCHIVE_LIST: + return EhEngine.getArchiveList(this, mOkHttpClient, (String) params[0]); + case METHOD_DOWNLOAD_ARCHIVE: + return EhEngine.downloadArchive(this, mOkHttpClient, (Long) params[0], (String) params[1], (String) params[2], (String) params[3]); default: return new IllegalStateException("Can't detect method " + mMethod); } diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java index 8cd40fca3..afacabb89 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java @@ -31,6 +31,7 @@ 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.ParseException; +import com.hippo.ehviewer.client.parser.ArchiveParser; import com.hippo.ehviewer.client.parser.FavoritesParser; import com.hippo.ehviewer.client.parser.ForumsParser; import com.hippo.ehviewer.client.parser.GalleryApiParser; @@ -599,6 +600,74 @@ public class EhEngine { return result; } + public static Pair[]> getArchiveList(@Nullable EhClient.Task task, OkHttpClient okHttpClient, + String url) throws Exception { + Log.d(TAG, url); + Request request = new EhRequestBuilder(url, null != task ? task.getEhConfig() : Settings.getEhConfig()).build(); + Call call = okHttpClient.newCall(request); + + // Put call + if (null != task) { + task.setCall(call); + } + + String body = null; + Headers headers = null; + Pair[]> result; + int code = -1; + try { + Response response = call.execute(); + code = response.code(); + headers = response.headers(); + body = response.body().string(); + result = ArchiveParser.parse(body); + } catch (Exception e) { + throwException(call, code, headers, body, e); + throw e; + } + + return result; + } + + public static Void downloadArchive(@Nullable EhClient.Task task, OkHttpClient okHttpClient, + long gid, String token, String or, String res) throws Exception { + if (or == null || or.length() == 0) { + throw new EhException("Invalid form param or: " + or); + } + if (res == null || res.length() == 0) { + throw new EhException("Invalid res: " + res); + } + FormBody.Builder builder = new FormBody.Builder(); + builder.add("hathdl_xres", res); + String url = EhUrl.getDownloadArchive(gid, token, or); + Log.d(TAG, url); + Request request = new EhRequestBuilder(url, null != task ? task.getEhConfig() : Settings.getEhConfig()) + .post(builder.build()) + .build(); + Call call = okHttpClient.newCall(request); + + // Put call + if (null != task) { + task.setCall(call); + } + + String body = null; + Headers headers = null; + int code = -1; + try { + Response response = call.execute(); + code = response.code(); + headers = response.headers(); + body = response.body().string(); + throwException(call, code, headers, body, null); + } catch (Exception e) { + throwException(call, code, headers, body, e); + throw e; + } + + return null; + } + public static List getWhatsHot(@Nullable EhClient.Task task, OkHttpClient okHttpClient) throws Exception { String url = EhUrl.HOST_E; diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java index bb13f91cd..d7e1bf2b8 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java @@ -108,6 +108,10 @@ public class EhUrl { return getHost() + "gallerypopups.php?gid=" + gid + "&t=" + token + "&act=addfav"; } + public static String getDownloadArchive(long gid, String token, String or) { + return getHost() + "archiver.php?gid=" + gid + "&token=" + token + "&or=" + or; + } + public static String getTagDefinitionUrl(String tag) { return "https://ehwiki.org/wiki/" + tag.replace(' ', '_'); } diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java index 109c5ed9e..5b11dfbf8 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java +++ b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java @@ -27,6 +27,7 @@ public class GalleryDetail extends GalleryInfo { public String apiKey; public int torrentCount; public String torrentUrl; + public String archiveUrl; public String parent; public String visible; public String language; @@ -50,6 +51,7 @@ public class GalleryDetail extends GalleryInfo { super.writeToParcel(dest, flags); dest.writeInt(this.torrentCount); dest.writeString(this.torrentUrl); + dest.writeString(this.archiveUrl); dest.writeString(this.parent); dest.writeString(this.visible); dest.writeString(this.language); @@ -71,6 +73,7 @@ public class GalleryDetail extends GalleryInfo { super(in); this.torrentCount = in.readInt(); this.torrentUrl = in.readString(); + this.archiveUrl = in.readString(); this.parent = in.readString(); this.visible = in.readString(); this.language = in.readString(); diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/ArchiveParser.java b/app/src/main/java/com/hippo/ehviewer/client/parser/ArchiveParser.java new file mode 100644 index 000000000..d07e71d94 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/ArchiveParser.java @@ -0,0 +1,48 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.client.parser; + +import android.util.Pair; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ArchiveParser { + + private static final Pattern PATTERN_FORM = Pattern.compile("
"); + private static final Pattern PATTERN_ARCHIVE = Pattern.compile("([^<]+)"); + + @SuppressWarnings("unchecked") + public static Pair[]> parse(String body) { + Matcher m = PATTERN_FORM.matcher(body); + if (!m.find()) { + return new Pair[]>("", new Pair[0]); + } + String paramOr = m.group(1); + List> archiveList = new ArrayList<>(); + m = PATTERN_ARCHIVE.matcher(body); + while (m.find()) { + String res = ParserUtils.trim(m.group(1)); + String name = ParserUtils.trim(m.group(2)); + Pair item = new Pair<>(res, name); + archiveList.add(item); + } + return new Pair[]>(paramOr, archiveList.toArray(new Pair[archiveList.size()])); + } +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java b/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java index 905eff0c1..cbaaa48ca 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java @@ -58,6 +58,7 @@ public class GalleryDetailParser { private static final Pattern PATTERN_ERROR = Pattern.compile("
\n

([^<]+)

"); private static final Pattern PATTERN_DETAIL = Pattern.compile("var gid = (\\d+);.+?var token = \"([a-f0-9]+)\";.+?var apiuid = ([\\-\\d]+);.+?var apikey = \"([a-f0-9]+)\";", Pattern.DOTALL); private static final Pattern PATTERN_TORRENT = Pattern.compile("]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Torrent Download \\( (\\d+) \\)"); + private static final Pattern PATTERN_ARCHIVE = Pattern.compile("]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Archive Download"); private static final Pattern PATTERN_TAG_GROUP = Pattern.compile("]+>([\\w\\s]+):(?:]+>]+>[\\w\\s]+
)+"); private static final Pattern PATTERN_TAG = Pattern.compile("]+>]+>([\\w\\s]+)"); private static final Pattern PATTERN_COMMENT = Pattern.compile("
Posted on ([^<>]+) by:   ]+>([^<>]+).+?
]*>(.+?)
[] mTorrentList; + private String mArchiveFormParamOr; + private Pair[] mArchiveList; + @State private int mState = STATE_INIT; @@ -464,18 +469,21 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene mHeart = (TextView) ViewUtils.$$(mHeartGroup, R.id.heart); mHeartOutline = (TextView) ViewUtils.$$(mHeartGroup, R.id.heart_outline); mTorrent = (TextView) ViewUtils.$$(mActions, R.id.torrent); + mArchive = (TextView) ViewUtils.$$(mActions, R.id.archive); mShare = (TextView) ViewUtils.$$(mActions, R.id.share); mRate = (TextView) ViewUtils.$$(mActions, R.id.rate); mSimilar = (TextView) ViewUtils.$$(mActions, R.id.similar); mSearchCover = (TextView) ViewUtils.$$(mActions, R.id.search_cover); Ripple.addRipple(mHeartGroup, false); Ripple.addRipple(mTorrent, false); + Ripple.addRipple(mArchive, false); Ripple.addRipple(mShare, false); Ripple.addRipple(mRate, false); Ripple.addRipple(mSimilar, false); Ripple.addRipple(mSearchCover, false); mHeartGroup.setOnClickListener(this); mTorrent.setOnClickListener(this); + mArchive.setOnClickListener(this); mShare.setOnClickListener(this); mRate.setOnClickListener(this); mSimilar.setOnClickListener(this); @@ -564,6 +572,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene mHeart = null; mHeartOutline = null; mTorrent = null; + mArchive = null; mShare = null; mRate = null; mSimilar = null; @@ -647,6 +656,8 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene setActionDrawable(mHeartOutline, heartOutline); Drawable torrent = DrawableManager.getDrawable(context, R.drawable.v_utorrent_primary_x48); setActionDrawable(mTorrent, torrent); + Drawable archive = DrawableManager.getDrawable(context, R.drawable.v_archive_primary_x48); + setActionDrawable(mArchive, archive); Drawable share = DrawableManager.getDrawable(context, R.drawable.v_share_primary_x48); setActionDrawable(mShare, share); Drawable rate = DrawableManager.getDrawable(context, R.drawable.v_thumb_up_primary_x48); @@ -1166,6 +1177,21 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene .show(); helper.setDialog(dialog, mGalleryDetail.torrentUrl); } + } else if (mArchive == v) { + if (mGalleryDetail == null) { + return; + } + if (mGalleryDetail.apiUid < 0) { + showTip(R.string.sign_in_first, LENGTH_SHORT); + return; + } + ArchiveListDialogHelper helper = new ArchiveListDialogHelper(); + Dialog dialog = new AlertDialog.Builder(context) + .setTitle(R.string.archives) + .setView(R.layout.dialog_archive_list) + .setOnDismissListener(helper) + .show(); + helper.setDialog(dialog, mGalleryDetail.archiveUrl); } else if (mRate == v) { if (mGalleryDetail == null) { return; @@ -1546,6 +1572,146 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene } } + private class DownloadArchiveListener extends EhCallback { + + public DownloadArchiveListener(Context context, int stageId, String sceneTag) { + super(context, stageId, sceneTag); + } + + @Override + public void onSuccess(Void result) { + showTip(R.string.download_archive_started, LENGTH_SHORT); + } + + @Override + public void onFailure(Exception e) { + showTip(R.string.download_archive_failure, LENGTH_SHORT); + } + + @Override + public void onCancel() {} + + @Override + public boolean isInstance(SceneFragment scene) { + return scene instanceof GalleryDetailScene; + } + } + + private class ArchiveListDialogHelper implements AdapterView.OnItemClickListener, + DialogInterface.OnDismissListener, EhClient.Callback[]>> { + + @Nullable + private ProgressView mProgressView; + @Nullable + private TextView mErrorText; + @Nullable + private ListView mListView; + @Nullable + private EhRequest mRequest; + @Nullable + private Dialog mDialog; + + public void setDialog(@Nullable Dialog dialog, String url) { + mDialog = dialog; + mProgressView = (ProgressView) ViewUtils.$$(dialog, R.id.progress); + mErrorText = (TextView) ViewUtils.$$(dialog, R.id.text); + mListView = (ListView) ViewUtils.$$(dialog, R.id.list_view); + mListView.setOnItemClickListener(this); + + Context context = getContext2(); + if (context != null) { + if (mArchiveList == null) { + mErrorText.setVisibility(View.GONE); + mListView.setVisibility(View.GONE); + mRequest = new EhRequest().setMethod(EhClient.METHOD_ARCHIVE_LIST) + .setArgs(url) + .setCallback(this); + EhApplication.getEhClient(context).execute(mRequest); + } else { + bind(mArchiveList); + } + } + } + + private void bind(Pair[] data) { + if (null == mDialog || null == mProgressView || null == mErrorText || null == mListView) { + return; + } + + if (0 == data.length) { + mProgressView.setVisibility(View.GONE); + mErrorText.setVisibility(View.VISIBLE); + mListView.setVisibility(View.GONE); + mErrorText.setText(R.string.no_archives); + } else { + String[] nameArray = new String[data.length]; + for (int i = 0, n = data.length; i < n; i++) { + nameArray[i] = data[i].second; + } + mProgressView.setVisibility(View.GONE); + mErrorText.setVisibility(View.GONE); + mListView.setVisibility(View.VISIBLE); + mListView.setAdapter(new ArrayAdapter<>(mDialog.getContext(), R.layout.item_select_dialog, nameArray)); + } + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Context context = getContext2(); + MainActivity activity = getActivity2(); + if (null != context && null != activity && null != mArchiveList && position < mArchiveList.length) { + String res = mArchiveList[position].first; + 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())); + EhApplication.getEhClient(context).execute(request); + } + + if (mDialog != null) { + mDialog.dismiss(); + mDialog = null; + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + if (mRequest != null) { + mRequest.cancel(); + mRequest = null; + } + mDialog = null; + mProgressView = null; + mErrorText = null; + mListView = null; + } + + @Override + public void onSuccess(Pair[]> result) { + if (mRequest != null) { + mRequest = null; + mArchiveFormParamOr = result.first; + mArchiveList = result.second; + bind(result.second); + } + } + + @Override + public void onFailure(Exception e) { + mRequest = null; + Context context = getContext2(); + if (null != context && null != mProgressView && null != mErrorText && null != mListView) { + mProgressView.setVisibility(View.GONE); + mErrorText.setVisibility(View.VISIBLE); + mListView.setVisibility(View.GONE); + mErrorText.setText(ExceptionUtils.getReadableString(e)); + } + } + + @Override + public void onCancel() { mRequest = null; } + } + private class TorrentListDialogHelper implements AdapterView.OnItemClickListener, DialogInterface.OnDismissListener, EhClient.Callback[]> { diff --git a/app/src/main/res/drawable/v_archive_primary_x48.xml b/app/src/main/res/drawable/v_archive_primary_x48.xml new file mode 100644 index 000000000..60342ec30 --- /dev/null +++ b/app/src/main/res/drawable/v_archive_primary_x48.xml @@ -0,0 +1,29 @@ + + + + + + + + diff --git a/app/src/main/res/layout/dialog_archive_list.xml b/app/src/main/res/layout/dialog_archive_list.xml new file mode 100644 index 000000000..4f9f8ad95 --- /dev/null +++ b/app/src/main/res/layout/dialog_archive_list.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + diff --git a/app/src/main/res/layout/gallery_detail_actions.xml b/app/src/main/res/layout/gallery_detail_actions.xml index d794beff8..b5df04806 100644 --- a/app/src/main/res/layout/gallery_detail_actions.xml +++ b/app/src/main/res/layout/gallery_detail_actions.xml @@ -74,6 +74,15 @@ android:drawablePadding="8dp" android:textColor="@color/primary_text_light"/> + + 年 + 归档 + 没有归档 + 归档下载开始 + 无法起始归档下载 + 下载归档 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 63db9985a..29154f73f 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -605,5 +605,10 @@ 年 + 檔案 + 沒有檔案 + 檔案下載開始 + 無法開始檔案下載 + 下載檔案 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ae2ea4ac9..8ed423341 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -605,5 +605,10 @@ 年 + 檔案 + 沒有檔案 + 檔案下載開始 + 無法開始檔案下載 + 下載檔案 diff --git a/app/src/main/res/values/pathdata.xml b/app/src/main/res/values/pathdata.xml index d016a43da..a13598bb4 100644 --- a/app/src/main/res/values/pathdata.xml +++ b/app/src/main/res/values/pathdata.xml @@ -77,5 +77,6 @@ M12,17C12.8,17,13.5,17.4,13.5,18S12.8,19,12,19S10.5,18.6,10.5,18S11.2,17,12,17Z M21.1,7.8C22.2,7.4,23,6.3,23,5C23,3.3,21.7,2,20,2C18.9,2,17.9,2.6,17.4,3.6L21.1,7.8M6.6,3.6C6.1,2.6,5.1,2,4,2C2.3,2,1,3.3,1,5C1,6.3,1.8,7.4,2.9,7.8L6.6,3.6M10.1,13L8,15.1C7.4,15.7,6.5,15.7,5.9,15.1L5.9,15.1C5.3,14.5,5.3,13.6,5.9,13L8,10.9C8.6,10.3,9.5,10.3,10.1,10.9L10.1,10.9C10.7,11.5,10.7,12.4,10.1,13M16,15.1L13.9,13C13.3,12.4,13.3,11.5,13.9,10.9L13.9,10.9C14.5,10.3,15.4,10.3,16,10.9L18.1,13C18.7,13.6,18.7,14.5,18.1,15.1L18.1,15.1C17.5,15.7,16.6,15.7,16,15.1M12,17C12.8,17,13.5,17.4,13.5,18S12.8,19,12,19S10.5,18.6,10.5,18S11.2,17,12,17Z M17.4,3.6C15.8,2.6,14,2,12,2S8.2,2.6,6.6,3.6L2.9,7.8C2.3,9.1,2,10.5,2,12C2,17.5,6.5,22,12,22S22,17.5,22,12C22,10.5,21.7,9.1,21.1,7.8L17.4,3.6Z + M19.35,10.04C18.67,6.59 15.64,4 12,4 9.11,4 6.6,5.64 5.35,8.04 2.34,8.36 0,10.91 0,14c0,3.31 2.69,6 6,6h13c2.76,0 5,-2.24 5,-5 0,-2.64 -2.05,-4.78 -4.65,-4.96zM10,17l-3.5,-3.5 1.41,-1.41L10,14.17 15.18,9l1.41,1.41L10,17z diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 82f1d9d62..8a6d67245 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -655,5 +655,10 @@ year years + Archives + No Archives + Archive download started + Failed to download archive + Archive