Skip to content

Instantly share code, notes, and snippets.

@jaylinski
Last active November 26, 2025 22:12
Show Gist options
  • Select an option

  • Save jaylinski/b89aaddc724961ce6f07582adeb450d6 to your computer and use it in GitHub Desktop.

Select an option

Save jaylinski/b89aaddc724961ce6f07582adeb450d6 to your computer and use it in GitHub Desktop.
Kodi playlist containing free and public TV streams from DE/AT/CH with DRM support.
#KODIPROP:inputstream=inputstream.adaptive
#KODIPROP:inputstream.adaptive.manifest_type=mpd
#KODIPROP:inputstream.adaptive.license_type=com.widevine.alpha
#KODIPROP:inputstream.adaptive.license_key=https://drm.ors.at/acquire-license/widevine?BrandGuid=13f2e056-53fe-4469-ba6d-999970dbe549&userToken=<token>||R{SSM}|
https://orf1.mdn.ors.at/out/u/orf1/drmqxa/manifest.mpd
@jaylinski
Copy link
Author

jaylinski commented Oct 16, 2025

@coloms90

package.json

{
  "name": "kodi-pvr-drm-bot",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "dependencies": {
    "@octokit/core": "^7.0.2"
  },
  "scripts": {
    "start": "node index.js"
  }
}

index.js

import { Octokit } from '@octokit/core';

const interval = 30 * 60 * 1000; // 30 minutes
const gistOrg = '<your gist org>';
const gistId = '<your gist id>';
const octokit = new Octokit();
const octokitAuthenticated = new Octokit({ auth: '<your github auth token>' });
const tokenEndpoint = '<your token endpoint>';

async function updateGist() {
  const tokenResponse = await octokit.request(`GET ${tokenEndpoint}`);
  const token = tokenResponse.data.base64;

  const playlistResponse = await octokit.request('GET https://gist.githubusercontent.com/{org}/{id}/raw/kodi_playlist', { org: gistOrg, id: gistId });
  const playlist = playlistResponse.data;
  const playlistPatched = playlist.replace(/&userToken=(.*)/gi, `&userToken=${token}|Content-Type=application/octet-stream|R{SSM}|`);

  const gistPatchResponse = await octokitAuthenticated.request('PATCH /gists/{id}', {
    id: gistId,
    files: {
      kodi_playlist: {
        content: playlistPatched,
      },
    },
  });

  if (gistPatchResponse.status !== 200) {
    throw new Error(`Error ${gistPatchResponse.status}`);
  } else {
    console.log(`Successfully patched gist with token '${token}'`);
  }
}

setInterval(updateGist, interval);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment