Vidio Live TV Scraper

JavaScriptPublic
by zx-apiAug 1, 2026, 05:23 PMExpires: Never8 views
Vidio Live TV Scraper
Raw
1/**
2 * Vidio Live TV Scraper (Advanced Edition)
3 */
4 
5
6class VidioLive {
7  constructor() {
8    this.liveUrl = 'https://www.vidio.com/live';
9    this.apiUrl = 'https://api.vidio.com/livestreamings';
10    this.headers = {
11      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
12      'Accept': 'application/json, text/plain, */*',
13      'Origin': 'https://www.vidio.com',
14      'Referer': 'https://www.vidio.com/'
15    };
16  }
17
18  extractValue(str, key) {
19    const regex = new RegExp(`"${key}":\\s*(?:"([^"]*)"|(null|true|false|[0-9]+))`);
20    const match = str.match(regex);
21    if (match) return match[1] !== undefined ? match[1] : match[2];
22    return null;
23  }
24
25  async getDetailStream(contentId) {
26    try {
27      const response = await fetch(`${this.apiUrl}/${contentId}`, { headers: this.headers });
28      const data = await response.json();
29      
30      let streamUrl = data?.data?.attributes?.stream_url;
31      
32      if (!streamUrl || streamUrl.trim() === "") {
33        streamUrl = `https://geo-id-etslive-v3-vidio-com-tokenized.akamaized.net/stream/${contentId}/file/drm/hls/master.m3u8`;
34      }
35      
36      return streamUrl;
37    } catch (err) {
38      return `https://geo-id-etslive-v3-vidio-com-tokenized.akamaized.net/stream/${contentId}/file/drm/hls/master.m3u8`;
39    }
40  }
41
42  async fetchAllChannels() {
43    const response = await fetch(this.liveUrl, { headers: this.headers });
44    if (!response.ok) throw new Error('Gagal mengakses Vidio Live');
45    
46    const html = await response.text();
47    const chunks = [...html.matchAll(/self\.__next_f\.push\(\[\d+,\s*"((?:[^"\\]|\\.)*)"\]\)/g)];
48    let rawPayload = chunks.map(m => m[1]).join('').replace(/\\"/g, '"').replace(/\\\\/g, '\\');
49
50    const blockPattern = /"content_id":(\d+),"content_type":"(livestreaming|livestreaming_schedule)",(.*?)(?=,"links":)/g;
51    let match;
52    const channelsData = {};
53
54    while ((match = blockPattern.exec(rawPayload)) !== null) {
55      const contentId = match[1];
56      const type = match[2];
57      const block = match[3];
58      
59      const title = this.extractValue(block, "title");
60      const altTitle = this.extractValue(block, "alt_title");
61      let streamUrl = this.extractValue(block, "stream_url");
62      const startTime = this.extractValue(block, "start_time");
63      const endTime = this.extractValue(block, "end_time");
64      const liveTitle = this.extractValue(block, "livestreaming_title");
65      
66      let channelName = type === 'livestreaming' ? altTitle : (liveTitle || altTitle);
67      if (!channelName) continue;
68      if (channelName.includes('·')) channelName = channelName.split('·').pop().trim();
69      
70      const channelKey = channelName.toLowerCase();
71
72      if (!channelsData[channelKey]) {
73        channelsData[channelKey] = { 
74          channel_id: parseInt(contentId),
75          channel_name: channelName, 
76          now_playing: 'Tidak ada informasi', 
77          stream_url: streamUrl === "null" || !streamUrl ? "" : streamUrl, 
78          schedules: [] 
79        };
80      }
81      
82      if (streamUrl && streamUrl !== "null" && streamUrl.trim() !== "") {
83        channelsData[channelKey].stream_url = streamUrl;
84      }
85
86      if (type === 'livestreaming') {
87        channelsData[channelKey].now_playing = title;
88      } else if (type === 'livestreaming_schedule') {
89        channelsData[channelKey].schedules.push({
90          title: title,
91          start_time: new Date(startTime).toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Jakarta' }),
92          end_time: new Date(endTime).toLocaleTimeString('id-ID', { hour: '2-digit', minute: '2-digit', timeZone: 'Asia/Jakarta' })
93        });
94      }
95    }
96
97    return channelsData;
98  }
99
100  async videoliveget(queries) {
101    const allChannels = await this.fetchAllChannels();
102    const results = [];
103
104    await Promise.all(queries.map(async (query) => {
105      const matchedKey = Object.keys(allChannels).find(k => k.includes(query.toLowerCase()));
106      
107      if (matchedKey) {
108        const channel = allChannels[matchedKey];
109        
110        if (!channel.stream_url || channel.stream_url.trim() === "") {
111          channel.stream_url = await this.getDetailStream(channel.channel_id);
112        }
113
114        results.push({
115          query: query,
116          status: "success",
117          data: {
118            channel_id: channel.channel_id,
119            channel_name: channel.channel_name,
120            now_playing: channel.now_playing,
121            stream_url: channel.stream_url,
122            total_schedules: channel.schedules.length,
123            schedules: channel.schedules
124          }
125        });
126      } else {
127        results.push({
128          query: query,
129          status: "not_found",
130          data: null
131        });
132      }
133    }));
134
135    return results;
136  }
137}
138
139(async () => {
140  const scraper = new VidioLive();
141  const targetChannels = ['indosiar', 'sctv', 'rcti', 'kompas tv'];
142  
143  try {
144    const extractedData = await scraper.videoliveget(targetChannels);
145    
146    const responseJson = {
147      status: 200,
148      message: "Berhasil mengekstrak jadwal dan live stream",
149      timestamp: new Date().toISOString(),
150      results: extractedData
151    };
152
153    console.log(JSON.stringify(responseJson, null, 2));
154
155  } catch (error) {
156    console.log(JSON.stringify({
157      status: 500,
158      message: error.message,
159      results: []
160    }, null, 2));
161  }
162})();
163
163 lines·5,564 chars·5.4 KB