package io.github.xwz.base.content; import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.provider.BaseColumns; import android.util.Log; import com.raizlabs.android.dbflow.list.FlowCursorList; import com.raizlabs.android.dbflow.sql.builder.Condition; import com.raizlabs.android.dbflow.sql.language.Select; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import io.github.xwz.base.api.ContentDatabaseCache; import io.github.xwz.base.api.EpisodeBaseModel; import io.github.xwz.base.api.EpisodeBaseModel$Table; import io.github.xwz.base.api.PlayHistory; import io.github.xwz.base.api.PlayHistory$Table; public abstract class ContentManagerBase { public static final String CONTENT_ID = "io.github.xwz.base.CONTENT_ID"; public static final String CONTENT_TAG = "io.github.xwz.base.CONTENT_TAG"; public static final String CONTENT_SHOW_LIST_FETCHING = "io.github.xwz.base.CONTENT_SHOW_LIST_FETCHING"; public static final String CONTENT_SHOW_LIST_START = "io.github.xwz.base.CONTENT_SHOW_LIST_START"; public static final String CONTENT_SHOW_LIST_DONE = "io.github.xwz.base.CONTENT_SHOW_LIST_DONE"; public static final String CONTENT_SHOW_LIST_ERROR = "io.github.xwz.base.CONTENT_SHOW_LIST_ERROR"; public static final String CONTENT_SHOW_LIST_PROGRESS = "io.github.xwz.base.CONTENT_SHOW_LIST_PROGRESS"; public static final String CONTENT_EPISODE_FETCHING = "io.github.xwz.base.CONTENT_EPISODE_FETCHING"; public static final String CONTENT_EPISODE_START = "io.github.xwz.base.CONTENT_EPISODE_START"; public static final String CONTENT_EPISODE_DONE = "io.github.xwz.base.CONTENT_EPISODE_DONE"; public static final String CONTENT_EPISODE_ERROR = "io.github.xwz.base.CONTENT_EPISODE_ERROR"; public static final String CONTENT_AUTH_FETCHING = "io.github.xwz.base.CONTENT_AUTH_FETCHING"; public static final String CONTENT_AUTH_START = "io.github.xwz.base.CONTENT_AUTH_START"; public static final String CONTENT_AUTH_DONE = "io.github.xwz.base.CONTENT_AUTH_DONE"; public static final String CONTENT_AUTH_ERROR = "io.github.xwz.base.CONTENT_AUTH_ERROR"; public static final String AUTH_FAILED_NETWORK = "AUTH_FAILED_NETWORK"; public static final String AUTH_FAILED_TOKEN = "AUTH_FAILED_TOKEN"; public static final String AUTH_FAILED_URL = "AUTH_FAILED_URL"; public static final String OTHER_EPISODES = "OTHER_EPISODES"; public static final String MORE_LIKE_THIS = "More Like This"; public static final String GLOBAL_SEARCH_INTENT = "GLOBAL_SEARCH_INTENT"; public static final String RECENTLY_PLAYED = "Recently played"; //The columns we'll include in the video database table public static final String KEY_SERIES_TITLE = SearchManager.SUGGEST_COLUMN_TEXT_1; public static final String KEY_TITLE = SearchManager.SUGGEST_COLUMN_TEXT_2; public static final String KEY_IMAGE = SearchManager.SUGGEST_COLUMN_RESULT_CARD_IMAGE; public static final String KEY_DATA_TYPE = SearchManager.SUGGEST_COLUMN_CONTENT_TYPE; public static final String KEY_VIDEO_WIDTH = SearchManager.SUGGEST_COLUMN_VIDEO_WIDTH; public static final String KEY_VIDEO_HEIGHT = SearchManager.SUGGEST_COLUMN_VIDEO_HEIGHT; public static final String KEY_PRODUCTION_YEAR = SearchManager.SUGGEST_COLUMN_PRODUCTION_YEAR; public static final String KEY_COLUMN_DURATION = SearchManager.SUGGEST_COLUMN_DURATION; public static final String KEY_ACTION = SearchManager.SUGGEST_COLUMN_INTENT_ACTION; public static final String KEY_EXTRA_DATA = SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA; public static final String KEY_EXTRA_NAME = SearchManager.EXTRA_DATA_KEY; private static final String TAG = "ContentManagerBase"; private static ContentManagerBase instance = null; private Context mContext = null; private ContentCacheManager mCache = null; private ContentDatabaseCache mDb = null; public enum RecommendationPosition { FIRST(0), SECOND(1); private final int id; private RecommendationPosition(int id) { this.id = id; } public int getId() { return id; } } public ContentManagerBase(Context context) { instance = this; mContext = context; mCache = new ContentCacheManager(context); mDb = new ContentDatabaseCache(); } public static ContentManagerBase getInstance() { return instance; } public static ContentCacheManager cache() { return getInstance().mCache; } public static ContentDatabaseCache db() { return getInstance().mDb; } protected Context getContext() { return mContext; } public void broadcastChange(String change, String tag, String id) { mCache.broadcastChange(change, tag, id); } public void broadcastChange(String change, String tag) { mCache.broadcastChange(change, tag); } public void broadcastChange(String change) { mCache.broadcastChange(change); } public List<EpisodeBaseModel> searchShows(String query) { List<EpisodeBaseModel> results = new ArrayList<>(); query = query.toLowerCase(); for (EpisodeBaseModel episode : mCache.getAllShows()) { if (episode.matches(query)) { results.add(episode); } } Log.d(TAG, "Search: '" + query + "' found : " + results.size()); return results; } public Cursor searchShowsCursor(String query) { String[] columns = new String[]{ BaseColumns._ID, KEY_SERIES_TITLE, KEY_TITLE, KEY_IMAGE, KEY_DATA_TYPE, KEY_VIDEO_WIDTH, KEY_VIDEO_HEIGHT, KEY_PRODUCTION_YEAR, KEY_COLUMN_DURATION, KEY_ACTION, KEY_EXTRA_DATA, KEY_EXTRA_NAME }; MatrixCursor cursor = new MatrixCursor(columns); for (EpisodeBaseModel ep : searchShows(query)) { LinkedHashMap row = new LinkedHashMap(); row.put(BaseColumns._ID, ep.getHref()); row.put(KEY_SERIES_TITLE, ep.getSeriesTitle()); row.put(KEY_TITLE, ep.getTitle()); row.put(KEY_IMAGE, ep.getThumbnail()); row.put(KEY_DATA_TYPE, "video/mp4"); row.put(KEY_VIDEO_WIDTH, 1280); row.put(KEY_VIDEO_HEIGHT, 720); row.put(KEY_PRODUCTION_YEAR, 2015); row.put(KEY_COLUMN_DURATION, ep.getDuration() * 1000); row.put(KEY_ACTION, GLOBAL_SEARCH_INTENT); row.put(KEY_EXTRA_DATA, ep.getHref()); row.put(KEY_EXTRA_NAME, KEY_EXTRA_DATA); cursor.addRow(row.values()); } return cursor; } public List<String> suggestions(String query) { return mCache.getSuggestions(query); } public List<EpisodeBaseModel> getAllShows() { return mCache.getAllShows(); } public List<EpisodeBaseModel> getAllShowsByCategory(String cat) { List<EpisodeBaseModel> all = getAllShowsByCategories().get(cat); if (all == null) { all = new ArrayList<>(); } return all; } public EpisodeBaseModel getEpisode(String href) { return mCache.getEpisode(href); } public Uri getEpisodeStreamUrl(EpisodeBaseModel episode) { return mCache.getEpisodeStreamUrl(episode.getHref()); } public LinkedHashMap<String, List<EpisodeBaseModel>> getAllShowsByCategories() { return cache().getCollections(); } public EpisodeBaseModel findNextEpisode(List<String> urls, String current) { String next = null; boolean found = false; for (String href : urls) { if (found) { next = href; break; } found = href.equals(current); } if (!found && next == null && urls.size() > 0) { next = urls.get(0); } if (next != null) { return getEpisode(next); } return null; } public List<EpisodeBaseModel> getRecentlyPlayed() { FlowCursorList<PlayHistory> cursor = new FlowCursorList<>(false, (new Select()).from(PlayHistory.class) .orderBy("CASE WHEN "+PlayHistory$Table.PROGRESS+" >= 75 THEN 1 ELSE 0 END ASC, "+PlayHistory$Table.TIMESTAMP+" DESC") .limit(30)); List<EpisodeBaseModel> recent = new ArrayList<>(); for (int i = 0, k = cursor.getCount(); i < k; i++) { PlayHistory history = cursor.getItem(i); EpisodeBaseModel ep = getEpisode(history.href); if (ep != null) { if (history.progress < 75) { ep.setResumePosition(history.position); } ep.setRecent(true); recent.add(ep); } } return recent; } public void recommendEpisode(Context context, EpisodeBaseModel ep, RecommendationPosition position) { Intent intent = new Intent(context, getRecommendationServiceClass()); intent.putExtra(CONTENT_ID, ep); intent.putExtra(CONTENT_TAG, position.getId()); context.startService(intent); } public void updateRecommendations(Context context) { List<EpisodeBaseModel> shows = getRecommendations(); int i = 0; for (EpisodeBaseModel show : shows) { Log.d(TAG, "Recommendation: " + i + ", " + show); if (i < 2) { recommendEpisode(context, show, RecommendationPosition.values()[i++]); } } } public abstract void fetchShowList(boolean force); public abstract void fetchAuthToken(EpisodeBaseModel episode); public abstract void fetchEpisode(EpisodeBaseModel episode); public abstract List<EpisodeBaseModel> getRecommendations(); public abstract Class getRecommendationServiceClass(); }