/** * Vidio Live TV Scraper (Advanced Edition) */ class VidioLive { constructor() { this.liveUrl = 'https://www.vidio.com/live'; this.apiUrl = 'https://api.vidio.com/livestreamings'; this.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Accept': 'application/json, text/plain, */*', 'Origin': 'https://www.vidio.com', 'Referer': 'https://www.vidio.com/' }; } extractValue(str, key) { const regex = new RegExp(`"${key}":\\s*(?:"([^"]*)"|(null|true|false|[0-9]+))`); const match = str.match(regex); if (match) return match[1] !== undefined ? match[1] : match[2]; return null; } async getDetailStream(contentId) { try { const response = await fetch(`${this.apiUrl}/${contentId}`, { headers: this.headers }); const data = await response.json(); let streamUrl = data?.data?.attributes?.stream_url; if (!streamUrl || streamUrl.trim() === "") { streamUrl = `https://geo-id-etslive-v3-vidio-com-tokenized.akamaized.net/stream/${contentId}/file/drm/hls/master.m3u8`; } return streamUrl; } catch (err) { return `https://geo-id-etslive-v3-vidio-com-tokenized.akamaized.net/stream/${contentId}/file/drm/hls/master.m3u8`; } } async fetchAllChannels() { const response = await fetch(this.liveUrl, { headers: this.headers }); if (!response.ok) throw new Error('Gagal mengakses Vidio Live'); const html = await response.text(); const chunks = [...html.matchAll(/self\.__next_f\.push\(\[\d+,\s*"((?:[^"\\]|\\.)*)"\]\)/g)]; let rawPayload = chunks.map(m => m[1]).join('').replace(/\\"/g, '"').replace(/\\\\/g, '\\'); const blockPattern = /"content_id":(\d+),"content_type":"(livestreaming|livestreaming_schedule)",(.*?)(?=,"links":)/g; let match; const channelsData = {}; while ((match = blockPattern.exec(rawPayload)) !== null) { const contentId = match[1]; const type = match[2]; const block = match[3]; const title = this.extractValue(block, "title"); const altTitle = this.extractValue(block, "alt_title"); let streamUrl = this.extractValue(block, "stream_url"); const startTime = this.extractValue(block, "start_time"); const endTime = this.extractValue(block, "end_time"); const liveTitle = this.extractValue(block, "livestreaming_title"); let channelName = type === 'livestreaming' ? altTitle : (liveTitle || altTitle); if (!channelName) continue; if (channelName.includes('·')) channelName = channelName.split('·').pop().trim(); const channelKey = channelName.toLowerCase(); if (!channelsData[channelKey]) { channelsData[channelKey] = { channel_id: parseInt(contentId), channel_name: channelName, now_playing: 'Tidak ada informasi', stream_url: streamUrl === "null" || !streamUrl ? "" : streamUrl, schedules: [] }; } if (streamUrl && streamUrl !== "null" && streamUrl.trim() !== "") { channelsData[channelKey].stream_url = streamUrl; } if (type === 'livestreaming') { channelsData[channelKey].now_playing = title; } else if (type === 'livestreaming_schedule') { channelsData[channelKey].schedules.push({ title: title, start_time: new Date(startTime).toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Jakarta' }), end_time: new Date(endTime).toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Jakarta' }) }); } } return channelsData; } async videoliveget(queries) { const allChannels = await this.fetchAllChannels(); const results = []; await Promise.all(queries.map(async (query) => { const matchedKey = Object.keys(allChannels).find(k => k.includes(query.toLowerCase())); if (matchedKey) { const channel = allChannels[matchedKey]; if (!channel.stream_url || channel.stream_url.trim() === "") { channel.stream_url = await this.getDetailStream(channel.channel_id); } results.push({ query: query, status: "success", data: { channel_id: channel.channel_id, channel_name: channel.channel_name, now_playing: channel.now_playing, stream_url: channel.stream_url, total_schedules: channel.schedules.length, schedules: channel.schedules } }); } else { results.push({ query: query, status: "not_found", data: null }); } })); return results; } } (async () => { const scraper = new VidioLive(); const targetChannels = ['indosiar', 'sctv', 'rcti', 'kompas tv']; try { const extractedData = await scraper.videoliveget(targetChannels); const responseJson = { status: 200, message: "Berhasil mengekstrak jadwal dan live stream", timestamp: new Date().toISOString(), results: extractedData }; console.log(JSON.stringify(responseJson, null, 2)); } catch (error) { console.log(JSON.stringify({ status: 500, message: error.message, results: [] }, null, 2)); } })();