Merge pull request #201 from na-ji/master
Implement parser for readmanga.today
This commit is contained in:
commit
71783657af
2 changed files with 282 additions and 1 deletions
|
@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.source.online.english.Mangahere
|
|||
import eu.kanade.tachiyomi.data.source.online.russian.Mangachan;
|
||||
import eu.kanade.tachiyomi.data.source.online.russian.Mintmanga;
|
||||
import eu.kanade.tachiyomi.data.source.online.russian.Readmanga;
|
||||
import eu.kanade.tachiyomi.data.source.online.english.ReadMangaToday
|
||||
import java.util.*
|
||||
|
||||
open class SourceManager(private val context: Context) {
|
||||
|
@ -22,8 +23,9 @@ open class SourceManager(private val context: Context) {
|
|||
val READMANGA = 5
|
||||
val MINTMANGA = 6
|
||||
val MANGACHAN = 7
|
||||
val READMANGATODAY = 8
|
||||
|
||||
val LAST_SOURCE = 7
|
||||
val LAST_SOURCE = 8
|
||||
|
||||
init {
|
||||
sourcesMap = createSourcesMap()
|
||||
|
@ -41,6 +43,7 @@ open class SourceManager(private val context: Context) {
|
|||
READMANGA -> Readmanga(context)
|
||||
MINTMANGA -> Mintmanga(context)
|
||||
MANGACHAN -> Mangachan(context)
|
||||
READMANGATODAY -> ReadMangaToday(context)
|
||||
else -> null
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,278 @@
|
|||
package eu.kanade.tachiyomi.data.source.online.english;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
||||
import eu.kanade.tachiyomi.data.source.Language;
|
||||
import eu.kanade.tachiyomi.data.source.LanguageKt;
|
||||
import eu.kanade.tachiyomi.data.source.base.Source;
|
||||
import eu.kanade.tachiyomi.data.source.model.MangasPage;
|
||||
import eu.kanade.tachiyomi.util.Parser;
|
||||
import okhttp3.Headers;
|
||||
import rx.Observable;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
public class ReadMangaToday extends Source {
|
||||
public static final String NAME = "ReadMangaToday";
|
||||
public static final String BASE_URL = "http://www.readmanga.today";
|
||||
public static final String POPULAR_MANGAS_URL = BASE_URL + "/hot-manga/%s";
|
||||
public static final String SEARCH_URL = BASE_URL + "/service/search?q=%s";
|
||||
|
||||
private static JsonParser parser = new JsonParser();
|
||||
private static Gson gson = new Gson();
|
||||
|
||||
public ReadMangaToday(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
return BASE_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInitialPopularMangasUrl() {
|
||||
return String.format(POPULAR_MANGAS_URL, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getInitialSearchUrl(String query) {
|
||||
return String.format(SEARCH_URL, Uri.encode(query), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Language getLang() {
|
||||
return LanguageKt.getEN();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Manga> parsePopularMangasFromHtml(Document parsedHtml) {
|
||||
List<Manga> mangaList = new ArrayList<>();
|
||||
|
||||
for (Element currentHtmlBlock : parsedHtml.select("div.hot-manga > div.style-list > div.box")) {
|
||||
Manga currentManga = constructPopularMangaFromHtmlBlock(currentHtmlBlock);
|
||||
mangaList.add(currentManga);
|
||||
}
|
||||
return mangaList;
|
||||
}
|
||||
|
||||
private Manga constructPopularMangaFromHtmlBlock(Element htmlBlock) {
|
||||
Manga manga = new Manga();
|
||||
manga.source = getId();
|
||||
|
||||
Element urlElement = Parser.element(htmlBlock, "div.title > h2 > a");
|
||||
if (urlElement != null) {
|
||||
manga.setUrl(urlElement.attr("href"));
|
||||
manga.title = urlElement.attr("title");
|
||||
}
|
||||
return manga;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseNextPopularMangasUrl(Document parsedHtml, MangasPage page) {
|
||||
Element next = Parser.element(parsedHtml, "div.hot-manga > ul.pagination > li > a:contains(»)");
|
||||
return next != null ? next.attr("href") : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Observable<MangasPage> searchMangasFromNetwork(MangasPage page, String query) {
|
||||
return networkService
|
||||
.requestBody(searchMangaRequest(page, query), true)
|
||||
.doOnNext(doc -> page.mangas = parseSearchFromJson(doc))
|
||||
.map(response -> page);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Headers.Builder headersBuilder() {
|
||||
return super.headersBuilder().add("X-Requested-With", "XMLHttpRequest");
|
||||
}
|
||||
|
||||
protected List<Manga> parseSearchFromJson(String unparsedJson) {
|
||||
List<Manga> mangaList = new ArrayList<>();
|
||||
|
||||
JsonArray mangasArray = parser.parse(unparsedJson).getAsJsonArray();
|
||||
|
||||
for (JsonElement mangaElement : mangasArray) {
|
||||
Manga currentManga = constructSearchMangaFromJsonObject(mangaElement.getAsJsonObject());
|
||||
mangaList.add(currentManga);
|
||||
}
|
||||
return mangaList;
|
||||
}
|
||||
|
||||
private Manga constructSearchMangaFromJsonObject(JsonObject jsonObject) {
|
||||
Manga manga = new Manga();
|
||||
manga.source = getId();
|
||||
|
||||
manga.setUrl(gson.fromJson(jsonObject.get("url"), String.class));
|
||||
manga.title = gson.fromJson(jsonObject.get("title"), String.class);
|
||||
|
||||
return manga;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Manga> parseSearchFromHtml(Document parsedHtml) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseNextSearchUrl(Document parsedHtml, MangasPage page, String query) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Manga parseHtmlToManga(String mangaUrl, String unparsedHtml) {
|
||||
int beginIndex = unparsedHtml.indexOf("<!-- content start -->");
|
||||
int endIndex = unparsedHtml.indexOf("<!-- /content-end -->", beginIndex);
|
||||
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
|
||||
|
||||
Document parsedDocument = Jsoup.parse(trimmedHtml);
|
||||
Element detailElement = parsedDocument.select("div.movie-meta").first();
|
||||
|
||||
Manga manga = Manga.create(mangaUrl);
|
||||
for (Element castHtmlBlock : parsedDocument.select("div.cast ul.cast-list > li")) {
|
||||
String name = Parser.text(castHtmlBlock, "ul > li > a");
|
||||
String role = Parser.text(castHtmlBlock, "ul > li:eq(1)");
|
||||
if (role.equals("Author")) {
|
||||
manga.author = name;
|
||||
} else if (role.equals("Artist")) {
|
||||
manga.artist = name;
|
||||
}
|
||||
}
|
||||
|
||||
String description = Parser.text(detailElement, "li.movie-detail");
|
||||
if (description != null) {
|
||||
manga.description = description;
|
||||
}
|
||||
String genres = Parser.text(detailElement, "dl.dl-horizontal > dd:eq(5)");
|
||||
if (genres != null) {
|
||||
manga.genre = genres;
|
||||
}
|
||||
manga.status = parseStatus(Parser.text(detailElement, "dl.dl-horizontal > dd:eq(3)"));
|
||||
manga.thumbnail_url = Parser.src(detailElement, "img.img-responsive");
|
||||
|
||||
manga.initialized = true;
|
||||
return manga;
|
||||
}
|
||||
|
||||
private int parseStatus(String status) {
|
||||
if (status.contains("Ongoing")) {
|
||||
return Manga.ONGOING;
|
||||
} else if (status.contains("Completed")) {
|
||||
return Manga.COMPLETED;
|
||||
}
|
||||
return Manga.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Chapter> parseHtmlToChapters(String unparsedHtml) {
|
||||
int beginIndex = unparsedHtml.indexOf("<!-- content start -->");
|
||||
int endIndex = unparsedHtml.indexOf("<!-- /content-end -->", beginIndex);
|
||||
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
|
||||
|
||||
Document parsedDocument = Jsoup.parse(trimmedHtml);
|
||||
|
||||
List<Chapter> chapterList = new ArrayList<>();
|
||||
|
||||
for (Element chapterElement : parsedDocument.select("ul.chp_lst > li")) {
|
||||
Chapter currentChapter = constructChapterFromHtmlBlock(chapterElement);
|
||||
chapterList.add(currentChapter);
|
||||
}
|
||||
return chapterList;
|
||||
}
|
||||
|
||||
private Chapter constructChapterFromHtmlBlock(Element chapterElement) {
|
||||
Chapter chapter = Chapter.create();
|
||||
|
||||
Element urlElement = chapterElement.select("a").first();
|
||||
Element dateElement = chapterElement.select("span.dte").first();
|
||||
|
||||
if (urlElement != null) {
|
||||
chapter.setUrl(urlElement.attr("href"));
|
||||
chapter.name = urlElement.select("span.val").text();
|
||||
}
|
||||
if (dateElement != null) {
|
||||
chapter.date_upload = parseDateFromElement(dateElement);
|
||||
}
|
||||
return chapter;
|
||||
}
|
||||
|
||||
private long parseDateFromElement(Element dateElement) {
|
||||
String dateAsString = dateElement.text();
|
||||
String[] dateWords = dateAsString.split(" ");
|
||||
|
||||
if (dateWords.length == 3) {
|
||||
int timeAgo = Integer.parseInt(dateWords[0]);
|
||||
Calendar date = Calendar.getInstance();
|
||||
|
||||
if (dateWords[1].contains("Minute")) {
|
||||
date.add(Calendar.MINUTE, - timeAgo);
|
||||
} else if (dateWords[1].contains("Hour")) {
|
||||
date.add(Calendar.HOUR_OF_DAY, - timeAgo);
|
||||
} else if (dateWords[1].contains("Day")) {
|
||||
date.add(Calendar.DAY_OF_YEAR, -timeAgo);
|
||||
} else if (dateWords[1].contains("Week")) {
|
||||
date.add(Calendar.WEEK_OF_YEAR, -timeAgo);
|
||||
} else if (dateWords[1].contains("Month")) {
|
||||
date.add(Calendar.MONTH, -timeAgo);
|
||||
} else if (dateWords[1].contains("Year")) {
|
||||
date.add(Calendar.YEAR, -timeAgo);
|
||||
}
|
||||
|
||||
return date.getTimeInMillis();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> parseHtmlToPageUrls(String unparsedHtml) {
|
||||
int beginIndex = unparsedHtml.indexOf("<!-- content start -->");
|
||||
int endIndex = unparsedHtml.indexOf("<!-- /content-end -->", beginIndex);
|
||||
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
|
||||
|
||||
Document parsedDocument = Jsoup.parse(trimmedHtml);
|
||||
|
||||
List<String> pageUrlList = new ArrayList<>();
|
||||
|
||||
Elements pageUrlElements = parsedDocument.select("ul.list-switcher-2 > li > select.jump-menu").first().getElementsByTag("option");
|
||||
for (Element pageUrlElement : pageUrlElements) {
|
||||
pageUrlList.add(pageUrlElement.attr("value"));
|
||||
}
|
||||
|
||||
return pageUrlList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseHtmlToImageUrl(String unparsedHtml) {
|
||||
int beginIndex = unparsedHtml.indexOf("<!-- content start -->");
|
||||
int endIndex = unparsedHtml.indexOf("<!-- /content-end -->", beginIndex);
|
||||
String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex);
|
||||
|
||||
Document parsedDocument = Jsoup.parse(trimmedHtml);
|
||||
|
||||
Element imageElement = Parser.element(parsedDocument, "img.img-responsive-2");
|
||||
|
||||
return imageElement.attr("src");
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue