pct.droid.base.providers.media.HaruProvider.java Source code

Java tutorial

Introduction

Here is the source code for pct.droid.base.providers.media.HaruProvider.java

Source

/*
 * This file is part of Popcorn Time.
 *
 * Popcorn Time 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.
 *
 * Popcorn Time 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 Popcorn Time. If not, see <http://www.gnu.org/licenses/>.
 */

package pct.droid.base.providers.media;

import android.accounts.NetworkErrorException;
import android.text.Html;

import com.google.gson.internal.LinkedTreeMap;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import pct.droid.base.PopcornApplication;
import pct.droid.base.R;
import pct.droid.base.providers.media.models.Episode;
import pct.droid.base.providers.media.models.Genre;
import pct.droid.base.providers.media.models.Media;
import pct.droid.base.providers.media.models.Movie;
import pct.droid.base.providers.media.models.Show;

public class HaruProvider extends MediaProvider {

    private static String API_URL = "http://ptp.haruhichan.com/";
    private static final MediaProvider sMediaProvider = new HaruProvider();

    @Override
    public Call getList(final ArrayList<Media> existingList, Filters filters, final Callback callback) {
        final ArrayList<Media> currentList;
        if (existingList == null) {
            currentList = new ArrayList<>();
        } else {
            currentList = (ArrayList<Media>) existingList.clone();
        }

        ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
        params.add(new NameValuePair("limit", "30"));

        if (filters == null) {
            filters = new Filters();
        }

        if (filters.keywords != null) {
            params.add(new NameValuePair("search", filters.keywords));
        }

        if (filters.genre != null) {
            params.add(new NameValuePair("genres", filters.genre));
        }

        if (filters.order == Filters.Order.DESC) {
            params.add(new NameValuePair("order", "desc"));
        } else {
            params.add(new NameValuePair("order", "asc"));
        }

        String sort = "";
        switch (filters.sort) {
        default:
        case POPULARITY:
            sort = "popularity";
            break;
        case YEAR:
            sort = "year";
            break;
        case DATE:
            sort = "updated";
            break;
        case RATING:
            sort = "rating";
            break;
        case ALPHABET:
            sort = "name";
            break;
        }

        params.add(new NameValuePair("sort", sort));

        String url = API_URL + "list.php";
        if (filters.page != null) {
            params.add(new NameValuePair("page", Integer.toString(filters.page - 1)));
        } else {
            params.add(new NameValuePair("page", "0"));
        }

        Request.Builder requestBuilder = new Request.Builder();
        String query = buildQuery(params);
        requestBuilder.url(url + "?" + query);
        requestBuilder.tag(MEDIA_CALL);

        return fetchList(currentList, requestBuilder, filters, callback);
    }

    /**
     * Fetch the list of movies from Haruhichan
     *
     * @param currentList    Current shown list to be extended
     * @param requestBuilder Request to be executed
     * @param callback       Network callback
     * @return Call
     */
    private Call fetchList(final ArrayList<Media> currentList, final Request.Builder requestBuilder,
            final Filters filters, final Callback callback) {
        return enqueue(requestBuilder.build(), new com.squareup.okhttp.Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                callback.onFailure(e);
            }

            @Override
            public void onResponse(Response response) throws IOException {
                try {
                    if (response.isSuccessful()) {
                        String responseStr = response.body().string();

                        ArrayList<LinkedTreeMap<String, Object>> list = null;
                        if (responseStr.isEmpty()) {
                            list = new ArrayList<>();
                        } else {
                            list = (ArrayList<LinkedTreeMap<String, Object>>) mGson.fromJson(responseStr,
                                    ArrayList.class);
                        }

                        HaruResponse result = new HaruResponse(list);
                        if (list == null) {
                            callback.onFailure(new NetworkErrorException("Empty response"));
                        } else {
                            ArrayList<Media> formattedData = result.formatListForPopcorn(currentList);
                            callback.onSuccess(filters, formattedData, list.size() > 0);
                            return;
                        }
                    }
                } catch (Exception e) {
                    callback.onFailure(e);
                }
                callback.onFailure(new NetworkErrorException("Couldn't connect to Haruhichan"));
            }
        });
    }

    @Override
    public Call getDetail(String videoId, final Callback callback) {
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(API_URL + "anime.php?id=" + videoId);
        requestBuilder.tag(MEDIA_CALL);

        return enqueue(requestBuilder.build(), new com.squareup.okhttp.Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                callback.onFailure(e);
            }

            @Override
            public void onResponse(Response response) throws IOException {
                if (response.isSuccessful()) {
                    String responseStr = response.body().string();
                    LinkedTreeMap<String, Object> map = mGson.fromJson(responseStr, LinkedTreeMap.class);
                    HaruResponse result = new HaruResponse(map);
                    if (map == null) {
                        callback.onFailure(new NetworkErrorException("Empty response"));
                    } else {
                        ArrayList<Media> formattedData = result.formatDetailForPopcorn();

                        if (formattedData.size() > 0) {
                            callback.onSuccess(null, formattedData, true);
                            return;
                        }
                        callback.onFailure(new IllegalStateException("Empty list"));
                        return;
                    }
                }
                callback.onFailure(new NetworkErrorException("Couldn't connect to Haruhichan API"));
            }
        });
    }

    @Override
    public int getLoadingMessage() {
        return R.string.loading_data;
    }

    @Override
    public List<NavInfo> getNavigation() {
        List<NavInfo> tabs = new ArrayList<>();
        tabs.add(new NavInfo(Filters.Sort.POPULARITY, Filters.Order.DESC,
                PopcornApplication.getAppContext().getString(R.string.popular_now)));
        tabs.add(new NavInfo(Filters.Sort.ALPHABET, Filters.Order.ASC,
                PopcornApplication.getAppContext().getString(R.string.a_to_z)));
        return tabs;
    }

    @Override
    public List<Genre> getGenres() {
        List<Genre> returnList = new ArrayList<>();
        returnList.add(new Genre("All", R.string.genre_all));
        returnList.add(new Genre("Action", R.string.genre_action));
        returnList.add(new Genre("Adventure", R.string.genre_adventure));
        returnList.add(new Genre("Cars", R.string.genre_cars));
        returnList.add(new Genre("Comedy", R.string.genre_comedy));
        returnList.add(new Genre("Dementia", R.string.genre_dementia));
        returnList.add(new Genre("Demons", R.string.genre_demons));
        returnList.add(new Genre("Drama", R.string.genre_drama));
        returnList.add(new Genre("Ecchi", R.string.genre_ecchi));
        returnList.add(new Genre("Fantasy", R.string.genre_fantasy));
        returnList.add(new Genre("Game", R.string.genre_game));
        returnList.add(new Genre("Harem", R.string.genre_harem));
        returnList.add(new Genre("Historical", R.string.genre_history));
        returnList.add(new Genre("Horror", R.string.genre_horror));
        returnList.add(new Genre("Josei", R.string.genre_josei));
        returnList.add(new Genre("Kids", R.string.genre_kids));
        returnList.add(new Genre("Magic", R.string.genre_magic));
        returnList.add(new Genre("Martial Arts", R.string.genre_martial_arts));
        returnList.add(new Genre("Mecha", R.string.genre_mecha));
        returnList.add(new Genre("Military", R.string.genre_military));
        returnList.add(new Genre("Music", R.string.genre_music));
        returnList.add(new Genre("Mystery", R.string.genre_mystery));
        returnList.add(new Genre("Parody", R.string.genre_parody));
        returnList.add(new Genre("Police", R.string.genre_police));
        returnList.add(new Genre("Psychological", R.string.genre_psychological));
        returnList.add(new Genre("Romance", R.string.genre_romance));
        returnList.add(new Genre("Samurai", R.string.genre_samurai));
        returnList.add(new Genre("School", R.string.genre_school));
        returnList.add(new Genre("Sci-Fi", R.string.genre_sci_fi));
        returnList.add(new Genre("Seinen", R.string.genre_seinen));
        returnList.add(new Genre("Shoujo", R.string.genre_shoujo));
        returnList.add(new Genre("Shoujo Ai", R.string.genre_shoujo_ai));
        returnList.add(new Genre("Shounen", R.string.genre_shounen));
        returnList.add(new Genre("Shounen Ai", R.string.genre_shounen_ai));
        returnList.add(new Genre("Slice of Life", R.string.genre_slice_of_life));
        returnList.add(new Genre("Space", R.string.genre_space));
        returnList.add(new Genre("Sports", R.string.genre_sport));
        returnList.add(new Genre("Super Power", R.string.genre_super_power));
        returnList.add(new Genre("Supernatural", R.string.genre_supernatural));
        returnList.add(new Genre("Thriller", R.string.genre_thriller));
        returnList.add(new Genre("Vampire", R.string.genre_vampire));
        return returnList;
    }

    private class HaruResponse {
        LinkedTreeMap<String, Object> detailData;
        ArrayList<LinkedTreeMap<String, Object>> showsList;

        Show.Status[] statusArray = new Show.Status[] { Show.Status.NOT_AIRED_YET, Show.Status.CONTINUING,
                Show.Status.ENDED };

        public HaruResponse(LinkedTreeMap<String, Object> detailData) {
            this.detailData = detailData;
        }

        public ArrayList<Media> formatDetailForPopcorn() {
            ArrayList<Media> list = new ArrayList<>();

            String image = detailData.get("malimg").toString();
            String id = detailData.get("id").toString();
            String synopsis = Html.fromHtml(detailData.get("synopsis").toString()).toString();
            List<LinkedTreeMap<String, Object>> episodes = (List<LinkedTreeMap<String, Object>>) detailData
                    .get("episodes");

            Media media;
            if (detailData.get("type").toString().equalsIgnoreCase("movie")) {
                Movie movie = new Movie(sMediaProvider, null);

                String duration = detailData.get("duration").toString();
                if (duration.contains("to"))
                    duration = duration.split("to ")[1];
                movie.runtime = duration.split(" min")[0];
                movie.synopsis = synopsis;

                for (LinkedTreeMap<String, Object> item : episodes) {
                    Pattern pattern = Pattern.compile("([0-9]+p)", Pattern.CASE_INSENSITIVE);
                    Matcher matcher = pattern.matcher(item.get("quality").toString());
                    if (matcher.find()) {
                        String quality = matcher.group(1);
                        if (!movie.torrents.containsKey(quality)) {
                            movie.torrents.put(quality,
                                    new Media.Torrent(item.get("magnet").toString(), 0, 0, null));
                        }
                    }
                }

                media = movie;
            } else {
                Show show = new Show(sMediaProvider, null);

                show.seasons = 1;

                String duration = detailData.get("duration").toString();
                if (duration.contains("to"))
                    duration = duration.split("to ")[1];
                show.runtime = duration;
                show.synopsis = synopsis;
                show.status = statusArray[Integer.parseInt(detailData.get("status").toString())];

                Map<Integer, Episode> episodeMap = new HashMap<>();

                for (LinkedTreeMap<String, Object> item : episodes) {
                    try {
                        Episode episode = new Episode(sMediaProvider, null, null);

                        Pattern pattern = Pattern.compile("([0-9]+p)", Pattern.CASE_INSENSITIVE);
                        Pattern match = Pattern.compile("[\\s_]([0-9]+(-[0-9]+)?|CM|OVA)[\\s_]",
                                Pattern.CASE_INSENSITIVE);
                        Matcher name = match.matcher(item.get("name").toString());
                        Matcher matcher = pattern.matcher(item.get("quality").toString());

                        if (name.find() && matcher.find()) {
                            String quality = matcher.group(1);

                            episode.dateBased = false;
                            episode.season = 1;
                            episode.episode = Integer.parseInt(name.group(1));

                            if (!episodeMap.containsKey(episode.episode)) {
                                episode.aired = -1;
                                episode.title = PopcornApplication.getAppContext().getString(R.string.episode) + " "
                                        + episode.episode;
                                episode.overview = PopcornApplication.getAppContext()
                                        .getString(R.string.overview_not_available);
                                episode.videoId = show.videoId + episode.season + episode.episode;
                                episode.imdbId = show.imdbId;
                                episode.image = episode.fullImage = episode.headerImage = image;
                            } else {
                                episode = episodeMap.get(episode.episode);
                            }

                            if (!episode.torrents.containsKey(quality)) {
                                episode.torrents.put(quality,
                                        new Media.Torrent(item.get("magnet").toString(), 0, 0, null));
                            }

                            episodeMap.put(episode.episode, episode);
                        }
                    } catch (Exception e) {
                        // Do nothing
                    }
                }

                show.episodes = new ArrayList<>(episodeMap.values());

                media = show;
            }

            media.title = (String) detailData.get("name");
            media.videoId = id;
            media.imdbId = "mal-" + media.videoId;
            String year = detailData.get("aired").toString().split(", ")[1];
            if (year.contains(" ")) {
                year = year.split(" ")[0];
            }
            media.year = year;
            media.image = media.headerImage = image;
            String genres = detailData.get("genres").toString();
            if (genres.contains(", ")) {
                genres = genres.split(", ")[0];
            }
            media.genre = genres;
            media.rating = "-1";

            list.add(media);

            return list;
        }

        public HaruResponse(ArrayList<LinkedTreeMap<String, Object>> showsList) {
            this.showsList = showsList;
        }

        public ArrayList<Media> formatListForPopcorn(ArrayList<Media> existingList) {
            for (LinkedTreeMap<String, Object> item : showsList) {
                Media media;
                if (item.get("type").toString().equalsIgnoreCase("movie")) {
                    media = new Movie(sMediaProvider, null);
                } else {
                    media = new Show(sMediaProvider, null);
                }

                media.title = (String) item.get("name");
                media.videoId = item.get("id").toString();
                media.imdbId = "mal-" + media.videoId;
                String year = item.get("aired").toString();
                if (year.contains(", ")) {
                    year = year.split(", ")[1];
                }
                if (year.contains(" ")) {
                    year = year.split(" ")[0];
                }
                media.year = year;
                media.image = media.headerImage = item.get("malimg").toString();

                existingList.add(media);
            }
            return existingList;
        }
    }

}