diff --git a/app/src/main/java/eu/kanade/mangafeed/data/helpers/SourceManager.java b/app/src/main/java/eu/kanade/mangafeed/data/helpers/SourceManager.java index 2cd673a3f..80e77d985 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/helpers/SourceManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/helpers/SourceManager.java @@ -6,15 +6,18 @@ import java.util.List; import eu.kanade.mangafeed.data.caches.CacheManager; import eu.kanade.mangafeed.sources.Batoto; +import eu.kanade.mangafeed.sources.MangaHere; import eu.kanade.mangafeed.sources.Source; public class SourceManager { public static final int BATOTO = 1; + public static final int MANGAHERE = 2; private HashMap mSourcesMap; private NetworkHelper mNetworkHelper; private CacheManager mCacheManager; + private Source selected; public SourceManager(NetworkHelper networkHelper, CacheManager cacheManager) { mSourcesMap = new HashMap<>(); @@ -35,6 +38,8 @@ public class SourceManager { switch (sourceKey) { case BATOTO: return new Batoto(mNetworkHelper, mCacheManager); + case MANGAHERE: + return new MangaHere(mNetworkHelper, mCacheManager); } return null; @@ -42,9 +47,18 @@ public class SourceManager { private void initializeSources() { mSourcesMap.put(BATOTO, createSource(BATOTO)); + mSourcesMap.put(MANGAHERE, createSource(MANGAHERE)); } public List getSources() { return new ArrayList(mSourcesMap.values()); } + + public void setSelectedSource(int sourceId) { + selected = get(sourceId); + } + + public Source getSelectedSource() { + return selected; + } } diff --git a/app/src/main/java/eu/kanade/mangafeed/presenter/SourcePresenter.java b/app/src/main/java/eu/kanade/mangafeed/presenter/SourcePresenter.java index edd9294e0..e05e96d7a 100644 --- a/app/src/main/java/eu/kanade/mangafeed/presenter/SourcePresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/presenter/SourcePresenter.java @@ -37,6 +37,7 @@ public class SourcePresenter { } public void onSourceClick(int position) { + sourceManager.setSelectedSource(adapter.getItem(position).getSource()); Intent intent = new Intent(view.getActivity(), CatalogueActivity.class); intent.putExtra(Intent.EXTRA_UID, adapter.getItem(position).getSource()); view.getActivity().startActivity(intent); diff --git a/app/src/main/java/eu/kanade/mangafeed/sources/MangaHere.java b/app/src/main/java/eu/kanade/mangafeed/sources/MangaHere.java new file mode 100644 index 000000000..b0ae67473 --- /dev/null +++ b/app/src/main/java/eu/kanade/mangafeed/sources/MangaHere.java @@ -0,0 +1,364 @@ +package eu.kanade.mangafeed.sources; + +import android.database.sqlite.SQLiteDatabase; + +import com.squareup.okhttp.Response; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.atomic.AtomicInteger; + +import eu.kanade.mangafeed.data.caches.CacheManager; +import eu.kanade.mangafeed.data.helpers.NetworkHelper; +import eu.kanade.mangafeed.data.helpers.SourceManager; +import eu.kanade.mangafeed.data.models.Chapter; +import eu.kanade.mangafeed.data.models.Manga; +import rx.Observable; +import rx.functions.Action0; +import rx.functions.Action1; +import rx.functions.Func1; +import rx.functions.FuncN; +import rx.schedulers.Schedulers; + +public class MangaHere extends Source { + + public static final String NAME = "MangaHere (EN)"; + public static final String BASE_URL = "www.mangahere.co"; + + private static final String INITIAL_UPDATE_URL = "http://www.mangahere.co/latest/"; + private static final String INITIAL_SEARCH_URL = "http://www.mangahere.co/search.php?"; + + public MangaHere(NetworkHelper networkService, CacheManager cacheManager) { + super(networkService, cacheManager); + } + + @Override + public String getName() { + return NAME; + } + + public int getSource() { + return SourceManager.MANGAHERE; + } + + @Override + protected String getUrlFromPageNumber(int page) { + return INITIAL_UPDATE_URL + page + "/"; + } + + @Override + protected String getSearchUrl(String query, int page) { + return INITIAL_SEARCH_URL + "name=" + query + "&page=" + page; + } + + public Observable> getGenres() { + List genres = new ArrayList<>(30); + + genres.add("Action"); + genres.add("Adventure"); + genres.add("Comedy"); + genres.add("Drama"); + genres.add("Ecchi"); + genres.add("Fantasy"); + genres.add("Gender Bender"); + genres.add("Harem"); + genres.add("Historical"); + genres.add("Horror"); + genres.add("Josei"); + genres.add("Martial Arts"); + genres.add("Mature"); + genres.add("Mecha"); + genres.add("Mystery"); + genres.add("One Shot"); + genres.add("Psychological"); + genres.add("Romance"); + genres.add("School Life"); + genres.add("Sci-fi"); + genres.add("Seinen"); + genres.add("Shoujo"); + genres.add("Shoujo Ai"); + genres.add("Shounen"); + genres.add("Shounen Ai"); + genres.add("Slice of Life"); + genres.add("Sports"); + genres.add("Supernatural"); + genres.add("Tragedy"); + genres.add("Yaoi"); + genres.add("Yuri"); + + return Observable.just(genres); + } + + @Override + public List parsePopularMangasFromHtml(String unparsedHtml) { + Document parsedDocument = Jsoup.parse(unparsedHtml); + + List updatedMangaList = new ArrayList<>(); + + Elements updatedHtmlBlocks = parsedDocument.select("div.manga_updates dl"); + for (Element currentHtmlBlock : updatedHtmlBlocks) { + Manga currentlyUpdatedManga = constructMangaFromHtmlBlock(currentHtmlBlock); + + updatedMangaList.add(currentlyUpdatedManga); + } + + return updatedMangaList; + } + + @Override + protected List parseSearchFromHtml(String unparsedHtml) { + return null; + } + + private Manga constructMangaFromHtmlBlock(Element htmlBlock) { + Manga mangaFromHtmlBlock = new Manga(); + mangaFromHtmlBlock.source = getSource(); + + Element urlElement = htmlBlock.select("a.manga_info").first(); + Element nameElement = htmlBlock.select("a.manga_info").first(); + Element updateElement = htmlBlock.select("span.time").first(); + + if (urlElement != null) { + String fieldUrl = urlElement.attr("href"); + mangaFromHtmlBlock.url = fieldUrl; + } + if (nameElement != null) { + String fieldName = nameElement.text(); + mangaFromHtmlBlock.title = fieldName; + } + if (updateElement != null) { + long fieldUpdate = parseUpdateFromElement(updateElement); + mangaFromHtmlBlock.last_update = fieldUpdate; + } + + return mangaFromHtmlBlock; + } + + private long parseUpdateFromElement(Element updateElement) { + String updatedDateAsString = updateElement.text(); + + if (updatedDateAsString.contains("Today")) { + Calendar today = Calendar.getInstance(); + today.set(Calendar.HOUR_OF_DAY, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + today.set(Calendar.MILLISECOND, 0); + + try { + Date withoutDay = new SimpleDateFormat("MMM d, yyyy h:mma", Locale.ENGLISH).parse(updatedDateAsString.replace("Today", "")); + return today.getTimeInMillis() + withoutDay.getTime(); + } catch (ParseException e) { + return today.getTimeInMillis(); + } + } else if (updatedDateAsString.contains("Yesterday")) { + Calendar yesterday = Calendar.getInstance(); + yesterday.add(Calendar.DATE, -1); + yesterday.set(Calendar.HOUR_OF_DAY, 0); + yesterday.set(Calendar.MINUTE, 0); + yesterday.set(Calendar.SECOND, 0); + yesterday.set(Calendar.MILLISECOND, 0); + + try { + Date withoutDay = new SimpleDateFormat("MMM d, yyyy h:mma", Locale.ENGLISH).parse(updatedDateAsString.replace("Yesterday", "")); + return yesterday.getTimeInMillis() + withoutDay.getTime(); + } catch (ParseException e) { + return yesterday.getTimeInMillis(); + } + } else { + try { + Date specificDate = new SimpleDateFormat("MMM d, yyyy h:mma", Locale.ENGLISH).parse(updatedDateAsString); + + return specificDate.getTime(); + } catch (ParseException e) { + // Do Nothing. + } + } + + return 0; + } + + 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); + + Elements detailElements = parsedDocument.select("ul.detail_topText li"); + + Element artistElement = parsedDocument.select("a[href^=http://www.mangahere.co/artist/]").first(); + Element authorElement = parsedDocument.select("a[href^=http://www.mangahere.co/author/]").first(); + Element descriptionElement = detailElements.select("#show").first(); + Element genreElement = detailElements.get(3); + Element statusElement = detailElements.get(6); + + Manga newManga = new Manga(); + newManga.url = mangaUrl; + + if (artistElement != null) { + String fieldArtist = artistElement.text(); + newManga.artist = fieldArtist; + } + if (authorElement != null) { + String fieldAuthor = authorElement.text(); + newManga.author = fieldAuthor; + } + if (descriptionElement != null) { + String fieldDescription = descriptionElement.text().substring(0, descriptionElement.text().length() - "Show less".length()); + newManga.description = fieldDescription; + } + if (genreElement != null) { + String fieldGenre = genreElement.text().substring("Genre(s):".length()); + newManga.genre = fieldGenre; + } + if (statusElement != null) { + boolean fieldCompleted = statusElement.text().contains("Completed"); + newManga.status = fieldCompleted + ""; + } + + beginIndex = unparsedHtml.indexOf("", beginIndex); + trimmedHtml = unparsedHtml.substring(beginIndex, endIndex + 2); + parsedDocument = Jsoup.parse(trimmedHtml); + Element thumbnailUrlElement = parsedDocument.select("img").first(); + + if (thumbnailUrlElement != null) { + String fieldThumbnailUrl = thumbnailUrlElement.attr("src"); + newManga.thumbnail_url = fieldThumbnailUrl; + } + + newManga.initialized = true; + + return newManga; + } + + @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(); + + Elements chapterElements = parsedDocument.getElementsByTag("li"); + for (Element chapterElement : chapterElements) { + Chapter currentChapter = constructChapterFromHtmlBlock(chapterElement); + + chapterList.add(currentChapter); + } + + return chapterList; + } + + private Chapter constructChapterFromHtmlBlock(Element chapterElement) { + Chapter newChapter = Chapter.newChapter(); + + Element urlElement = chapterElement.select("a").first(); + Element nameElement = chapterElement.select("a").first(); + Element dateElement = chapterElement.select("span.right").first(); + + if (urlElement != null) { + String fieldUrl = urlElement.attr("href"); + newChapter.url = fieldUrl; + } + if (nameElement != null) { + String fieldName = nameElement.text(); + newChapter.name = fieldName; + } + if (dateElement != null) { + long fieldDate = parseDateFromElement(dateElement); + newChapter.date_upload = fieldDate; + } + newChapter.date_fetch = new Date().getTime(); + + return newChapter; + } + + private long parseDateFromElement(Element dateElement) { + String dateAsString = dateElement.text(); + + if (dateAsString.contains("Today")) { + Calendar today = Calendar.getInstance(); + today.set(Calendar.HOUR_OF_DAY, 0); + today.set(Calendar.MINUTE, 0); + today.set(Calendar.SECOND, 0); + today.set(Calendar.MILLISECOND, 0); + + try { + Date withoutDay = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(dateAsString.replace("Today", "")); + return today.getTimeInMillis() + withoutDay.getTime(); + } catch (ParseException e) { + return today.getTimeInMillis(); + } + } else if (dateAsString.contains("Yesterday")) { + Calendar yesterday = Calendar.getInstance(); + yesterday.add(Calendar.DATE, -1); + yesterday.set(Calendar.HOUR_OF_DAY, 0); + yesterday.set(Calendar.MINUTE, 0); + yesterday.set(Calendar.SECOND, 0); + yesterday.set(Calendar.MILLISECOND, 0); + + try { + Date withoutDay = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(dateAsString.replace("Yesterday", "")); + return yesterday.getTimeInMillis() + withoutDay.getTime(); + } catch (ParseException e) { + return yesterday.getTimeInMillis(); + } + } else { + try { + Date date = new SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(dateAsString); + + return date.getTime(); + } catch (ParseException e) { + // Do Nothing. + } + } + + 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("select.wid60").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 = parsedDocument.getElementById("image"); + + return imageElement.attr("src"); + } + +}