Last active
June 11, 2024 07:08
-
-
Save jcoding09/80682b345ce4935e324bb6c256bae2a4 to your computer and use it in GitHub Desktop.
Television link
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Update M3U8 Playlist | |
on: | |
schedule: | |
- cron: '0 */2 * * *' | |
workflow_dispatch: | |
jobs: | |
update-playlist: | |
runs-on: ubuntu-latest | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Node.js | |
uses: actions/setup-node@v4 | |
with: | |
node-version: '20' | |
- name: Install Dependencies | |
run: npm install node-fetch@2 winston | |
- name: Run Script | |
run: node run.js | |
- name: Configure git user | |
run: | | |
git config --global user.name 'jcoding09' | |
git config --global user.email "${{ secrets.USER_EMAIL }}" | |
- name: Commit and Push Changes | |
run: | | |
git add ts.m3u | |
git commit -m 'Update M3U8 playlist' | |
git push origin ${{ github.ref }} | |
env: | |
GITHUB_TOKEN: ${{ secrets.PAT }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const fetch = require('node-fetch'); | |
const fs = require('fs'); | |
const winston = require('winston'); | |
// Set up logging | |
const logger = winston.createLogger({ | |
level: 'info', | |
format: winston.format.combine( | |
winston.format.timestamp(), | |
winston.format.printf(({ timestamp, level, message }) => `${timestamp} - ${level.toUpperCase()} - ${message}`) | |
), | |
transports: [ | |
new winston.transports.Console() | |
] | |
}); | |
// Constants | |
const API_URL = "https://tplayapi.code-crafters.app/321codecrafters/fetcher.json"; | |
const HMAC_URL = "https://tplayapi.code-crafters.app/321codecrafters/hmac.json"; | |
const RETRIES = 3; | |
async function fetchApi(url, retries) { | |
for (let attempt = 0; attempt < retries; attempt++) { | |
try { | |
const response = await fetch(url); | |
if (!response.ok) { | |
throw new Error(`HTTP error! Status: ${response.status}`); | |
} | |
return await response.json(); | |
} catch (error) { | |
logger.error(`Error fetching API data (attempt ${attempt + 1}/${retries}): ${error.message}`); | |
if (attempt < retries - 1) { | |
continue; | |
} else { | |
return null; | |
} | |
} | |
} | |
} | |
function generateM3U8(data, hmac) { | |
let m3u8Content = `#EXTM3U x-tvg-url="https://raw.githubusercontent.com/mitthu786/tvepg/main/tataplay/epg.xml.gz"\n\n`; | |
for (const channel of data.channels) { | |
if (channel.clearkeys && channel.clearkeys.length > 0) { | |
const clearkey = channel.clearkeys[0].base64; | |
const userAgent = channel.manifest_headers['User-Agent']; | |
// Use the correct 'hdntl' key | |
const cookie = hmac.hmac.hdntl.value; | |
m3u8Content += `#EXTINF:-1 tvg-id="${channel.id}" group-title="${channel.genres.join(', ')}", tvg-logo="${channel.logo_url}", ${channel.name}\n`; | |
m3u8Content += `#KODIPROP:inputstream.adaptive.license_type=clearkey\n`; | |
m3u8Content += `#KODIPROP:inputstream.adaptive.license_key=${JSON.stringify(clearkey)}\n`; | |
m3u8Content += `#EXTVLCOPT:http-user-agent=${userAgent}\n`; | |
m3u8Content += `#EXTHTTP:{"cookie":"${cookie}"}\n`; | |
m3u8Content += `${channel.manifest_url}|cookie:${cookie}\n\n`; | |
} | |
} | |
return m3u8Content; | |
} | |
async function main() { | |
const fetcherData = await fetchApi(API_URL, RETRIES); | |
const hmacData = await fetchApi(HMAC_URL, RETRIES); | |
if (fetcherData && hmacData) { | |
const m3u8Content = generateM3U8(fetcherData.data, hmacData.data); | |
fs.writeFileSync('ts.m3u', m3u8Content); | |
logger.info("M3U8 playlist generated and saved to playlist.m3u8"); | |
} else { | |
logger.error("Failed to fetch data from API"); | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
repo setting > Actions > General > allow workflow permission
repo setting > Secret and Variables > Actions > add Repository secrets which you don't want to expose.