com.nttec.everychan.chans.sevenchan.SevenchanModule.java Source code

Java tutorial

Introduction

Here is the source code for com.nttec.everychan.chans.sevenchan.SevenchanModule.java

Source

/*
 * Everychan 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 com.nttec.everychan.chans.sevenchan;

import java.io.InputStream;
import java.util.regex.Pattern;

import com.nttec.everychan.R;
import com.nttec.everychan.api.AbstractKusabaModule;
import com.nttec.everychan.api.interfaces.CancellableTask;
import com.nttec.everychan.api.interfaces.ProgressListener;
import com.nttec.everychan.api.models.BoardModel;
import com.nttec.everychan.api.models.CaptchaModel;
import com.nttec.everychan.api.models.PostModel;
import com.nttec.everychan.api.models.SendPostModel;
import com.nttec.everychan.api.models.SimpleBoardModel;
import com.nttec.everychan.api.models.ThreadModel;
import com.nttec.everychan.api.models.UrlPageModel;
import com.nttec.everychan.api.util.ChanModels;
import com.nttec.everychan.api.util.RegexUtils;
import com.nttec.everychan.api.util.WakabaReader;
import com.nttec.everychan.http.ExtendedMultipartBuilder;
import com.nttec.everychan.http.recaptcha.Recaptcha;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.preference.PreferenceGroup;
import android.support.v4.content.res.ResourcesCompat;

public class SevenchanModule extends AbstractKusabaModule {
    private static final String CHAN_NAME = "7chan.org";
    private static final String RECAPTCHA_KEY = "6LdVg8YSAAAAAOhqx0eFT1Pi49fOavnYgy7e-lTO";
    static final String TIMEZONE = "GMT+4"; // ?

    private static final Pattern THREAD_REFERENCE_ALT = Pattern
            .compile("read.php\\?b=([^&]+)&t=(\\d+)(?:&p=)?(\\d*).*");

    private static final SimpleBoardModel[] BOARDS = new SimpleBoardModel[] {
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "7ch", "Site Discussion", "7chan & Related Services",
                    false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "ch7", "Channel7 & Radio7", "7chan & Related Services",
                    true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "irc", "Internet Relay Circlejerk",
                    "7chan & Related Services", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "777", "/selfhelp/", "Premium Content", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "b", "Random", "Premium Content", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "banner", "Banners", "Premium Content", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "fl", "Flash", "Premium Content", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "gfx", "Graphics Manipulation", "Premium Content", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "class", "The Finer Things", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "co", "Comics and Cartoons", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "eh", "Particularly uninteresting conversation", "SFW",
                    false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "fit", "Fitness & Health", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "halp", "Technical Support", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "jew", "Thrifty Living", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "lit", "Literature", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "phi", "Philosophy", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "pr", "Programming", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "rnb", "Rage and Baww", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "sci", "Science, Technology, Engineering, and Mathematics",
                    "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "tg", "Tabletop Games", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "w", "Weapons", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "zom", "Zombies", "SFW", false),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "a", "Anime & Manga", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "grim", "Cold, Grim & Miserable", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "hi", "History and Culture", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "me", "Film, Music & Television", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "rx", "Drugs", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "vg", "", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "wp", "Wallpapers", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "x", "Paranormal & Conspiracy", "General", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "cake", "Delicious", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "cd", "Crossdressing", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "d", "Alternative Hentai", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "di", "Sexy Beautiful Traps", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "elit", "Erotic Literature", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "fag", "Men Discussion", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "fur", "Furry", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "gif", "Animated GIFs", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "h", "Hentai", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "men", "Sexy Beautiful Men", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "pco", "Porn Comics", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "s", "Sexy Beautiful Women", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "sm", "Shotacon", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "ss", "Straight Shotacon", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "unf", "Uniforms", "Porn", true),
            ChanModels.obtainSimpleBoardModel(CHAN_NAME, "v", "The Vineyard", "Porn", true) };

    private Recaptcha lastCaptcha = null;

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

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

    @Override
    public String getDisplayingName() {
        return "7chan";
    }

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

    @Override
    protected String getUsingDomain() {
        return "7chan.org";
    }

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

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

    private boolean loadOnlyNewPosts() {
        return loadOnlyNewPosts(true);
    }

    @Override
    public void addPreferencesOnScreen(PreferenceGroup preferenceGroup) {
        addOnlyNewPostsPreference(preferenceGroup, true);
        super.addPreferencesOnScreen(preferenceGroup);
    }

    @Override
    protected WakabaReader getKusabaReader(InputStream stream, UrlPageModel urlModel) {
        return new SevenchanReader(stream);
    }

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

    @Override
    public BoardModel getBoard(String shortName, ProgressListener listener, CancellableTask task) throws Exception {
        BoardModel board = super.getBoard(shortName, listener, task);
        board.timeZoneId = TIMEZONE;
        board.defaultUserName = "";
        board.requiredFileForNewThread = !shortName.equals("halp") && !shortName.equals("7ch");
        board.allowNames = !shortName.equals("b");
        board.attachmentsFormatFilters = shortName.equals("fl") ? new String[] { "swf" } : null;
        board.markType = BoardModel.MARK_BBCODE;
        return board;
    }

    @Override
    public PostModel[] getPostsList(String boardName, String threadNumber, ProgressListener listener,
            CancellableTask task, PostModel[] oldList) throws Exception {
        if (loadOnlyNewPosts() && oldList != null && oldList.length > 0) {
            String url = getUsingUrl() + "ajax.php?act=spy&board=" + boardName + "&thread=" + threadNumber
                    + "&pastid=" + oldList[oldList.length - 1].number;
            ThreadModel[] page = readWakabaPage(url, listener, task, true, null);
            if (page != null && page.length > 0) {
                PostModel[] posts = new PostModel[oldList.length + page[0].posts.length];
                for (int i = 0; i < oldList.length; ++i)
                    posts[i] = oldList[i];
                for (int i = 0; i < page[0].posts.length; ++i)
                    posts[oldList.length + i] = page[0].posts[i];
                return posts;
            } else {
                return oldList;
            }
        }
        PostModel[] result = super.getPostsList(boardName, threadNumber, listener, task, oldList);
        if (result.length >= 1000 && loadOnlyNewPosts())
            return getPostsList(boardName, threadNumber, listener, task, result);
        return result;
    }

    @Override
    public CaptchaModel getNewCaptcha(String boardName, String threadNumber, ProgressListener listener,
            CancellableTask task) throws Exception {
        if (threadNumber != null)
            return null;
        Recaptcha recaptcha = Recaptcha.obtain(RECAPTCHA_KEY, task, httpClient, useHttps() ? "https" : "http");
        CaptchaModel model = new CaptchaModel();
        model.type = CaptchaModel.TYPE_NORMAL;
        model.bitmap = recaptcha.bitmap;
        lastCaptcha = recaptcha;
        return model;
    }

    @Override
    protected void setSendPostEntityMain(SendPostModel model, ExtendedMultipartBuilder postEntityBuilder)
            throws Exception {
        super.setSendPostEntityMain(model, postEntityBuilder);
        if (model.threadNumber == null) {
            if (lastCaptcha == null)
                throw new Exception("Invalid captcha");
            postEntityBuilder.addString("recaptcha_challenge_field", lastCaptcha.challenge)
                    .addString("recaptcha_response_field", model.captchaAnswer);
            lastCaptcha = null;

            postEntityBuilder.addString("embed", "");
        }
    }

    @Override
    protected void setSendPostEntityAttachments(SendPostModel model, ExtendedMultipartBuilder postEntityBuilder)
            throws Exception {
        if (model.attachments != null && model.attachments.length > 0)
            postEntityBuilder.addFile("imagefile[]", model.attachments[0], model.randomHash);
        else if (model.threadNumber == null)
            postEntityBuilder.addString("nofile", "on");
    }

    @Override
    public UrlPageModel parseUrl(String url) throws IllegalArgumentException {
        return super.parseUrl(RegexUtils.replaceAll(url, THREAD_REFERENCE_ALT, "$1/res/$2.html#$3"));
    }

    @Override
    public String fixRelativeUrl(String url) {
        if (url.startsWith("//"))
            return (useHttps() ? "https:" : "http:") + url;
        return super.fixRelativeUrl(url);
    }

}