{
  "id": 18803975,
  "title": "My 1.17 MB player's catalog grid: the channelId trap, overlapping pages, and a cursor echo",
  "url": "https://urgent.news/2026/11/07/my-1-17-mb-players-catalog-grid-the-channelid-trap-overlapping-pages",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-07T22:35:40.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/hammiwor/my-117-mb-players-catalog-grid-the-channelid-trap-overlapping-pages-and-a-cursor-echo-2k2p"
  },
  "original_language": "en",
  "account": "The 1.17 MB Android 4K media player, RKMovies, consists of a thin WebView over a catalog API. The player does not have a backend, and the app calls the upstream /api/filter through a proxy. The grid of listings presented issues concerning the channelId parameter, overlapping pages, and hidden cursors.\n\nFirstly, the channelId parameter is mandatory. Routes map to channels like /movies for channelId 1, /tv-series for channelId 2, and /animated-series for channelId 1006. If this parameter is omitted, the upstream silently defaults the channel, resulting in movies and TV being mixed together without any error. Tile links carry tabId values instead of channel parameters, and the client derives the correct channelId from tabId values, such as tabId 2 becoming channelId 1, and tabId 5 becoming channelId 2.\n\nSecondly, pages overlap, and the real cursor is hidden one level down. The proxy consumes several upstream pages per client page, with 30 cards each, as it filters out junk re-uploads server-side. The client echoes the upstream cursor pager.upNext in every request with page=1. Skipping this step leads to infinite scroll re-serving the same raw pages.\n\nLastly, infinite scroll is implemented using an IntersectionObserver with a loading guard. A sentinel div, rootMargin: 300px, ensures pages load before reaching the bottom. The _scrollLoading flag is set while a fetch is in flight, preventing the observer from firing twice. The filter bar is a custom dropdown component: a button with a menu and a hidden native select for semantics, which closes on outside click or pressing Escape. The listing layer is approximately 280 lines long, with zero dependencies, contributing to the APK's 1.17 MB size.",
  "summary": "My 1.17 MB player's catalog grid: the channelId trap, overlapping pages, and a cursor echo Disclosure: I built RKMovies , a 1.17 MB Android 4K media player (plus a Windows build ). This is a dev diary about the listing layer. Get the Android APK . The player is a thin WebView over a catalog API. There is no backend of ours for listings, the app calls the upstream /api/filter through its proxy.…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}