nya.miku.wishmaster.chans.diochan.DiochanModule.java Source code

Java tutorial

Introduction

Here is the source code for nya.miku.wishmaster.chans.diochan.DiochanModule.java

Source

/*
 * Overchan Android (Meta Imageboard Client)
 * Copyright (C) 2014-2016  miku-nyan <https://github.com/miku-nyan>
 *     
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package nya.miku.wishmaster.chans.diochan;

import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.support.v4.content.res.ResourcesCompat;

import org.apache.commons.lang3.StringEscapeUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import nya.miku.wishmaster.R;
import nya.miku.wishmaster.api.AbstractKusabaModule;
import nya.miku.wishmaster.api.models.AttachmentModel;
import nya.miku.wishmaster.api.models.BadgeIconModel;
import nya.miku.wishmaster.api.models.PostModel;
import nya.miku.wishmaster.api.models.SimpleBoardModel;
import nya.miku.wishmaster.api.models.UrlPageModel;
import nya.miku.wishmaster.api.util.ChanModels;
import nya.miku.wishmaster.api.util.RegexUtils;
import nya.miku.wishmaster.api.util.WakabaReader;
import nya.miku.wishmaster.common.Logger;

public class DiochanModule extends AbstractKusabaModule {
    public static final String[] DOMAINS = { "www.diochan.com", "diochan.com" };
    private static final String TAG = "DiochanModule";
    private static final DateFormat DATE_FORMAT;
    private static final String CHAN_NAME = "www.diochan.com";
    private static final String DISPLAYING_NAME = "Diochan";
    private static final SimpleBoardModel[] BOARDS = new SimpleBoardModel[] {
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "b", "Random", "", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "int", "International", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "s", "Sexy Beautiful Women", "", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "hd", "Help Desk", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "h", "Hentai", "", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "a", "Anime", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "v", "Video Games", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "co", "Fumetti e Cartoni", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "film", "Film", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "litness", "La palestra della mente", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "ck", "Cucina", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "mu", "Musica", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "sci", "Scienza & Tecnologia", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "pol", "Politica", "", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "scr", "Scrittura", "", false), };

    static {
        DATE_FORMAT = new SimpleDateFormat("dd/MM/yy HH:mm");
        DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+2"));
    }

    public DiochanModule(SharedPreferences preferences, Resources resources) {
        super(preferences, resources);
    }

    @Override
    protected String getUsingDomain() {
        return DOMAINS[0];
    }

    @Override
    public String getChanName() {
        return CHAN_NAME;
    }

    @Override
    public String getDisplayingName() {
        return DISPLAYING_NAME;
    }

    @Override
    protected boolean canHttps() {
        return true;
    }

    @Override
    protected boolean canCloudflare() {
        return true;
    }

    @Override
    public Drawable getChanFavicon() {
        return ResourcesCompat.getDrawable(resources, R.drawable.favicon_diochan, null);
    }

    @Override
    protected SimpleBoardModel[] getBoardsList() {
        return BOARDS;
    }

    @Override
    protected WakabaReader getKusabaReader(InputStream stream, UrlPageModel urlModel) {
        return new DiochanReader(stream, DATE_FORMAT, canCloudflare(), getKusabaFlags());
    }

    private class DiochanReader extends KusabaReader {
        private final Pattern PATTERN_IFRAME = Pattern.compile("<iframe([^>]*)>", Pattern.DOTALL);

        private final Pattern PATTERN_SRC = Pattern.compile("src=\"([^\"]+)\"");

        private final Pattern PATTERN_SCRIPT = Pattern.compile("<script type=\"text/javascript\">[^<]+</script>",
                Pattern.DOTALL);
        private final Pattern ATTACHMENT_SIZE_PATTERN = Pattern.compile("([,\\.\\d]+) ?([km])[b]",
                Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
        private final Pattern ATTACHMENT_PX_SIZE_PATTERN = Pattern.compile("(\\d+)x(\\d+)");
        private final Pattern ATTACHMENT_ORIGINAL_NAME_PATTERN = Pattern.compile("title=\"([^\"]*)\"");
        private final Pattern ATTACHMENT_THUMBNAIL_PATTERN = Pattern.compile("<img src=\"([^\"]*)\"");
        private final char[] COUNTRY_ICON_FILTER = "<span class=\"flags\">".toCharArray();
        private final char[] ATTACHMENT_START_FILTER = "<div class=\"file_reply\">".toCharArray();
        private final char[] ATTACHMENT_END = "</div>".toCharArray();
        private final String FILE_INFO_START = "<span class=\"fileinfo\">";
        private final String FILE_INFO_END = "</span>";
        private int iconCurPos = 0;
        private int attachmentCurPos = 0;

        public DiochanReader(InputStream in, DateFormat dateFormat, boolean canCloudflare, int flags) {
            super(in, dateFormat, canCloudflare, flags);
        }

        public DiochanReader(Reader reader, DateFormat dateFormat, boolean canCloudflare, int flags) {
            super(reader, dateFormat, canCloudflare, flags);
        }

        private void parseDiochanAttachment(String html) throws IOException {
            AttachmentModel attachment = new AttachmentModel();
            attachment.size = -1;

            int startHref, endHref;
            if ((startHref = html.indexOf("href=\"")) != -1
                    && (endHref = html.indexOf('\"', startHref + 6)) != -1) {
                attachment.path = html.substring(startHref + 6, endHref);
                String pathLower = attachment.path.toLowerCase(Locale.US);
                if (pathLower.endsWith(".jpg") || pathLower.endsWith(".jpeg") || pathLower.endsWith(".png"))
                    attachment.type = AttachmentModel.TYPE_IMAGE_STATIC;
                else if (pathLower.endsWith(".gif"))
                    attachment.type = AttachmentModel.TYPE_IMAGE_GIF;
                else if (pathLower.endsWith(".svg") || pathLower.endsWith(".svgz"))
                    attachment.type = AttachmentModel.TYPE_IMAGE_SVG;
                else if (pathLower.endsWith(".webm") || pathLower.endsWith(".mp4") || pathLower.endsWith(".ogv"))
                    attachment.type = AttachmentModel.TYPE_VIDEO;
                else if (pathLower.endsWith(".mp3") || pathLower.endsWith(".ogg"))
                    attachment.type = AttachmentModel.TYPE_AUDIO;
                else if (pathLower.startsWith("http") && (pathLower.contains("youtube.")))
                    attachment.type = AttachmentModel.TYPE_OTHER_NOTFILE;
                else
                    attachment.type = AttachmentModel.TYPE_OTHER_FILE;
            } else {
                return;
            }
            int fileInfoStart = html.indexOf(FILE_INFO_START);
            int fileInfoEnd = html.indexOf(FILE_INFO_END, fileInfoStart + FILE_INFO_START.length());
            if (fileInfoStart >= 0 && fileInfoEnd > 0) {
                String fileInfo = html.substring(fileInfoStart + FILE_INFO_START.length(), fileInfoEnd);
                Matcher byteSizeMatcher = ATTACHMENT_SIZE_PATTERN.matcher(fileInfo);
                if (byteSizeMatcher.find()) {
                    try {
                        String digits = byteSizeMatcher.group(1).replace(',', '.');
                        int multiplier = 1;
                        String prefix = byteSizeMatcher.group(2);
                        if (prefix != null) {
                            if (prefix.equalsIgnoreCase("") || prefix.equalsIgnoreCase("k"))
                                multiplier = 1024;
                            else if (prefix.equalsIgnoreCase("") || prefix.equalsIgnoreCase("m"))
                                multiplier = 1024 * 1024;
                        }
                        int value = Math.round(Float.parseFloat(digits) / 1024 * multiplier);
                        attachment.size = value;
                    } catch (NumberFormatException e) {
                    }
                }

                Matcher pxSizeMatcher = ATTACHMENT_PX_SIZE_PATTERN.matcher(fileInfo);
                if (pxSizeMatcher.find()) {
                    try {
                        int width = Integer.parseInt(pxSizeMatcher.group(1));
                        int height = Integer.parseInt(pxSizeMatcher.group(2));
                        attachment.width = width;
                        attachment.height = height;
                    } catch (NumberFormatException e) {
                    }
                }
            }

            Matcher originalNameMatcher = ATTACHMENT_ORIGINAL_NAME_PATTERN.matcher(html);
            if (originalNameMatcher.find()) {
                String originalName = originalNameMatcher.group(1).trim();
                if (originalName.length() > 0) {
                    attachment.originalName = StringEscapeUtils.unescapeHtml4(originalName);
                    try {
                        attachment.originalName += attachment.path.substring(attachment.path.lastIndexOf("."));
                    } catch (IndexOutOfBoundsException e) {
                    }

                }
            }

            Matcher thumbnailMatcher = ATTACHMENT_THUMBNAIL_PATTERN.matcher(html);
            if (thumbnailMatcher.find()) {
                String thumbnail = thumbnailMatcher.group(1);
                if (thumbnail.length() > 0) {
                    attachment.thumbnail = StringEscapeUtils.unescapeHtml4(thumbnail);
                }
            }

            ++currentThread.attachmentsCount;
            currentAttachments.add(attachment);
        }

        @Override
        protected void customFilters(int ch) throws IOException {
            super.customFilters(ch);
            if (ch == COUNTRY_ICON_FILTER[iconCurPos]) {
                ++iconCurPos;
                if (iconCurPos == COUNTRY_ICON_FILTER.length) {
                    BadgeIconModel iconModel = new BadgeIconModel();
                    String htmlIcon = readUntilSequence("</span>".toCharArray());
                    int start, end;
                    if ((start = htmlIcon.indexOf("src=\"")) != -1
                            && (end = htmlIcon.indexOf('\"', start + 5)) != -1) {
                        iconModel.source = htmlIcon.substring(start + 5, end);
                    }
                    iconModel.description = "";
                    int currentIconsCount = currentPost.icons == null ? 0 : currentPost.icons.length;
                    BadgeIconModel[] newIconsArray = new BadgeIconModel[currentIconsCount + 1];
                    for (int i = 0; i < currentIconsCount; ++i)
                        newIconsArray[i] = currentPost.icons[i];
                    newIconsArray[currentIconsCount] = iconModel;
                    currentPost.icons = newIconsArray;
                    iconCurPos = 0;
                }
            } else {
                if (iconCurPos != 0)
                    iconCurPos = ch == COUNTRY_ICON_FILTER[0] ? 1 : 0;
            }
            if (ch == ATTACHMENT_START_FILTER[attachmentCurPos]) {
                ++attachmentCurPos;
                if (attachmentCurPos == ATTACHMENT_START_FILTER.length) {
                    String html = readUntilSequence(ATTACHMENT_END);
                    parseDiochanAttachment(html);
                    attachmentCurPos = 0;
                }
            } else {
                if (attachmentCurPos != 0)
                    attachmentCurPos = ch == ATTACHMENT_START_FILTER[0] ? 1 : 0;
            }
        }

        @Override
        protected void parseDate(String date) {
            date = RegexUtils.removeHtmlTags(date).trim();
            date = RegexUtils.replaceAll(date, Pattern.compile("\\([A-Za-z]+\\)\\s?"), " ");
            if (date.length() > 0) {
                try {
                    currentPost.timestamp = dateFormat.parse(date).getTime();
                } catch (Exception e) {
                    Logger.e(TAG, "cannot parse date; make sure you choose the right DateFormat for this chan", e);
                }
            }
        }

        @Override
        protected void postprocessPost(PostModel post) {
            super.postprocessPost(post);
            post.comment = RegexUtils.replaceAll(post.comment, PATTERN_SCRIPT, "");
            Matcher matcher = PATTERN_IFRAME.matcher(post.comment);
            while (matcher.find()) {
                Matcher srcMatcher = PATTERN_SRC.matcher(matcher.group(1));
                if (!srcMatcher.find())
                    continue;
                String url = srcMatcher.group(1).replace("youtube.com/embed/", "youtube.com/watch?v=");
                String id = null;
                if (url.contains("youtube") && url.contains("v=")) {
                    id = url.substring(url.indexOf("v=") + 2);
                    if (id.contains("&"))
                        id = id.substring(0, id.indexOf("&"));
                }
                AttachmentModel attachment = new AttachmentModel();
                attachment.type = AttachmentModel.TYPE_OTHER_NOTFILE;
                attachment.size = -1;
                attachment.path = url;
                attachment.thumbnail = id != null ? ("http://img.youtube.com/vi/" + id + "/default.jpg") : null;

                int oldCount = post.attachments != null ? post.attachments.length : 0;
                AttachmentModel[] attachments = new AttachmentModel[oldCount + 1];
                for (int i = 0; i < oldCount; ++i)
                    attachments[i] = post.attachments[i];
                attachments[oldCount] = attachment;
                post.attachments = attachments;
            }
        }
    }
}