From 3d6760776818ea04a033af6c2a6e1c1729dbc15d Mon Sep 17 00:00:00 2001 From: Naji Astier Date: Tue, 22 Mar 2016 20:02:10 +0100 Subject: [PATCH] Merge remote-tracking branch 'upstream/master' --- .../tachiyomi/data/source/SourceManager.kt | 5 +- .../source/online/english/ReadMangaToday.java | 278 ++++++++++++++++++ 2 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/ReadMangaToday.java diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/SourceManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/source/SourceManager.kt index 65b6518ac..e9bdaaf39 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/source/SourceManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/SourceManager.kt @@ -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 } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/ReadMangaToday.java b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/ReadMangaToday.java new file mode 100644 index 000000000..b94ac7871 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/source/online/english/ReadMangaToday.java @@ -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 parsePopularMangasFromHtml(Document parsedHtml) { + List 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 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 parseSearchFromJson(String unparsedJson) { + List 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 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(""); + int endIndex = unparsedHtml.indexOf("", 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 parseHtmlToChapters(String unparsedHtml) { + int beginIndex = unparsedHtml.indexOf(""); + int endIndex = unparsedHtml.indexOf("", beginIndex); + String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex); + + Document parsedDocument = Jsoup.parse(trimmedHtml); + + List 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 parseHtmlToPageUrls(String unparsedHtml) { + int beginIndex = unparsedHtml.indexOf(""); + int endIndex = unparsedHtml.indexOf("", beginIndex); + String trimmedHtml = unparsedHtml.substring(beginIndex, endIndex); + + Document parsedDocument = Jsoup.parse(trimmedHtml); + + List 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(""); + int endIndex = unparsedHtml.indexOf("", 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"); + } + +}