Make EhClient request cancellable

This commit is contained in:
seven332 committed 2015-07-11 20:08:49 +08:00
1 parent 30ff85e25b
commit 8d5c8c4236
43 files changed
+1841 -1251

No files matched your search

@@ -1,11 +1,11 @@
/*
* Copyright (C) 2015 Hippo Seven
* 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
* 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,
@@ -18,13 +18,13 @@ package com.hippo.ehviewer;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Build;
import android.webkit.CookieSyncManager;
import com.hippo.beerbelly.SimpleDiskCache;
import com.hippo.conaco.Conaco;
import com.hippo.ehviewer.network.EhOkHttpClient;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.network.EhHttpClient;
import com.hippo.ehviewer.util.Settings;
import com.hippo.httpclient.HttpClient;
import com.hippo.scene.SceneApplication;
import com.hippo.util.Log;
import com.hippo.vectorold.content.VectorContext;
@@ -34,6 +34,8 @@ import java.io.IOException;
public class EhApplication extends SceneApplication {
private HttpClient mHttpClient;
private EhClient mEhClient;
private Conaco mConaco;
private SimpleDiskCache mReadcache;
@@ -41,11 +43,10 @@ public class EhApplication extends SceneApplication {
public void onCreate() {
super.onCreate();
Config.initialize(this);
Settings.initialize(this);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(this);
}
mHttpClient = new EhHttpClient(this);
mEhClient = new EhClient(mHttpClient);
Conaco.Builder conacoBuilder = new Conaco.Builder();
conacoBuilder.hasMemoryCache = true;
@@ -53,7 +54,7 @@ public class EhApplication extends SceneApplication {
conacoBuilder.hasDiskCache = true;
conacoBuilder.diskCacheDir = new File(getCacheDir(), "conaco");
conacoBuilder.diskCacheMaxSize = 50 * 1024 * 1024;
conacoBuilder.httpClient = EhOkHttpClient.getInstance();
conacoBuilder.httpClient = mHttpClient;
mConaco = conacoBuilder.build();
try {
@@ -84,6 +85,16 @@ public class EhApplication extends SceneApplication {
}
}
public static HttpClient getHttpClient(Context context) {
EhApplication application = (EhApplication) context.getApplicationContext();
return application.mHttpClient;
}
public static EhClient getEhClient(Context context) {
EhApplication application = (EhApplication) context.getApplicationContext();
return application.mEhClient;
}
public static Conaco getConaco(Context context) {
EhApplication application = (EhApplication) context.getApplicationContext();
return application.mConaco;
@@ -16,7 +16,9 @@
package com.hippo.ehviewer.client;
public interface Cancellable {
public class CanceledException extends EhException {
void cancel();
public CanceledException() {
super("CANCELED");
}
}
@@ -19,510 +19,240 @@ package com.hippo.ehviewer.client;
import android.os.AsyncTask;
import android.os.Process;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.ehviewer.network.EhOkHttpClient;
import com.hippo.network.ResponseCodeException;
import com.hippo.ehviewer.network.EhHttpRequest;
import com.hippo.httpclient.HttpClient;
import com.hippo.util.PriorityThreadFactory;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import org.json.JSONObject;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
// TODO Make request cancle
public final class EhClient {
private static final String TAG = EhClient.class.getSimpleName();
public static final String TAG = EhClient.class.getSimpleName();
public static final MediaType JSON = MediaType.parse("application/json");
/**
* Sign in
*
* <table>
* <tr>
* <th>param</th>
* <th>info</th>
* </tr>
* <tr>
* <td>username</td>
* <td>the username</td>
* </tr>
* <tr>
* <td>password</td>
* <td>the password</td>
* </tr>
* <tr>
* <td>listener</td>
* <td>the listener for callback</td>
* </tr>
* </table>
*/
public static final int METHOD_SIGN_IN = 0;
public static final int SOURCE_G = 0x0;
public static final int SOURCE_EX = 0x1;
public static final int SOURCE_LOFI = 0x2;
/**
* Get gallery list
*
* <table>
* <tr>
* <th>param</th>
* <th>info</th>
* </tr>
* <tr>
* <td>url</td>
* <td>the url to get gallery list</td>
* </tr>
* <tr>
* <td>source</td>
* <td>the source, one of {@link EhUrl#SOURCE_G},
* {@link EhUrl#SOURCE_EX} and {@link EhUrl#SOURCE_LOFI}</td>
* </tr>
* <tr>
* <td>listener</td>
* <td>the listener for callback</td>
* </tr>
* </table>
*/
public static final int METHOD_GET_GALLERY_LIST = 1;
public static final String API_G = "http://g.e-hentai.org/api.php";
public static final String API_EX = "http://exhentai.org/api.php";
public static final long APIUID = 1363542;
public static final String APIKEY = "f4b5407ab1727b9d08d7";
/**
* Get popular
*
* <table>
* <tr>
* <th>param</th>
* <th>info</th>
* </tr>
* <tr>
* <td>listener</td>
* <td>the listener for callback</td>
* </tr>
* </table>
*/
public static final int METHOD_GET_POPULAR = 2;
private static final String SIGN_IN_URL =
"http://forums.e-hentai.org/index.php?act=Login&CODE=01";
private static final String FORUMS_URL = "http://forums.e-hentai.org/index.php";
/**
* Get gallery detail
*
* <table>
* <tr>
* <th>param</th>
* <th>info</th>
* </tr>
* <tr>
* <td>url</td>
* <td>the url to get gallery detail</td>
* </tr>
* <tr>
* <td>source</td>
* <td>the source, one of {@link EhUrl#SOURCE_G},
* {@link EhUrl#SOURCE_EX} and {@link EhUrl#SOURCE_LOFI}</td>
* </tr>
* <tr>
* <td>listener</td>
* <td>the listener for callback</td>
* </tr>
* </table>
*/
public static final int METHOD_GET_GALLERY_DETAIL = 3;
public static final String HOST_G = "G.E-Hentai";
public static final String HOST_EX = "ExHentai";
public static final String HOST_LOFI = "Lofi.E-Hentai";
public static final String HEADER_G = "http://g.e-hentai.org/";
public static final String HEADER_EX = "http://exhentai.org/";
public static final String HEADER_LOFI = "http://lofi.e-hentai.org/";
public static final String API_EHVIEWER = "http://www.ehviewer.com/API";
private static final String SAD_PANDA_DISPOSITION = "inline; filename=\"sadpanda.jpg\"";
private static final String SAD_PANDA_TYPE = "image/gif";
private static final String SAD_PANDA_LENGTH = "9615";
/**
* Get gallery preview set
*
* <table>
* <tr>
* <th>param</th>
* <th>info</th>
* </tr>
* <tr>
* <td>url</td>
* <td>the url to get gallery preview set</td>
* </tr>
* <tr>
* <td>source</td>
* <td>the source, one of {@link EhUrl#SOURCE_G},
* {@link EhUrl#SOURCE_EX} and {@link EhUrl#SOURCE_LOFI}</td>
* </tr>
* <tr>
* <td>listener</td>
* <td>the listener for callback</td>
* </tr>
* </table>
*/
public static final int METHOD_GET_PREVIEW_SET = 4;
private final ThreadPoolExecutor mRequestThreadPool;
private final EhOkHttpClient mHttpClient;
private final HttpClient mHttpClient;
private static final EhClient sInstance;
static {
sInstance = new EhClient();
}
public static EhClient getInstance() {
return sInstance;
}
private EhClient() {
public EhClient(HttpClient httpClient) {
int poolSize = 3;
BlockingQueue<Runnable> requestWorkQueue = new LinkedBlockingQueue<>();
ThreadFactory threadFactory = new PriorityThreadFactory(TAG,
Process.THREAD_PRIORITY_BACKGROUND);
mRequestThreadPool = new ThreadPoolExecutor(poolSize, poolSize,
1L, TimeUnit.SECONDS, requestWorkQueue, threadFactory);
mHttpClient = EhOkHttpClient.getInstance();
mHttpClient = httpClient;
}
public static String getReadableHost(int source) {
switch (source) {
default:
case SOURCE_G:
return HOST_G;
case SOURCE_EX:
return HOST_EX;
case SOURCE_LOFI:
return HOST_LOFI;
public void execute(EhRequest request) {
if (!request.isCanceled()) {
Task task = new Task(request.method, request.ehListener, request.ehConfig);
task.executeOnExecutor(mRequestThreadPool, request.args);
request.task = task;
} else {
request.ehListener.onCanceled();
}
}
public static String getUrlHeader(int source) {
switch (source) {
default:
case SOURCE_G:
return HEADER_G;
case SOURCE_EX:
return HEADER_EX;
case SOURCE_LOFI:
return HEADER_LOFI;
}
public static abstract class EhListener<E> {
public abstract void onSuccess(E result);
public abstract void onFailure(Exception e);
public abstract void onCanceled();
}
/**
* Get gellary detail url in target source
*/
public static String getDetailUrl(int source, int gid, String token, int pageIndex) {
StringBuilder sb = new StringBuilder(getUrlHeader(source));
sb.append("g/").append(gid).append('/').append(token).append('/');
if (pageIndex > 0) {
sb.append("?p=").append(pageIndex);
}
class Task extends AsyncTask<Object, Void, Object> {
return sb.toString();
}
private int mMethod;
private EhListener mListener;
private EhHttpRequest mEhHttpRequest;
public interface SimpleListener {
void onFailure(Exception e);
}
private boolean mStop;
private void doBgJob(BgJobHelper bjh) {
new AsyncTask<BgJobHelper, Void, BgJobHelper>() {
@Override
protected BgJobHelper doInBackground(BgJobHelper... params) {
BgJobHelper bjh = params[0];
bjh.doInBackground();
return bjh;
}
@Override
protected void onPostExecute(BgJobHelper bjh) {
bjh.onPostExecute();
}
}.executeOnExecutor(mRequestThreadPool, bjh);
}
private interface BgJobHelper {
void doInBackground();
void onPostExecute();
}
private abstract class SimpleBgJobHelper implements BgJobHelper {
private SimpleListener mListener;
private Exception mException;
public SimpleBgJobHelper(SimpleListener listener) {
public Task(int method, EhListener listener, EhConfig ehConfig) {
mMethod = method;
mListener = listener;
mEhHttpRequest = new EhHttpRequest();
mEhHttpRequest.setEhConfig(ehConfig);
}
@Override
public void doInBackground() {
try {
doBgJob();
} catch (Exception e) {
mException = e;
}
}
public void stop() {
if (!mStop) {
mStop = true;
@Override
public void onPostExecute() {
if (mListener != null) {
if (mException == null) {
doSuccessCallback();
} else {
mListener.onFailure(mException);
Status status = getStatus();
if (status == Status.PENDING) {
cancel(false);
// If it is pending, onPostExecute will not be called,
// need to call mListener.onCanceled here
mListener.onCanceled();
// Clear
mEhHttpRequest = null;
mListener = null;
} else if (status == Status.FINISHED) {
mEhHttpRequest.cancel();
}
}
}
public abstract void doBgJob() throws Exception;
public abstract void doSuccessCallback();
}
private void checkResponse(Response response) throws Exception {
final int responseCode = response.code();
if (responseCode >= 400) {
throw new ResponseCodeException(responseCode);
}
String disposition = response.header("Content-Disposition", null);
String type = response.header("Content-Type", null);
String length = response.header("Content-Length", null);
if (SAD_PANDA_DISPOSITION.equals(disposition) && SAD_PANDA_TYPE.equals(type) &&
SAD_PANDA_LENGTH.equals(length)) {
throw new EhException("Sad Panda");
}
}
private Object[] doGetGalleryList(int source, String url) throws Exception {
Request request = new Request.Builder()
.url(url)
.build();
Response response = mHttpClient.newCall(request).execute();
checkResponse(response);
GalleryListParser parser = new GalleryListParser();
parser.parse(response.body().string(), source);
return new Object[]{parser.giList, parser.pageNum};
}
public abstract static class OnGetGalleryListListener implements SimpleListener {
public abstract void onSuccess(List<GalleryInfo> glList, int pageNum);
}
private final class GetGalleryListHelper extends SimpleBgJobHelper {
private int mSource;
private String mUrl;
private OnGetGalleryListListener mListener;
private List<GalleryInfo> mGlList;
private int mPageNum;
public GetGalleryListHelper(int source, String url, OnGetGalleryListListener listener) {
super(listener);
mSource = source;
mUrl = url;
mListener = listener;
}
@Override
public void doBgJob() throws Exception {
Object[] objs = doGetGalleryList(mSource, mUrl);
mGlList = (List<GalleryInfo>) objs[0];
mPageNum = (int) objs[1];
protected Object doInBackground(Object... params) {
try {
switch (mMethod) {
case METHOD_SIGN_IN:
return EhEngine.signIn(mHttpClient, mEhHttpRequest, (String) params[0], (String) params[1]);
case METHOD_GET_GALLERY_LIST:
return EhEngine.getGalleryList(mHttpClient, mEhHttpRequest, (String) params[0], (Integer) params[1]);
case METHOD_GET_POPULAR:
return EhEngine.getPopular(mHttpClient, mEhHttpRequest);
case METHOD_GET_GALLERY_DETAIL:
return EhEngine.getGalleryDetail(mHttpClient, mEhHttpRequest, (String) params[0], (Integer) params[1]);
case METHOD_GET_PREVIEW_SET:
return EhEngine.getPreviewSet(mHttpClient, mEhHttpRequest, (String) params[0], (Integer) params[1]);
default:
return new IllegalStateException("Can't detect method");
}
} catch (Exception e) {
return e;
}
}
@SuppressWarnings("unchecked")
@Override
public void doSuccessCallback() {
mListener.onSuccess(mGlList, mPageNum);
protected void onPostExecute(Object result) {
if (result instanceof CanceledException) {
mListener.onCanceled();
} else if (result instanceof Exception) {
mListener.onFailure((Exception) result);
} else {
mListener.onSuccess(result);
}
// Clear
mEhHttpRequest = null;
mListener = null;
}
}
/**
* Get gallery list
*
* @param source the source, one of {@link #SOURCE_G}, {@link #SOURCE_EX} and
* {@link #SOURCE_LOFI}
* @param url the url to get gallery list
* @param listener the listener for callback
*/
public void getGalleryList(int source, String url, OnGetGalleryListListener listener) {
doBgJob(new GetGalleryListHelper(source, url, listener));
}
private Object[] doGetPopular() throws Exception {
final JSONObject json = new JSONObject();
json.put("method", "popular");
RequestBody body = RequestBody.create(JSON, json.toString());
Request request = new Request.Builder()
.url(API_EHVIEWER)
.post(body)
.build();
Response response = mHttpClient.newCall(request).execute();
checkResponse(response);
PopularParser parser = new PopularParser();
parser.parse(response.body().string());
return new Object[]{parser.galleryInfoList, parser.timeStamp};
}
public abstract static class OnGetPopularListener implements SimpleListener {
public abstract void onSuccess(List<GalleryInfo> giList, long timeStamp);
}
private final class GetPopularHelper extends SimpleBgJobHelper {
private OnGetPopularListener mListener;
private List<GalleryInfo> mGiList;
private long mTimeStamp;
public GetPopularHelper(OnGetPopularListener listener) {
super(listener);
mListener = listener;
}
@Override
public void doBgJob() throws Exception {
Object[] objs = doGetPopular();
mGiList = (List<GalleryInfo>) objs[0];
mTimeStamp = (Long) objs[1];
}
@Override
public void doSuccessCallback() {
mListener.onSuccess(mGiList, mTimeStamp);
}
}
/**
* Get popular gallery list
*
* @param listener the listener for callback
*/
public void getPopular(OnGetPopularListener listener) {
doBgJob(new GetPopularHelper(listener));
}
private String doSignIn(String username, String password) throws Exception {
RequestBody formBody = new FormEncodingBuilder()
.add("UserName", username)
.add("PassWord", password)
.add("submit", "Log me in")
.add("CookieDate", "1")
.add("temporary_https", "off")
.build();
Request request = new Request.Builder()
.url(SIGN_IN_URL)
.post(formBody)
.build();
Response response = mHttpClient.newCall(request).execute();
checkResponse(response);
SignInParser parser = new SignInParser();
parser.parse(response.body().string());
return parser.displayname;
}
public abstract static class OnSignInListener implements SimpleListener {
public abstract void onSuccess(String displayname);
}
private final class SignInHelper extends SimpleBgJobHelper {
private String mUsername;
private String mPassword;
private OnSignInListener mListener;
private String mDisplayname;
public SignInHelper(String username, String password, OnSignInListener listener) {
super(listener);
mUsername = username;
mPassword = password;
mListener = listener;
}
@Override
public void doBgJob() throws Exception {
mDisplayname = doSignIn(mUsername, mPassword);
}
@Override
public void doSuccessCallback() {
mListener.onSuccess(mDisplayname);
}
}
/**
* Sign in
*/
public void signIn(String username, String password, OnSignInListener listener) {
doBgJob(new SignInHelper(username, password, listener));
}
private GalleryDetail doGetGalleryDetail(int source, String url) throws Exception {
Request request = new Request.Builder()
.url(url)
.build();
Response response = mHttpClient.newCall(request).execute();
checkResponse(response);
GalleryDetailParser parser = new GalleryDetailParser();
parser.parse(response.body().string(), GalleryDetailParser.REQUEST_DETAIL |
GalleryDetailParser.REQUEST_TAG |
GalleryDetailParser.REQUEST_PREVIEW_INFO |
GalleryDetailParser.REQUEST_PREVIEW |
GalleryDetailParser.REQUEST_COMMENT,
source);
GalleryDetail gd = new GalleryDetail();
gd.gid = parser.gid;
gd.token = parser.token;
gd.thumb = parser.thumb;
gd.title = parser.title;
gd.titleJpn = parser.titleJpn;
gd.category = parser.category;
gd.uploader = parser.uploader;
gd.torrentCount = parser.torrentCount;
gd.torrentUrl = parser.torrentUrl;
gd.posted = parser.posted;
gd.parent = parser.parent;
gd.visible = parser.visible;
gd.language = parser.language;
gd.size = parser.size;
gd.resize = parser.resize;
gd.pageCount = parser.pageCount;
gd.favoredTimes = parser.favoredTimes;
gd.isFavored = parser.isFavored;
gd.rating = parser.rating;
gd.ratedTimes = parser.ratedTimes;
gd.tags = parser.tags;
gd.comments = parser.comments;
gd.previewPageCount = parser.previewPageCount;
gd.previewSetArray = new PreviewSet[gd.previewPageCount];
gd.previewSetArray[0] = parser.previewSet;
gd.previewSetArray[0].setStartIndex(0);
gd.previewSetArray[0].setGid(gd.gid);
return gd;
}
public abstract static class OnGetGalleryDetailListener implements SimpleListener {
public abstract void onSuccess(GalleryDetail galleryDetail);
}
private final class GetGalleryDetailHelper extends SimpleBgJobHelper {
private int mSource;
private String mUrl;
private OnGetGalleryDetailListener mListener;
private GalleryDetail mGalleryDetail;
public GetGalleryDetailHelper(int source, String url, OnGetGalleryDetailListener listener) {
super(listener);
mSource = source;
mUrl = url;
mListener = listener;
}
@Override
public void doBgJob() throws Exception {
mGalleryDetail = doGetGalleryDetail(mSource, mUrl);
}
@Override
public void doSuccessCallback() {
mListener.onSuccess(mGalleryDetail);
}
}
/**
* Get gallery detail
*/
public void getGalleryDetail(int source, String url, OnGetGalleryDetailListener listener) {
doBgJob(new GetGalleryDetailHelper(source, url, listener));
}
public abstract static class OnGetPreviewSetListener implements SimpleListener {
public abstract void onSuccess(PreviewSet previewSet);
}
private PreviewSet doGetPreviewSet(int source, String url) throws Exception {
Request request = new Request.Builder()
.url(url)
.build();
Response response = mHttpClient.newCall(request).execute();
checkResponse(response);
GalleryDetailParser parser = new GalleryDetailParser();
parser.parse(response.body().string(), GalleryDetailParser.REQUEST_PREVIEW,
source);
return parser.previewSet;
}
private final class GetPreviewSetHelper extends SimpleBgJobHelper {
private int mSource;
private String mUrl;
private OnGetPreviewSetListener mListener;
private PreviewSet mPreviewSet;
public GetPreviewSetHelper(int source, String url, OnGetPreviewSetListener listener) {
super(listener);
mSource = source;
mUrl = url;
mListener = listener;
}
@Override
public void doBgJob() throws Exception {
mPreviewSet = doGetPreviewSet(mSource, mUrl);
}
@Override
public void doSuccessCallback() {
mListener.onSuccess(mPreviewSet);
}
}
/**
* Get gallery preview set
*/
public void getPreviewSet(int source, String url, OnGetPreviewSetListener listener) {
doBgJob(new GetPreviewSetHelper(source, url, listener));
}
}
@@ -0,0 +1,655 @@
/*
* 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.ehviewer.client;
import android.text.TextUtils;
import com.hippo.httpclient.Cookie;
/**
* Some configurable stuff about EH. It ends up cookie.
*/
public class EhConfig implements Cloneable {
/**
* The Cookie key of uconfig
*/
public static final String KEY_UCONFIG = "uconfig";
/**
* The key of load images through the Hentai@Home Network
*/
private static final String KEY_LOAD_FROM_HAH = "uh";
/**
* The key of scale images width
*/
private static final String KEY_SCALE_WIDTH = "rx";
/**
* The key of scale images height
*/
private static final String KEY_SCALE_HEIGHT = "ry";
/**
* The key of the behavior for downloading archiver
*/
private static final String KEY_ARCHIVER_DOWNLOAD = "ar";
/**
* The key of display mode would you like to use on the front and search pages
*/
private static final String KEY_LAYOUT_MODE = "dm";
/**
* The key of categories would you like to view as default on the front page
*/
private static final String KEY_DEFAULT_CATEGORIES = "cats";
/**
* The key of exclude certain namespaces from a default tag search
*/
private static final String KEY_EXCLUDED_NAMESPACES = "xns";
/**
* The key of hide galleries in certain languages from the gallery list and searches
*/
private static final String KEY_EXCLUDED_LANGUAGES = "xl";
/**
* The key of how many results would you like per page for the index/search page and torrent search pages
*/
private static final String KEY_RESULT_COUNT = "rc";
/**
* The key of mouse-over thumb
*/
private static final String KEY_MOUSE_OVER = "tl";
/**
* The key of preview size
*/
private static final String KEY_PREVIEW_SIZE = "ts";
/**
* The key of preview row per page
*/
private static final String KEY_PREVIEW_ROW = "tr";
/**
* The key of sort order for gallery comments
*/
private static final String KEY_COMMENTS_SORT = "cs";
/**
* The key of show gallery comment votes
*/
private static final String KEY_COMMENTS_VOTES = "sc";
/**
* The key of sort order for gallery tags
*/
private static final String KEY_TAGS_SORT = "to";
/**
* The key of show gallery page numbers
*/
private static final String KEY_SHOW_GALLERY_INDEX = "pn";
/**
* The key of the IP:Port of a proxy-enabled Hentai@Home Client
* to load all images
*/
private static final String KEY_HAH_CLIENT_IP_PORT = "hp";
/**
* The key of the passkey of a proxy-enabled Hentai@Home Client
* to load all images
*/
private static final String KEY_HAH_CLIENT_PASSKEY = "hk";
/**
* The key of enable Tag Flagging
*/
private static final String KEY_ENABLE_TAG_FLAGGING = "tf";
/**
* The key of always display the original images instead of the resampled versions
*/
private static final String KEY_ALWAYS_ORIGINAL = "oi";
/**
* The key of enable the multi-Page Viewer
*/
private static final String KEY_MULTI_PAGE = "qb";
/**
* The key of multi-Page Viewer Display Style
*/
private static final String KEY_MULTI_PAGE_STYLE = "ms";
/**
* The key of multi-Page Viewer Thumbnail Pane
*/
private static final String KEY_MULTI_PAGE_THUMB = "mt";
/**
* The Cookie key of lofi resolution
*/
public static final String KEY_LOFI_RESOLUTION = "xres";
/**
* The Cookie key of show warning
*/
public static final String KEY_CONTENT_WARNING = "nw";
/**
* load images through the Hentai@Home Network
*/
public static final String LOAD_FROM_HAH_YES = "y";
/**
* do not load images through the Hentai@Home Network
*/
public static final String LOAD_FROM_HAH_NO = "n";
/**
* Manual Accept, Manual Start
*/
public static final String ARCHIVER_DOWNLOAD_MAMS = "0";
/**
* >Manual Accept, Auto Start
*/
public static final String ARCHIVER_DOWNLOAD_AAMS = "1";
/**
* Auto Accept, Manual Start
*/
public static final String ARCHIVER_DOWNLOAD_MAAS = "2";
/**
* Auto Accept, Auto Start
*/
public static final String ARCHIVER_DOWNLOAD_AAAS = "3";
/**
* List View on the front and search pages
*/
public static final String LAYOUT_MODE_LIST = "l";
/**
* Thumbnail View on the front and search pages
*/
public static final String LAYOUT_MODE_THUMB = "t";
public static final int MISC = 0x1;
public static final int DOUJINSHI = 0x2;
public static final int MANGA = 0x4;
public static final int ARTIST_CG = 0x8;
public static final int GAME_CG = 0x10;
public static final int IMAGE_SET = 0x20;
public static final int COSPLAY = 0x40;
public static final int ASIAN_PORN = 0x80;
public static final int NON_H = 0x100;
public static final int WESTERN = 0x200;
public static final int NAMESPACES_RECLASS = 0x1;
public static final int NAMESPACES_LANGUAGE = 0x2;
public static final int NAMESPACES_PARODY = 0x4;
public static final int NAMESPACES_CHARACTER = 0x8;
public static final int NAMESPACES_GROUP = 0x10;
public static final int NAMESPACES_ARTIST = 0x20;
public static final int NAMESPACES_MALE = 0x40;
public static final int NAMESPACES_FEMALE = 0x80;
public static final int JAPANESE_TRANSLATED = 1024;
public static final int JAPANESE_REWRITE = 2048;
public static final int ENGLISH_ORIGINAL = 1;
public static final int ENGLISH_TRANSLATED = 1025;
public static final int ENGLISH_REWRITE = 2049;
public static final int CHINESE_ORIGINAL = 10;
public static final int CHINESE_TRANSLATED = 1034;
public static final int CHINESE_REWRITE = 2058;
public static final int DUTCH_ORIGINAL = 20;
public static final int DUTCH_TRANSLATED = 1044;
public static final int DUTCH_REWRITE = 2068;
public static final int FRENCH_ORIGINAL = 30;
public static final int FRENCH_TRANSLATED = 1054;
public static final int FRENCH_REWRITE = 2078;
public static final int GERMAN_ORIGINAL = 40;
public static final int GERMAN_TRANSLATED = 1064;
public static final int GERMAN_REWRITE = 2088;
public static final int HUNGARIAN_ORIGINAL = 50;
public static final int HUNGARIAN_TRANSLATED = 1074;
public static final int HUNGARIAN_REWRITE = 2098;
public static final int ITALIAN_ORIGINAL = 60;
public static final int ITALIAN_TRANSLATED = 1084;
public static final int ITALIAN_REWRITE = 2108;
public static final int KOREAN_ORIGINAL = 70;
public static final int KOREAN_TRANSLATED = 1094;
public static final int KOREAN_REWRITE = 2118;
public static final int POLISH_ORIGINAL = 80;
public static final int POLISH_TRANSLATED = 1104;
public static final int POLISH_REWRITE = 2128;
public static final int PORTUGUESE_ORIGINAL = 90;
public static final int PORTUGUESE_TRANSLATED = 1114;
public static final int PORTUGUESE_REWRITE = 2138;
public static final int RUSSIAN_ORIGINAL = 100;
public static final int RUSSIAN_TRANSLATED = 1124;
public static final int RUSSIAN_REWRITE = 2148;
public static final int SPANISH_ORIGINAL = 110;
public static final int SPANISH_TRANSLATED = 1134;
public static final int SPANISH_REWRITE = 2158;
public static final int THAI_ORIGINAL = 120;
public static final int THAI_TRANSLATED = 1144;
public static final int THAI_REWRITE = 2168;
public static final int VIETNAMESE_ORIGINAL = 130;
public static final int VIETNAMESE_TRANSLATED = 1154;
public static final int VIETNAMESE_REWRITE = 2178;
public static final int NA_ORIGINAL = 254;
public static final int NA_TRANSLATED = 1278;
public static final int NA_REWRITE = 2302;
public static final int OTHER_ORIGINAL = 255;
public static final int OTHER_TRANSLATED = 1279;
public static final int OTHER_REWRITE = 2303;
/**
* 25 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_25 = "0";
/**
* 50 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_50 = "1";
/**
* 100 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_100 = "2";
/**
* 200 results per page for the index/search page and torrent search pages
*/
public static final String RESULT_COUNT_200 = "3";
/**
* On mouse-over
*/
public static final String MOUSE_OVER_YES = "m";
/**
* On page load
*/
public static final String MOUSE_OVER_NO = "p";
/**
* Preview normal size
*/
public static final String PREVIEW_SIZE_NORMAL = "m";
/**
* Preview large size
*/
public static final String PREVIEW_SIZE_LARGE = "l";
/**
* 4 row preview per page
*/
public static final String PREVIEW_ROW_4 = "2";
/**
* 10 row preview per page
*/
public static final String PREVIEW_ROW_10 = "5";
/**
* 20 row preview per page
*/
public static final String PREVIEW_ROW_20 = "10";
/**
* 40 row preview per page
*/
public static final String PREVIEW_ROW_40 = "20";
/**
* Oldest comments first
*/
public static final String COMMENTS_SORT_OLDEST_FIRST = "a";
/**
* Recent comments first
*/
public static final String COMMENTS_SORT_RECENT_FIRST = "d";
/**
* By highest score
*/
public static final String COMMENTS_SORT_HIGHEST_SCORE_FIRST = "s";
/**
* Show gallery comment votes On score hover or click
*/
public static final String COMMENTS_VOTES_POP = "0";
/**
* Always show gallery comment votes
*/
public static final String COMMENTS_VOTES_ALWAYS = "1";
/**
* Sort order for gallery tags alphabetically
*/
public static final String TAGS_SORT_ALPHABETICAL = "a";
/**
* Sort order for gallery tags by tag power
*/
public static final String TAGS_SORT_POWER = "p";
/**
* Show gallery page numbers
*/
public static final String SHOW_GALLERY_INDEX_YES = "1";
/**
* Do not show gallery page numbers
*/
public static final String SHOW_GALLERY_INDEX_NO = "0";
/**
* Enable Tag Flagging
*/
public static final String ENABLE_TAG_FLAGGING_YES = "y";
/**
* Do not enable Tag Flagging
*/
public static final String ENABLE_TAG_FLAGGING_NO = "n";
/**
* Always display the original images
*/
public static final String ALWAYS_ORIGINAL_YES = "y";
/**
* Do not Always display the original images
*/
public static final String ALWAYS_ORIGINAL_NO = "n";
/**
* Enable the Multi-Page Viewe
*/
public static final String MULTI_PAGE_YES = "y";
/**
* Do not enable the Multi-Page Viewe
*/
public static final String MULTI_PAGE_NO = "n";
/**
* Align left, only scale if image is larger than browser width
*/
public static final String MULTI_PAGE_STYLE_N = "n";
/**
* Align center, only scale if image is larger than browser width
*/
public static final String MULTI_PAGE_STYLE_C = "c";
/**
* Align center, Always scale images to fit browser width
*/
public static final String MULTI_PAGE_STYLE_Y = "y";
/**
* Show Multi-Page Viewer Thumbnail Pane
*/
public static final String MULTI_PAGE_THUMB_SHOW = "n";
/**
* Hide Multi-Page Viewer Thumbnail Pane
*/
public static final String MULTI_PAGE_THUMB_HIDE = "y";
/**
* 460x for lofi resolution
*/
public static final String LOFI_RESOLUTION_460X = "1";
/**
* 780X for lofi resolution
*/
public static final String LOFI_RESOLUTION_780X = "2";
/**
* 980X for lofi resolution
*/
public static final String LOFI_RESOLUTION_980X = "3";
/**
* show warning
*/
private static final String CONTENT_WARNING_SHOW = "0";
/**
* not show warning
*/
private static final String CONTENT_WARNING_NOT_SHOW = "1";
/**
* Load images through the Hentai@Home Network<br/>
* key: {@link #KEY_LOAD_FROM_HAH}<br/>
* value: {@link #LOAD_FROM_HAH_YES}, {@link #LOAD_FROM_HAH_NO}
*/
public String loadFromHAH = LOAD_FROM_HAH_YES;
/**
* Scale width<br/>
* key: {@link #KEY_SCALE_WIDTH}<br/>
* value: 0 for no limit
*/
public int scaleWidth = 0;
/**
* Scale height<br/>
* key: {@link #KEY_SCALE_HEIGHT}<br/>
* value: 0 for no limit
*/
public int scaleHeight = 0;
/**
* The default behavior for downloading an archiver<br/>
* key: {@link #KEY_ARCHIVER_DOWNLOAD}<br/>
* value: {@link #ARCHIVER_DOWNLOAD_MAMS}, {@link #ARCHIVER_DOWNLOAD_AAMS},
* {@link #ARCHIVER_DOWNLOAD_MAAS}, {@link #ARCHIVER_DOWNLOAD_AAAS}
*/
public String archiverDownload = ARCHIVER_DOWNLOAD_MAMS;
/**
* Display mode used on the front and search pages<br/>
* false for list, true for thumb<br/>
* key: {@link #KEY_LAYOUT_MODE}<br/>
* value: {@link #LAYOUT_MODE_LIST}, {@link #LAYOUT_MODE_THUMB}
*/
public String layoutMode = LAYOUT_MODE_LIST;
/**
* Default categories on the front page<br/>
* key: {@link #KEY_DEFAULT_CATEGORIES}<br/>
* value: the value of categories, for multiple use & operation,
* 0 for none
*/
public int defaultCategories = 0;
/**
* Certain namespaces excluded from a default tag search<br/>
* key: {@link #KEY_EXCLUDED_NAMESPACES}<br/>
* value: the value of namespaces, for multiple use & operation,
* 0 for none
*/
public int excludedNamespaces = 0;
/**
* Certain languages excluded from list and searches<br/>
* key: {@link #KEY_EXCLUDED_LANGUAGES}<br/>
* value: {@link #JAPANESE_TRANSLATED}, {@link #JAPANESE_REWRITE} ...
* For multiple languages, use <code>x<code/> to combine them, like 1x1024x2048
*/
public String excludedLanguages = "";
/**
* How many results would you like per page for the index/search page
* and torrent search pages<br/>
* key: {@link #KEY_RESULT_COUNT}<br/>
* value: {@link #RESULT_COUNT_25}, {@link #RESULT_COUNT_50},
* {@link #RESULT_COUNT_100}, {@link #RESULT_COUNT_200}<br/>
* Require <code>Hath Perk:Paging Enlargement</code>
*/
public String resultCount = RESULT_COUNT_25;
/**
* mouse-over thumb<br/>
* key: {@link #KEY_MOUSE_OVER}<br/>
* value: {@link #MOUSE_OVER_YES}, {@link #MOUSE_OVER_NO}
*/
public String mouseOver = MOUSE_OVER_YES;
/**
* Default preview mode<br/>
* key: {@link #KEY_PREVIEW_SIZE}<br/>
* value: {@link #PREVIEW_SIZE_NORMAL}, {@link #PREVIEW_SIZE_LARGE}
*/
public String previewSize = PREVIEW_SIZE_NORMAL;
/**
* Preview row<br/>
* key: {@link #KEY_PREVIEW_ROW}<br/>
* value: {@link #PREVIEW_ROW_4}, {@link #PREVIEW_ROW_10},
* {@link #PREVIEW_ROW_20}, {@link #PREVIEW_ROW_40}
*/
public String previewRow = PREVIEW_ROW_4;
/**
* Sort order for gallery comments<br/>
* key: {@link #KEY_COMMENTS_SORT}<br/>
* value: {@link #COMMENTS_SORT_OLDEST_FIRST}, {@link #COMMENTS_SORT_RECENT_FIRST},
* {@link #COMMENTS_SORT_HIGHEST_SCORE_FIRST}
*/
public String commentSort = COMMENTS_SORT_OLDEST_FIRST;
/**
* Show gallery comment votes mode<br/>
* key: {@link #KEY_COMMENTS_VOTES}<br/>
* value: {@link #COMMENTS_VOTES_POP}, {@link #COMMENTS_VOTES_ALWAYS}
*/
public String commentVotes = COMMENTS_VOTES_POP;
/**
* Sort order for gallery tags<br/>
* key: {@link #KEY_TAGS_SORT}<br/>
* value: {@link #TAGS_SORT_ALPHABETICAL}, {@link #TAGS_SORT_POWER}
*/
public String tagSort = TAGS_SORT_ALPHABETICAL;
/**
* Show gallery page numbers<br/>
* key: {@link #KEY_SHOW_GALLERY_INDEX}<br/>
* value: {@link #SHOW_GALLERY_INDEX_YES}, {@link #SHOW_GALLERY_INDEX_NO}
*/
public String showGalleryIndex = SHOW_GALLERY_INDEX_YES;
/**
* The IP of a proxy-enabled Hentai@Home Client
* to load all images<br/>
* key: {@link #KEY_HAH_CLIENT_IP_PORT}<br/>
*/
public String hahClientIp = "";
/**
* The PORT of a proxy-enabled Hentai@Home Client
* to load all images<br/>
* key: {@link #KEY_HAH_CLIENT_IP_PORT}<br/>
*/
public int hahClientPort = -1;
/**
* The passkey of a proxy-enabled Hentai@Home Client
* to load all images<br/>
* key: {@link #KEY_HAH_CLIENT_PASSKEY}<br/>
*/
public String hahClientPasskey = "";
/**
* Enable tag flagging
* key: {@link #KEY_ENABLE_TAG_FLAGGING}<br/>
* value: {@link #ENABLE_TAG_FLAGGING_YES}, {@link #ENABLE_TAG_FLAGGING_NO}<br/>
* <code>Bronze Star</code> or <code>Hath Perk: Tag Flagging</code> Required
*/
public String enableTagFlagging = ENABLE_TAG_FLAGGING_NO;
/**
* Always display the original images instead of the resampled versions<br/>
* key: {@link #KEY_ALWAYS_ORIGINAL}<br/>
* value: {@link #ALWAYS_ORIGINAL_YES}, {@link #ALWAYS_ORIGINAL_NO}<br/>
* <code>Silver Star</code> or <code>Hath Perk: Source Nexus</code> Required
*/
public String alwaysOriginal = ALWAYS_ORIGINAL_NO;
/**
* Enable the multi-Page Viewer<br/>
* key: {@link #KEY_MULTI_PAGE}<br/>
* value: {@link #MULTI_PAGE_YES}, {@link #MULTI_PAGE_NO}<br/>
* <code>Gold Star</code> or <code>Hath Perk: Multi-Page Viewer</code> Required
*/
public String multiPage = MULTI_PAGE_NO;
/**
* Multi-Page Viewer Display Style<br/>
* key: {@link #KEY_MULTI_PAGE_STYLE}<br/>
* value: {@link #MULTI_PAGE_STYLE_N}, {@link #MULTI_PAGE_STYLE_C},
* {@link #MULTI_PAGE_STYLE_Y}<br/>
* <code>Gold Star</code> or <code>Hath Perk: Multi-Page Viewer</code> Required
*/
public String multiPageStyle = MULTI_PAGE_STYLE_N;
/**
* Multi-Page Viewer Thumbnail Pane<br/>
* key: {@link #KEY_MULTI_PAGE_THUMB}<br/>
* value: {@link #MULTI_PAGE_THUMB_SHOW}, {@link #MULTI_PAGE_THUMB_HIDE}<br/>
* <code>Gold Star</code> or <code>Hath Perk: Multi-Page Viewer</code> Required
*/
public String multiPageThumb = MULTI_PAGE_THUMB_SHOW;
/**
* Lofi resolution
* key: {@link #KEY_LOFI_RESOLUTION}<br/>
* value: {@link #LOFI_RESOLUTION_460X}, {@link #LOFI_RESOLUTION_780X},
* {@link #LOFI_RESOLUTION_980X}
*/
public String lofiResolution = LOFI_RESOLUTION_980X;
/**
* Show content warning
* key: {@link #KEY_CONTENT_WARNING}<br/>
* value: {@link #CONTENT_WARNING_SHOW}, {@link #CONTENT_WARNING_NOT_SHOW}
*/
public String contentWarning = CONTENT_WARNING_NOT_SHOW;
private String mUconfig;
private boolean mDirty = true;
public void setDirty() {
mDirty = true;
}
private void updateUconfig() {
String hahClientIpPort = (TextUtils.isEmpty(hahClientIp) || hahClientPort == -1) ?
"" : hahClientIp + "%3A" + hahClientPort;
mUconfig = KEY_LOAD_FROM_HAH + "_" + loadFromHAH + "-" +
KEY_SCALE_WIDTH + "_" + scaleWidth + "-" +
KEY_SCALE_HEIGHT + "_" + scaleHeight + "-" +
KEY_ARCHIVER_DOWNLOAD + "_" + archiverDownload + "-" +
KEY_LAYOUT_MODE + "_" + layoutMode + "-" +
KEY_DEFAULT_CATEGORIES + "_" + defaultCategories + "-" +
KEY_EXCLUDED_NAMESPACES + "_" + excludedNamespaces + "-" +
KEY_EXCLUDED_LANGUAGES + "_" + excludedLanguages + "-" +
KEY_RESULT_COUNT + "_" + resultCount + "-" +
KEY_MOUSE_OVER + "_" + mouseOver + "-" +
KEY_PREVIEW_SIZE + "_" + previewSize + "-" +
KEY_PREVIEW_ROW + "_" + previewRow + "-" +
KEY_COMMENTS_SORT + "_" + commentSort + "-" +
KEY_COMMENTS_VOTES + "_" + commentVotes + "-" +
KEY_TAGS_SORT + "_" + tagSort + "-" +
KEY_SHOW_GALLERY_INDEX + "_" + showGalleryIndex + "-" +
KEY_HAH_CLIENT_IP_PORT + "_" + hahClientIpPort + "-" +
KEY_HAH_CLIENT_PASSKEY + "_" + hahClientPasskey + "-" +
KEY_ENABLE_TAG_FLAGGING + "_" + enableTagFlagging + "-" +
KEY_ALWAYS_ORIGINAL + "_" + alwaysOriginal + "-" +
KEY_MULTI_PAGE + "_" + multiPage + "-" +
KEY_MULTI_PAGE_STYLE + "_" + multiPageStyle + "-" +
KEY_MULTI_PAGE_THUMB + "_" + multiPageThumb;
}
public void fillCookie(Cookie cookie) {
if (mDirty) {
mDirty = false;
updateUconfig();
}
cookie.put(KEY_UCONFIG, mUconfig);
cookie.put(KEY_LOFI_RESOLUTION, lofiResolution);
cookie.put(KEY_CONTENT_WARNING, contentWarning);
}
}
@@ -0,0 +1,139 @@
/*
* 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.ehviewer.client;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.httpclient.FormPoster;
import com.hippo.httpclient.HttpClient;
import com.hippo.httpclient.HttpRequest;
import com.hippo.httpclient.HttpResponse;
import com.hippo.httpclient.JsonPoster;
import org.json.JSONObject;
class EhEngine {
private static final String SIGN_IN_URL = "http://forums.e-hentai.org/index.php?act=Login&CODE=01";
public static final String API_EHVIEWER = "http://www.ehviewer.com/API";
public static String signIn(HttpClient httpClient, HttpRequest httpRequest,
String username, String password) throws Exception {
try {
FormPoster formPoster = new FormPoster();
formPoster.addData("UserName", username)
.addData("PassWord", password)
.addData("submit", "Log me in")
.addData("CookieDate", "1")
.addData("temporary_https", "off");
httpRequest.setUrl(SIGN_IN_URL);
httpRequest.setHttpImpl(formPoster);
HttpResponse response = httpClient.execute(httpRequest);
String body = response.getString();
return SignInParser.parse(body);
} catch (Exception e) {
if (httpRequest.isCanceled()) {
throw new CanceledException();
} else {
throw e;
}
} finally {
httpRequest.disconnect();
}
}
public static GalleryListParser.Result getGalleryList(HttpClient httpClient,
HttpRequest httpRequest, String url, int source) throws Exception {
try {
httpRequest.setUrl(url);
HttpResponse response = httpClient.execute(httpRequest);
String body = response.getString();
return GalleryListParser.parse(body, source);
} catch (Exception e) {
if (httpRequest.isCanceled()) {
throw new CanceledException();
} else {
throw e;
}
} finally {
httpRequest.disconnect();
}
}
public static PopularParser.Result getPopular(HttpClient httpClient,
HttpRequest httpRequest) throws Exception {
try {
final JSONObject json = new JSONObject();
json.put("method", "popular");
JsonPoster jsonPoster = new JsonPoster(json);
httpRequest.setUrl(API_EHVIEWER);
httpRequest.setHttpImpl(jsonPoster);
HttpResponse response = httpClient.execute(httpRequest);
String body = response.getString();
return PopularParser.parse(body);
} catch (Exception e) {
if (httpRequest.isCanceled()) {
throw new CanceledException();
} else {
throw e;
}
} finally {
httpRequest.disconnect();
}
}
public static GalleryDetail getGalleryDetail(HttpClient httpClient,
HttpRequest httpRequest, String url, int source) throws Exception {
try {
httpRequest.setUrl(url);
HttpResponse response = httpClient.execute(httpRequest);
String body = response.getString();
return GalleryDetailParser.parse(body, source,
GalleryDetailParser.REQUEST_DETAIL |
GalleryDetailParser.REQUEST_TAG |
GalleryDetailParser.REQUEST_PREVIEW_INFO |
GalleryDetailParser.REQUEST_PREVIEW |
GalleryDetailParser.REQUEST_COMMENT);
} catch (Exception e) {
if (httpRequest.isCanceled()) {
throw new CanceledException();
} else {
throw e;
}
} finally {
httpRequest.disconnect();
}
}
public static PreviewSet getPreviewSet(HttpClient httpClient,
HttpRequest httpRequest, String url, int source) throws Exception {
try {
httpRequest.setUrl(url);
HttpResponse response = httpClient.execute(httpRequest);
String body = response.getString();
return GalleryDetailParser.parsePreview(body, source);
} catch (Exception e) {
if (httpRequest.isCanceled()) {
throw new CanceledException();
} else {
throw e;
}
} finally {
httpRequest.disconnect();
}
}
}
@@ -0,0 +1,58 @@
/*
* 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.ehviewer.client;
public class EhRequest {
int method;
Object[] args;
EhClient.EhListener ehListener;
EhConfig ehConfig;
EhClient.Task task;
private boolean mCancel = false;
public void setMethod(int method) {
this.method = method;
}
public void setArgs(Object... args) {
this.args = args;
}
public void setEhConfig(EhConfig ehConfig) {
this.ehConfig = ehConfig;
}
public void setEhListener(EhClient.EhListener ehListener) {
this.ehListener = ehListener;
}
public void cancel() {
if (!mCancel) {
mCancel = true;
if (task != null) {
task.stop();
}
}
}
public boolean isCanceled() {
return mCancel;
}
}
@@ -0,0 +1,70 @@
/*
* 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.ehviewer.client;
public class EhUrl {
public static final int SOURCE_G = 0x0;
public static final int SOURCE_EX = 0x1;
public static final int SOURCE_LOFI = 0x2;
public static final String HOST_G = "G.E-Hentai";
public static final String HOST_EX = "ExHentai";
public static final String HOST_LOFI = "Lofi.E-Hentai";
public static final String HEADER_G = "http://g.e-hentai.org/";
public static final String HEADER_EX = "http://exhentai.org/";
public static final String HEADER_LOFI = "http://lofi.e-hentai.org/";
public static String getReadableHost(int source) {
switch (source) {
default:
case SOURCE_G:
return HOST_G;
case SOURCE_EX:
return HOST_EX;
case SOURCE_LOFI:
return HOST_LOFI;
}
}
public static String getUrlHeader(int source) {
switch (source) {
default:
case SOURCE_G:
return HEADER_G;
case SOURCE_EX:
return HEADER_EX;
case SOURCE_LOFI:
return HEADER_LOFI;
}
}
/**
* Get gellary detail url in target source
*/
public static String getDetailUrl(int source, int gid, String token, int pageIndex) {
StringBuilder sb = new StringBuilder(getUrlHeader(source));
sb.append("g/").append(gid).append('/').append(token).append('/');
if (pageIndex > 0) {
sb.append("?p=").append(pageIndex);
}
return sb.toString();
}
}
@@ -17,12 +17,12 @@
package com.hippo.ehviewer.client;
import com.hippo.ehviewer.client.data.Comment;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.LargePreviewSet;
import com.hippo.ehviewer.client.data.NormalPreviewSet;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.ehviewer.client.data.TagGroup;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.util.AssertUtils;
import com.hippo.util.Utils;
import java.text.DateFormat;
@@ -31,7 +31,6 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Matcher;
@@ -60,90 +59,22 @@ public class GalleryDetailParser {
private static final CommentSort COMMENT_SORTER = new CommentSort();
public int gid;
public String token;
public String thumb;
public String title;
public String titleJpn;
public int category;
public String uploader;
public int torrentCount;
public String torrentUrl;
public String posted;
public String parent;
public String visible;
public String language;
public String size;
public String resize;
public int pageCount;
public int favoredTimes;
public boolean isFavored;
public float rating;
public int ratedTimes;
public List<TagGroup> tags;
public List<Comment> comments;
public int previewPageCount;
public PreviewSet previewSet;
private String sortOut(String str) {
// Avoid null
if (str == null) {
str = "";
}
return Utils.unescapeXml(str).trim();
}
private int sortOutInteger(String str, int defaultValue) {
return Utils.parseIntSafely(sortOut(str).replace(",", ""), defaultValue);
}
private void parseTagGroup(TagGroup tagGroup, String body) {
Pattern p = Pattern.compile("<div[^<>]+><a[^<>]+>([\\w\\s]+)</a></div>");
Matcher m = p.matcher(body);
while (m.find()) {
tagGroup.addTag(sortOut(m.group(1)));
public static GalleryDetail parse(String body, int source, int request) throws Exception {
switch (source) {
default:
case EhUrl.SOURCE_G:
case EhUrl.SOURCE_EX: {
return parse(body, request);
}
case EhUrl.SOURCE_LOFI: {
//parseLofi(body, request);
//break;
throw new EhException("Not support lofi now");
}
}
}
private void parseNormalPreview(String body) {
Pattern p = Pattern.compile("<div[^<>]*class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*>");
Matcher m = p.matcher(body);
NormalPreviewSet normalPreviewSet = new NormalPreviewSet();
while (m.find()) {
normalPreviewSet.addItem(m.group(3), Integer.parseInt(m.group(4)), 0,
Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
m.group(5));
}
previewSet = normalPreviewSet;
}
private void parseLargePreview(String body) {
Pattern p = Pattern.compile("<div class=\"gdtl\".+?<a href=\"(.+?)\"><img.+?src=\"(.+?)\"");
Matcher m = p.matcher(body);
LargePreviewSet largePreviewSet = new LargePreviewSet();
while (m.find()) {
largePreviewSet.addItem(m.group(2), m.group(1));
}
previewSet = largePreviewSet;
}
private void parsePreview(String body) {
if (body.contains("<div class=\"gdtm\"")) {
parseNormalPreview(body);
} else {
parseLargePreview(body);
}
}
private void parse(String body, int request) throws EhException {
Pattern p;
Matcher m;
private static GalleryDetail parse(String body, int request) throws EhException {
if (!body.startsWith("<")) {
throw new EhException(body);
}
@@ -156,6 +87,9 @@ public class GalleryDetailParser {
throw new PiningException();
}
Pattern p;
Matcher m;
// TODO I can't remember what's this for
p = Pattern.compile("<div class=\"d\">\n<p>([^<]+)</p>");
m = p.matcher(body);
@@ -163,6 +97,8 @@ public class GalleryDetailParser {
throw new EhException(m.group(1));
}
GalleryDetail galleryDetail = new GalleryDetail();
if ((request & REQUEST_DETAIL) != 0) {
p = Pattern.compile("var gid = (\\d+)" // 1 gid
+ ".+?"
@@ -195,70 +131,70 @@ public class GalleryDetailParser {
+ "<a id=\"favoritelink\"[^<>]*>(.+?)</a>", Pattern.DOTALL); // 20 isFavored "Favorite Gallery" for favorite
m = p.matcher(body);
if (m.find()) {
gid = sortOutInteger(m.group(1), 0);
token = sortOut(m.group(2));
thumb = sortOut(m.group(3));
title = sortOut(m.group(4));
titleJpn = sortOut(m.group(5));
torrentUrl = sortOut(m.group(6));
torrentCount = sortOutInteger(m.group(7), 0);
category = EhUtils.getCategory(sortOut(m.group(8)));
uploader = sortOut(m.group(9));
posted = sortOut(m.group(10));
parent = sortOut(m.group(11));
visible = sortOut(m.group(12));
language = sortOut(m.group(13));
size = sortOut(m.group(14));
resize = sortOut(m.group(15));
pageCount = sortOutInteger(m.group(16), 0);
galleryDetail.gid = ParserUtils.parseInt(m.group(1));
galleryDetail.token = ParserUtils.trim(m.group(2));
galleryDetail.thumb = ParserUtils.trim(m.group(3));
galleryDetail.title = ParserUtils.trim(m.group(4));
galleryDetail.titleJpn = ParserUtils.trim(m.group(5));
galleryDetail.torrentUrl = ParserUtils.trim(m.group(6));
galleryDetail.torrentCount = ParserUtils.parseInt(m.group(7));
galleryDetail.category = EhUtils.getCategory(ParserUtils.trim(m.group(8)));
galleryDetail.uploader = ParserUtils.trim(m.group(9));
galleryDetail.posted = ParserUtils.trim(m.group(10));
galleryDetail.parent = ParserUtils.trim(m.group(11));
galleryDetail.visible = ParserUtils.trim(m.group(12));
galleryDetail.language = ParserUtils.trim(m.group(13));
galleryDetail.size = ParserUtils.trim(m.group(14));
galleryDetail.resize = ParserUtils.trim(m.group(15));
galleryDetail.pageCount = ParserUtils.parseInt(m.group(16));
String favTimeStr = sortOut(m.group(17));
String favTimeStr = ParserUtils.trim(m.group(17));
switch (favTimeStr) {
case "Never":
favoredTimes = 0;
galleryDetail.favoredTimes = 0;
break;
case "Once":
favoredTimes = 1;
galleryDetail.favoredTimes = 1;
break;
default:
int index = favTimeStr.indexOf(' ');
if (index == -1) {
favoredTimes = 0;
galleryDetail.favoredTimes = 0;
} else {
favoredTimes = Utils.parseIntSafely(favTimeStr.substring(0, index), 0);
galleryDetail.favoredTimes = ParserUtils.parseInt(favTimeStr.substring(0, index));
}
break;
}
ratedTimes = sortOutInteger(m.group(18), 0);
galleryDetail.ratedTimes = ParserUtils.parseInt(m.group(18));
String ratingStr = sortOut(m.group(19));
String ratingStr = ParserUtils.trim(m.group(19));
if ("Not Yet Rated".equals(ratingStr)) {
rating = Float.NaN;
galleryDetail.rating = Float.NaN;
} else {
int index = ratingStr.indexOf(' ');
if (index == -1 || index >= ratingStr.length()) {
rating = 0f;
galleryDetail.rating = 0f;
} else {
rating = Utils.parseFloatSafely(ratingStr.substring(index + 1), 0f);
galleryDetail.rating = Utils.parseFloatSafely(ratingStr.substring(index + 1), 0f);
}
}
isFavored = "Favorite Gallery".equals(sortOut(m.group(20)));
galleryDetail.isFavored = "Favorite Gallery".equals(ParserUtils.trim(m.group(20)));
} else {
throw new ParseException("Parse gallery body error", body);
throw new ParseException("Parse gallery detail error", body);
}
}
if ((request & REQUEST_TAG) != 0) {
tags = new LinkedList<>();
galleryDetail.tags = new LinkedList<>();
p = Pattern.compile("<tr><td[^<>]+>([\\w\\s]+):</td><td>(?:<div[^<>]+><a[^<>]+>[\\w\\s]+</a></div>)+</td></tr>");
m = p.matcher(body);
while (m.find()) {
TagGroup tagGroup = new TagGroup();
tagGroup.groupName = sortOut(m.group(1));
tagGroup.groupName = ParserUtils.trim(m.group(1));
parseTagGroup(tagGroup, m.group(0));
tags.add(tagGroup);
galleryDetail.tags.add(tagGroup);
}
}
@@ -267,27 +203,30 @@ public class GalleryDetailParser {
p = Pattern.compile("<td[^>]+><a[^>]+>([\\d,]+)</a></td><td[^>]+>(?:<a[^>]+>)?&gt;(?:</a>)?</td>");
m = p.matcher(body);
if (m.find()) {
previewPageCount = sortOutInteger(m.group(1), 0);
galleryDetail.previewPageCount = ParserUtils.parseInt(m.group(1));
} else {
previewPageCount = 0;
galleryDetail.previewPageCount = 0;
}
if (previewPageCount <= 0) {
if (galleryDetail.previewPageCount <= 0) {
throw new ParseException("Parse preview page count error", body);
}
}
// Get preview
if ((request & REQUEST_PREVIEW) != 0) {
parsePreview(body);
PreviewSet previewSet = parsePreview(body);
previewSet.setGid(galleryDetail.gid); // TODO What if not set REQUEST_DETAIL
galleryDetail.previewSetArray = new PreviewSet[galleryDetail.previewPageCount];
galleryDetail.previewSetArray[0] = previewSet;
}
// Get comment
if ((request & REQUEST_COMMENT) != 0) {
p = Pattern.compile("<div class=\"c3\">Posted on ([^<>]+) by: &nbsp; <a[^<>]+>([^<>]+)</a>.+?<div class=\"c6\"[^>]*>(.+?)</div><div class=\"c[78]\"");
m = p.matcher(body);
comments = new LinkedList<>();
galleryDetail.comments = new LinkedList<>();
while (m.find()) {
String webDateString = sortOut(m.group(1));
String webDateString = ParserUtils.trim(m.group(1));
Date date;
try {
date = WEB_COMMENT_DATA_FORMAT.parse(webDateString);
@@ -295,34 +234,67 @@ public class GalleryDetailParser {
date = new Date(0l);
}
String outDateString = OUT_COMMENT_DATA_FORMAT.format(date);
comments.add(new Comment(outDateString, date, sortOut(m.group(2)), m.group(3)));
galleryDetail.comments.add(new Comment(outDateString, date, ParserUtils.trim(m.group(2)), m.group(3)));
}
Collections.sort(comments, COMMENT_SORTER);
Collections.sort(galleryDetail.comments, COMMENT_SORTER);
}
if ((request & REQUEST_COMMENT) != 0) {
return galleryDetail;
}
private static void parseTagGroup(TagGroup tagGroup, String body) {
Pattern p = Pattern.compile("<div[^<>]+><a[^<>]+>([\\w\\s]+)</a></div>");
Matcher m = p.matcher(body);
while (m.find()) {
tagGroup.addTag(ParserUtils.trim(m.group(1)));
}
}
public void parse(String body, int request, int source) throws Exception {
AssertUtils.assertNotNull("Body is null when parse gallery list", body);
public static PreviewSet parsePreview(String body, int source) throws EhException {
switch (source) {
default:
case EhClient.SOURCE_G:
case EhClient.SOURCE_EX: {
parse(body, request);
break;
case EhUrl.SOURCE_G:
case EhUrl.SOURCE_EX: {
return parsePreview(body);
}
case EhClient.SOURCE_LOFI: {
//parseLofi(body, request);
case EhUrl.SOURCE_LOFI: {
//parsePreviewLofi(body);
//break;
throw new EhException("Not support lofi now");
}
}
}
public static PreviewSet parsePreview(String body) {
if (body.contains("<div class=\"gdtm\"")) {
return parseNormalPreview(body);
} else {
return parseLargePreview(body);
}
}
private static NormalPreviewSet parseNormalPreview(String body) {
Pattern p = Pattern.compile("<div[^<>]*class=\"gdtm\"[^<>]*><div[^<>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*><a[^<>]*href=\"(.+?)\"[^<>]*>");
Matcher m = p.matcher(body);
NormalPreviewSet normalPreviewSet = new NormalPreviewSet();
while (m.find()) {
normalPreviewSet.addItem(m.group(3), Integer.parseInt(m.group(4)), 0,
Integer.parseInt(m.group(1)), Integer.parseInt(m.group(2)),
m.group(5));
}
return normalPreviewSet;
}
private static LargePreviewSet parseLargePreview(String body) {
Pattern p = Pattern.compile("<div class=\"gdtl\".+?<a href=\"(.+?)\"><img.+?src=\"(.+?)\"");
Matcher m = p.matcher(body);
LargePreviewSet largePreviewSet = new LargePreviewSet();
while (m.find()) {
largePreviewSet.addItem(m.group(2), m.group(1));
}
return largePreviewSet;
}
static class CommentSort implements Comparator<Comment> {
@Override
@@ -16,6 +16,8 @@
package com.hippo.ehviewer.client;
import android.support.annotation.NonNull;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.LofiGalleryInfo;
import com.hippo.ehviewer.util.EhUtils;
@@ -29,99 +31,120 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GalleryListParser {
private static final String PARSE_MESSAGE = "Gallery list parser error";
private static final int DEFAULT_LIST_SIZE = 25;
public static class Result {
public static final int CURRENT_PAGE_IS_LAST = -1;
public static final int NOT_FOUND = 0;
/**
* If NOT FOUND, pageNum is 0.<br>
* For lofi, we can not get pages number,
* so pageNum is {@link java.lang.Integer#MAX_VALUE} when it is not the last page,
* pageNum is {@link #CURRENT_PAGE_IS_LAST} when it is the last page
*/
public int pageNum;
public static final int CURRENT_PAGE_IS_LAST = -1;
public List<GalleryInfo> giList;
public static final int KEEP_LOADING = Integer.MAX_VALUE;
private void parse(String body) throws EhException {
Pattern p;
Matcher m;
/**
* If NOT FOUND, pageNum is 0.<br>
* For lofi, we can not get pages number,
* so pageNum is {@link java.lang.Integer#MAX_VALUE} when it is not the last page,
* pageNum is {@link #CURRENT_PAGE_IS_LAST} when it is the last page
*/
public int pages;
public List<GalleryInfo> galleryInfos;
}
// Get page number
p = Pattern.compile("<a[^<>]+>([\\d]+)</a></td><td[^<>]+>(?:<a[^<>]+>)?&");
m = p.matcher(body);
if (m.find()) {
pageNum = Integer.parseInt(m.group(1));
} else if (body.contains("No hits found</p>")) {
pageNum = 0;
} else {
// Can not get page number
throw new EhException(PARSE_MESSAGE);
}
// Get gallery
giList = new ArrayList<>(DEFAULT_LIST_SIZE);
p = Pattern.compile("<td class=\"itdc\">(?:<a.+?>)?<img.+?alt=\"(.+?)\".+?/>(?:</a>)?</td>" // category
+ "<td.+?>(.+?)</td>" // posted
+ "<td.+?><div.+?><div.+?height:(\\d+)px; width:(\\d+)px\">"
+ "(?:<img.+?src=\"(.+?)\".+?alt=\"(.+?)\" style.+?/>"
+ "|init~([^<>\"~]+~[^<>\"~]+)~([^<>]+))" // thumb and title
+ "</div>"
+ ".+?"
+ "<div class=\"it5\"><a href=\"([^<>\"]+)\"[^<>]+>(.+?)</a></div>" // url and title
+ ".+?"
+ "<div class=\"ir it4r\" style=\"([^<>\"]+)\">" // rating
+ ".+?"
+ "<td class=\"itu\"><div><a.+?>(.+?)</a>"); // uploader
m = p.matcher(body);
while (m.find()) {
GalleryInfo gi = new GalleryInfo();
gi.category = EhUtils.getCategory(m.group(1));
gi.posted = m.group(2);
gi.thumbHeight = Integer.parseInt(m.group(3));
gi.thumbWidth = Integer.parseInt(m.group(4));
if (m.group(5) == null) {
gi.thumb = Utils.unescapeXml("http://"
+ m.group(7).replace('~', '/'));
gi.title = Utils.unescapeXml(m.group(8));
} else {
gi.thumb = Utils.unescapeXml(m.group(5));
gi.title = Utils.unescapeXml(m.group(6));
public static Result parse(@NonNull String body, int source) throws Exception {
switch (source) {
default:
case EhUrl.SOURCE_G:
case EhUrl.SOURCE_EX: {
return parse(body);
}
Pattern pattern = Pattern
.compile("/(\\d+)/(\\w+)");
Matcher matcher = pattern.matcher(m.group(9));
if (matcher.find()) {
gi.gid = Integer.parseInt(matcher.group(1));
gi.token = matcher.group(2);
} else {
continue;
case EhUrl.SOURCE_LOFI: {
return parseLofi(body);
}
gi.rating = Utils.parseFloatSafely(getRate(m.group(11)), Float.NaN);
gi.uploader = m.group(12);
gi.generateSLang();
giList.add(gi);
}
if (giList.size() == 0) {
throw new EhException(PARSE_MESSAGE);
}
}
private void parseLofi(String body) throws Exception {
private static Result parse(String body) throws EhException {
Result result = new Result();
Pattern p;
Matcher m;
// Get gallery
giList = new ArrayList<>(DEFAULT_LIST_SIZE);
// pages
p = Pattern.compile("<a[^<>]+>([\\d]+)</a></td><td[^<>]+>(?:<a[^<>]+>)?&");
m = p.matcher(body);
if (m.find()) {
result.pages = ParserUtils.parseInt(m.group(1));
} else if (body.contains("No hits found</p>")) {
result.pages = Result.NOT_FOUND;
} else {
// Can not get page number
throw new ParseException("Can't parse gallery list", body);
}
if (result.pages > 0) {
List<GalleryInfo> list = new ArrayList<>(25);
result.galleryInfos = list;
p = Pattern.compile("<td class=\"itdc\">(?:<a.+?>)?<img.+?alt=\"(.+?)\".+?/>(?:</a>)?</td>" // category
+ "<td.+?>(.+?)</td>" // posted
+ "<td.+?><div.+?><div.+?height:(\\d+)px; width:(\\d+)px\">"
+ "(?:<img.+?src=\"(.+?)\".+?alt=\"(.+?)\" style.+?/>"
+ "|init~([^<>\"~]+~[^<>\"~]+)~([^<>]+))" // thumb and title
+ "</div>"
+ ".+?"
+ "<div class=\"it5\"><a href=\"([^<>\"]+)\"[^<>]+>(.+?)</a></div>" // url and title
+ ".+?"
+ "<div class=\"ir it4r\" style=\"([^<>\"]+)\">" // rating
+ ".+?"
+ "<td class=\"itu\"><div><a.+?>(.+?)</a>"); // uploader
m = p.matcher(body);
while (m.find()) {
GalleryInfo gi = new GalleryInfo();
gi.category = EhUtils.getCategory(ParserUtils.trim(m.group(1)));
gi.posted = ParserUtils.trim(m.group(2));
gi.thumbHeight = ParserUtils.parseInt(m.group(3));
gi.thumbWidth = ParserUtils.parseInt(m.group(4));
if (m.group(5) == null) {
gi.thumb = ParserUtils.trim("http://" + m.group(7).replace('~', '/'));
gi.title = ParserUtils.trim(m.group(8));
} else {
gi.thumb = ParserUtils.trim(m.group(5));
gi.title = ParserUtils.trim(m.group(6));
}
Pattern pattern = Pattern
.compile("/(\\d+)/(\\w+)");
Matcher matcher = pattern.matcher(m.group(9));
if (matcher.find()) {
gi.gid = ParserUtils.parseInt(matcher.group(1));
gi.token = ParserUtils.trim(matcher.group(2));
} else {
continue;
}
gi.rating = Utils.parseFloatSafely(getRate(m.group(11)), Float.NaN);
gi.uploader = ParserUtils.trim(m.group(12));
gi.generateSLang();
list.add(gi);
}
if (list.size() == 0) {
throw new ParseException("Can't parse gallery list", body);
}
}
return result;
}
private static Result parseLofi(String body) throws Exception {
Result result = new Result();
Pattern p;
Matcher m;
List<GalleryInfo> list = new ArrayList<>(25);
result.galleryInfos = list;
p = Pattern.compile("<td class=\"ii\"><a href=\"(.+?)\">" // detail url
+ "<img src=\"(.+?)\".+?/>" // thumb url
+ ".+?<a class=\"b\" href=\".+?\">(.+?)</a>" // title
@@ -139,8 +162,8 @@ public class GalleryListParser {
lgi.gid = dup.gid;
lgi.token = dup.token;
lgi.thumb = Utils.unescapeXml(m.group(2));
lgi.title = Utils.unescapeXml(m.group(3));
lgi.thumb = ParserUtils.trim(m.group(2));
lgi.title = ParserUtils.trim(m.group(3));
getPostedAndUploader(m.group(4), pau);
lgi.posted = pau[0];
@@ -159,44 +182,29 @@ public class GalleryListParser {
lgi.rating = getStartNum(rating);
lgi.generateSLang();
giList.add(lgi);
list.add(lgi);
}
if (giList.size() == 0) {
if (list.size() == 0) {
if (body.contains("No hits found</div>")) {
pageNum = 0;
result.pages = Result.NOT_FOUND;
} else if (body.contains("No more hits found</div>")) {
throw new EhException("Index is out of range");
} else {
throw new EhException(PARSE_MESSAGE);
throw new ParseException("Can't parse gallery list", body);
}
} else {
if (!body.contains("Next Page &gt;</a>")) {
pageNum = CURRENT_PAGE_IS_LAST;
result.pages = Result.CURRENT_PAGE_IS_LAST;
} else {
pageNum = Integer.MAX_VALUE;
result.pages = Result.KEEP_LOADING;
}
}
return result;
}
public void parse(String body, int source) throws Exception {
AssertUtils.assertNotNull("Body is null when parse gallery list", body);
switch (source) {
default:
case EhClient.SOURCE_G:
case EhClient.SOURCE_EX: {
parse(body);
break;
}
case EhClient.SOURCE_LOFI: {
parseLofi(body);
break;
}
}
}
private String getRate(String rawRate) {
private static String getRate(String rawRate) {
Pattern p = Pattern.compile("\\d+px");
Matcher m = p.matcher(rawRate);
int num1;
@@ -204,11 +212,11 @@ public class GalleryListParser {
int rate = 5;
String re;
if (m.find())
num1 = Integer.parseInt(m.group().replace("px", ""));
num1 = ParserUtils.parseInt(m.group().replace("px", ""));
else
return null;
if (m.find())
num2 = Integer.parseInt(m.group().replace("px", ""));
num2 = ParserUtils.parseInt(m.group().replace("px", ""));
else
return null;
rate = rate - num1 / 16;
@@ -223,14 +231,14 @@ public class GalleryListParser {
private static final String PAU_SPACER = " by ";
private void getPostedAndUploader(String raw, String[] pau) throws AssertException {
private static void getPostedAndUploader(String raw, String[] pau) throws AssertException {
int index = raw.indexOf(PAU_SPACER);
AssertUtils.assertNotEqualsEx("Can not parse posted and uploader", index, -1);
pau[0] = raw.substring(0, index);
pau[1] = raw.substring(index + PAU_SPACER.length());
}
private int getStartNum(String str) {
private static int getStartNum(String str) {
int startNum = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == '*')
@@ -0,0 +1,34 @@
/*
* 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.ehviewer.client;
import com.hippo.util.Utils;
public class ParserUtils {
public static String trim(String str) {
// Avoid null
if (str == null) {
str = "";
}
return Utils.unescapeXml(str).trim();
}
public static int parseInt(String str) {
return Integer.parseInt(trim(str).replace(",", ""));
}
}
@@ -28,22 +28,27 @@ import java.util.List;
public class PopularParser {
public List<GalleryInfo> galleryInfoList;
public long timeStamp;
public static class Result {
public void parse(String body) throws Exception {
galleryInfoList = new ArrayList<>();
public long timeStamp;
public List<GalleryInfo> galleryInfos;
}
public static Result parse(String body) throws Exception {
Result result = new Result();
JSONObject js = new JSONObject(body);
js = js.getJSONObject("popular");
js = js.getJSONObject("popular");
if (!js.has("galleries")) {
if (js.has("error")) {
throw new EhException(js.getString("error"));
} else {
throw new EhException("Parser error"); // TODO
throw new ParseException("Can't parse popular", body);
}
}
List<GalleryInfo> list = new ArrayList<>();
result.galleryInfos = list;
JSONArray ja = js.getJSONArray("galleries");
for (int i = 0; i < ja.length(); i++) {
JSONObject j = ja.getJSONObject(i);
@@ -57,13 +62,15 @@ public class PopularParser {
gi.uploader = j.getString("uploader");
gi.rating = Float.parseFloat(j.getString("rating"));
gi.generateSLang();
galleryInfoList.add(gi);
list.add(gi);
}
if (js.has("time")) {
timeStamp = js.getLong("time");
result.timeStamp = js.getLong("time");
} else {
timeStamp = -1;
result.timeStamp = -1;
}
return result;
}
}
@@ -20,17 +20,15 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SignInParser {
public String displayname;
public boolean parse(String body) throws Exception {
public static String parse(String body) throws Exception {
Pattern p;
Matcher m;
p = Pattern.compile("<p>You are now logged in as: (.+?)<br />");
m = p.matcher(body);
if (m.find()) {
displayname = m.group(1);
return true;
return m.group(1);
} else {
p = Pattern.compile("(?:<h4>The error returned was:</h4>\\s*<p>(.+?)</p>)"
+ "|(?:<span class=\"postcolor\">(.+?)</span>)");
@@ -16,7 +16,8 @@
package com.hippo.ehviewer.client.data;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.widget.AdvanceSearchTable;
import com.hippo.network.UrlBuilder;
@@ -128,18 +129,18 @@ public class ListUrlBuilder {
case MODE_NORMAL:
case MODE_UPLOADER: {
boolean filter = false;
UrlBuilder ub = new UrlBuilder(EhClient.getUrlHeader(source));
UrlBuilder ub = new UrlBuilder(EhUrl.getUrlHeader(source));
if (mCategory != EhUtils.NONE) {
ub.addQuery("f_doujinshi", ((mCategory & EhUtils.DOUJINSHI) == 0) ? "0" : "1");
ub.addQuery("f_manga", ((mCategory & EhUtils.MANGA) == 0) ? "0" : "1");
ub.addQuery("f_artistcg", ((mCategory & EhUtils.ARTIST_CG) == 0) ? "0" : "1");
ub.addQuery("f_gamecg", ((mCategory & EhUtils.GAME_CG) == 0) ? "0" : "1");
ub.addQuery("f_western", ((mCategory & EhUtils.WESTERN) == 0) ? "0" : "1");
ub.addQuery("f_non-h", ((mCategory & EhUtils.NON_H) == 0) ? "0" : "1");
ub.addQuery("f_imageset", ((mCategory & EhUtils.IMAGE_SET) == 0) ? "0" : "1");
ub.addQuery("f_cosplay", ((mCategory & EhUtils.COSPLAY) == 0) ? "0" : "1");
ub.addQuery("f_asianporn", ((mCategory & EhUtils.ASIAN_PORN) == 0) ? "0" : "1");
ub.addQuery("f_misc", ((mCategory & EhUtils.MISC) == 0) ? "0" : "1");
ub.addQuery("f_doujinshi", ((mCategory & EhConfig.DOUJINSHI) == 0) ? "0" : "1");
ub.addQuery("f_manga", ((mCategory & EhConfig.MANGA) == 0) ? "0" : "1");
ub.addQuery("f_artistcg", ((mCategory & EhConfig.ARTIST_CG) == 0) ? "0" : "1");
ub.addQuery("f_gamecg", ((mCategory & EhConfig.GAME_CG) == 0) ? "0" : "1");
ub.addQuery("f_western", ((mCategory & EhConfig.WESTERN) == 0) ? "0" : "1");
ub.addQuery("f_non-h", ((mCategory & EhConfig.NON_H) == 0) ? "0" : "1");
ub.addQuery("f_imageset", ((mCategory & EhConfig.IMAGE_SET) == 0) ? "0" : "1");
ub.addQuery("f_cosplay", ((mCategory & EhConfig.COSPLAY) == 0) ? "0" : "1");
ub.addQuery("f_asianporn", ((mCategory & EhConfig.ASIAN_PORN) == 0) ? "0" : "1");
ub.addQuery("f_misc", ((mCategory & EhConfig.MISC) == 0) ? "0" : "1");
filter = true;
}
// Search key
@@ -180,10 +181,10 @@ public class ListUrlBuilder {
return ub.build();
}
case MODE_TAG: {
if (source == EhClient.SOURCE_LOFI) {
if (source == EhUrl.SOURCE_LOFI) {
throw new UnsupportedSearchException("Lofi do not support tag search");
}
StringBuilder sb = new StringBuilder(EhClient.getUrlHeader(source));
StringBuilder sb = new StringBuilder(EhUrl.getUrlHeader(source));
sb.append("tag/");
try {
sb.append(URLEncoder.encode(mKeyword, "UTF-8"));
@@ -0,0 +1,146 @@
/*
* 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.ehviewer.network;
import android.content.Context;
import android.os.Build;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.ehviewer.util.Settings;
import com.hippo.httpclient.Cookie;
import com.hippo.httpclient.HttpClient;
import com.hippo.util.MathUtils;
import com.hippo.util.Utils;
import java.net.URL;
public class EhHttpClient extends HttpClient {
private static String[] EHENTAI_DOMAIN = {
"exhentai.org",
"e-hentai.org"
};
private static final String HOST_EX = "exhentai.org";
private static final String KEY_IPD_MEMBER_ID = "ipb_member_id";
private static final String KEY_IPD_PASS_HASH = "ipb_pass_hash";
private static final String KEY_IGNEOUS = "igneous";
private static final String KEY_YAY = "yay";
private final CookieManager mCookieManager;
private EhConfig mEhConfig;
@SuppressWarnings("deprecation")
public EhHttpClient(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
CookieSyncManager.createInstance(context);
}
mCookieManager = CookieManager.getInstance();
mEhConfig = Settings.getEhConfig();
}
private String getDomain(URL uri) {
String host = uri.getHost();
int length = host.length();
int dotCount = 0;
int i = length;
while(i-- != 0) {
char ch = host.charAt(i);
if (ch == '.') {
dotCount++;
}
if (dotCount == 2) {
// Get it
break;
}
}
return host.substring(MathUtils.clamp(i + 1, 0, length));
}
@Override
protected void fillCookie(URL url, Cookie cookie) {
boolean isSignIn = Settings.getSignIn();
String host = url.getHost();
cookie.putRaw(mCookieManager.getCookie(url.toString()));
if (Utils.contain(EHENTAI_DOMAIN, getDomain(url)))
if (!isSignIn && HOST_EX.equals(host)) {
cookie.put("yay", "louder");
} else {
cookie.putRaw(mCookieManager.getCookie(url.toString()));
if (Utils.contain(EHENTAI_DOMAIN, getDomain(url))) {
if (Settings.getSignIn()) {
// Put login info
String ipdMemberId = Settings.getIpdNumberId();
String ipdPassHash = Settings.getIpdPassHash();
String igneous = Settings.getIgneous();
if (ipdMemberId != null) {
cookie.put(KEY_IPD_MEMBER_ID, ipdMemberId);
}
if (ipdPassHash != null) {
cookie.put(KEY_IPD_PASS_HASH, ipdPassHash);
}
if (igneous != null) {
cookie.put(KEY_IGNEOUS, igneous);
}
} else if (HOST_EX.equals(url.getHost())) {
cookie.put("yay", "louder");
}
mEhConfig.fillCookie(cookie);
}
}
}
@Override
protected void storeCookie(URL url, String cookieStr) {
Cookie cookie = new Cookie();
cookie.putRaw(cookieStr);
String ipdMemberId = cookie.get(KEY_IPD_MEMBER_ID);
String ipdPassHash = cookie.get(KEY_IPD_PASS_HASH);
String igneous = cookie.get(KEY_IGNEOUS);
if (ipdMemberId != null) {
Settings.putIpdMemberId(ipdMemberId);
}
if (ipdPassHash != null) {
Settings.putIpdPassHash(ipdPassHash);
}
if (igneous != null) {
Settings.putIgneous(igneous);
}
cookie.remove(KEY_IPD_MEMBER_ID);
cookie.remove(KEY_IPD_MEMBER_ID);
cookie.remove(KEY_IGNEOUS);
cookie.remove(KEY_YAY);
cookie.remove(EhConfig.KEY_UCONFIG);
cookie.remove(EhConfig.KEY_LOFI_RESOLUTION);
cookie.remove(EhConfig.KEY_CONTENT_WARNING);
mCookieManager.setCookie(url.toString(), cookie.toString());
}
}
@@ -0,0 +1,67 @@
/*
* 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.ehviewer.network;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.ehviewer.client.EhException;
import com.hippo.httpclient.Cookie;
import com.hippo.httpclient.HttpRequest;
import com.hippo.httpclient.ResponseCodeException;
import java.net.HttpURLConnection;
import java.net.URL;
public class EhHttpRequest extends HttpRequest {
private static final String SAD_PANDA_DISPOSITION = "inline; filename=\"sadpanda.jpg\"";
private static final String SAD_PANDA_TYPE = "image/gif";
private static final String SAD_PANDA_LENGTH = "9615";
private EhConfig mEhConfig;
public void setEhConfig(EhConfig ehConfig) {
mEhConfig = ehConfig;
}
@Override
protected void fillCookie(URL url, Cookie cookie) {
super.fillCookie(url, cookie);
if (mEhConfig != null) {
mEhConfig.fillCookie(cookie);
}
}
@Override
protected void onAfterConnect(HttpURLConnection conn) throws Exception {
super.onAfterConnect(conn);
final int responseCode = conn.getResponseCode();
if (responseCode >= 400) {
throw new ResponseCodeException(responseCode);
}
String disposition = conn.getHeaderField("Content-Disposition");
String type = conn.getHeaderField("Content-Type");
String length = conn.getHeaderField("Content-Length");
if (SAD_PANDA_DISPOSITION.equals(disposition) && SAD_PANDA_TYPE.equals(type) &&
SAD_PANDA_LENGTH.equals(length)) {
throw new EhException("Sad Panda");
}
}
}
@@ -1,193 +0,0 @@
/*
* Copyright (C) 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.ehviewer.network;
import android.webkit.CookieManager;
import com.hippo.ehviewer.util.Config;
import com.hippo.network.Cookie;
import com.hippo.util.MathUtils;
import com.hippo.util.Utils;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
import java.io.IOException;
import java.net.CookieHandler;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
public class EhOkHttpClient extends OkHttpClient {
public static final String DEFAULT_USER_AGENT =
"Mozilla/5.0 (Windows NT 6.1; WOW64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) " +
"Chrome/39.0.2171.95 Safari/537.36";
public static final String USER_AGENT =
System.getProperty("http.agent", DEFAULT_USER_AGENT);
private static String[] EHENTAI_DOMAIN = {
"exhentai.org",
"e-hentai.org"
};
private static final String HOST_EX = "exhentai.org";
private static final String HOST_LOFI = "lofi.e-hentai.org";
private static final String KEY_IPD_MEMBER_ID = "ipb_member_id";
private static final String KEY_IPD_PASS_HASH = "ipb_pass_hash";
private static final String KEY_IGNEOUS = "igneous";
private static final String KEY_UCONFIG = "uconfig";
private static final String KEY_XRES = "xres";
private static final String KEY_YAY = "yay";
private static CookieHandler mCookieHandler = new CookieHandler() {
private final CookieManager mCookieManager = CookieManager.getInstance();
public String getDomain(URI uri) {
String host = uri.getHost();
int length = host.length();
int dotCount = 0;
int i = length;
while(i-- != 0) {
char ch = host.charAt(i);
if (ch == '.') {
dotCount++;
}
if (dotCount == 2) {
// Get it
break;
}
}
return host.substring(MathUtils.clamp(i + 1, 0, length));
}
@Override
public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException {
boolean isSignIn = Config.getSignIn();
String host = uri.getHost();
Cookie cookie = new Cookie();
if (!isSignIn && HOST_EX.equals(host)) {
cookie.put("yay", "louder");
} else {
cookie.putRaw(mCookieManager.getCookie(uri.toString()));
if (isSignIn && Utils.contain(EHENTAI_DOMAIN, getDomain(uri))) {
String ipdMemberId = Config.getIpdNumberId();
String ipdPassHash = Config.getIpdPassHash();
String igneous = Config.getIgneous();
if (ipdMemberId != null) {
cookie.put(KEY_IPD_MEMBER_ID, ipdMemberId);
}
if (ipdPassHash != null) {
cookie.put(KEY_IPD_PASS_HASH, ipdPassHash);
}
if (igneous != null) {
cookie.put(KEY_IGNEOUS, igneous);
}
// TODO cookie.put(KEY_UCONFIG, Config.getUconfig());
}
if (HOST_LOFI.equals(host)) {
// TODO cookie.put(KEY_XRES, Config.getXres());
}
}
List<String> cookieList = new ArrayList<>();
cookieList.add(cookie.toString());
// Map to return
Map<String, List<String>> cookieMap = new HashMap<>(requestHeaders);
cookieMap.put("Cookie" , cookieList);
return Collections.unmodifiableMap(cookieMap);
}
@Override
public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException {
Cookie cookie = new Cookie();
List<String> cookieList = responseHeaders.get("Set-Cookie");
if (cookieList != null) {
for (String cookieString : cookieList) {
cookie.putRaw(cookieString);
}
}
String ipdMemberId = cookie.get(KEY_IPD_MEMBER_ID);
String ipdPassHash = cookie.get(KEY_IPD_PASS_HASH);
String igneous = cookie.get(KEY_IGNEOUS);
if (ipdMemberId != null) {
Config.putIpdMemberId(ipdMemberId);
}
if (ipdPassHash != null) {
Config.putIpdPassHash(ipdPassHash);
}
if (igneous != null) {
Config.putIgneous(igneous);
}
cookie.remove(KEY_IPD_MEMBER_ID);
cookie.remove(KEY_IPD_MEMBER_ID);
cookie.remove(KEY_UCONFIG);
cookie.remove(KEY_XRES);
cookie.remove(KEY_YAY);
mCookieManager.setCookie(uri.toString(), cookie.toString());
}
};
public static class UserAgentInterceptor implements Interceptor {
private String mUserAgent;
public UserAgentInterceptor(String userAgent) {
mUserAgent = userAgent;
}
@Override
public Response intercept(Chain chain) throws IOException {
Request originalRequest = chain.request();
Request requestWithUserAgent = originalRequest.newBuilder()
.removeHeader("User-Agent")
.addHeader("User-Agent", mUserAgent)
.build();
return chain.proceed(requestWithUserAgent);
}
}
private static final EhOkHttpClient sInstance = new EhOkHttpClient();
public static EhOkHttpClient getInstance() {
return sInstance;
}
private EhOkHttpClient() {
setCookieHandler(mCookieHandler);
setConnectTimeout(5, TimeUnit.SECONDS);
setReadTimeout(5, TimeUnit.SECONDS);
setFollowRedirects(true);
networkInterceptors().add(new UserAgentInterceptor(USER_AGENT));
}
}
@@ -31,7 +31,7 @@ import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.scene.GalleryListScene;
import com.hippo.ehviewer.ui.scene.MainSettingsScene;
import com.hippo.ehviewer.ui.scene.SignInScene;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.Settings;
import com.hippo.ehviewer.widget.DrawerLeftPanel;
import com.hippo.ehviewer.widget.FitStageLayout;
import com.hippo.scene.Announcer;
@@ -130,7 +130,7 @@ public final class ContentActivity extends StageActivity
@Override
protected boolean isShowStats() {
return Config.getShowApplicationStats();
return Settings.getShowApplicationStats();
}
@SuppressLint("RtlHardcoded")
@@ -242,7 +242,7 @@ public final class ContentActivity extends StageActivity
@Override
public void onClickSignOut() {
Config.putSignIn(false);
Settings.putSignIn(false);
Messenger.getInstance().notify(Constants.MESSENGER_ID_SIGN_IN_OR_OUT, null);
}
}
@@ -38,14 +38,16 @@ import com.hippo.ehviewer.EhImageKeyFactory;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhException;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.ehviewer.client.OffensiveException;
import com.hippo.ehviewer.client.data.Comment;
import com.hippo.ehviewer.client.data.GalleryDetail;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.PreviewSet;
import com.hippo.ehviewer.client.data.TagGroup;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.util.Settings;
import com.hippo.ehviewer.widget.LoadImageView;
import com.hippo.ehviewer.widget.PreviewLayout;
import com.hippo.ehviewer.widget.RatingView;
@@ -118,9 +120,16 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
private GalleryDetail mGalleryDetail;
private void requestGalleryDetail(GalleryInfo gi) {
EhClient.getInstance().getGalleryDetail(Config.getEhSource(),
EhClient.getDetailUrl(Config.getEhSource(), gi.gid, gi.token, 0),
new EhDetailListener());
EhClient client = EhApplication.getEhClient(getStageActivity());
int source = Settings.getEhSource();
String url = EhUrl.getDetailUrl(source, gi.gid, gi.token, 0);
EhRequest request = new EhRequest();
request.setMethod(EhClient.METHOD_GET_GALLERY_DETAIL);
request.setEhListener(new EhDetailListener());
request.setArgs(url, source);
// TODO request.setEhConfig();
client.execute(request);
}
private void handleAnnouncer(Announcer announcer) {
@@ -270,7 +279,7 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
} else if (v == mShare) {
StartActivityHelper.share(getStageActivity(),
EhClient.getDetailUrl(Config.getEhSource(), gd.gid, gd.token, 0));
EhUrl.getDetailUrl(Settings.getEhSource(), gd.gid, gd.token, 0));
}
}
@@ -421,7 +430,7 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
}
}
private class EhDetailListener extends EhClient.OnGetGalleryDetailListener {
private class EhDetailListener extends EhClient.EhListener<GalleryDetail> {
@Override
public void onSuccess(GalleryDetail galleryDetail) {
@@ -483,28 +492,44 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
}).show(GalleryDetailScene.this);
}
}
@Override
public void onCanceled() {
}
}
class SimplePreviewHelper implements PreviewLayout.PreviewHelper {
@Override
public void onRequstPreview(PreviewLayout previewLayout, final int index) {
int source = Config.getEhSource();
EhClient.getInstance().getPreviewSet(source,
EhClient.getDetailUrl(source, mGalleryDetail.gid, mGalleryDetail.token, index),
new EhClient.OnGetPreviewSetListener() {
EhClient client = EhApplication.getEhClient(getStageActivity());
int source = Settings.getEhSource();
String url = EhUrl.getDetailUrl(source, mGalleryDetail.gid, mGalleryDetail.token, index);
@Override
public void onSuccess(PreviewSet previewSet) {
mPreviewLayout.onGetPreview(previewSet, index);
}
EhRequest request = new EhRequest();
request.setMethod(EhClient.METHOD_GET_PREVIEW_SET);
// TODO request.setEhConfig();
request.setArgs(url, source);
request.setEhListener(new EhClient.EhListener<PreviewSet>() {
@Override
public void onFailure(Exception e) {
// TODO
e.printStackTrace();
}
});
@Override
public void onSuccess(PreviewSet result) {
mPreviewLayout.onGetPreview(result, index);
}
@Override
public void onFailure(Exception e) {
e.printStackTrace();
}
@Override
public void onCanceled() {
}
});
client.execute(request);
}
@Override
@@ -44,13 +44,16 @@ import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.EhImageKeyFactory;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.ehviewer.client.GalleryListParser;
import com.hippo.ehviewer.client.PopularParser;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.data.UnsupportedSearchException;
import com.hippo.ehviewer.ui.ContentActivity;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.util.Settings;
import com.hippo.ehviewer.widget.ContentLayout;
import com.hippo.ehviewer.widget.LoadImageView;
import com.hippo.ehviewer.widget.OffsetLayout;
@@ -72,8 +75,6 @@ import com.hippo.widget.FabLayout;
import com.hippo.widget.FloatingActionButton;
import com.hippo.widget.recyclerview.EasyRecyclerView;
import java.util.List;
// TODO remeber the data in ContentHelper after screen dirction change
// TODO Must refresh when change source
// TODO disable click action when animating
@@ -891,22 +892,33 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
@Override
protected void getPageData(int taskId, int type, int page) {
EhClient client = EhApplication.getEhClient(getStageActivity());
int mode = mListUrlBuilder.getMode();
if (mode == ListUrlBuilder.MODE_POPULAR) {
PopularListener listener = new PopularListener(taskId);
listener.setGalleryListHelper(this);
mListener = listener;
EhClient.getInstance().getPopular(listener);
EhRequest request = new EhRequest();
request.setMethod(EhClient.METHOD_GET_POPULAR);
request.setEhListener(listener);
client.execute(request);
} else {
try {
int source = Config.getEhSource();
int source = Settings.getEhSource();
mListUrlBuilder.setPageIndex(page);
String url = mListUrlBuilder.build(source);
GalleryListListener listener = new GalleryListListener(taskId,
type, page, source);
listener.setGalleryListHelper(this);
mListener = listener;
EhClient.getInstance().getGalleryList(source, url, listener);
EhRequest request = new EhRequest();
request.setMethod(EhClient.METHOD_GET_GALLERY_LIST);
request.setEhListener(listener);
request.setArgs(url, source);
client.execute(request);
} catch (UnsupportedSearchException e) {
onGetPageData(taskId, e);
}
@@ -940,7 +952,7 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
}
}
private static class GalleryListListener extends EhClient.OnGetGalleryListListener
private static class GalleryListListener extends EhClient.EhListener<GalleryListParser.Result>
implements GalleryListHelperSettable {
private int mTaskId;
@@ -963,18 +975,18 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
}
@Override
public void onSuccess(List<GalleryInfo> glList, int pageNum) {
public void onSuccess(GalleryListParser.Result result) {
if (mHelper != null) {
if (mSource == EhClient.SOURCE_LOFI) {
if (pageNum == GalleryListParser.CURRENT_PAGE_IS_LAST) {
if (mSource == EhUrl.SOURCE_LOFI) {
if (result.pages == GalleryListParser.Result.CURRENT_PAGE_IS_LAST) {
mHelper.setPageCount(mTargetPage);
} else if (mTaskType == ContentLayout.ContentHelper.TYPE_REFRESH) {
mHelper.setPageCount(Integer.MAX_VALUE);
}
} else {
mHelper.setPageCount(pageNum);
mHelper.setPageCount(result.pages);
}
mHelper.onGetPageData(mTaskId, glList);
mHelper.onGetPageData(mTaskId, result.galleryInfos);
mHelper.clearLastGalleryListHelperSettable(this);
}
@@ -988,9 +1000,14 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
mHelper.clearLastGalleryListHelperSettable(this);
}
}
@Override
public void onCanceled() {
}
}
private static class PopularListener extends EhClient.OnGetPopularListener
private static class PopularListener extends EhClient.EhListener<PopularParser.Result>
implements GalleryListHelperSettable {
private int mTaskId;
@@ -1006,10 +1023,10 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
}
@Override
public void onSuccess(List<GalleryInfo> glList, long timeStamp) {
public void onSuccess(PopularParser.Result result) {
if (mHelper != null) {
mHelper.setPageCount(1);
mHelper.onGetPageData(mTaskId, glList);
mHelper.onGetPageData(mTaskId, result.galleryInfos);
mHelper.clearLastGalleryListHelperSettable(this);
}
@@ -1023,6 +1040,11 @@ public final class GalleryListScene extends Scene implements SearchBar.Helper,
mHelper.clearLastGalleryListHelperSettable(this);
}
}
@Override
public void onCanceled() {
}
}
private interface GalleryListHelperSettable {
@@ -23,9 +23,11 @@ import android.widget.EditText;
import android.widget.TextView;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.ehviewer.util.Settings;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.Scene;
import com.hippo.util.Messenger;
@@ -39,11 +41,11 @@ public final class SignInScene extends Scene implements View.OnClickListener,
private TextView mSignUp;
private TextView mSignIn;
private EhClient.OnSignInListener mSignInListener = new EhClient.OnSignInListener() {
private EhClient.EhListener<String> mSignInListener = new EhClient.EhListener<String>() {
@Override
public void onSuccess(String displayname) {
Config.putSignIn(true);
Config.putDisplayName(displayname);
Settings.putSignIn(true);
Settings.putDisplayName(displayname);
Messenger.getInstance().notify(Constants.MESSENGER_ID_SIGN_IN_OR_OUT, displayname);
}
@@ -51,6 +53,11 @@ public final class SignInScene extends Scene implements View.OnClickListener,
public void onFailure(Exception e) {
e.printStackTrace();
}
@Override
public void onCanceled() {
}
};
@Override
@@ -88,7 +95,13 @@ public final class SignInScene extends Scene implements View.OnClickListener,
if (v == mSignIn) {
String username = mUsername.getText().toString();
String password = mPassword.getText().toString();
EhClient.getInstance().signIn(username, password, mSignInListener);
EhClient client = EhApplication.getEhClient(getStageActivity());
EhRequest request = new EhRequest();
request.setMethod(EhClient.METHOD_SIGN_IN);
request.setEhListener(mSignInListener);
request.setArgs(username, password);
client.execute(request);
}
}
@@ -18,10 +18,9 @@ package com.hippo.ehviewer.ui.scene.preference;
import android.content.res.Resources;
import com.hippo.ehviewer.BuildConfig;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.scene.preference.ListPreference;
import com.hippo.scene.preference.Preference;
import com.hippo.scene.preference.PreferenceCategory;
@@ -32,8 +31,7 @@ import com.hippo.util.Messenger;
public final class EHSettingsScene extends PreferenceScene {
private static final String KEY_EH_SOURCE = "eh_source";
private static final int DEFAULT_EH_SOURCE = BuildConfig.DEBUG ?
EhClient.SOURCE_EX : EhClient.SOURCE_G;
private static final int DEFAULT_EH_SOURCE = EhUrl.SOURCE_G;
@Override
protected void onCreate(boolean rebirth) {
@@ -18,6 +18,8 @@ package com.hippo.ehviewer.util;
import android.graphics.Color;
import com.hippo.ehviewer.client.EhConfig;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;
@@ -29,16 +31,6 @@ public final class EhUtils {
public static final String EH_DOWNLOAD_FILENAME = ".ehviewer";
public static final int NONE = -1; // Use it for homepage
public static final int MISC = 0x1;
public static final int DOUJINSHI = 0x2;
public static final int MANGA = 0x4;
public static final int ARTIST_CG = 0x8;
public static final int GAME_CG = 0x10;
public static final int IMAGE_SET = 0x20;
public static final int COSPLAY = 0x40;
public static final int ASIAN_PORN = 0x80;
public static final int NON_H = 0x100;
public static final int WESTERN = 0x200;
public static final int UNKNOWN = 0x400;
public static final int BG_COLOR_DOUJINSHI = 0xfff44336;
@@ -54,16 +46,16 @@ public final class EhUtils {
public static final int BG_COLOR_UNKNOWN = Color.BLACK;
private static final int[] CATEGORY_VALUES = {
MISC,
DOUJINSHI,
MANGA,
ARTIST_CG,
GAME_CG,
IMAGE_SET,
COSPLAY,
ASIAN_PORN,
NON_H,
WESTERN,
EhConfig.MISC,
EhConfig.DOUJINSHI,
EhConfig.MANGA,
EhConfig.ARTIST_CG,
EhConfig.GAME_CG,
EhConfig.IMAGE_SET,
EhConfig.COSPLAY,
EhConfig.ASIAN_PORN,
EhConfig.NON_H,
EhConfig.WESTERN,
UNKNOWN };
private static final String[][] CATEGORY_STRINGS = {
@@ -102,25 +94,25 @@ public final class EhUtils {
public static int getCategoryColor(int category) {
switch (category) {
case DOUJINSHI:
case EhConfig.DOUJINSHI:
return BG_COLOR_DOUJINSHI;
case MANGA:
case EhConfig.MANGA:
return BG_COLOR_MANGA;
case ARTIST_CG:
case EhConfig.ARTIST_CG:
return BG_COLOR_ARTIST_CG;
case GAME_CG:
case EhConfig.GAME_CG:
return BG_COLOR_GAME_CG;
case WESTERN:
case EhConfig.WESTERN:
return BG_COLOR_WESTERN;
case NON_H:
case EhConfig.NON_H:
return BG_COLOR_NON_H;
case IMAGE_SET:
case EhConfig.IMAGE_SET:
return BG_COLOR_IMAGE_SET;
case COSPLAY:
case EhConfig.COSPLAY:
return BG_COLOR_COSPLAY;
case ASIAN_PORN:
case EhConfig.ASIAN_PORN:
return BG_COLOR_ASIAN_PORN;
case MISC:
case EhConfig.MISC:
return BG_COLOR_MISC;
default:
return BG_COLOR_UNKNOWN;
@@ -1,11 +1,11 @@
/*
* Copyright (C) 2015 Hippo Seven
* 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
* 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,
@@ -21,64 +21,60 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import com.hippo.ehviewer.BuildConfig;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.ehviewer.client.EhUrl;
public final class Config {
public final class Settings {
private static SharedPreferences sConfigPre;
private Config() {
}
private static SharedPreferences sSettingsPre;
public static void initialize(Context context) {
sConfigPre = PreferenceManager.getDefaultSharedPreferences(context);
sSettingsPre = PreferenceManager.getDefaultSharedPreferences(context);
}
public static boolean getBoolean(String key, boolean defValue) {
return sConfigPre.getBoolean(key, defValue);
return sSettingsPre.getBoolean(key, defValue);
}
public static void putBoolean(String key, boolean value) {
sConfigPre.edit().putBoolean(key, value).apply();
sSettingsPre.edit().putBoolean(key, value).apply();
}
public static int getInt(String key, int defValue) {
return sConfigPre.getInt(key, defValue);
return sSettingsPre.getInt(key, defValue);
}
public static void putInt(String key, int value) {
sConfigPre.edit().putInt(key, value).apply();
sSettingsPre.edit().putInt(key, value).apply();
}
public static long getLong(String key, long defValue) {
return sConfigPre.getLong(key, defValue);
return sSettingsPre.getLong(key, defValue);
}
public static void putLong(String key, long value) {
sConfigPre.edit().putLong(key, value).apply();
sSettingsPre.edit().putLong(key, value).apply();
}
public static float getFloat(String key, float defValue) {
return sConfigPre.getFloat(key, defValue);
return sSettingsPre.getFloat(key, defValue);
}
public static void putFloat(String key, float value) {
sConfigPre.edit().putFloat(key, value).apply();
sSettingsPre.edit().putFloat(key, value).apply();
}
public static String getString(String key, String defValue) {
return sConfigPre.getString(key, defValue);
return sSettingsPre.getString(key, defValue);
}
public static void putString(String key, String value) {
sConfigPre.edit().putString(key, value).apply();
sSettingsPre.edit().putString(key, value).apply();
}
/****** ******/
/****** EH ******/
private static final String KEY_EH_SOURCE = "eh_source";
private static final int DEFAULT_EH_SOURCE = BuildConfig.DEBUG ?
EhClient.SOURCE_EX : EhClient.SOURCE_G;
private static final int DEFAULT_EH_SOURCE = EhUrl.SOURCE_G;
private static final String KEY_SIGN_IN = "sign_in";
private static final boolean DEFAULT_SIGN_IN = false;
private static final String KEY_DISPLAY_NAME = "display_name";
@@ -92,14 +88,14 @@ public final class Config {
public static int getEhSource() {
int value = getInt(KEY_EH_SOURCE, DEFAULT_EH_SOURCE);
if (value < EhClient.SOURCE_G || value > EhClient.SOURCE_LOFI) {
if (value < EhUrl.SOURCE_G || value > EhUrl.SOURCE_LOFI) {
value = DEFAULT_EH_SOURCE;
}
return value;
}
public static void putEhSource(int value) {
if (value < EhClient.SOURCE_G || value > EhClient.SOURCE_LOFI) {
if (value < EhUrl.SOURCE_G || value > EhUrl.SOURCE_LOFI) {
value = DEFAULT_EH_SOURCE;
}
putInt(KEY_EH_SOURCE, value);
@@ -152,9 +148,14 @@ public final class Config {
}
}
/****** EhConfig ******/
private static EhConfig sEhConfig = new EhConfig();
public static EhConfig getEhConfig() {
return sEhConfig;
}
/****** Advance ******/
private static final String KEY_SHOW_APPLICATION_STATS = "show_application_stats";
private static final boolean DEFAULT_SHOW_APPLICATION_STATS = BuildConfig.DEBUG;
@@ -25,7 +25,7 @@ import android.view.ViewGroup;
import android.widget.TableLayout;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.util.Utils;
import com.hippo.widget.CheckTextView;
@@ -86,16 +86,16 @@ public class CategoryTable extends TableLayout {
* @param category target category
*/
public void setCategory(int category) {
mDoujinshi.setChecked(!Utils.int2boolean(category & EhUtils.DOUJINSHI), false);
mManga.setChecked(!Utils.int2boolean(category & EhUtils.MANGA), false);
mArtistCG.setChecked(!Utils.int2boolean(category & EhUtils.ARTIST_CG), false);
mGameCG.setChecked(!Utils.int2boolean(category & EhUtils.GAME_CG), false);
mWestern.setChecked(!Utils.int2boolean(category & EhUtils.WESTERN), false);
mNonH.setChecked(!Utils.int2boolean(category & EhUtils.NON_H), false);
mImageSets.setChecked(!Utils.int2boolean(category & EhUtils.IMAGE_SET), false);
mCosplay.setChecked(!Utils.int2boolean(category & EhUtils.COSPLAY), false);
mAsianPorn.setChecked(!Utils.int2boolean(category & EhUtils.ASIAN_PORN), false);
mMisc.setChecked(!Utils.int2boolean(category & EhUtils.MISC), false);
mDoujinshi.setChecked(!Utils.int2boolean(category & EhConfig.DOUJINSHI), false);
mManga.setChecked(!Utils.int2boolean(category & EhConfig.MANGA), false);
mArtistCG.setChecked(!Utils.int2boolean(category & EhConfig.ARTIST_CG), false);
mGameCG.setChecked(!Utils.int2boolean(category & EhConfig.GAME_CG), false);
mWestern.setChecked(!Utils.int2boolean(category & EhConfig.WESTERN), false);
mNonH.setChecked(!Utils.int2boolean(category & EhConfig.NON_H), false);
mImageSets.setChecked(!Utils.int2boolean(category & EhConfig.IMAGE_SET), false);
mCosplay.setChecked(!Utils.int2boolean(category & EhConfig.COSPLAY), false);
mAsianPorn.setChecked(!Utils.int2boolean(category & EhConfig.ASIAN_PORN), false);
mMisc.setChecked(!Utils.int2boolean(category & EhConfig.MISC), false);
}
/**
@@ -104,16 +104,16 @@ public class CategoryTable extends TableLayout {
*/
public int getCategory() {
int category = 0;
if (!mDoujinshi.isChecked()) category |= EhUtils.DOUJINSHI;
if (!mManga.isChecked()) category |= EhUtils.MANGA;
if (!mArtistCG.isChecked()) category |= EhUtils.ARTIST_CG;
if (!mGameCG.isChecked()) category |= EhUtils.GAME_CG;
if (!mWestern.isChecked()) category |= EhUtils.WESTERN;
if (!mNonH.isChecked()) category |= EhUtils.NON_H;
if (!mImageSets.isChecked()) category |= EhUtils.IMAGE_SET;
if (!mCosplay.isChecked()) category |= EhUtils.COSPLAY;
if (!mAsianPorn.isChecked()) category |= EhUtils.ASIAN_PORN;
if (!mMisc.isChecked()) category |= EhUtils.MISC;
if (!mDoujinshi.isChecked()) category |= EhConfig.DOUJINSHI;
if (!mManga.isChecked()) category |= EhConfig.MANGA;
if (!mArtistCG.isChecked()) category |= EhConfig.ARTIST_CG;
if (!mGameCG.isChecked()) category |= EhConfig.GAME_CG;
if (!mWestern.isChecked()) category |= EhConfig.WESTERN;
if (!mNonH.isChecked()) category |= EhConfig.NON_H;
if (!mImageSets.isChecked()) category |= EhConfig.IMAGE_SET;
if (!mCosplay.isChecked()) category |= EhConfig.COSPLAY;
if (!mAsianPorn.isChecked()) category |= EhConfig.ASIAN_PORN;
if (!mMisc.isChecked()) category |= EhConfig.MISC;
return category;
}
@@ -30,7 +30,7 @@ import android.widget.TextView;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.Settings;
import com.hippo.rippleold.RippleSalon;
import com.hippo.util.Messenger;
import com.hippo.widget.DrawerListView;
@@ -135,11 +135,11 @@ public class DrawerLeftPanel extends LinearLayout implements FitPaddingImpl {
mUserPanelOriginalPaddingTop = mUserPanel.getPaddingTop();
mDrawerListViewOriginalPaddingBottom = mDrawerListView.getPaddingBottom();
mSignIn = Config.getSignIn();
mSignIn = Settings.getSignIn();
if (mSignIn) {
// TODO
mAvatar.setImageResource(DEFAULT_AVATAR_ID);
mUsename.setText(Config.getDisplayName());
mUsename.setText(Settings.getDisplayName());
mAction.setText(getContext().getString(R.string.signout));
} else {
mAvatar.setImageResource(DEFAULT_AVATAR_ID);
@@ -51,8 +51,8 @@ import com.hippo.drawable.DrawerArrowDrawable;
import com.hippo.effect.ViewTransition;
import com.hippo.ehviewer.Constants;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.ehviewer.util.Settings;
import com.hippo.util.MathUtils;
import com.hippo.util.Messenger;
import com.hippo.util.ViewUtils;
@@ -162,7 +162,7 @@ public class SearchBar extends CardView implements View.OnClickListener,
}
});
setSource(Config.getEhSource());
setSource(Settings.getEhSource());
}
@Override
@@ -192,7 +192,7 @@ public class SearchBar extends CardView implements View.OnClickListener,
Drawable searchImage = resources.getDrawable(R.drawable.ic_search);
SpannableStringBuilder ssb = new SpannableStringBuilder(" ");
ssb.append(String.format(resources.getString(R.string.search_bar_hint),
EhClient.getReadableHost(source)));
EhUrl.getReadableHost(source)));
int textSize = (int) (mEditText.getTextSize() * 1.25);
searchImage.setBounds(0, 0, textSize, textSize);
ssb.setSpan(new ImageSpan(searchImage), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -1,86 +0,0 @@
/*
* Copyright (C) 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.network;
import com.hippo.util.Utils;
import java.util.HashMap;
import java.util.Map;
public class Cookie {
private static final String KEY_DOMAIN = "domain";
private static final String KEY_PATH = "path";
private static final String KEY_EXPIRES = "expires";
private static final String[] UNSUPPORT_KEY = {
KEY_DOMAIN,
KEY_PATH,
KEY_EXPIRES
};
private Map<String, String> mItems = new HashMap<>();
public void putRaw(String cookieString) {
if (cookieString != null) {
String[] pieces = cookieString.split(";");
for (String p : pieces) {
int index = p.indexOf('=');
if (index != -1) {
String key = p.substring(0, index).trim();
String value = p.substring(index + 1).trim();
if (!Utils.contain(UNSUPPORT_KEY, key)) {
mItems.put(key, value);
}
}
}
}
}
public void put(String key, String value) {
if (!Utils.contain(UNSUPPORT_KEY, key)) {
mItems.put(key, value);
}
}
public void remove(String key) {
mItems.remove(key);
}
public String get(String key) {
return mItems.get(key);
}
public String toString() {
StringBuilder sb = new StringBuilder();
String separator1 = "; ";
String separator2 = "=";
boolean first = true;
for (String key : mItems.keySet()) {
String value = mItems.get(key);
if (first) {
first = false;
} else {
sb.append(separator1);
}
sb.append(key).append(separator2).append(value);
}
return sb.toString();
}
}
@@ -1,87 +0,0 @@
/*
* Copyright (C) 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.network;
import android.util.SparseArray;
public class ResponseCodeException extends Exception {
private static final SparseArray<String> ERROR_MESSAGE_ARRAY;
private static final String DEFAULT_ERROR_MESSAGE = "Error response code";
private final int mResponseCode;
private final String mMessage;
static {
ERROR_MESSAGE_ARRAY = new SparseArray<>(24);
ERROR_MESSAGE_ARRAY.append(400, "Bad Request");
ERROR_MESSAGE_ARRAY.append(401, "Unauthorized");
ERROR_MESSAGE_ARRAY.append(402, "Payment Required");
ERROR_MESSAGE_ARRAY.append(403, "Forbidden");
ERROR_MESSAGE_ARRAY.append(404, "Not Found");
ERROR_MESSAGE_ARRAY.append(405, "Method Not Allowed");
ERROR_MESSAGE_ARRAY.append(406, "Not Acceptable");
ERROR_MESSAGE_ARRAY.append(407, "Proxy Authentication Required");
ERROR_MESSAGE_ARRAY.append(408, "Request Timeout");
ERROR_MESSAGE_ARRAY.append(409, "Conflict");
ERROR_MESSAGE_ARRAY.append(410, "Gone");
ERROR_MESSAGE_ARRAY.append(411, "Length Required");
ERROR_MESSAGE_ARRAY.append(412, "Precondition Failed");
ERROR_MESSAGE_ARRAY.append(413, "Request Entity Too Large");
ERROR_MESSAGE_ARRAY.append(414, "Request-URI Too Long");
ERROR_MESSAGE_ARRAY.append(415, "Unsupported Media Type");
ERROR_MESSAGE_ARRAY.append(416, "Requested Range Not Satisfiable");
ERROR_MESSAGE_ARRAY.append(417, "Expectation Failed");
ERROR_MESSAGE_ARRAY.append(500, "Internal Server Error");
ERROR_MESSAGE_ARRAY.append(501, "Not Implemented");
ERROR_MESSAGE_ARRAY.append(502, "Bad Gateway");
ERROR_MESSAGE_ARRAY.append(503, "Service Unavailable");
ERROR_MESSAGE_ARRAY.append(504, "Gateway Timeout");
ERROR_MESSAGE_ARRAY.append(505, "HTTP Version Not Supported");
}
public ResponseCodeException(int responseCode) {
mResponseCode = responseCode;
mMessage = ERROR_MESSAGE_ARRAY.get(responseCode, DEFAULT_ERROR_MESSAGE);
}
public ResponseCodeException(int responseCode, String message) {
mResponseCode = responseCode;
mMessage = message;
}
public int getResponseCode() {
return mResponseCode;
}
public boolean isIdentifiedResponseCode() {
return !DEFAULT_ERROR_MESSAGE.equals(mMessage);
}
@Override
public String getMessage() {
return mMessage;
}
@Override
public String getLocalizedMessage() {
return getMessage();
}
}
@@ -19,7 +19,7 @@ package com.hippo.scene.preference;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.Settings;
import com.hippo.scene.Scene;
import com.hippo.scene.SimpleDialog;
@@ -62,7 +62,7 @@ public class ListPreference extends Preference {
}
private int getValuePosition() {
return getValuePosition(Config.getInt(getKey(), mDefaultValue));
return getValuePosition(Settings.getInt(getKey(), mDefaultValue));
}
private int getValuePosition(int value) {
@@ -77,7 +77,7 @@ public class ListPreference extends Preference {
@Override
protected void storeValue(Object newValue) {
Config.putInt(getKey(), (Integer) newValue);
Settings.putInt(getKey(), (Integer) newValue);
}
@Override
@@ -24,7 +24,7 @@ import android.view.LayoutInflater;
import android.widget.FrameLayout;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.util.Config;
import com.hippo.ehviewer.util.Settings;
public class SwitchPreference extends Preference {
@@ -59,7 +59,7 @@ public class SwitchPreference extends Preference {
}
private boolean getValue() {
return Config.getBoolean(getKey(), mDefaultValue);
return Settings.getBoolean(getKey(), mDefaultValue);
}
private SwitchCompat getSwitch(RecyclerView.ViewHolder viewHolder) {
@@ -68,7 +68,7 @@ public class SwitchPreference extends Preference {
@Override
protected void storeValue(Object newValue) {
Config.putBoolean(getKey(), (Boolean) newValue);
Settings.putBoolean(getKey(), (Boolean) newValue);
}
@Override
@@ -23,7 +23,7 @@ import android.support.annotation.Nullable;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhException;
import com.hippo.network.ResponseCodeException;
import com.hippo.httpclient.ResponseCodeException;
import org.apache.http.conn.ConnectTimeoutException;