/* * Copyright (C) 2014 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.ehclient; import com.hippo.ehviewer.data.Comment; import com.hippo.ehviewer.data.LargePreviewList; import com.hippo.ehviewer.data.NormalPreviewList; import com.hippo.ehviewer.data.PreviewList; import com.hippo.ehviewer.util.EhUtils; import com.hippo.ehviewer.util.Utils; import java.util.Collections; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.regex.Matcher; import java.util.regex.Pattern; public class DetailParser { private static final String OFFENSIVE_STRING = "

(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 final int DETAIL = 0x1; public static final int TAG = 0x2; public static final int PREVIEW_INFO = 0x4; public static final int PREVIEW = 0x8; public static final int COMMENT = 0x10; public static final int OFFENSIVE = 0x20; public static final int PINING = 0x40; public static final int ERROR = 0x80; private static final CommentSort cs = new CommentSort(); public String eMesg; public String thumb; public String title; public String title_jpn; public int category; public String uploader; public String posted; public int pages; public String size; public String resized; public String parent; public String visible; public String language; public int people; public float rating; public String firstPage; public int previewPerPage; public int previewSum; public LinkedHashMap> tags; public PreviewList previewList; public LinkedList comments; public void reset() { eMesg = null; thumb = null; title = null; title_jpn = null; category = 0; uploader = null; posted = null; pages = 0; size = null; resized = null; parent = null; visible = null; language = null; people = 0; rating = 0; firstPage = null; previewPerPage = 0; previewSum = 0; tags = null; previewList = null; comments = null; } public int parser(String body, int mode) { int re = 0; Pattern p; Matcher m; if (body == null) return 0; if (!body.contains("<")) { eMesg = body; return ERROR; } if (body.contains(OFFENSIVE_STRING)) { return OFFENSIVE; } if (body.contains(PINING_STRING)) { return PINING; } p = Pattern.compile("
\n

([^<]+)

"); m = p.matcher(body); if (m.find()) { eMesg = m.group(1); return ERROR; } // Get detail if ((mode & DETAIL) != 0) { p = Pattern .compile("
]+>
" // thumb + "
" + "
" + "

([^<>]+)

" // title + "

([^<>]*)

" // title_jpn might be empty string + "
" + ".+" + "
]+><[^<>]*alt=\"([\\w|\\-]+)\"[^<>]*>
" // category + "
]+>([^<>]+)" // uploader + ".+" + "]*>Posted:]*>([\\w|\\-|\\s|:]+)" // posted //+ "]*>Images:]*>([\\d]+) @ ([\\w|\\.|\\s]+)" // pages and size //+ "]*>Resized:]*>([^<>]+)" // resized + "]*>Parent:]*>(?:]*>)?([^<>]+)(?:)?" // parent + "]*>Visible:]*>([^<>]+)" // visible + "]*>Language:]*>([^<>]+)(?:]*>[^<>]*)?" // language + "]*>File Size:]*>([^<>]+)(?:]*>([^<>]+))?" // File size and resize + "]*>Length:]*>([\\d|,]+) pages" // pages + "]*>Favorited:<[^<>]*>([^<>]+)" // Favorite times ([\d|,]+) times or Never + ".+" + "([\\d|,]+)" // people + "" + "]*>([^<>]+)" // rating + ".+" + "
]*>(?:]*>)?]*href=\"([^<>\"]+)\"[^<>]*>"); // get firstPage m = p.matcher(body); if (m.find()) { re |= DETAIL; thumb = Utils.unescapeXml(m.group(1)); title = Utils.unescapeXml(m.group(2)); title_jpn = Utils.unescapeXml(m.group(3)); category = EhUtils.getCategory(m.group(4)); uploader = m.group(5); posted = m.group(6); parent = m.group(7); visible = m.group(8); language = Utils.unescapeXml(m.group(9)).trim(); size = Utils.unescapeXml(m.group(10)).trim(); resized = m.group(11); pages = Integer.parseInt(m.group(12).replace(",", "")); // favoriteTimes = m.group(13) people = Integer.parseInt(m.group(14).replace(",", "")); Pattern pattern = Pattern.compile("([\\d|\\.]+)"); Matcher matcher = pattern.matcher(m.group(15)); if (matcher.find()) rating = Float.parseFloat(matcher.group(1)); else rating = Float.NaN; firstPage = m.group(16); } } // Get tag if ((mode & TAG) != 0) { tags = new LinkedHashMap<>(); p = Pattern .compile("]+>([\\w\\s]+):(?:]+>]+>[\\w\\s]+
)+"); m = p.matcher(body); while (m.find()) { re |= TAG; String groupName = m.group(1); LinkedList group = getTagGroup(m.group(0)); if (group != null) { tags.put(groupName, group); } } } // Get preview info if ((mode & PREVIEW_INFO) != 0) { p = Pattern.compile("]+>]+>([\\d,]+)]+>(?:]+>)?>(?:)?"); m = p.matcher(body); if (m.find()) { re |= PREVIEW_INFO; previewSum = Integer.valueOf(m.group(1).replace(",", "")); } } // Get preview if ((mode & PREVIEW) != 0) { boolean isLargePreview = false; if (body.contains("
]*class=\"gdtm\"[^<>]*>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*>]*href=\"(.+?)\"[^<>]*>"); m = p.matcher(body); while (m.find()) { re |= PREVIEW; ((NormalPreviewList)previewList).addItem(m.group(3), m.group(4), "0", m.group(1), m.group(2), m.group(5)); } } // Set previewPerPage if (previewList != null) previewPerPage = previewList.size(); } // Get comment if ((mode & COMMENT) != 0) { p = Pattern .compile("
Posted on ([^<>]+) by ]+>([^<>]+).+?
]*>(.+?)
(); while (m.find()) { re |= COMMENT; comments.add(new Comment(m.group(1), m.group(2), m.group(3))); } Collections.sort(comments, cs); } return re; } private LinkedList getTagGroup(String pageContent) { LinkedList list = new LinkedList(); Pattern p = Pattern.compile("]+>]+>([\\w\\s]+)
"); Matcher m = p.matcher(pageContent); while (m.find()) list.add(m.group(1)); if (list.size() == 0) return null; else return list; } static class CommentSort implements Comparator { private int compareNum(String n1, String n2, int median) { int re = 0; for (int i = 0; i < median; i++) { re *= 10; re += n1.charAt(i) - n2.charAt(i); } return re; } private int getMonth(String m) { if (m.equals("January")) return 1; else if (m.equals("February")) return 2; else if (m.equals("March")) return 3; else if (m.equals("April")) return 4; else if (m.equals("May")) return 5; else if (m.equals("June")) return 6; else if (m.equals("July")) return 7; else if (m.equals("August")) return 8; else if (m.equals("September")) return 9; else if (m.equals("October")) return 10; else if (m.equals("November")) return 11; else if (m.equals("December")) return 12; else return 0; } @Override public int compare(Comment c1, Comment c2) { int re = 0; Pattern p = Pattern.compile("(\\d{2}) (\\w+) (\\d{4}), (\\d{2}):(\\d{2})"); Matcher m1 = p.matcher(c1.time); Matcher m2 = p.matcher(c2.time); if (!m1.find() || !m2.find()) return 0; // year re += compareNum(m1.group(3), m2.group(3), 4); re <<= 4; // Month re += getMonth(m1.group(2)) - getMonth(m2.group(2)); re <<= 5; // Day re += compareNum(m1.group(1), m2.group(1), 2); re <<= 5; // Hour re += compareNum(m1.group(4), m2.group(4), 2); re <<= 6; // Minute re += compareNum(m1.group(5), m2.group(5), 2); return re; } } }