Edit: bittvcuriv211
Nama Worker
Kode Sumber
// Konfigurasi untuk folder /mio/ (JSON biasa) const GITHUB_USERNAME = 'brodatv1'; const GITHUB_REPO = 'jsonp'; const GITHUB_BRANCH = 'master'; const GITHUB_FOLDER = 'mio'; // Daftar file JSON yang akan digabungkan. const JSON_FILES = [ 'AA.json', 'AU.json', 'BR.json', 'EV.json', 'GB.json', 'ID.json', 'JP.json', 'KD.json', 'KR.json', 'LO.json', 'MI.json', 'MY.json', 'RI.json', 'SA.json', 'SG.json', 'SP.json' ]; const BASE_URL = `https://raw.githubusercontent.com/${GITHUB_USERNAME}/${GITHUB_REPO}/${GITHUB_BRANCH}/${GITHUB_FOLDER}/`; // Fungsi bantuan untuk mengubah format lisensi function b64urlToHex(b64url) { try { const base64 = b64url.replace(/-/g, '+').replace(/_/g, '/'); const raw = atob(base64); let hex = ''; for (let i = 0; i < raw.length; i++) { hex += ('0' + raw.charCodeAt(i).toString(16)).slice(-2); } return hex; } catch (e) { return ''; } } addEventListener('fetch', event => { event.respondWith(handleRequest(event.request)); }); async function handleRequest(request) { try { let m3uContent = '#EXTM3U\n'; // === PERUBAHAN UTAMA: MEMPROSES FILE SATU PER SATU === // Ini untuk menghindari error limit CPU di Cloudflare for (const file of JSON_FILES) { try { const response = await fetch(BASE_URL + file); if (response.ok) { const jsonData = await response.json(); // Langsung parsing JSON biasa if (jsonData && Array.isArray(jsonData.info)) { const groupName = jsonData.country_name || 'General'; const channels = jsonData.info; channels.forEach(channel => { if (channel && channel.name && channel.hls) { const logo = channel.image ? `tvg-logo="${channel.image}"` : ''; m3uContent += `#EXTINF:-1 ${logo} group-title="${groupName}",${channel.name}\n`; if (channel.jenis === 'dash-clearkey' && channel.url_license) { m3uContent += `#KODIPROP:inputstream.adaptive.license_type=clearkey\n`; let licenseKey = channel.url_license; try { const licenseJson = JSON.parse(atob(licenseKey)); if (licenseJson.keys && licenseJson.keys[0]) { const kid = b64urlToHex(licenseJson.keys[0].kid); const key = b64urlToHex(licenseJson.keys[0].k); licenseKey = `${kid}:${key}`; } } catch (e) {} m3uContent += `#KODIPROP:inputstream.adaptive.license_key=${licenseKey}\n`; } if (channel.header_iptv) { try { const headers = JSON.parse(channel.header_iptv); if (headers['User-Agent'] && headers['User-Agent'] !== 'none') m3uContent += `#EXTVLCOPT:http-user-agent=${headers['User-Agent']}\n`; if (headers['Referer'] && headers['Referer'] !== 'none') m3uContent += `#EXTVLCOPT:http-referrer=${headers['Referer']}\n`; if (headers['Origin'] && headers['Origin'] !== 'none') m3uContent += `#EXTVLCOPT:http-origin=${headers['Origin']}\n`; } catch (e) {} } m3uContent += `${channel.hls}\n`; } }); } } } catch (e) { // Jika satu file error, lewati dan lanjutkan ke file berikutnya console.error(`Gagal memproses file ${file}:`, e); } } // ======================================================= return new Response(m3uContent, { headers: { 'Content-Type': 'application/vnd.apple.mpegurl; charset=utf-8', 'Access-Control-Allow-Origin': '*' } }); } catch (error) { return new Response(`Error: ${error.message}`, { status: 500 }); } }
Bindings
Tambah KV
Tambah R2
Tambah D1
← Kembali
Simpan & Deploy
Hapus Script Worker Ini