/*
* 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.nullchan;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.io.SequenceInputStream;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.preference.PreferenceGroup;
import cz.msebera.android.httpclient.NameValuePair;
import cz.msebera.android.httpclient.message.BasicNameValuePair;
import nya.miku.wishmaster.api.AbstractKusabaModule;
import nya.miku.wishmaster.api.interfaces.CancellableTask;
import nya.miku.wishmaster.api.interfaces.ProgressListener;
import nya.miku.wishmaster.api.models.AttachmentModel;
import nya.miku.wishmaster.api.models.BoardModel;
import nya.miku.wishmaster.api.models.CaptchaModel;
import nya.miku.wishmaster.api.models.DeletePostModel;
import nya.miku.wishmaster.api.models.PostModel;
import nya.miku.wishmaster.api.models.SendPostModel;
import nya.miku.wishmaster.api.models.ThreadModel;
import nya.miku.wishmaster.api.models.UrlPageModel;
import nya.miku.wishmaster.api.util.WakabaReader;
import nya.miku.wishmaster.http.ExtendedMultipartBuilder;
public abstract class AbstractInstant0chan extends AbstractKusabaModule {
public AbstractInstant0chan(SharedPreferences preferences, Resources resources) {
super(preferences, resources);
}
protected boolean loadOnlyNewPosts() {
return loadOnlyNewPosts(true);
}
@Override
public void addPreferencesOnScreen(PreferenceGroup preferenceGroup) {
addOnlyNewPostsPreference(preferenceGroup, true);
super.addPreferencesOnScreen(preferenceGroup);
}
@Override
public BoardModel getBoard(String shortName, ProgressListener listener, CancellableTask task) throws Exception {
BoardModel model = super.getBoard(shortName, listener, task);
model.timeZoneId = "GMT+3";
model.defaultUserName = "Anonymous";
model.requiredFileForNewThread = !shortName.equals("0");
model.allowReport = BoardModel.REPORT_SIMPLE;
model.allowNames = !shortName.equals("b");
model.allowEmails = false;
return model;
}
@Override
protected final DateFormat getDateFormat() {
return null;
}
@Override
protected WakabaReader getKusabaReader(InputStream stream, UrlPageModel urlModel) {
if (urlModel != null && urlModel.chanName != null && urlModel.chanName.equals("expand")) {
stream = new SequenceInputStream(new ByteArrayInputStream("<form id=\"delform\">".getBytes()), stream);
}
return new Instant0chanReader(stream, canCloudflare());
}
@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() + "expand.php?after=" + oldList[oldList.length-1].number + "&board=" + boardName + "&threadid=" + threadNumber;
UrlPageModel object = new UrlPageModel();
object.chanName = "expand";
ThreadModel[] page = readWakabaPage(url, listener, task, true, object);
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;
}
}
return super.getPostsList(boardName, threadNumber, listener, task, oldList);
}
@Override
public CaptchaModel getNewCaptcha(String boardName, String threadNumber, ProgressListener listener, CancellableTask task) throws Exception {
String captchaUrl = getUsingUrl() + "captcha.php?" + Math.random();
CaptchaModel captchaModel = downloadCaptcha(captchaUrl, listener, task);
captchaModel.type = CaptchaModel.TYPE_NORMAL;
return captchaModel;
}
@Override
protected void setSendPostEntity(SendPostModel model, ExtendedMultipartBuilder postEntityBuilder) throws Exception {
postEntityBuilder.
addString("board", model.boardName).
addString("replythread", model.threadNumber == null ? "0" : model.threadNumber).
addString("name", model.name);
if (model.sage) postEntityBuilder.addString("em", "sage");
postEntityBuilder.
addString("captcha", model.captchaAnswer).
addString("subject", model.subject).
addString("message", model.comment).
addString("postpassword", model.password);
setSendPostEntityAttachments(model, postEntityBuilder);
postEntityBuilder.addString("embed", "");
postEntityBuilder.addString("redirecttothread", "1");
}
@Override
protected List<? extends NameValuePair> getReportFormAllValues(DeletePostModel model) {
List<NameValuePair> pairs = new ArrayList<NameValuePair>();
pairs.add(new BasicNameValuePair("board", model.boardName));
pairs.add(new BasicNameValuePair("post[]", model.postNumber));
pairs.add(new BasicNameValuePair("reportpost", "Отправить"));
return pairs;
}
@Override
protected String getDeleteFormValue(DeletePostModel model) {
return "Удалить";
}
@SuppressLint("SimpleDateFormat")
protected static class Instant0chanReader extends KusabaReader {
private static final Pattern PATTERN_EMBEDDED = Pattern.compile("<div (?:[^>]*)data-id=\"([^\"]*)\"(?:[^>]*)>", Pattern.DOTALL);
private static final DateFormat DATE_FORMAT;
static {
DateFormatSymbols symbols = new DateFormatSymbols();
symbols.setShortMonths(new String[] { "Янв", "Фев", "Мар", "Апр", "Май", "Июн", "Июл", "Авг", "Сен", "Окт", "Ноя", "Дек"});
DATE_FORMAT = new SimpleDateFormat("yyyy MMM dd HH:mm:ss", symbols);
DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT+3"));
}
public Instant0chanReader(InputStream in, boolean canCloudflare) {
super(in, DATE_FORMAT, canCloudflare, ~FLAG_HANDLE_EMBEDDED_POST_POSTPROCESS);
}
public Instant0chanReader(Reader reader, boolean canCloudflare) {
super(reader, DATE_FORMAT, canCloudflare, ~FLAG_HANDLE_EMBEDDED_POST_POSTPROCESS);
}
@Override
protected void parseDate(String date) {
date = date.replace("#", "");
date = date.replaceAll("(?:[^\\d]*)(\\d(?:.*))", "$1");
super.parseDate(date);
}
@Override
protected void postprocessPost(PostModel post) {
super.postprocessPost(post);
Matcher matcher = PATTERN_EMBEDDED.matcher(post.comment);
while (matcher.find()) {
String id = matcher.group(1);
String div = matcher.group(0).toLowerCase(Locale.US);
String url = null;
if (div.contains("youtube")) {
url = "http://www.youtube.com/watch?v=" + id;
} else if (div.contains("vimeo")) {
url = "http://vimeo.com/" + id;
} else if (div.contains("coub")) {
url = "http://coub.com/view/" + id;
}
if (url != null) {
AttachmentModel attachment = new AttachmentModel();
attachment.type = AttachmentModel.TYPE_OTHER_NOTFILE;
attachment.path = url;
attachment.thumbnail = div.contains("youtube") ? ("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;
}
}
}
}
}