package io.github.xwz.sbs.api; import android.content.Context; import android.net.Uri; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import com.google.gson.annotations.SerializedName; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import io.github.xwz.base.api.EpisodeBaseModel; import io.github.xwz.base.api.HttpApiBase; import io.github.xwz.sbs.BuildConfig; abstract class SBSApiBase extends HttpApiBase { private static final String TAG = "SBSApiBase"; private static final String API_URL = BuildConfig.API_URL; private static final String VIDEO_URL = BuildConfig.VIDEO_URL; private static final String PATH_FEATURED = "f/Bgtm9B/sbs-featured-programs-prod"; private static final String PATH_PROGRAMS = "f/Bgtm9B/sbs-section-programs"; private static final String PATH_RELATED = "related"; private static final String PATH_TRENDING = "trending"; private static final String CACHE_PATH = "sbs-api"; private static final Pattern ID_PATTERN = Pattern.compile("/(\\d+)$"); private int lastEntryCount = 0; public SBSApiBase(Context context) { super(context); } protected String getCachePath() { return CACHE_PATH; } Uri buildApiUrl(Map<String, String> params) { return buildUrlWithPath(PATH_PROGRAMS, params); } Uri buildRelatedUrl(Map<String, String> params) { return buildUrlWithPath(PATH_RELATED, params); } Uri buildFeaturedUrl(Map<String, String> params) { return buildUrlWithPath(PATH_FEATURED, params); } Uri buildTrendingUrl(Map<String, String> params) { return buildUrlWithPath(PATH_TRENDING, params); } protected Uri createStreamUrl(String href) { String id = getIdFromUrl(href); if (id != null) { Uri.Builder uri = Uri.parse(VIDEO_URL).buildUpon(); uri.appendPath(id); return uri.build(); } return null; } private Uri buildUrlWithPath(String path, Map<String, String> params) { Uri.Builder uri = Uri.parse(API_URL).buildUpon(); for (String part : path.split("/")) { uri.appendPath(part); } if (params != null) { for (Map.Entry<String, String> param : params.entrySet()) { uri.appendQueryParameter(param.getKey(), param.getValue()); } } return uri.build(); } String getIdFromUrl(String url) { Matcher m = ID_PATTERN.matcher(url); if (m.find()) { return m.group(1); } return null; } protected int getLastEntryCount() { return lastEntryCount; } List<EpisodeBaseModel> fetchContent(Uri url, int staleness) { InputStream response = fetchStream(url, staleness); List<EpisodeBaseModel> all = new ArrayList<>(); if (response != null) { try { JsonReader reader = new JsonReader(new InputStreamReader(response, "UTF-8")); reader.beginObject(); while (reader.hasNext()) { JsonToken token = reader.peek(); if (token == JsonToken.NAME) { String name = reader.nextName(); if (name.equals("entryCount")) { lastEntryCount = reader.nextInt(); } else if (name.equals("entries")) { all.addAll(readEntriesArray(reader)); } else { reader.skipValue(); } } } reader.endObject(); reader.close(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } return all; } private List<EpisodeModel> readEntriesArray(JsonReader reader) throws IOException { reader.beginArray(); Gson gson = new GsonBuilder().create(); List<EpisodeModel> all = new ArrayList<>(); while (reader.hasNext()) { try { Entry entry = gson.fromJson(reader, Entry.class); EpisodeModel ep = EpisodeModel.create(entry); all.add(ep); } catch (JsonSyntaxException e) { e.printStackTrace(); } } reader.endArray(); return all; } static class Category { @SerializedName("media$name") private String name; @SerializedName("media$scheme") private String scheme; @SerializedName("media$label") private String label; public String toString() { return name + " : " + scheme + " : " + label; } public String getName() { if (name != null) { String[] parts = name.split("/"); return parts.length > 1 ? parts[1] : name; } return name; } public String getScheme() { if (scheme != null && scheme.length() > 0) { return scheme; } if (name != null) { String[] parts = name.split("/"); return parts.length > 1 ? parts[0] : scheme; } return scheme; } } static class Thumbnail { @SerializedName("plfile$height") private int height; @SerializedName("plfile$width") private int width; @SerializedName("plfile$downloadUrl") private String url; @SerializedName("plfile$assetTypes") private List<String> types; public boolean hasPoster() { return hasType("Poster"); } public boolean hasType(String str) { if (types != null) { for (String type : types) { if (type != null && type.contains(str)) { return true; } } } return false; } public String toString() { return width + "x" + height + ":" + url; } } static class Content { @SerializedName("plfile$duration") private String duration; @SerializedName("plfile$bitrate") private int bitrate; @SerializedName("plfile$downloadUrl") private String url; } static class Rating { private String rating; } public static class Entry { String id; String guid; String title; String author; String description; @SerializedName("plmedia$defaultThumbnailUrl") String thumbnail; @SerializedName("pl1$programName") String series; @SerializedName("pl1$seriesId") String seriesId; @SerializedName("pl1$shortSynopsis") String synopsis; @SerializedName("media$expirationDate") long expiry; long pubDate; @SerializedName("media$categories") private List<Category> categories; @SerializedName("media$thumbnails") private List<Thumbnail> thumbnails; @SerializedName("media$content") private List<Content> contents; @SerializedName("media$ratings") private List<Rating> ratings; @SerializedName("pl1$collections") private List<String> collections; public String toString() { return id + " : " + title + " : " + series; } public String getThumbnail() { Thumbnail largest = null; if (thumbnails != null) { for (Thumbnail t : thumbnails) { if (largest == null || (t.width >= t.height && t.width > largest.width)) { largest = t; } } } if (largest != null) { return largest.url; } return thumbnail; } public String getCover() { Thumbnail largest = null; if (thumbnails != null) { for (Thumbnail t : thumbnails) { if (t.hasPoster()) { if (largest == null || (t.height > t.width && t.height > largest.height)) { largest = t; } } } } if (largest != null) { return largest.url; } return null; } public List<String> getCategories() { List<String> cats = new ArrayList<>(); boolean isFilm = false; if (categories != null) { for (Category c : categories) { String scheme = c.getScheme(); if ("Channel".equals(scheme) || "Genre".equals(scheme) || "Film".equals(scheme)) { String name = c.getName(); if ("Film".equals(scheme)) { isFilm = true; } if (name != null && !scheme.equals(name)) { cats.add(scheme + "/" + name.trim()); } } } } if (collections != null && isFilm) { for (String collection : collections) { cats.add("Film/" + collection.trim()); } } return cats; } public String getChannel() { if (categories != null) { for (Category c : categories) { if ("Channel".equals(c.scheme)) { String name = c.getName(); if (name != null) { return name; } } } } return ""; } public String getRating() { if (ratings != null && ratings.size() > 0) { String details = ratings.get(0).rating; return details != null && details.length() > 0 ? details.toUpperCase() : null; } return ""; } public int getDuration() { if (contents != null && contents.size() > 0) { try { return Math.round(Float.parseFloat(contents.get(0).duration)); } catch (NumberFormatException e) { e.printStackTrace(); } } return 0; } public boolean isFilm() { for (String cat : getCategories()) { if (cat.contains("Film/")) { return true; } } return false; } } }