diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhClient.java b/app/src/main/java/com/hippo/ehviewer/client/EhClient.java index fa3dca732..e26cdf3b5 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhClient.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhClient.java @@ -20,6 +20,7 @@ import android.content.Context; import android.os.AsyncTask; import com.hippo.ehviewer.EhApplication; +import com.hippo.ehviewer.client.exception.CancelledException; import com.hippo.yorozuya.PriorityThreadFactory; import com.hippo.yorozuya.SimpleHandler; @@ -38,6 +39,7 @@ public class EhClient { public static final int METHOD_SIGN_IN = 0; public static final int METHOD_GET_GALLERY_LIST = 1; + public static final int METHOD_GET_GALLERY_DETAIL = 2; private final ThreadPoolExecutor mRequestThreadPool; private final OkHttpClient mOkHttpClient; @@ -124,6 +126,16 @@ public class EhClient { } } + private Object getGalleryDetail(Object... params) throws Exception { + Call call = EhEngine.prepareGetGalleryDetail(mOkHttpClient, (String) params[0]); + if (!mStop) { + mCall = call; + return EhEngine.doGetGalleryDetail(call); + } else { + throw new CancelledException(); + } + } + @Override protected Object doInBackground(Object... params) { try { @@ -132,6 +144,8 @@ public class EhClient { return signIn(params); case METHOD_GET_GALLERY_LIST: return getGalleryList(params); + case METHOD_GET_GALLERY_DETAIL: + return getGalleryDetail(params); default: return new IllegalStateException("Can't detect method " + mMethod); } diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java index da9088055..16015fa7f 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.java @@ -19,6 +19,9 @@ package com.hippo.ehviewer.client; import android.support.annotation.Nullable; import android.util.Log; +import com.hippo.ehviewer.client.exception.CancelledException; +import com.hippo.ehviewer.client.exception.EhException; +import com.hippo.ehviewer.client.parser.GalleryDetailParser; import com.hippo.ehviewer.client.parser.GalleryListParser; import com.hippo.ehviewer.client.parser.SignInParser; import com.hippo.network.StatusCodeException; @@ -114,4 +117,25 @@ public class EhEngine { } } + public static Call prepareGetGalleryDetail(OkHttpClient okHttpClient, String url) { + Log.d(TAG, url); + Request request = new EhRequestBuilder(url).build(); + return okHttpClient.newCall(request); + } + + public static GalleryDetailParser.Result doGetGalleryDetail(Call call) throws Exception { + String body = null; + Headers headers = null; + int code = -1; + try { + Response response = call.execute(); + code = response.code(); + headers = response.headers(); + body = response.body().string(); + return GalleryDetailParser.parse(body); + } catch (Exception e) { + throwException(call, code, headers, body, e); + throw e; + } + } } diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java index d1a250e4a..eb43fffa2 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java +++ b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.java @@ -25,8 +25,7 @@ public class EhUrl { public static final String API_SIGN_IN = "http://forums.e-hentai.org/index.php?act=Login&CODE=01"; - - - - + public static String getGalleryDetailUrl(int gid, String token) { + return HOST_EX + "g/" + gid + '/' + token; + } } diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryComment.java b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryComment.java new file mode 100644 index 000000000..431c98722 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryComment.java @@ -0,0 +1,58 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.client.data; + +import android.os.Parcel; +import android.os.Parcelable; + +public class GalleryComment implements Parcelable { + + public long time; + public String user; + public String comment; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(this.time); + dest.writeString(this.user); + dest.writeString(this.comment); + } + + public GalleryComment() { + } + + protected GalleryComment(Parcel in) { + this.time = in.readLong(); + this.user = in.readString(); + this.comment = in.readString(); + } + + public static final Creator CREATOR = new Creator() { + public GalleryComment createFromParcel(Parcel source) { + return new GalleryComment(source); + } + + public GalleryComment[] newArray(int size) { + return new GalleryComment[size]; + } + }; +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java new file mode 100644 index 000000000..5009978d5 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryDetail.java @@ -0,0 +1,93 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.client.data; + +import android.os.Parcel; + +public class GalleryDetail extends GalleryInfo { + + public int torrentCount; + public String torrentUrl; + public String parent; + public String visible; + public String language; + public String size; + public String resize; + public int pages; + public int favoredTimes; + public boolean isFavored; + public int ratedTimes; + public GalleryTagGroup[] tags; + public GalleryComment[] comments; + public int previewPages; + + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeInt(this.torrentCount); + dest.writeString(this.torrentUrl); + dest.writeString(this.parent); + dest.writeString(this.visible); + dest.writeString(this.language); + dest.writeString(this.size); + dest.writeString(this.resize); + dest.writeInt(this.pages); + dest.writeInt(this.favoredTimes); + dest.writeByte(isFavored ? (byte) 1 : (byte) 0); + dest.writeInt(this.ratedTimes); + dest.writeParcelableArray(this.tags, 0); + dest.writeParcelableArray(this.comments, 0); + dest.writeInt(this.previewPages); + } + + public GalleryDetail() { + } + + protected GalleryDetail(Parcel in) { + super(in); + this.torrentCount = in.readInt(); + this.torrentUrl = in.readString(); + this.parent = in.readString(); + this.visible = in.readString(); + this.language = in.readString(); + this.size = in.readString(); + this.resize = in.readString(); + this.pages = in.readInt(); + this.favoredTimes = in.readInt(); + this.isFavored = in.readByte() != 0; + this.ratedTimes = in.readInt(); + this.tags = in.createTypedArray(GalleryTagGroup.CREATOR); + this.comments = in.createTypedArray(GalleryComment.CREATOR); + this.previewPages = in.readInt(); + } + + public static final Creator CREATOR = new Creator() { + public GalleryDetail createFromParcel(Parcel source) { + return new GalleryDetail(source); + } + + public GalleryDetail[] newArray(int size) { + return new GalleryDetail[size]; + } + }; +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/GalleryTagGroup.java b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryTagGroup.java new file mode 100644 index 000000000..c38fd71dd --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/data/GalleryTagGroup.java @@ -0,0 +1,69 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.client.data; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; + +public class GalleryTagGroup implements Parcelable { + + public String groupName; + private ArrayList mTagList = new ArrayList<>(); + + public void addTag(String tag) { + mTagList.add(tag); + } + + public int size() { + return mTagList.size(); + } + + public String getTagAt(int position) { + return mTagList.get(position); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(this.groupName); + dest.writeStringList(this.mTagList); + } + + public GalleryTagGroup() { + } + + protected GalleryTagGroup(Parcel in) { + this.groupName = in.readString(); + this.mTagList = in.createStringArrayList(); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public GalleryTagGroup createFromParcel(Parcel source) { + return new GalleryTagGroup(source); + } + + public GalleryTagGroup[] newArray(int size) { + return new GalleryTagGroup[size]; + } + }; +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/data/LargePreviewSet.java b/app/src/main/java/com/hippo/ehviewer/client/data/LargePreviewSet.java new file mode 100644 index 000000000..eca38aa8a --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/data/LargePreviewSet.java @@ -0,0 +1,42 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.client.data; + +import java.util.ArrayList; + +public class LargePreviewSet { + + private ArrayList mImageUrlList = new ArrayList<>(); + private ArrayList mPageUrlList = new ArrayList<>(); + + public int size() { + return mImageUrlList.size(); + } + + public void addItem(String imageUrl, String pageUrl) { + mImageUrlList.add(imageUrl); + mPageUrlList.add(pageUrl); + } + + public String getImageUrlAt(int index) { + return mImageUrlList.get(index); + } + + public String getPageUrlAt(int index) { + return mPageUrlList.get(index); + } +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/CancelledException.java b/app/src/main/java/com/hippo/ehviewer/client/exception/CancelledException.java similarity index 94% rename from app/src/main/java/com/hippo/ehviewer/client/CancelledException.java rename to app/src/main/java/com/hippo/ehviewer/client/exception/CancelledException.java index 93c7ffa0b..62283ec24 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/CancelledException.java +++ b/app/src/main/java/com/hippo/ehviewer/client/exception/CancelledException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.hippo.ehviewer.client; +package com.hippo.ehviewer.client.exception; public class CancelledException extends Exception { diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhException.java b/app/src/main/java/com/hippo/ehviewer/client/exception/EhException.java similarity index 94% rename from app/src/main/java/com/hippo/ehviewer/client/EhException.java rename to app/src/main/java/com/hippo/ehviewer/client/exception/EhException.java index fa090b06e..6aeb355b2 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhException.java +++ b/app/src/main/java/com/hippo/ehviewer/client/exception/EhException.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.hippo.ehviewer.client; +package com.hippo.ehviewer.client.exception; public class EhException extends Exception { diff --git a/app/src/main/java/com/hippo/ehviewer/client/exception/NotFoundException.java b/app/src/main/java/com/hippo/ehviewer/client/exception/NotFoundException.java index e5740796a..73398db16 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/exception/NotFoundException.java +++ b/app/src/main/java/com/hippo/ehviewer/client/exception/NotFoundException.java @@ -16,8 +16,6 @@ package com.hippo.ehviewer.client.exception; -import com.hippo.ehviewer.client.EhException; - public class NotFoundException extends EhException { public static final String MESSAGE = "Not found"; diff --git a/app/src/main/java/com/hippo/ehviewer/client/exception/OffensiveException.java b/app/src/main/java/com/hippo/ehviewer/client/exception/OffensiveException.java new file mode 100644 index 000000000..b9ea8b33c --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/exception/OffensiveException.java @@ -0,0 +1,27 @@ +/* + * 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.client.exception; + +/** + * It is an exception for get offensive tip for g.e-hentai.org + */ +public class OffensiveException extends EhException { + + public OffensiveException() { + super("OFFENSIVE"); + } +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/exception/ParseException.java b/app/src/main/java/com/hippo/ehviewer/client/exception/ParseException.java index bf38e5bee..4b662fba5 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/exception/ParseException.java +++ b/app/src/main/java/com/hippo/ehviewer/client/exception/ParseException.java @@ -16,8 +16,6 @@ package com.hippo.ehviewer.client.exception; -import com.hippo.ehviewer.client.EhException; - public class ParseException extends EhException { private String mBody; diff --git a/app/src/main/java/com/hippo/ehviewer/client/exception/PiningException.java b/app/src/main/java/com/hippo/ehviewer/client/exception/PiningException.java new file mode 100644 index 000000000..828521e38 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/exception/PiningException.java @@ -0,0 +1,24 @@ +/* + * 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.client.exception; + +public class PiningException extends EhException { + + public PiningException() { + super("pining for the fjords"); + } +} diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java b/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java new file mode 100644 index 000000000..9b49a3855 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java @@ -0,0 +1,271 @@ +/* + * Copyright 2016 Hippo Seven + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.hippo.ehviewer.client.parser; + +import com.hippo.ehviewer.client.EhUtils; +import com.hippo.ehviewer.client.data.GalleryComment; +import com.hippo.ehviewer.client.data.GalleryDetail; +import com.hippo.ehviewer.client.data.GalleryTagGroup; +import com.hippo.ehviewer.client.data.LargePreviewSet; +import com.hippo.ehviewer.client.exception.EhException; +import com.hippo.ehviewer.client.exception.OffensiveException; +import com.hippo.ehviewer.client.exception.ParseException; +import com.hippo.ehviewer.client.exception.PiningException; +import com.hippo.yorozuya.NumberUtils; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +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; +import java.util.regex.Pattern; + +public class GalleryDetailParser { + + private static final DateFormat WEB_COMMENT_DATE_FORMAT = new SimpleDateFormat("dd MMMMM yyyy, HH:mm z", Locale.US); + + private static final Pattern ERROR_PATTERN = Pattern.compile("
\n

([^<]+)

"); + private static final Pattern DETAIL_PATTERN = Pattern.compile( + "var gid = (\\d+)" // 1 gid + + ".+?" + + "var token = \"([a-z0-9A]+)\"" // 2 token + + ".+?" + + "
]+>
" // 3 thumb + + "
" + + "
" + + "

([^<>]+)

" // 4 title + + "

([^<>]*)

" // 5 title_jpn might be empty string + + "
" + + ".+?" + + "]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Torrent Download \\( (\\d+) \\)" // 6 torrentUrl, 7 torrentCount + + ".+?" + + "
]+><[^<>]*alt=\"([\\w\\-]+)\"[^<>]*>
" // 8 category + + "
]+>([^<>]+)" // 9 uploader + + ".+?" + + "]*>Posted:]*>([\\w\\-\\s:]+)" // 10 posted + + "]*>Parent:]*>(?:]*>)?([^<>]+)(?:)?" // 11 parent + + "]*>Visible:]*>([^<>]+)" // 12 visible + + "]*>Language:]*>([^<>]+)(?:]*>[^<>]*)?" // 13 language + + "]*>File Size:]*>([^<>]+)(?:]*>([^<>]+))?" // 14 File size, 15 resize + + "]*>Length:]*>([\\d,]+) pages" // 16 pageCount + + "]*>Favorited:<[^<>]*>([^<>]+)" // 17 Favorite times "([\d,]+) times" or "Once" or "Never" + + ".+?" + + "([\\d,]+)" // 18 ratedTimes + + "" + + "]*>([^<>]+)" // 19 rating "Average: x.xx" or "Not Yet Rated" + + ".+?" + + "]*>(.+?)", Pattern.DOTALL); // 20 isFavored "Favorite Gallery" for favorite + private static final Pattern TAG_GROUP_PATTERN = Pattern.compile("]+>([\\w\\s]+):(?:]+>]+>[\\w\\s]+
)+"); + private static final Pattern TAG_PATTERN = Pattern.compile("]+>]+>([\\w\\s]+)"); + + + private static final Pattern COMMENT_PATTERN = Pattern.compile("
Posted on ([^<>]+) by:   ]+>([^<>]+).+?
]*>(.+?)
]*>Length:]*>([\\d,]+) pages"); + public static final Pattern PREVIEW_PAGES_PATTERN = Pattern.compile("]+>]+>([\\d,]+)]+>(?:]+>)?>(?:)?"); + private static final Pattern NORMAL_PREVIEW_PATTERN = Pattern.compile("]*class=\"gdtm\"[^<>]*>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*>]*href=\"(.+?)\"[^<>]*>"); + private static final Pattern LARGE_PREVIEW_PATTERN = Pattern.compile("
(And if you choose to ignore this warning, you lose all rights to complain about it in the future.)

"; + private static final String PINING_STRING = + "

This gallery is pining for the fjords.

"; + + public static class Result { + public GalleryDetail galleryDetail; + public LargePreviewSet previewSet; + } + + public static GalleryDetailParser.Result parse(String body) throws EhException { + if (body.contains(OFFENSIVE_STRING)) { + throw new OffensiveException(); + } + + if (body.contains(PINING_STRING)) { + throw new PiningException(); + } + + // Error info + Matcher m = ERROR_PATTERN.matcher(body); + if (m.find()) { + throw new EhException(m.group(1)); + } + + GalleryDetail galleryDetail = new GalleryDetail(); + parseDetail(body, galleryDetail); + galleryDetail.tags = parseTagGroup(body); + galleryDetail.comments = parseComment(body); + galleryDetail.previewPages = parsePreviewPages(body); + + LargePreviewSet previewSet = parsePreview(body); + + Result result = new Result(); + result.galleryDetail = galleryDetail; + result.previewSet = previewSet; + return result; + } + + + public static void parseDetail(String body, GalleryDetail gd) throws EhException { + Matcher m = DETAIL_PATTERN.matcher(body); + if (!m.find()) { + throw new ParseException("Parse gallery detail error", body); + } + + gd.gid = ParserUtils.parseInt(m.group(1)); + gd.token = ParserUtils.trim(m.group(2)); + gd.thumb = ParserUtils.trim(m.group(3)); + gd.title = ParserUtils.trim(m.group(4)); + gd.titleJpn = ParserUtils.trim(m.group(5)); + gd.torrentUrl = ParserUtils.trim(m.group(6)); + gd.torrentCount = ParserUtils.parseInt(m.group(7)); + gd.category = EhUtils.getCategory(ParserUtils.trim(m.group(8))); + gd.uploader = ParserUtils.trim(m.group(9)); + gd.posted = ParserUtils.trim(m.group(10)); + gd.parent = ParserUtils.trim(m.group(11)); + gd.visible = ParserUtils.trim(m.group(12)); + gd.language = ParserUtils.trim(m.group(13)); + gd.size = ParserUtils.trim(m.group(14)); + gd.resize = ParserUtils.trim(m.group(15)); + gd.pages = ParserUtils.parseInt(m.group(16)); + String favTimeStr = ParserUtils.trim(m.group(17)); + + switch (favTimeStr) { + case "Never": + gd.favoredTimes = 0; + break; + case "Once": + gd.favoredTimes = 1; + break; + default: + int index = favTimeStr.indexOf(' '); + if (index == -1) { + gd.favoredTimes = 0; + } else { + gd.favoredTimes = ParserUtils.parseInt(favTimeStr.substring(0, index)); + } + break; + } + + gd.ratedTimes = ParserUtils.parseInt(m.group(18)); + + String ratingStr = ParserUtils.trim(m.group(19)); + if ("Not Yet Rated".equals(ratingStr)) { + gd.rating = Float.NaN; + } else { + int index = ratingStr.indexOf(' '); + if (index == -1 || index >= ratingStr.length()) { + gd.rating = 0f; + } else { + gd.rating = NumberUtils.parseFloatSafely(ratingStr.substring(index + 1), 0f); + } + } + + gd.isFavored = "Favorite Gallery".equals(ParserUtils.trim(m.group(20))); + } + + + public static GalleryTagGroup[] parseTagGroup(String body) throws EhException { + List list = new LinkedList<>(); + + Matcher m = TAG_GROUP_PATTERN.matcher(body); + while (m.find()) { + GalleryTagGroup tagGroup = new GalleryTagGroup(); + tagGroup.groupName = ParserUtils.trim(m.group(1)); + parseGroup(tagGroup, m.group(0)); + list.add(tagGroup); + } + + return list.toArray(new GalleryTagGroup[list.size()]); + } + + private static void parseGroup(GalleryTagGroup tagGroup, String body) { + Matcher m = TAG_PATTERN.matcher(body); + while (m.find()) { + tagGroup.addTag(ParserUtils.trim(m.group(1))); + } + } + + public static GalleryComment[] parseComment(String body) { + List list = new LinkedList<>(); + + Matcher m = COMMENT_PATTERN.matcher(body); + while (m.find()) { + String webDateString = ParserUtils.trim(m.group(1)); + Date date; + try { + date = WEB_COMMENT_DATE_FORMAT.parse(webDateString); + } catch (java.text.ParseException e) { + date = new Date(0L); + } + GalleryComment comment = new GalleryComment(); + comment.time = date.getTime(); + comment.user = ParserUtils.trim(m.group(2)); + comment.comment = m.group(3); + list.add(comment); + } + + return list.toArray(new GalleryComment[list.size()]); + } + + public static int parsePreviewPages(String body) throws ParseException { + Matcher m = PREVIEW_PAGES_PATTERN.matcher(body); + int previewPages = -1; + if (m.find()) { + previewPages = ParserUtils.parseInt(m.group(1)); + } + + if (previewPages <= 0) { + throw new ParseException("Parse preview page count error", body); + } + + return previewPages; + } + + public static int parsePages(String body) throws ParseException { + Matcher m = PAGES_PATTERN.matcher(body); + if (m.find()) { + return ParserUtils.parseInt(m.group(1)); + } else { + throw new ParseException("Parse pages error", body); + } + } + + public static LargePreviewSet parsePreview(String body) throws EhException { + if (body.contains("