Add eh gallery spider

This commit is contained in:
seven332 committed 2016-02-19 22:53:24 +08:00
1 parent 6f37491471
commit 31ffa6f8a9
43 files changed
+2337 -180

No files matched your search

@@ -0,0 +1,71 @@
/*
* 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;
import android.content.Context;
import android.os.Environment;
import android.support.annotation.Nullable;
import com.hippo.yorozuya.FileUtils;
import java.io.File;
public class AppConfig {
private static final String APP_DIRNAME = "EhViewer";
private static final String SPIDER_INFO = "spider_info";
private static final String DOWNLOAD = "download";
private static Context sContext;
public static void initialize(Context context) {
sContext = context.getApplicationContext();
}
public static File getSpiderInfoCacheDir() {
File dir = new File(sContext.getCacheDir(), SPIDER_INFO);
return FileUtils.ensureDirectory(dir) ? dir : null;
}
@Nullable
public static File getExternalAppDir() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File dir = new File(Environment.getExternalStorageDirectory(), APP_DIRNAME);
return FileUtils.ensureDirectory(dir) ? dir : null;
}
return null;
}
/**
* mkdirs and get
*/
@Nullable
public static File getDirInAppDir(String filename) {
File appFolder = getExternalAppDir();
if (appFolder != null) {
File dir = new File(appFolder, filename);
return FileUtils.ensureDirectory(dir) ? dir : null;
}
return null;
}
@Nullable
public static File getDefaultDownloadDir() {
return getDirInAppDir(DOWNLOAD);
}
}
@@ -30,6 +30,7 @@ import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhCookieStore;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.LargePreviewSet;
import com.hippo.ehviewer.spider.SpiderDen;
import com.hippo.network.StatusCodeException;
import com.hippo.okhttp.CookieDB;
import com.hippo.scene.SceneApplication;
@@ -73,6 +74,8 @@ public class EhApplication extends SceneApplication {
Settings.initialize(this);
ReadableTime.initialize(this);
Html.initialize(this);
AppConfig.initialize(this);
SpiderDen.initialize(this);
if (DEBUG_NATIVE_MEMORY) {
debugNativeMemory();
@@ -18,9 +18,13 @@ package com.hippo.ehviewer;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.NumberUtils;
public class Settings {
@@ -121,4 +125,36 @@ public class Settings {
public static boolean getShowJpnTitle() {
return getBoolean(KEY_SHOW_JPN_TITLE, DEFAULT_SHOW_JPN_TITLE);
}
public static final String KEY_DOWNLOAD_SAVE_SCHEME = "image_scheme";
public static final String KEY_DOWNLOAD_SAVE_AUTHORITY = "image_authority";
public static final String KEY_DOWNLOAD_SAVE_PATH = "image_path";
public static final String KEY_DOWNLOAD_SAVE_QUERY = "image_query";
public static final String KEY_DOWNLOAD_SAVE_FRAGMENT = "image_fragment";
@Nullable
public static UniFile getDownloadLocation() {
UniFile dir = null;
try {
Uri.Builder builder = new Uri.Builder();
builder.scheme(getString(KEY_DOWNLOAD_SAVE_SCHEME, null));
builder.encodedAuthority(getString(KEY_DOWNLOAD_SAVE_AUTHORITY, null));
builder.encodedPath(getString(KEY_DOWNLOAD_SAVE_PATH, null));
builder.encodedQuery(getString(KEY_DOWNLOAD_SAVE_QUERY, null));
builder.encodedFragment(getString(KEY_DOWNLOAD_SAVE_FRAGMENT, null));
dir = UniFile.fromUri(sContext, builder.build());
} catch (Exception e) {
// Ignore
}
return dir != null ? dir : UniFile.fromFile(AppConfig.getDefaultDownloadDir());
}
public static void putImageSaveLocation(@NonNull UniFile location) {
Uri uri = location.getUri();
putString(KEY_DOWNLOAD_SAVE_SCHEME, uri.getScheme());
putString(KEY_DOWNLOAD_SAVE_AUTHORITY, uri.getEncodedAuthority());
putString(KEY_DOWNLOAD_SAVE_PATH, uri.getEncodedPath());
putString(KEY_DOWNLOAD_SAVE_QUERY, uri.getEncodedQuery());
putString(KEY_DOWNLOAD_SAVE_FRAGMENT, uri.getEncodedFragment());
}
}
@@ -39,6 +39,7 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
@@ -87,7 +88,7 @@ public class EhEngine {
}
public static Call prepareSignIn(OkHttpClient okHttpClient,
EhConfig ehConfig, String username, String password) {
EhConfig ehConfig, String username, String password) throws MalformedURLException {
FormBody.Builder builder = new FormBody.Builder()
.add("UserName", username)
.add("PassWord", password)
@@ -120,7 +121,7 @@ public class EhEngine {
}
public static Call prepareGetGalleryList(OkHttpClient okHttpClient,
EhConfig ehConfig, String url) {
EhConfig ehConfig, String url) throws MalformedURLException {
Log.d(TAG, url);
Request request = new EhRequestBuilder(url, ehConfig).build();
return okHttpClient.newCall(request);
@@ -232,7 +233,7 @@ public class EhEngine {
}
public static Call prepareGetGalleryDetail(OkHttpClient okHttpClient,
EhConfig ehConfig, String url) {
EhConfig ehConfig, String url) throws MalformedURLException {
Log.d(TAG, url);
Request request = new EhRequestBuilder(url, ehConfig).build();
return okHttpClient.newCall(request);
@@ -255,7 +256,7 @@ public class EhEngine {
}
public static Call prepareGetLargePreviewSet(OkHttpClient okHttpClient,
EhConfig ehConfig, String url) {
EhConfig ehConfig, String url) throws MalformedURLException {
Log.d(TAG, url);
Request request = new EhRequestBuilder(url, ehConfig).build();
return okHttpClient.newCall(request);
@@ -279,7 +280,7 @@ public class EhEngine {
// rating 0.0 - 0.5
public static Call prepareRateGallery(OkHttpClient okHttpClient,
EhConfig ehConfig, int gid, String token, float rating) throws JSONException {
EhConfig ehConfig, int gid, String token, float rating) throws JSONException, MalformedURLException {
final JSONObject json = new JSONObject();
json.put("method", "rategallery");
json.put("apiuid", APIUID);
@@ -316,7 +317,7 @@ public class EhEngine {
}
public static Call prepareCommentGallery(OkHttpClient okHttpClient,
EhConfig ehConfig, String url, String comment) {
EhConfig ehConfig, String url, String comment) throws MalformedURLException {
FormBody.Builder builder = new FormBody.Builder()
.add("commenttext", comment)
.add("postcomment", "Post New");
@@ -354,7 +355,7 @@ public class EhEngine {
* }
*/
public static Call prepareGetGalleryToken(OkHttpClient okHttpClient,
EhConfig ehConfig, int gid, String gtoken, int page) throws JSONException {
EhConfig ehConfig, int gid, String gtoken, int page) throws JSONException, MalformedURLException {
JSONObject json = new JSONObject()
.put("method", "gtoken")
.put("pagelist", new JSONArray().put(
@@ -19,13 +19,15 @@ package com.hippo.ehviewer.client;
import com.hippo.ehviewer.Settings;
import com.hippo.okhttp.ChromeRequestBuilder;
import java.net.MalformedURLException;
public class EhRequestBuilder extends ChromeRequestBuilder {
public EhRequestBuilder(String url) {
public EhRequestBuilder(String url) throws MalformedURLException {
this(url, Settings.getEhConfig());
}
public EhRequestBuilder(String url, EhConfig ehConfig) {
public EhRequestBuilder(String url, EhConfig ehConfig) throws MalformedURLException {
super(url);
tag(ehConfig);
}
@@ -46,4 +46,8 @@ public class EhUrl {
}
return builder.build();
}
public static String getPageUrl(int gid, int index, String pToken) {
return HOST_EX + "s/" + pToken + '/' + gid + '-' + (index + 1);
}
}
@@ -25,7 +25,7 @@ import android.util.Log;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser;
import com.hippo.ehviewer.client.parser.GalleryListUrlParser;
import com.hippo.ehviewer.client.parser.GalleryUrlParser;
import com.hippo.ehviewer.client.parser.GalleryPageUrlParser;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.ehviewer.ui.scene.GalleryDetailScene;
import com.hippo.ehviewer.ui.scene.GalleryListScene;
@@ -68,7 +68,7 @@ public class EhUrlOpener {
return true;
}
GalleryUrlParser.Result result2 = GalleryUrlParser.parse(url);
GalleryPageUrlParser.Result result2 = GalleryPageUrlParser.parse(url);
if (result2 != null) {
Bundle args = new Bundle();
args.putString(ProgressScene.KEY_ACTION, ProgressScene.ACTION_GALLERY_TOKEN);
@@ -17,6 +17,9 @@
package com.hippo.ehviewer.client.data;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Arrays;
public class GalleryDetail extends GalleryInfo {
@@ -78,17 +81,29 @@ public class GalleryDetail extends GalleryInfo {
this.favoredTimes = in.readInt();
this.isFavored = in.readByte() != 0;
this.ratedTimes = in.readInt();
this.tags = in.createTypedArray(GalleryTagGroup.CREATOR);
this.comments = in.createTypedArray(GalleryComment.CREATOR);
Parcelable[] array = in.readParcelableArray(GalleryTagGroup.class.getClassLoader());
if (array != null) {
this.tags = Arrays.copyOf(array, array.length, GalleryTagGroup[].class);
} else {
this.tags = null;
}
array = in.readParcelableArray(GalleryComment.class.getClassLoader());
if (array != null) {
this.comments = Arrays.copyOf(array, array.length, GalleryComment[].class);
} else {
this.comments = null;
}
this.previewPages = in.readInt();
this.previewSet = in.readParcelable(LargePreviewSet.class.getClassLoader());
}
public static final Creator<GalleryDetail> CREATOR = new Creator<GalleryDetail>() {
@Override
public GalleryDetail createFromParcel(Parcel source) {
return new GalleryDetail(source);
}
@Override
public GalleryDetail[] newArray(int size) {
return new GalleryDetail[size];
}
@@ -24,7 +24,7 @@ import java.util.ArrayList;
public class GalleryTagGroup implements Parcelable {
public String groupName;
private ArrayList<String> mTagList = new ArrayList<>();
private ArrayList<String> mTagList;
public void addTag(String tag) {
mTagList.add(tag);
@@ -50,6 +50,7 @@ public class GalleryTagGroup implements Parcelable {
}
public GalleryTagGroup() {
mTagList = new ArrayList<>();
}
protected GalleryTagGroup(Parcel in) {
@@ -58,10 +59,12 @@ public class GalleryTagGroup implements Parcelable {
}
public static final Parcelable.Creator<GalleryTagGroup> CREATOR = new Parcelable.Creator<GalleryTagGroup>() {
@Override
public GalleryTagGroup createFromParcel(Parcel source) {
return new GalleryTagGroup(source);
}
@Override
public GalleryTagGroup[] newArray(int size) {
return new GalleryTagGroup[size];
}
@@ -25,9 +25,9 @@ import java.util.ArrayList;
public class LargePreviewSet implements Parcelable {
private IntList mIndexList = new IntList();
private ArrayList<String> mImageUrlList = new ArrayList<>();
private ArrayList<String> mPageUrlList = new ArrayList<>();
private IntList mIndexList;
private ArrayList<String> mImageUrlList;
private ArrayList<String> mPageUrlList;
public int size() {
return mImageUrlList.size();
@@ -58,26 +58,30 @@ public class LargePreviewSet implements Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
this.mIndexList.writeToParcel(dest, flags);
dest.writeParcelable(this.mIndexList, 0);
dest.writeParcelable(this.mIndexList, flags);
dest.writeStringList(this.mImageUrlList);
dest.writeStringList(this.mPageUrlList);
}
public LargePreviewSet() {
mIndexList = new IntList();
mImageUrlList = new ArrayList<>();
mPageUrlList = new ArrayList<>();
}
protected LargePreviewSet(Parcel in) {
this.mIndexList = IntList.CREATOR.createFromParcel(in);
this.mIndexList = in.readParcelable(IntList.class.getClassLoader());
this.mImageUrlList = in.createStringArrayList();
this.mPageUrlList = in.createStringArrayList();
}
public static final Parcelable.Creator<LargePreviewSet> CREATOR = new Parcelable.Creator<LargePreviewSet>() {
@Override
public LargePreviewSet createFromParcel(Parcel source) {
return new LargePreviewSet(source);
}
@Override
public LargePreviewSet[] newArray(int size) {
return new LargePreviewSet[size];
}
@@ -0,0 +1,55 @@
/*
* 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.data;
import com.hippo.yorozuya.IntList;
import java.util.ArrayList;
public class NormalPreviewSet {
private IntList mIndexList = new IntList();
private ArrayList<String> mImageUrlList = new ArrayList<>();
private IntList mXOffsetList = new IntList();
private IntList mYOffsetList = new IntList();
private IntList mWidthList = new IntList();
private IntList mHeightList = new IntList();
private ArrayList<String> mPageUrlList = new ArrayList<>();
public void addItem(int index, String imageUrl, int xOffset, int yOffset, int width,
int height, String pageUrl) {
mIndexList.add(index);
mImageUrlList.add(imageUrl);
mXOffsetList.add(xOffset);
mYOffsetList.add(yOffset);
mWidthList.add(width);
mHeightList.add(height);
mPageUrlList.add(pageUrl);
}
public int size() {
return mIndexList.size();
}
public int getIndexAt(int index) {
return mIndexList.get(index);
}
public String getPageUrlAt(int index) {
return mPageUrlList.get(index);
}
}
@@ -0,0 +1,24 @@
/*
* 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.exception;
public class Image509Exception extends EhException {
public Image509Exception() {
super("509");
}
}
@@ -16,22 +16,18 @@
package com.hippo.ehviewer.client.parser;
import android.util.Log;
import com.hippo.ehviewer.client.EhUtils;
import com.hippo.ehviewer.client.data.GalleryComment;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.GalleryTagGroup;
import com.hippo.ehviewer.client.data.LargePreviewSet;
import com.hippo.ehviewer.client.data.NormalPreviewSet;
import com.hippo.ehviewer.client.exception.EhException;
import com.hippo.ehviewer.client.exception.OffensiveException;
import com.hippo.ehviewer.client.exception.ParseException;
import com.hippo.ehviewer.client.exception.PiningException;
import com.hippo.yorozuya.NumberUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@@ -74,9 +70,11 @@ public class GalleryDetailParser {
+ ".+?"
+ "<td id=\"grt3\"><span id=\"rating_count\">([\\d,]+)</span></td>" // 18 ratedTimes
+ "</tr>"
+ "<tr><td[^<>]*>([^<>]+)</td>" // 19 rating "Average: x.xx" or "Not Yet Rated"
+ ".+?"
+ "<a id=\"favoritelink\"[^<>]*>(.+?)</a>", Pattern.DOTALL); // 20 isFavored "Favorite Gallery" for favorite
+ "<tr><td[^<>]*>([^<>]+)</td>", // 19 rating "Average: x.xx" or "Not Yet Rated"
Pattern.DOTALL);
private static final Pattern IS_FAVORED_PATTERN = Pattern.compile("<a id=\"favoritelink\"[^<>]*>(.+?)</a>"); // isFavored "Favorite Gallery" for favorite
private static final Pattern TAG_GROUP_PATTERN = Pattern.compile("<tr><td[^<>]+>([\\w\\s]+):</td><td>(?:<div[^<>]+><a[^<>]+>[\\w\\s]+</a></div>)+</td></tr>");
private static final Pattern TAG_PATTERN = Pattern.compile("<div[^<>]+><a[^<>]+>([\\w\\s]+)</a></div>");
@@ -85,7 +83,7 @@ public class GalleryDetailParser {
public static final Pattern PAGES_PATTERN = Pattern.compile("<tr><td[^<>]*>Length:</td><td[^<>]*>([\\d,]+) pages</td></tr>");
public static final Pattern PREVIEW_PAGES_PATTERN = Pattern.compile("<td[^>]+><a[^>]+>([\\d,]+)</a></td><td[^>]+>(?:<a[^>]+>)?&gt;(?:</a>)?</td>");
private static final Pattern NORMAL_PREVIEW_PATTERN = Pattern.compile("<div[^<>]*class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*>");
private static final Pattern NORMAL_PREVIEW_PATTERN = Pattern.compile("<div class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*><img alt=\"([\\d,]+)\"");
private static final Pattern LARGE_PREVIEW_PATTERN = Pattern.compile("<div class=\"gdtl\".+?<a href=\"(.+?)\"><img alt=\"([\\d,]+)\".+?src=\"(.+?)\"");
static {
@@ -117,7 +115,7 @@ public class GalleryDetailParser {
galleryDetail.tags = parseTagGroup(body);
galleryDetail.comments = parseComment(body);
galleryDetail.previewPages = parsePreviewPages(body);
galleryDetail.previewSet = parsePreview(body);
galleryDetail.previewSet = parseLargePreview(body);
return galleryDetail;
}
@@ -176,10 +174,10 @@ public class GalleryDetailParser {
}
}
gd.isFavored = "Favorite Gallery".equals(ParserUtils.trim(m.group(20)));
m = IS_FAVORED_PATTERN.matcher(body);
gd.isFavored = m.find() && "Favorite Gallery".equals(ParserUtils.trim(m.group(1)));
}
public static GalleryTagGroup[] parseTagGroup(String body) throws EhException {
List<GalleryTagGroup> list = new LinkedList<>();
@@ -246,18 +244,7 @@ public class GalleryDetailParser {
}
}
public static LargePreviewSet parsePreview(String body) throws EhException {
return parseLargePreview(body);
/*
if (body.contains("<div class=\"gdtm\"")) {
throw new EhException("Not support normal preview now");
} else {
return parseLargePreview(body);
}
*/
}
public static LargePreviewSet parseLargePreview(String body) {
public static LargePreviewSet parseLargePreview(String body) throws ParseException {
Matcher m = LARGE_PREVIEW_PATTERN.matcher(body);
LargePreviewSet largePreviewSet = new LargePreviewSet();
@@ -267,16 +254,27 @@ public class GalleryDetailParser {
}
if (largePreviewSet.size() == 0) {
Log.d("TAG", "largePreviewSet.size() == 0");
try {
OutputStream os = new FileOutputStream(new File("/data/data/com.hippo.ehviewer/cache/empty.txt"));
os.write(body.getBytes("utf-8"));
os.close();
} catch (Exception e) {
e.printStackTrace();
}
throw new ParseException("Can't parse large preview", body);
}
return largePreviewSet;
}
public static NormalPreviewSet parseNormalPreviewSet(String body) throws ParseException {
Matcher m = NORMAL_PREVIEW_PATTERN.matcher(body);
NormalPreviewSet normalPreviewSet = new NormalPreviewSet();
while (m.find()) {
normalPreviewSet.addItem(ParserUtils.parseInt(m.group(6)) - 1,
ParserUtils.trim(m.group(3)), ParserUtils.parseInt((m.group(4))), 0,
ParserUtils.parseInt(m.group(1)), ParserUtils.parseInt(m.group(2)),
ParserUtils.trim(m.group(5)));
}
if (normalPreviewSet.size() == 0) {
throw new ParseException("Can't parse large preview", body);
}
return normalPreviewSet;
}
}
@@ -0,0 +1,53 @@
/*
* 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.text.TextUtils;
import com.hippo.ehviewer.client.exception.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GalleryPageParser {
private static Pattern IMAGE_URL_PATTERN = Pattern.compile("<div id=\"i3\"><a[^>]+><img id=\"img\" src=\"([^\"]+)\"");
private static Pattern SKIP_HATH_KEY_PATTERN = Pattern.compile("onclick=\"return nl\\('([^\\)]+)'\\)");
public static Result parse(String body) throws ParseException {
Matcher m;
Result result = new Result();
m = IMAGE_URL_PATTERN.matcher(body);
if (m.find()) {
result.imageUrl = ParserUtils.trim(m.group(1));
}
m = SKIP_HATH_KEY_PATTERN.matcher(body);
if (m.find()) {
result.skipHathKey = ParserUtils.trim(m.group(1));
}
if (!TextUtils.isEmpty(result.imageUrl) && !TextUtils.isEmpty(result.skipHathKey)) {
return result;
} else {
throw new ParseException("Parse image url and skip hath key error", body);
}
}
public static class Result {
public String imageUrl;
public String skipHathKey;
}
}
@@ -24,7 +24,7 @@ import java.util.regex.Pattern;
/**
* Like http://exhentai.org/s/91ea4b6d89/901103-12
*/
public final class GalleryUrlParser {
public final class GalleryPageUrlParser {
public static final Pattern URL_PATTERN = Pattern.compile("http://(?:" +
EhUrl.DOMAIN_EX + "|" + EhUrl.DOMAIN_G + "|" + EhUrl.DOMAIN_LOFI + ")/s/(\\w+)/(\\d+)-(\\d+)");
@@ -46,7 +46,6 @@ public class DirGalleryProvider extends GalleryProvider implements Runnable {
private Thread mBgThread;
private volatile int mSize = STATE_WAIT;
private String mError;
private boolean mStarted = false;
public DirGalleryProvider(File dir) {
mDir = dir;
@@ -54,26 +53,21 @@ public class DirGalleryProvider extends GalleryProvider implements Runnable {
@Override
public void start() {
if (mStarted) {
throw new IllegalStateException("Can't start it twice");
}
mStarted = true;
super.start();
if (mBgThread == null || mBgThread.isInterrupted()) {
mBgThread = new PriorityThread(this, TAG + '-' + sIdGenerator.incrementAndGet(),
Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start();
}
mBgThread = new PriorityThread(this, TAG + '-' + sIdGenerator.incrementAndGet(),
Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start();
}
@Override
public void stop() {
if (mBgThread == null || mBgThread.isInterrupted()) {
return;
}
super.stop();
mBgThread.interrupt();
mBgThread = null;
if (mBgThread != null) {
mBgThread.interrupt();
mBgThread = null;
}
}
@Override
@@ -82,16 +76,10 @@ public class DirGalleryProvider extends GalleryProvider implements Runnable {
}
@Override
@Result
public int request(int index) {
if (index < 0 || index >= size()) {
return RESULT_ERROR;
} else {
synchronized (mRequests) {
mRequests.add(index);
mRequests.notify();
}
return RESULT_WAIT;
public void request(int index) {
synchronized (mRequests) {
mRequests.add(index);
mRequests.notify();
}
}
@@ -108,7 +96,6 @@ public class DirGalleryProvider extends GalleryProvider implements Runnable {
if (files == null) {
mSize = STATE_ERROR;
mError = GetText.getString(R.string.error_not_folder_path);
mBgThread = null;
// Notify to to show error
notifyDataChanged();
@@ -139,6 +126,12 @@ public class DirGalleryProvider extends GalleryProvider implements Runnable {
index = mRequests.pop();
}
// Check index valid
if (index < 0 || index >= files.length) {
notifyPageFailed(index, GetText.getString(R.string.error_out_of_range));
continue;
}
try {
InputStream is = new FileInputStream(new File(mDir, files[index]));
Image image = Image.decode(is, false);
@@ -152,9 +145,6 @@ public class DirGalleryProvider extends GalleryProvider implements Runnable {
}
}
// Clear
mBgThread = null;
Log.i(TAG, "ImageDecoder end");
}
@@ -16,30 +16,107 @@
package com.hippo.ehviewer.gallery;
public class EhGalleryProvider extends GalleryProvider {
import android.content.Context;
import android.support.annotation.Nullable;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.spider.SpiderQueen;
import com.hippo.image.Image;
public class EhGalleryProvider extends GalleryProvider implements SpiderQueen.OnSpiderListener {
private Context mContext;
private GalleryInfo mGalleryInfo;
@Nullable
private SpiderQueen mSpiderQueen;
public EhGalleryProvider(Context context, GalleryInfo galleryInfo) {
mContext = context;
mGalleryInfo = galleryInfo;
}
@Override
public void start() {
super.start();
mSpiderQueen = SpiderQueen.obtainSpiderQueen(mContext, mGalleryInfo, SpiderQueen.MODE_READ);
mSpiderQueen.addOnSpiderListener(this);
}
@Override
public void stop() {
super.stop();
if (mSpiderQueen != null) {
mSpiderQueen.removeOnSpiderListener(this);
SpiderQueen.releaseSpiderQueen(mSpiderQueen, SpiderQueen.MODE_READ);
}
}
@Override
public int size() {
return 0;
if (mSpiderQueen != null) {
return mSpiderQueen.size();
} else {
return GalleryProvider.STATE_ERROR;
}
}
@Override
public int request(int index) {
return 0;
public void request(int index) {
if (mSpiderQueen != null) {
Object object = mSpiderQueen.request(index);
if (object instanceof Float) {
notifyPagePercent(index, (Float) object);
} else if (object instanceof String) {
notifyPageFailed(index, (String) object);
}
}
}
@Override
public String getError() {
return null;
if (mSpiderQueen != null) {
return mSpiderQueen.getError();
} else {
return "Error"; // TODO
}
}
@Override
public void onGetPages(int pages) {
notifyDataChanged();
}
@Override
public void onGet509(int index) {
// TODO
}
@Override
public void onDownload(int index, long contentLength, long receivedSize, int bytesRead) {
if (contentLength > 0) {
notifyPagePercent(index, (float) receivedSize / contentLength);
}
}
@Override
public void onSuccess(int index) {
notifyDataChanged(index);
}
@Override
public void onFailure(int index, String error) {
notifyPageFailed(index, error);
}
@Override
public void onGetImageSuccess(int index, Image image) {
notifyPageSucceed(index, image);
}
@Override
public void onGetImageFailure(int index, String error) {
notifyPageFailed(index, error);
}
}
@@ -18,28 +18,22 @@ package com.hippo.ehviewer.gallery;
import android.os.Handler;
import android.support.annotation.IntDef;
import android.support.annotation.UiThread;
import com.hippo.image.Image;
import com.hippo.yorozuya.OSUtils;
import com.hippo.yorozuya.Pool;
import com.hippo.yorozuya.SimpleHandler;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
public abstract class GalleryProvider {
@IntDef({RESULT_WAIT, RESULT_ERROR})
@Retention(RetentionPolicy.SOURCE)
public @interface Result {}
public static final int RESULT_WAIT = 0;
public static final int RESULT_ERROR = 1;
public static final int STATE_WAIT = -1;
public static final int STATE_ERROR = -2;
// With dot
public static final String[] SUPPORT_IMAGE_EXTENSIONS = {
".jpg", // Joint Photographic Experts Group
".jpeg",
@@ -47,34 +41,46 @@ public abstract class GalleryProvider {
".gif", // Graphics Interchange Format
};
private List<GalleryProviderListener> mGalleryProviderListeners = new ArrayList<>(2);
private GalleryProviderListener mGalleryProviderListener;
private Pool<NotifyTask> mNotifyTaskPool = new Pool<>(5);
private Handler mHandler = SimpleHandler.getInstance();
public abstract void start();
private boolean mStarted = false;
public abstract void stop();
@UiThread
public void start() {
OSUtils.checkMainLoop();
if (mStarted) {
throw new IllegalStateException("Can't start it twice");
}
mStarted = true;
}
@UiThread
public void stop() {
OSUtils.checkMainLoop();
}
/**
* @return {@link #STATE_WAIT} for wait, 0 for empty
*/
public abstract int size();
@Result
public abstract int request(int index);
public abstract void request(int index);
public abstract String getError();
public void addGalleryProviderListener(GalleryProviderListener listener) {
mGalleryProviderListeners.add(listener);
}
public void removeGalleryProviderListener(GalleryProviderListener listener) {
mGalleryProviderListeners.remove(listener);
public void setGalleryProviderListener(GalleryProviderListener listener) {
mGalleryProviderListener = listener;
}
public void notifyDataChanged() {
notify(NotifyTask.TYPE_DATA_CHANGED, 0, 0.0f, null, null);
notify(NotifyTask.TYPE_DATA_CHANGED, -1, 0.0f, null, null);
}
public void notifyDataChanged(int index) {
notify(NotifyTask.TYPE_DATA_CHANGED, index, 0.0f, null, null);
}
public void notifyPagePercent(int index, float percent) {
@@ -90,9 +96,14 @@ public abstract class GalleryProvider {
}
private void notify(@NotifyTask.Type int type, int index, float percent, Image image, String error) {
GalleryProviderListener listener = mGalleryProviderListener;
if (listener == null) {
return;
}
NotifyTask task = mNotifyTaskPool.pop();
if (task == null) {
task = new NotifyTask(mGalleryProviderListeners, mNotifyTaskPool);
task = new NotifyTask(listener, mNotifyTaskPool);
}
task.setData(type, index, percent, image, error);
mHandler.post(task);
@@ -109,7 +120,7 @@ public abstract class GalleryProvider {
public static final int TYPE_SUCCEED = 2;
public static final int TYPE_FAILED = 3;
private List<GalleryProviderListener> mGalleryProviderListeners;
private GalleryProviderListener mGalleryProviderListener;
private Pool<NotifyTask> mPool;
@Type
@@ -119,8 +130,8 @@ public abstract class GalleryProvider {
private Image mImage;
private String mError;
public NotifyTask(List<GalleryProviderListener> galleryProviderListeners, Pool<NotifyTask> pool) {
mGalleryProviderListeners = galleryProviderListeners;
public NotifyTask(GalleryProviderListener galleryProviderListener, Pool<NotifyTask> pool) {
mGalleryProviderListener = galleryProviderListener;
mPool = pool;
}
@@ -136,24 +147,20 @@ public abstract class GalleryProvider {
public void run() {
switch (mType) {
case TYPE_DATA_CHANGED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onDataChanged();
if (mIndex < 0) {
mGalleryProviderListener.onDataChanged();
} else {
mGalleryProviderListener.onDataChanged(mIndex);
}
break;
case TYPE_PERCENT:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPagePercent(mIndex, mPercent);
}
mGalleryProviderListener.onPagePercent(mIndex, mPercent);
break;
case TYPE_SUCCEED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPageSucceed(mIndex, mImage);
}
mGalleryProviderListener.onPageSucceed(mIndex, mImage);
break;
case TYPE_FAILED:
for (int i = 0, n = mGalleryProviderListeners.size(); i < n; i++) {
mGalleryProviderListeners.get(i).onPageFailed(mIndex, mError);
}
mGalleryProviderListener.onPageFailed(mIndex, mError);
break;
}
@@ -27,4 +27,6 @@ public interface GalleryProviderListener {
void onPageSucceed(int index, Image image);
void onPageFailed(int index, String error);
void onDataChanged(int index);
}
@@ -51,7 +51,6 @@ public class ZipGalleryProvider extends GalleryProvider implements Runnable {
private Thread mBgThread;
private volatile int mSize = STATE_WAIT;
private String mError;
private boolean mStarted = false;
public ZipGalleryProvider(File file) {
mFile = file;
@@ -59,26 +58,21 @@ public class ZipGalleryProvider extends GalleryProvider implements Runnable {
@Override
public void start() {
if (mStarted) {
throw new IllegalStateException("Can't start it twice");
}
mStarted = true;
super.start();
if (mBgThread == null || mBgThread.isInterrupted()) {
mBgThread = new PriorityThread(this, TAG + '-' + sIdGenerator.incrementAndGet(),
Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start();
}
mBgThread = new PriorityThread(this, TAG + '-' + sIdGenerator.incrementAndGet(),
Process.THREAD_PRIORITY_BACKGROUND);
mBgThread.start();
}
@Override
public void stop() {
if (mBgThread == null || mBgThread.isInterrupted()) {
return;
}
super.stop();
mBgThread.interrupt();
mBgThread = null;
if (mBgThread != null) {
mBgThread.interrupt();
mBgThread = null;
}
}
@Override
@@ -87,15 +81,10 @@ public class ZipGalleryProvider extends GalleryProvider implements Runnable {
}
@Override
public int request(int index) {
if (index < 0 || index >= mSize) {
return RESULT_ERROR;
} else {
synchronized (mRequests) {
mRequests.add(index);
mRequests.notify();
}
return RESULT_WAIT;
public void request(int index) {
synchronized (mRequests) {
mRequests.add(index);
mRequests.notify();
}
}
@@ -123,7 +112,6 @@ public class ZipGalleryProvider extends GalleryProvider implements Runnable {
if (mError == null) {
mError = GetText.getString(R.string.error_unknown);
}
mBgThread = null;
// Notify to to show error
notifyDataChanged();
@@ -163,6 +151,12 @@ public class ZipGalleryProvider extends GalleryProvider implements Runnable {
index = mRequests.pop();
}
// Check index valid
if (index < 0 || index >= filenames.size()) {
notifyPageFailed(index, GetText.getString(R.string.error_out_of_range));
continue;
}
try {
ZipEntry zipEntry = zipFile.getEntry(filenames.get(index));
if (zipEntry != null) {
@@ -187,7 +181,6 @@ public class ZipGalleryProvider extends GalleryProvider implements Runnable {
} catch (IOException e) {
// Ignore
}
mBgThread = null;
Log.i(TAG, "ImageDecoder end");
}
@@ -35,6 +35,7 @@ import com.hippo.yorozuya.MathUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
// TODO Not safe ! Ensure change component in render thread
public class PagerLayoutManager extends GalleryView.LayoutManager {
@IntDef({MODE_LEFT_TO_RIGHT, MODE_RIGHT_TO_LEFT})
@@ -30,6 +30,7 @@ import com.hippo.yorozuya.AssertUtils;
import java.util.Iterator;
import java.util.LinkedList;
// TODO Not safe ! Ensure change component in render thread
public class ScrollLayoutManager extends GalleryView.LayoutManager {
private static final String TAG = ScrollLayoutManager.class.getSimpleName();
@@ -0,0 +1,296 @@
/*
* 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.spider;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.support.annotation.Nullable;
import android.webkit.MimeTypeMap;
import com.hippo.beerbelly.SimpleDiskCache;
import com.hippo.ehviewer.Settings;
import com.hippo.ehviewer.client.EhCacheKeyFactory;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.gallery.GalleryProvider;
import com.hippo.io.UniFileInputStreamPipe;
import com.hippo.io.UniFileOutputStreamPipe;
import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.FileUtils;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.Utilities;
import com.hippo.yorozuya.io.InputStreamPipe;
import com.hippo.yorozuya.io.OutputStreamPipe;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Locale;
public final class SpiderDen {
private UniFile mDownloadDir;
private volatile int mMode = SpiderQueen.MODE_READ;
private final int mGid;
@Nullable
private static SimpleDiskCache sCache;
public static void initialize(Context context) {
try {
sCache = new SimpleDiskCache(new File(context.getCacheDir(), "image"), 160 * 1024 * 1024);
} catch (IOException e) {
e.printStackTrace();
}
}
public SpiderDen(GalleryInfo galleryInfo) {
mGid = galleryInfo.gid;
UniFile dir = Settings.getDownloadLocation();
if (dir != null) {
mDownloadDir = dir.subFile(FileUtils.sanitizeFilename(galleryInfo.gid + "-" + galleryInfo.title));
}
}
public void setMode(@SpiderQueen.Mode int mode) {
mMode = mode;
if (mode == SpiderQueen.MODE_DOWNLOAD) {
ensureDownloadDir();
}
}
private boolean ensureDownloadDir() {
return mDownloadDir != null && mDownloadDir.ensureDir();
}
public UniFile getDownloadDir() {
return mDownloadDir != null && mDownloadDir.isDirectory() ? mDownloadDir : null;
}
private boolean containInCache(int index) {
if (sCache == null) {
return false;
}
String key = EhCacheKeyFactory.getImageKey(mGid, index);
return sCache.contain(key);
}
/**
* @param extension with dot
*/
public static String generateImageFilename(int index, String extension) {
return String.format(Locale.US, "%08d%s", index + 1, extension);
}
private static UniFile findImageFile(UniFile dir, int index) {
for (String extension : GalleryProvider.SUPPORT_IMAGE_EXTENSIONS) {
String filename = generateImageFilename(index, extension);
UniFile file = dir.findFile(filename);
if (file != null) {
return file;
}
}
return null;
}
private boolean containInDownloadDir(int index) {
UniFile dir = getDownloadDir();
if (dir == null) {
return false;
}
// Find image file in download dir
return findImageFile(dir, index) != null;
}
/**
* @param extension with dot
*/
private String fixExtension(String extension) {
if (Utilities.contain(GalleryProvider.SUPPORT_IMAGE_EXTENSIONS, extension)) {
return extension;
} else {
return GalleryProvider.SUPPORT_IMAGE_EXTENSIONS[0];
}
}
private boolean copyFromCacheToDownloadDir(int index) {
if (sCache == null) {
return false;
}
UniFile dir = getDownloadDir();
if (dir == null) {
return false;
}
// Find image file in cache
String key = EhCacheKeyFactory.getImageKey(mGid, index);
InputStreamPipe pipe = sCache.getInputStreamPipe(key);
if (pipe == null) {
return false;
}
OutputStream os = null;
try {
// Get extension
String extension;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
pipe.obtain();
BitmapFactory.decodeStream(pipe.open(), null, options);
pipe.close();
extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(options.outMimeType);
if (extension != null) {
extension = '.' + extension;
} else {
return false;
}
// Fix extension
extension = fixExtension(extension);
// Copy from cache to download dir
UniFile file = dir.createFile(generateImageFilename(index, extension));
if (file == null) {
return false;
}
os = file.openOutputStream();
IOUtils.copy(pipe.open(), os);
return true;
} catch (IOException e) {
return false;
} finally {
IOUtils.closeQuietly(os);
pipe.close();
pipe.release();
}
}
public boolean contain(int index) {
if (mMode == SpiderQueen.MODE_READ) {
return containInCache(index) || containInDownloadDir(index);
} else if (mMode == SpiderQueen.MODE_DOWNLOAD) {
return containInDownloadDir(index) || copyFromCacheToDownloadDir(index);
} else {
return false;
}
}
private void removeFromCache(int index) {
if (sCache == null) {
return;
}
String key = EhCacheKeyFactory.getImageKey(mGid, index);
sCache.remove(key);
}
private void removeFromDownloadDir(int index) {
UniFile dir = getDownloadDir();
if (dir == null) {
return;
}
for (int i = 0, n = GalleryProvider.SUPPORT_IMAGE_EXTENSIONS.length; i < n; i++) {
String filename = generateImageFilename(index, GalleryProvider.SUPPORT_IMAGE_EXTENSIONS[i]);
UniFile file = dir.subFile(filename);
if (file != null) {
file.delete();
}
}
}
public void remove(int index) {
removeFromCache(index);
removeFromDownloadDir(index);
}
private OutputStreamPipe openCacheOutputStreamPipe(int index) {
if (sCache == null) {
return null;
}
String key = EhCacheKeyFactory.getImageKey(mGid, index);
return sCache.getOutputStreamPipe(key);
}
/**
* @param extension without dot
*/
private OutputStreamPipe openDownloadOutputStreamPipe(int index, @Nullable String extension) {
UniFile dir = getDownloadDir();
if (dir == null) {
return null;
}
extension = fixExtension('.' + extension);
UniFile file = dir.createFile(generateImageFilename(index, extension));
if (file != null) {
return new UniFileOutputStreamPipe(file);
} else {
return null;
}
}
@Nullable
public OutputStreamPipe openOutputStreamPipe(int index, @Nullable String extension) {
if (mMode == SpiderQueen.MODE_READ) {
return openCacheOutputStreamPipe(index);
} else if (mMode == SpiderQueen.MODE_DOWNLOAD) {
return openDownloadOutputStreamPipe(index, extension);
} else {
return null;
}
}
private InputStreamPipe openCacheInputStreamPipe(int index) {
if (sCache == null) {
return null;
}
String key = EhCacheKeyFactory.getImageKey(mGid, index);
return sCache.getInputStreamPipe(key);
}
public InputStreamPipe openDownloadInputStreamPipe(int index) {
UniFile dir = getDownloadDir();
if (dir == null) {
return null;
}
UniFile file = findImageFile(dir, index);
if (file != null) {
return new UniFileInputStreamPipe(file);
} else {
return null;
}
}
@Nullable
public InputStreamPipe openInputStreamPipe(int index) {
if (mMode == SpiderQueen.MODE_READ) {
InputStreamPipe pipe = openCacheInputStreamPipe(index);
if (pipe == null) {
pipe = openDownloadInputStreamPipe(index);
}
return pipe;
} else if (mMode == SpiderQueen.MODE_DOWNLOAD) {
return openDownloadInputStreamPipe(index);
} else {
return null;
}
}
}
@@ -0,0 +1,138 @@
/*
* 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.spider;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.SparseArray;
import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class SpiderInfo {
private static final String TAG = SpiderInfo.class.getSimpleName();
static final String TOKEN_FAILED = "failed";
static final String TOKEN_WAIT = "wait";
int currentIndex = 0;
int gid = -1;
String token = null;
int pages = -1;
int previewPages = -1;
int previewPerPage = -1;
SparseArray<String> pTokenMap = null;
@SuppressWarnings("InfiniteLoopStatement")
public static SpiderInfo readFromUniFile(@Nullable UniFile file) {
if (file == null) {
return null;
}
InputStream is = null;
SpiderInfo spiderInfo = null;
try {
is = file.openInputStream();
spiderInfo = new SpiderInfo();
// Current index
spiderInfo.currentIndex = Integer.parseInt(IOUtils.readAsciiLine(is), 16);
// Gid
spiderInfo.gid = Integer.parseInt(IOUtils.readAsciiLine(is));
// Token
spiderInfo.token = IOUtils.readAsciiLine(is);
// Deprecated, mode, only ex is support now, MUST be 1
if (1 != Integer.parseInt(IOUtils.readAsciiLine(is))) {
Log.w(TAG, "Not ex mode");
return null;
}
// Preview pages
spiderInfo.previewPages = Integer.parseInt(IOUtils.readAsciiLine(is));
// Preview pre page
spiderInfo.previewPerPage = Integer.parseInt(IOUtils.readAsciiLine(is));
// Pages
spiderInfo.pages = Integer.parseInt(IOUtils.readAsciiLine(is));
// PToken
spiderInfo.pTokenMap = new SparseArray<>(spiderInfo.pages);
while (true) { // EOFException will raise
String line = IOUtils.readAsciiLine(is);
int pos = line.indexOf(" ");
if (pos > 0 || pos < line.length() - 1) {
int index = Integer.parseInt(line.substring(0, pos));
String pToken = line.substring(pos + 1);
spiderInfo.pTokenMap.put(index, pToken);
} else {
Log.e(TAG, "Can't parse index and pToken, index = " + pos);
}
}
} catch (IOException | NumberFormatException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(is);
}
if (spiderInfo == null || spiderInfo.gid == -1 || spiderInfo.token == null ||
spiderInfo.previewPages == -1 || spiderInfo.previewPerPage == -1 ||
spiderInfo.pages == -1 || spiderInfo.pTokenMap == null) {
return null;
} else {
return spiderInfo;
}
}
public void write(@NonNull OutputStream os) {
OutputStreamWriter writer = null;
try {
writer = new OutputStreamWriter(os);
writer.write(String.format("%08x", currentIndex));
writer.write("\n");
writer.write(Integer.toString(gid));
writer.write("\n");
writer.write(token);
writer.write("\n");
writer.write('1');
writer.write("\n");
writer.write(Integer.toString(previewPages));
writer.write("\n");
writer.write(Integer.toString(previewPerPage));
writer.write("\n");
writer.write(Integer.toString(pages));
writer.write("\n");
for (int i = 0; i < pTokenMap.size(); i++) {
if (TOKEN_FAILED.equals(pTokenMap.valueAt(i))) {
continue;
}
writer.write(Integer.toString(pTokenMap.keyAt(i)));
writer.write(" ");
writer.write(pTokenMap.valueAt(i));
writer.write("\n");
}
writer.flush();
} catch (IOException e) {
// Ignore
} finally {
IOUtils.closeQuietly(writer);
IOUtils.closeQuietly(os);
}
}
}
File diff suppressed because it is too large. Load diff
@@ -26,7 +26,9 @@ import android.util.SparseIntArray;
import android.view.KeyEvent;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.gallery.DirGalleryProvider;
import com.hippo.ehviewer.gallery.EhGalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProvider;
import com.hippo.ehviewer.gallery.GalleryProviderListener;
import com.hippo.ehviewer.gallery.ZipGalleryProvider;
@@ -49,13 +51,11 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
public static final String KEY_ACTION = "action";
public static final String KEY_FILENAME = "filename";
public static final String KEY_GID = "gid";
public static final String KEY_TOKEN = "token";
public static final String KEY_GALLERY_INFO = "gallery_info";
private String mAction;
private String mFilename;
private int mGid;
private String mToken;
private GalleryInfo mGalleryInfo;
@Nullable
private GalleryView mGalleryView;
@@ -83,7 +83,9 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
mGalleryProvider = new ZipGalleryProvider(new File(mFilename));
}
} else if (ACTION_EH.equals(mAction)) {
if (mGalleryInfo != null) {
mGalleryProvider = new EhGalleryProvider(this, mGalleryInfo);
}
}
}
@@ -95,16 +97,14 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
mAction = intent.getAction();
mFilename = intent.getStringExtra(KEY_FILENAME);
mGid = intent.getIntExtra(KEY_GID, -1);
mToken = intent.getStringExtra(KEY_TOKEN);
mGalleryInfo = intent.getParcelableExtra(KEY_GALLERY_INFO);
buildProvider();
}
private void onRestore(@NonNull Bundle savedInstanceState) {
mAction = savedInstanceState.getString(KEY_ACTION);
mFilename = savedInstanceState.getString(KEY_FILENAME);
mGid = savedInstanceState.getInt(KEY_GID, -1);
mToken = savedInstanceState.getString(KEY_TOKEN);
mGalleryInfo = savedInstanceState.getParcelable(KEY_GALLERY_INFO);
buildProvider();
}
@@ -113,8 +113,9 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
super.onSaveInstanceState(outState);
outState.putString(KEY_ACTION, mAction);
outState.putString(KEY_FILENAME, mFilename);
outState.putInt(KEY_GID, mGid);
outState.putString(KEY_TOKEN, mToken);
if (mGalleryInfo != null) {
outState.putParcelable(KEY_GALLERY_INFO, mGalleryInfo);
}
}
@Override
@@ -131,7 +132,7 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
finish();
return;
}
mGalleryProvider.addGalleryProviderListener(this);
mGalleryProvider.setGalleryProviderListener(this);
mGalleryProvider.start();
setContentView(R.layout.activity_gallery);
@@ -161,7 +162,7 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
mPageTextTexture = null;
}
if (mGalleryProvider != null) {
mGalleryProvider.removeGalleryProviderListener(this);
mGalleryProvider.setGalleryProviderListener(null);
mGalleryProvider.stop();
mGalleryProvider = null;
}
@@ -299,6 +300,14 @@ public class GalleryActivity extends AppCompatActivity implements GalleryProvide
}
}
@Override
public void onDataChanged(int index) {
GalleryPageView page = findPageByIndex(index);
if (page != null && mGalleryProvider != null) {
mGalleryProvider.request(index);
}
}
private class GalleryPageIterator extends GalleryView.PageIterator {
private IntIdGenerator mIdGenerator = new IntIdGenerator();
@@ -871,8 +871,18 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
} else if (mDownload == v) {
// TODO
} else if (mRead == v) {
Intent intent = new Intent(getActivity(), GalleryActivity.class);
startActivity(intent);
GalleryInfo galleryInfo = null;
if (mGalleryInfo != null) {
galleryInfo = mGalleryInfo;
} else if (mGalleryDetail != null) {
galleryInfo = mGalleryDetail;
}
if (galleryInfo != null) {
Intent intent = new Intent(getActivity(), GalleryActivity.class);
intent.setAction(GalleryActivity.ACTION_EH);
intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, galleryInfo);
startActivity(intent);
}
} else if (mInfo == v) {
Bundle args = new Bundle();
args.putParcelable(GalleryInfoScene.KEY_GALLERY_DETAIL, mGalleryDetail);
@@ -929,11 +939,12 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
@Override
public void onBackPressed() {
if (mViewTransition.getShownViewIndex() == 0 && ApiHelper.SUPPORT_TRANSITION) {
if (mViewTransition.getShownViewIndex() == 0 && ApiHelper.SUPPORT_TRANSITION && mThumb.isShown()) {
int[] location = new int[2];
mThumb.getLocationInWindow(location);
// Only show transaction when thumb can be seen
if (location[1] + mThumb.getHeight() > 0) {
setTransitionName();
finish(new EnterGalleryListTransaction(mThumb, mTitle, mUploader, mCategory));
return;
}
@@ -0,0 +1,64 @@
/*
* Copyright 2015 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.io;
import android.support.annotation.NonNull;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.io.InputStreamPipe;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileInputStreamPipe implements InputStreamPipe {
private File mFile;
private InputStream mIs;
public FileInputStreamPipe(File file) {
mFile = file;
}
@Override
public void obtain() {
// Empty
}
@Override
public void release() {
// Empty
}
@NonNull
@Override
public InputStream open() throws IOException {
if (mIs != null) {
throw new IllegalStateException("Please close it first");
}
mIs = new FileInputStream(mFile);
return mIs;
}
@Override
public void close() {
IOUtils.closeQuietly(mIs);
mIs = null;
}
}
@@ -0,0 +1,64 @@
/*
* Copyright 2015 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.io;
import android.support.annotation.NonNull;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.io.OutputStreamPipe;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileOutputStreamPipe implements OutputStreamPipe {
private File mFile;
private OutputStream mOs;
public FileOutputStreamPipe(File file) {
mFile = file;
}
@Override
public void obtain() {
// Empty
}
@Override
public void release() {
// Empty
}
@NonNull
@Override
public OutputStream open() throws IOException {
if (mOs != null) {
throw new IllegalStateException("Please close it first");
}
mOs = new FileOutputStream(mFile);
return mOs;
}
@Override
public void close() {
IOUtils.closeQuietly(mOs);
mOs = null;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2015 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.io;
import android.support.annotation.NonNull;
import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.io.InputStreamPipe;
import java.io.IOException;
import java.io.InputStream;
public class UniFileInputStreamPipe implements InputStreamPipe {
private UniFile mFile;
private InputStream mIs;
public UniFileInputStreamPipe(UniFile file) {
mFile = file;
}
@Override
public void obtain() {
// Empty
}
@Override
public void release() {
// Empty
}
@NonNull
@Override
public InputStream open() throws IOException {
if (mIs != null) {
throw new IllegalStateException("Please close it first");
}
mIs = mFile.openInputStream();
return mIs;
}
@Override
public void close() {
IOUtils.closeQuietly(mIs);
mIs = null;
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2015 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.io;
import android.support.annotation.NonNull;
import com.hippo.unifile.UniFile;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.io.OutputStreamPipe;
import java.io.IOException;
import java.io.OutputStream;
public class UniFileOutputStreamPipe implements OutputStreamPipe {
private UniFile mUniFile;
private OutputStream mOs;
public UniFileOutputStreamPipe(UniFile uniFile) {
mUniFile = uniFile;
}
@Override
public void obtain() {
// Empty
}
@Override
public void release() {
// Empty
}
@Override
public @NonNull OutputStream open() throws IOException {
if (mOs != null) {
throw new IllegalStateException("Please close it first");
}
mOs = mUniFile.openOutputStream();
return mOs;
}
@Override
public void close() {
IOUtils.closeQuietly(mOs);
mOs = null;
}
}
@@ -26,16 +26,8 @@ public class ChromeRequestBuilder extends Request.Builder {
private static final String CHROME_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36";
public ChromeRequestBuilder(String url) {
URL u;
try {
u = new URL(url);
} catch (MalformedURLException e) {
throw new IllegalStateException(e);
}
url(u);
public ChromeRequestBuilder(String url) throws MalformedURLException {
url(new URL(url));
addHeader("User-Agent", CHROME_USER_AGENT);
}
}