From a896307d82c99190b6d3c15cd853621cdc3d01e0 Mon Sep 17 00:00:00 2001 From: davigamer987 Date: Wed, 18 Dec 2024 17:06:02 -0300 Subject: [PATCH 1/4] Sort recent anime by popularity and increase image res Also cleaned up some unused commented out code --- .../androidtv/animetvjmto/AnimeProvider.java | 113 ++++++++---------- 1 file changed, 47 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java index 6c50fda1..b267cefe 100644 --- a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java +++ b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java @@ -35,6 +35,12 @@ import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; + + public class AnimeProvider { private static final String _TAG="ATVLOG-CHANNEL"; @@ -126,76 +132,66 @@ public void loadRecent(RecentCallback cb){ AsyncTask.execute(() ->loadRecentExec(cb)); } - private void parseRecent(JSONArray r, String buf) throws JSONException{ - JSONObject jo=new JSONObject(buf); - JSONArray rs= - jo.getJSONObject("data") - .getJSONObject("Page") - .getJSONArray("airingSchedules"); - for (int i=0;i animeList = new ArrayList<>(); + + for (int i = 0; i < rs.length(); i++) { try { - JSONObject med = rs.getJSONObject(i).getJSONObject("media"); + JSONObject airingSchedule = rs.getJSONObject(i); + JSONObject med = airingSchedule.getJSONObject("media"); JSONObject medT = med.getJSONObject("title"); - String en = medT.isNull("english")?"":medT.getString("english"); - String jp = medT.isNull("romaji")?"":medT.getString("romaji"); + String en = medT.isNull("english") ? "" : medT.getString("english"); + String jp = medT.isNull("romaji") ? "" : medT.getString("romaji"); JSONObject medI = med.getJSONObject("coverImage"); - String img=medI.getString("large"); - String format=med.isNull("format")?"":med.getString("format"); - if (format.equalsIgnoreCase("TV_SHORT")){ - format="TV"; + String img = medI.getString("extraLarge"); + String format = med.isNull("format") ? "" : med.getString("format"); + if (format.equalsIgnoreCase("TV_SHORT")) { + format = "TV"; } - int ep=med.isNull("episodes")?0:med.getInt("episodes"); - long id=med.getLong("id"); + int ep = med.isNull("episodes") ? 0 : med.getInt("episodes"); + long id = med.getLong("id"); + int popularity = med.isNull("popularity") ? 0 : med.getInt("popularity"); JSONObject d = new JSONObject("{}"); - d.put("url", id+"/"+ep); - d.put("title", en.isEmpty()?jp:en); + d.put("url", id + "/" + ep); + d.put("title", en.isEmpty() ? jp : en); d.put("poster", img); d.put("ep", ep); d.put("type", format); d.put("tip", id); - r.put(d); - - }catch (JSONException ignored){} + d.put("popularity", popularity); + animeList.add(d); + } catch (JSONException ignored) { + } } - /* - if (jo.has("result")){ - String res=jo.getString("result"); - Document doc = Jsoup.parse(res); - Elements els=doc.getElementsByClass("item"); - for (int i=0;i 0) ? sb.get(0).text().trim() : ""); - d.put("type", (rg.size() > 0) ? rg.get(0).text().trim() : ""); - d.put("tip", tt.attr("data-tip")); - r.put(d); - } - } + // Sort anime by popularity + Collections.sort(animeList, new Comparator() { + @Override + public int compare(JSONObject a, JSONObject b) { + try { + return Integer.compare(b.getInt("popularity"), a.getInt("popularity")); + } catch (JSONException e) { + return 0; } - catch(Exception ignored){} } - }*/ + }); + + for (JSONObject anime : animeList) { + r.put(anime); + } } private static String ANILIST_GRAPHQL ="{\"query\":\"query ($tm: Int, " + "$page: Int, $perPage: Int){ Page(page: $page, perPage: $perPage) { " + "pageInfo { perPage hasNextPage currentPage } airingSchedules" + "(airingAt_lesser:$tm,sort:TIME_DESC){ airingAt episode " + - "timeUntilAiring media{ id title{ romaji english } coverImage{ large " + - "} episodes format } } } }\",\"variables\":{\"tm\":0xFFFFFF," + + "timeUntilAiring media{ id title{ romaji english } coverImage{ extraLarge " + + "} episodes format popularity } } } }\",\"variables\":{\"tm\":0xFFFFFF," + "\"page\":1,\"perPage\":30}}"; /* Get latest updated sub */ @@ -215,21 +211,6 @@ private void loadRecentExec(RecentCallback cb){ cb.onFinish(r.toString()); - - /* - AnimeApi.Http http=new AnimeApi.Http( - "https://"+Conf.getDomain()+"/ajax/home/widget/updated-sub"); - http.execute(); - JSONArray r=new JSONArray("[]"); - parseRecent(r,http.body.toString()); - - http=new AnimeApi.Http( - "https://"+Conf.getDomain()+"/ajax/home/widget/updated-sub" + - "?page=2"); - http.execute(); - parseRecent(r,http.body.toString()); - */ - if (r.length()>0) { Log.d(_TAG,"GOT RECENTS => "+r.length()); cb.onFinish(r.toString()); From ba4a5290313eaea82e7e575580bc84184b91c7df Mon Sep 17 00:00:00 2001 From: davigamer987 Date: Wed, 18 Dec 2024 17:52:48 -0300 Subject: [PATCH 2/4] Provide Popular Anime Channel --- .../androidtv/animetvjmto/AnimeProvider.java | 205 +++++++++++++++--- 1 file changed, 180 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java index b267cefe..757a2333 100644 --- a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java +++ b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java @@ -69,7 +69,22 @@ public interface RecentCallback { public static void executeJob(Context c){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - new AnimeProvider(c).startLoadRecent(); + AnimeProvider recentProvider = new AnimeProvider( + c, + "Anime Recent", + "AnimeTV_Recent", + R.drawable.splash + ); + recentProvider.startLoadRecent(); + + AnimeProvider popularProvider = new AnimeProvider( + c, + "Anime Popular", + "AnimeTV_Popular", + R.drawable.splash + ); + popularProvider.startLoadPopular(); + scheduleJob(c); } } @@ -117,13 +132,13 @@ public void startLoadRecent(){ }catch (Exception ignored){} } - public AnimeProvider(Context c){ - ctx=c; + public AnimeProvider(Context c, String channelName, String internalProviderId, int logoResourceId) { + ctx = c; AnimeApi.initHttpEngine(c); try { - CHANNEL_ID = initChannel(); - }catch (Exception ex){ - CHANNEL_ID=-1; + CHANNEL_ID = initChannel(channelName, internalProviderId, logoResourceId); + } catch (Exception ex) { + CHANNEL_ID = -1; Log.d(_TAG, ex.toString()); } } @@ -220,6 +235,111 @@ private void loadRecentExec(RecentCallback cb){ cb.onFinish(""); } + private static String POPULAR_ANIME_GRAPHQL = "{\"query\":\"query ($page: Int, $perPage: Int){ " + + "Page(page: $page, perPage: $perPage) { " + + "pageInfo { perPage hasNextPage currentPage } " + + "media(sort:POPULARITY_DESC,isAdult:false, type: ANIME, status_not_in:[HIATUS,CANCELLED,NOT_YET_RELEASED]) { " + + "id title{ romaji english } " + + "coverImage{ large } " + + "episodes format " + + "} } }\",\"variables\":{\"page\":1,\"perPage\":30}}"; + + public void startLoadPopular() { + if (CHANNEL_ID < 1) return; + try { + loadPopular(result -> { + try { + JSONArray ja = new JSONArray(result); + if (ja.length() > 0) { + clearPrograms(); + for (int i = 0; i < ja.length(); i++) { + try { + JSONObject o = ja.getJSONObject(i); + String uri = o.getString("url"); + String title = o.getString("title"); + String poster = o.getString("poster"); + String tip = o.getString("tip"); + String ep = o.getString("ep"); + String desc = o.getString("type"); + if (!ep.equals("") && !ep.equals("0")) { + desc += " Episode " + ep; + } + desc = desc.trim(); + addProgram(title, desc, poster, uri, tip); + } catch (Exception ignored) { + } + } + } + } catch (JSONException ignored) { + } + Log.d(_TAG, "Popular Anime RES = " + result); + }); + } catch (Exception ignored) {} + } + + public void loadPopular(RecentCallback cb) { + AsyncTask.execute(() -> loadPopularExec(cb)); + } + + private void loadPopularExec(RecentCallback cb) { + try { + AnimeApi.Http http = new AnimeApi.Http("https://graphql.anilist.co/"); + http.addHeader("Accept", "application/json"); + + http.setMethod("POST", POPULAR_ANIME_GRAPHQL, "application/json"); + http.execute(); + + JSONArray r = new JSONArray("[]"); + parsePopular(r, http.body.toString()); + + cb.onFinish(r.toString()); + + if (r.length() > 0) { + Log.d(_TAG, "GOT POPULAR ANIME => " + r.length()); + cb.onFinish(r.toString()); + return; + } + } catch (Exception ignored) {} + cb.onFinish(""); + } + + private void parsePopular(JSONArray r, String buf) throws JSONException { + JSONObject jo = new JSONObject(buf); + JSONArray rs = jo.getJSONObject("data") + .getJSONObject("Page") + .getJSONArray("media"); + + List animeList = new ArrayList<>(); + + for (int i = 0; i < rs.length(); i++) { + try { + JSONObject media = rs.getJSONObject(i); + JSONObject medT = media.getJSONObject("title"); + String en = medT.isNull("english") ? "" : medT.getString("english"); + String jp = medT.isNull("romaji") ? "" : medT.getString("romaji"); + JSONObject medI = media.getJSONObject("coverImage"); + String img = medI.getString("large"); + String format = media.isNull("format") ? "" : media.getString("format"); + int ep = media.isNull("episodes") ? 0 : media.getInt("episodes"); + long id = media.getLong("id"); + + JSONObject d = new JSONObject("{}"); + d.put("url", id + "/" + ep); + d.put("title", en.isEmpty() ? jp : en); + d.put("poster", img); + d.put("ep", ep); + d.put("type", format); + d.put("tip", id); + animeList.add(d); + } catch (JSONException ignored) { + } + } + + for (JSONObject anime : animeList) { + r.put(anime); + } + } + /* Drawable to bitmap */ @NonNull public static Bitmap convertToBitmap(Context context, int resourceId) { @@ -240,37 +360,72 @@ public static Bitmap convertToBitmap(Context context, int resourceId) { } /* Create Channel */ - private long initChannel() { - Cursor cursor = - ctx.getContentResolver() - .query( - TvContractCompat.Channels.CONTENT_URI, - CHANNELS_PROJECTION, - null, - null, - null); - if (cursor != null && cursor.moveToFirst()) { - Channel channel = Channel.fromCursor(cursor); - Log.d(_TAG,"Existing channel = "+channel.getDisplayName()); - return channel.getId(); + private long initChannel(String channelName, String internalProviderId, int logoResourceId) { + long existingChannelId = findExistingChannelId(internalProviderId); + if (existingChannelId != -1) { + return existingChannelId; } + Intent myIntent = new Intent(ctx, MainActivity.class); myIntent.setPackage(ctx.getPackageName()); - Uri intentUri= Uri.parse(myIntent.toUri(Intent.URI_ANDROID_APP_SCHEME)); - Channel ch = new Channel.Builder().setType(TvContractCompat.Channels.TYPE_PREVIEW) - .setDisplayName("AnimeTV") - .setInternalProviderId("AnimeTV") + Uri intentUri = Uri.parse(myIntent.toUri(Intent.URI_ANDROID_APP_SCHEME)); + + Channel ch = new Channel.Builder() + .setType(TvContractCompat.Channels.TYPE_PREVIEW) + .setDisplayName(channelName) + .setInternalProviderId(internalProviderId) .setAppLinkIntentUri(intentUri) .build(); + Uri uri = ctx.getContentResolver().insert(TvContract.Channels.CONTENT_URI, ch.toContentValues()); - Log.d(_TAG,"Created New Channel = "+uri); + Log.d(_TAG, "Created Channel = " + uri); + long channelId = ContentUris.parseId(uri); Log.d(_TAG, "channel id " + channelId); - Bitmap bitmap = convertToBitmap(ctx, R.drawable.splash); + + Bitmap bitmap = convertToBitmap(ctx, logoResourceId); ChannelLogoUtils.storeChannelLogo(ctx, channelId, bitmap); + return channelId; } + private long findExistingChannelId(String internalProviderId) { + try { + Uri channelUri = TvContractCompat.Channels.CONTENT_URI; + String[] projection = { + TvContractCompat.Channels._ID, + TvContractCompat.Channels.COLUMN_INTERNAL_PROVIDER_ID + }; + + Cursor cursor = ctx.getContentResolver().query( + channelUri, + projection, + null, + null, + null + ); + + if (cursor != null) { + int idColumnIndex = cursor.getColumnIndex(TvContractCompat.Channels._ID); + int providerIdColumnIndex = cursor.getColumnIndex(TvContractCompat.Channels.COLUMN_INTERNAL_PROVIDER_ID); + + while (cursor.moveToNext()) { + String storedProviderId = cursor.getString(providerIdColumnIndex); + if (internalProviderId.equals(storedProviderId)) { + long channelId = cursor.getLong(idColumnIndex); + Log.d(_TAG, "Found existing channel ID: " + channelId); + cursor.close(); + return channelId; + } + } + cursor.close(); + } + } catch (Exception e) { + Log.e(_TAG, "Error finding channel", e); + } + return -1; + } + @SuppressLint("RestrictedApi") private void clearPrograms() { Cursor cursor = From 8bde3ba98745fda3fa1ba6c0393bcef6e65038bf Mon Sep 17 00:00:00 2001 From: davigamer987 Date: Wed, 18 Dec 2024 19:21:27 -0300 Subject: [PATCH 3/4] Add score and reformat description --- .../androidtv/animetvjmto/AnimeProvider.java | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java index 757a2333..557eec1d 100644 --- a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java +++ b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java @@ -115,11 +115,7 @@ public void startLoadRecent(){ String poster = o.getString("poster"); String tip = o.getString("tip"); String ep = o.getString("ep"); - String desc = o.getString("type"); - if (!ep.equals("") && !ep.equals("0")) { - desc += " Episode " + ep; - } - desc = desc.trim(); + String desc = o.getString("ep"); addProgram(title, desc, poster, uri, tip); } catch (Exception ignored) { } @@ -171,11 +167,12 @@ private void parseRecent(JSONArray r, String buf) throws JSONException { int ep = med.isNull("episodes") ? 0 : med.getInt("episodes"); long id = med.getLong("id"); int popularity = med.isNull("popularity") ? 0 : med.getInt("popularity"); + int score = med.isNull("averageScore") ? 0 : med.getInt("averageScore"); JSONObject d = new JSONObject("{}"); d.put("url", id + "/" + ep); d.put("title", en.isEmpty() ? jp : en); d.put("poster", img); - d.put("ep", ep); + d.put("ep", ep + " " + " Episodes | Score: " + score + " | " + format); d.put("type", format); d.put("tip", id); d.put("popularity", popularity); @@ -206,7 +203,7 @@ public int compare(JSONObject a, JSONObject b) { "pageInfo { perPage hasNextPage currentPage } airingSchedules" + "(airingAt_lesser:$tm,sort:TIME_DESC){ airingAt episode " + "timeUntilAiring media{ id title{ romaji english } coverImage{ extraLarge " + - "} episodes format popularity } } } }\",\"variables\":{\"tm\":0xFFFFFF," + + "} episodes format popularity averageScore } } } }\",\"variables\":{\"tm\":0xFFFFFF," + "\"page\":1,\"perPage\":30}}"; /* Get latest updated sub */ @@ -241,7 +238,7 @@ private void loadRecentExec(RecentCallback cb){ "media(sort:POPULARITY_DESC,isAdult:false, type: ANIME, status_not_in:[HIATUS,CANCELLED,NOT_YET_RELEASED]) { " + "id title{ romaji english } " + "coverImage{ large } " + - "episodes format " + + "episodes format averageScore " + "} } }\",\"variables\":{\"page\":1,\"perPage\":30}}"; public void startLoadPopular() { @@ -260,11 +257,7 @@ public void startLoadPopular() { String poster = o.getString("poster"); String tip = o.getString("tip"); String ep = o.getString("ep"); - String desc = o.getString("type"); - if (!ep.equals("") && !ep.equals("0")) { - desc += " Episode " + ep; - } - desc = desc.trim(); + String desc = o.getString("ep"); addProgram(title, desc, poster, uri, tip); } catch (Exception ignored) { } @@ -321,13 +314,14 @@ private void parsePopular(JSONArray r, String buf) throws JSONException { String img = medI.getString("large"); String format = media.isNull("format") ? "" : media.getString("format"); int ep = media.isNull("episodes") ? 0 : media.getInt("episodes"); + int score = media.isNull("averageScore") ? 0 : media.getInt("averageScore"); long id = media.getLong("id"); JSONObject d = new JSONObject("{}"); d.put("url", id + "/" + ep); d.put("title", en.isEmpty() ? jp : en); d.put("poster", img); - d.put("ep", ep); + d.put("ep", ep + " " + " Episodes | Score: " + score + " | " + format); d.put("type", format); d.put("tip", id); animeList.add(d); From 1a3f5db433e524dc5ad56bb6e19a28897c445e22 Mon Sep 17 00:00:00 2001 From: davigamer987 Date: Wed, 18 Dec 2024 19:52:00 -0300 Subject: [PATCH 4/4] Remove episodes tag from movies --- .../com/amarullz/androidtv/animetvjmto/AnimeProvider.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java index 557eec1d..d224cf61 100644 --- a/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java +++ b/app/src/main/java/com/amarullz/androidtv/animetvjmto/AnimeProvider.java @@ -172,7 +172,11 @@ private void parseRecent(JSONArray r, String buf) throws JSONException { d.put("url", id + "/" + ep); d.put("title", en.isEmpty() ? jp : en); d.put("poster", img); + if (format.equals("MOVIE") || ep == 0) { + d.put("ep", "Score: " + score + " | " + format); + } else { d.put("ep", ep + " " + " Episodes | Score: " + score + " | " + format); + } d.put("type", format); d.put("tip", id); d.put("popularity", popularity); @@ -321,7 +325,11 @@ private void parsePopular(JSONArray r, String buf) throws JSONException { d.put("url", id + "/" + ep); d.put("title", en.isEmpty() ? jp : en); d.put("poster", img); + if (format.equals("MOVIE") || ep == 0) { + d.put("ep", "Score: " + score + " | " + format); + } else { d.put("ep", ep + " " + " Episodes | Score: " + score + " | " + format); + } d.put("type", format); d.put("tip", id); animeList.add(d);