{
  "id": 19387028,
  "title": "Why I moved a TV app's source contract into JavaScript plugins on QuickJS",
  "url": "https://urgent.news/2026/11/10/why-i-moved-a-tv-apps-source-contract-into-javascript-plugins-on",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-11-10T20:00:00.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/yonto/why-i-moved-a-tv-apps-source-contract-into-javascript-plugins-on-quickjs-31g9"
  },
  "original_language": "en",
  "account": "The Jellyfin app originally used an HTTP API to communicate with media servers, but this created issues when media servers changed their data structures. To address this, the contract was kept as JSON, while the transport was made an implementation detail. This allowed the app to use JavaScript plugins instead of Kotlin code. A plugin is a single JavaScript file with a manifest comment and exports functions required by the app, such as getCategories, getMediaList, getMediaDetail and search. The app provides a global yonto object for making requests, accessing settings and handling errors. Plugins are checked using a command-line tool that runs them against the same contract as the app. QuickJS was chosen as the JavaScript engine for plugins due to its JVM compatibility and ability to be tested on a laptop.",
  "summary": "Yonto Player talks to a media server, or to a folder, through one interface: ContentSourceAdapter . The rule itself is covered in the opening post of the series. This one is about what sits behind the interface, and how it changed. The short version is that the source contract started out as an HTTP API, moved into the app as JavaScript plugins, and is now the way every Jellyfin, Plex and Emby…",
  "key_points": [
    "Jellyfin app switched from HTTP API to JavaScript plugins",
    "QuickJS chosen as JavaScript engine for plugins",
    "Plugins checked against app contract using command-line tool"
  ],
  "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."
}