diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java b/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java index fc6b453c7..5eb09494b 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/GalleryDetailParser.java @@ -46,14 +46,12 @@ import org.jsoup.select.Elements; import org.jsoup.select.NodeTraversor; import org.jsoup.select.NodeVisitor; -import java.text.DateFormat; -import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; -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; @@ -64,9 +62,6 @@ public class GalleryDetailParser { private static final Pattern PATTERN_TORRENT = Pattern.compile("]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Torrent Download[^<]+(\\d+)[^<]+]*onclick=\"return popUp\\('([^']+)'[^)]+\\)\">Archive Download"); private static final Pattern PATTERN_COVER = Pattern.compile("width:(\\d+)px; height:(\\d+)px.+?url\\((.+?)\\)"); - private static final Pattern PATTERN_TAG_GROUP = Pattern.compile("]+>([\\w\\s]+):(?:]+>]+>[\\w\\s]+)+"); - private static final Pattern PATTERN_TAG = Pattern.compile("]+>]+>([\\w\\s]+)"); - private static final Pattern PATTERN_COMMENT = Pattern.compile("
Posted on ([^<>]+) by:   ]+>([^<>]+).+?
]*>(.+?)
]*>Length:]*>([\\d,]+) pages"); private static final Pattern PATTERN_PREVIEW_PAGES = Pattern.compile("]+>]+>([\\d,]+)]+>(?:]+>)?>(?:)?"); private static final Pattern PATTERN_NORMAL_PREVIEW = Pattern.compile("
]*>]*width:(\\d+)[^<>]*height:(\\d+)[^<>]*\\((.+?)\\)[^<>]*-(\\d+)px[^<>]*>]*href=\"(.+?)\"[^<>]*>\"([\\d,]+)\""); gd.favoriteCount = 0; + case "Once" -> gd.favoriteCount = 1; + default -> { int index = value.indexOf(' '); if (index == -1) { gd.favoriteCount = 0; } else { gd.favoriteCount = NumberUtils.parseIntSafely(value.substring(0, index), 0); } - break; + } } } } @@ -375,6 +362,7 @@ public class GalleryDetailParser { public static GalleryTagGroup[] parseTagGroups(Document document) { try { Element taglist = document.getElementById("taglist"); + assert taglist != null; Elements tagGroups = taglist.child(0).child(0).children(); return parseTagGroups(tagGroups); } catch (Throwable e) { @@ -394,7 +382,7 @@ public class GalleryDetailParser { list.add(group); } } - return list.toArray(new GalleryTagGroup[list.size()]); + return list.toArray(new GalleryTagGroup[0]); } catch (Throwable e) { ExceptionUtils.throwIfFatal(e); e.printStackTrace(); @@ -402,31 +390,6 @@ public class GalleryDetailParser { } } - /** - * Parse tag groups with regular expressions - */ - @NonNull - private static GalleryTagGroup[] parseTagGroups(String body) throws EhException { - List list = new LinkedList<>(); - - Matcher m = PATTERN_TAG_GROUP.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 = PATTERN_TAG.matcher(body); - while (m.find()) { - tagGroup.addTag(ParserUtils.trim(m.group(1))); - } - } - @Nullable @SuppressWarnings("ConstantConditions") public static GalleryComment parseComment(Element element) { @@ -444,17 +407,15 @@ public class GalleryDetailParser { } for (Element e : c4.children()) { switch (e.text()) { - case "Vote+": + case "Vote+" -> { comment.voteUpAble = true; comment.voteUpEd = !StringUtils.trim(e.attr("style")).isEmpty(); - break; - case "Vote-": + } + case "Vote-" -> { comment.voteDownAble = true; comment.voteDownEd = !StringUtils.trim(e.attr("style")).isEmpty(); - break; - case "Edit": - comment.editable = true; - break; + } + case "Edit" -> comment.editable = true; } } } @@ -475,7 +436,7 @@ public class GalleryDetailParser { Element c3 = JsoupUtils.getElementByClass(element, "c3"); String temp = c3.ownText(); temp = temp.substring("Posted on ".length(), temp.length() - " by:".length()); - comment.time = WEB_COMMENT_DATE_FORMAT.parse(temp).getTime(); + comment.time = Instant.from(WEB_COMMENT_DATE_FORMAT.parse(temp)).toEpochMilli(); // user comment.user = c3.child(0).text(); // comment @@ -485,7 +446,7 @@ public class GalleryDetailParser { if (c8 != null) { Element e = c8.children().first(); if (e != null) { - comment.lastEdited = WEB_COMMENT_DATE_FORMAT.parse(temp).getTime(); + comment.lastEdited = Instant.from(WEB_COMMENT_DATE_FORMAT.parse(temp)).toEpochMilli(); } } return comment; @@ -503,6 +464,7 @@ public class GalleryDetailParser { public static GalleryCommentList parseComments(Document document) { try { Element cdiv = document.getElementById("cdiv"); + assert cdiv != null; Elements c1s = cdiv.getElementsByClass("c1"); List list = new ArrayList<>(c1s.size()); @@ -515,20 +477,21 @@ public class GalleryDetailParser { Element chd = cdiv.getElementById("chd"); MutableBoolean hasMore = new MutableBoolean(false); + assert chd != null; NodeTraversor.traverse(new NodeVisitor() { @Override - public void head(Node node, int depth) { + public void head(@NonNull Node node, int depth) { if (node instanceof Element && ((Element) node).text().equals("click to show all")) { hasMore.value = true; } } @Override - public void tail(Node node, int depth) { + public void tail(@NonNull Node node, int depth) { } }, chd); - return new GalleryCommentList(list.toArray(new GalleryComment[list.size()]), hasMore.value); + return new GalleryCommentList(list.toArray(new GalleryComment[0]), hasMore.value); } catch (Throwable e) { ExceptionUtils.throwIfFatal(e); e.printStackTrace(); @@ -536,38 +499,14 @@ public class GalleryDetailParser { } } - /** - * Parse comments with regular expressions - */ - @NonNull - public static GalleryComment[] parseComments(String body) { - List list = new LinkedList<>(); - - Matcher m = PATTERN_COMMENT.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()]); - } - /** * Parse preview pages with html parser */ public static int parsePreviewPages(Document document, String body) throws ParseException { try { - Elements elements = document.getElementsByClass("ptt").first().child(0).child(0).children(); + Element ptt = document.getElementsByClass("ptt").first(); + assert ptt != null; + Elements elements = ptt.child(0).child(0).children(); return Integer.parseInt(elements.get(elements.size() - 2).text()); } catch (Throwable e) { ExceptionUtils.throwIfFatal(e); @@ -634,9 +573,10 @@ public class GalleryDetailParser { try { LargePreviewSet largePreviewSet = new LargePreviewSet(); Element gdt = d.getElementById("gdt"); + assert gdt != null; Elements gdtls = gdt.getElementsByClass("gdtl"); int n = gdtls.size(); - if (n <= 0) { + if (n == 0) { throw new ParseException("Can't parse large preview", body); } for (int i = 0; i < n; i++) { diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/ParserUtils.java b/app/src/main/java/com/hippo/ehviewer/client/parser/ParserUtils.java index 19f48294c..33d2ce100 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/parser/ParserUtils.java +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/ParserUtils.java @@ -19,19 +19,18 @@ package com.hippo.ehviewer.client.parser; import com.hippo.yorozuya.NumberUtils; import com.hippo.yorozuya.StringUtils; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Locale; -import java.util.TimeZone; public class ParserUtils { - public static final DateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US); + public static final DateTimeFormatter formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd HH:mm", Locale.US).withZone(ZoneOffset.UTC); public static synchronized String formatDate(long time) { - sDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - return sDateFormat.format(new Date(time)); + return formatter.format(Instant.ofEpochMilli(time)); } public static String trim(String str) { @@ -50,7 +49,4 @@ public class ParserUtils { return NumberUtils.parseLongSafely(trim(str).replace(",", ""), defValue); } - public static float parseFloat(String str, float defValue) { - return NumberUtils.parseFloatSafely(trim(str).replace(",", ""), defValue); - } } diff --git a/app/src/main/java/com/hippo/ehviewer/widget/GalleryInfoContentHelper.kt b/app/src/main/java/com/hippo/ehviewer/widget/GalleryInfoContentHelper.kt index abad4a399..2b7c33612 100644 --- a/app/src/main/java/com/hippo/ehviewer/widget/GalleryInfoContentHelper.kt +++ b/app/src/main/java/com/hippo/ehviewer/widget/GalleryInfoContentHelper.kt @@ -16,8 +16,6 @@ package com.hippo.ehviewer.widget import android.annotation.SuppressLint -import android.icu.text.SimpleDateFormat -import android.icu.util.Calendar import android.os.Bundle import android.os.Parcelable import com.hippo.ehviewer.EhApplication @@ -25,7 +23,12 @@ import com.hippo.ehviewer.FavouriteStatusRouter import com.hippo.ehviewer.client.data.GalleryInfo import com.hippo.widget.ContentLayout.ContentHelper import com.hippo.yorozuya.IntIdGenerator +import java.time.Instant +import java.time.ZoneOffset +import java.time.format.DateTimeFormatter import java.util.Locale +import kotlin.math.max +import kotlin.math.min abstract class GalleryInfoContentHelper : ContentHelper() { @JvmField @@ -64,8 +67,8 @@ abstract class GalleryInfoContentHelper : ContentHelper() { info?.let { if (maxGid == -1) maxGid = info.gid.toInt() if (minGid == -1) minGid = info.gid.toInt() - maxGid = Math.max(maxGid.toLong(), info.gid).toInt() - minGid = Math.min(minGid.toLong(), info.gid).toInt() + maxGid = max(maxGid.toLong(), info.gid).toInt() + minGid = min(minGid.toLong(), info.gid).toInt() map[info.gid] = info } } @@ -121,11 +124,9 @@ abstract class GalleryInfoContentHelper : ContentHelper() { } fun goTo(time: Long) { - val calendar = Calendar.getInstance() - calendar.timeInMillis = time - val date = calendar.time - val format = SimpleDateFormat("yyyy-MM-dd", Locale.US) - jumpTo = format.format(date) + val formatter = DateTimeFormatter + .ofPattern("yyyy-MM-dd", Locale.US).withZone(ZoneOffset.UTC) + jumpTo = formatter.format(Instant.ofEpochMilli(time)) doGoToPage(Int.MAX_VALUE / 2) } diff --git a/app/src/main/java/com/hippo/util/ReadableTime.java b/app/src/main/java/com/hippo/util/ReadableTime.java index 64fe3b79c..c4679240a 100644 --- a/app/src/main/java/com/hippo/util/ReadableTime.java +++ b/app/src/main/java/com/hippo/util/ReadableTime.java @@ -16,18 +16,17 @@ package com.hippo.util; -import android.annotation.SuppressLint; import android.content.Context; import android.content.res.Resources; import com.hippo.ehviewer.R; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Locale; -@SuppressLint("SimpleDateFormat") public final class ReadableTime { public static final long SECOND_MILLIS = 1000; @@ -51,38 +50,19 @@ public final class ReadableTime { R.plurals.minute, R.plurals.second }; - private static final Calendar sCalendar = Calendar.getInstance(); private static final Object sCalendarLock = new Object(); - private static final SimpleDateFormat DATE_FORMAT_WITHOUT_YEAR = new SimpleDateFormat("MMM d"); - private static final SimpleDateFormat DATE_FORMAT_WITH_YEAR = new SimpleDateFormat("MMM d, yyyy"); - private static final SimpleDateFormat DATE_FORMAT_WITHOUT_YEAR_ZH = new SimpleDateFormat("M月d日"); - private static final SimpleDateFormat DATE_FORMAT_WITH_YEAR_ZH = new SimpleDateFormat("yyyy年M月d日"); - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yy-MM-dd HH:mm"); - private static final Object sDateFormatLock1 = new Object(); - private static final SimpleDateFormat FILENAMABLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-SSS"); - private static final Object sDateFormatLock2 = new Object(); + private static final DateTimeFormatter DATE_FORMAT_WITHOUT_YEAR = DateTimeFormatter.ofPattern("MMM d"); + private static final DateTimeFormatter DATE_FORMAT_WITH_YEAR = DateTimeFormatter.ofPattern("MMM d, yyyy"); + private static final DateTimeFormatter DATE_FORMAT_WITHOUT_YEAR_ZH = DateTimeFormatter.ofPattern("M月d日"); + private static final DateTimeFormatter DATE_FORMAT_WITH_YEAR_ZH = DateTimeFormatter.ofPattern("yyyy年M月d日"); + private static final DateTimeFormatter FILENAMABLE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss-SSS"); + private static final Object sDateFormatLock = new Object(); private static Resources sResources; public static void initialize(Context context) { sResources = context.getApplicationContext().getResources(); } - /* - public static String getDisplayTime(long time) { - if (Settings.getPrettyTime()) { - return getTimeAgo(time); - } else { - return getPlainTime(time); - } - } - */ - - public static String getPlainTime(long time) { - synchronized (sDateFormatLock1) { - return DATE_FORMAT.format(new Date(time)); - } - } - public static String getTimeAgo(long time) { Resources resources = sResources; @@ -111,49 +91,23 @@ public final class ReadableTime { return resources.getString(R.string.some_days_ago, days); } else { synchronized (sCalendarLock) { - Date nowDate = new Date(now); - Date timeDate = new Date(time); - sCalendar.setTime(nowDate); - int nowYear = sCalendar.get(Calendar.YEAR); - sCalendar.setTime(timeDate); - int timeYear = sCalendar.get(Calendar.YEAR); + OffsetDateTime nowDate = Instant.ofEpochMilli(now).atOffset(ZoneOffset.UTC); + OffsetDateTime timeDate = Instant.ofEpochMilli(time).atOffset(ZoneOffset.UTC); + int nowYear = nowDate.getYear(); + int timeYear = timeDate.getYear(); boolean isZh = Locale.getDefault().getLanguage().equals("zh"); if (nowYear == timeYear) { - return (isZh ? DATE_FORMAT_WITHOUT_YEAR_ZH : DATE_FORMAT_WITHOUT_YEAR).format(timeDate); + return (isZh ? DATE_FORMAT_WITHOUT_YEAR_ZH : DATE_FORMAT_WITHOUT_YEAR) + .format(timeDate.toInstant().atOffset(ZoneOffset.UTC)); } else { - return (isZh ? DATE_FORMAT_WITH_YEAR_ZH : DATE_FORMAT_WITH_YEAR).format(timeDate); + return (isZh ? DATE_FORMAT_WITH_YEAR_ZH : DATE_FORMAT_WITH_YEAR) + .format(timeDate.toInstant().atOffset(ZoneOffset.UTC)); } } } } - public static String getTimeInterval(long time) { - StringBuilder sb = new StringBuilder(); - Resources resources = sResources; - - long leftover = time; - boolean start = false; - - for (int i = 0; i < SIZE; i++) { - long multiple = MULTIPLES[i]; - long quotient = leftover / multiple; - long remainder = leftover % multiple; - if (start || quotient != 0 || i == SIZE - 1) { - if (start) { - sb.append(" "); - } - sb.append(quotient) - .append(" ") - .append(resources.getQuantityString(UNITS[i], (int) quotient)); - start = true; - } - leftover = remainder; - } - - return sb.toString(); - } - public static String getShortTimeInterval(long time) { StringBuilder sb = new StringBuilder(); Resources resources = sResources; @@ -173,8 +127,8 @@ public final class ReadableTime { } public static String getFilenamableTime(long time) { - synchronized (sDateFormatLock2) { - return FILENAMABLE_DATE_FORMAT.format(new Date(time)); + synchronized (sDateFormatLock) { + return FILENAMABLE_DATE_FORMAT.format(Instant.ofEpochMilli(time)); } } }