Browse Source

Merge pull request #201 from na-ji/master

Implement parser for readmanga.today
inorichi 9 years ago
parent
commit
71783657af

+ 4 - 1
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
     }
 

+ 278 - 0
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<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");
+    }
+
+}