const host = 'https://api.dbokutv.com'; const headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36", "Referer": "https://www.duboku.tv/" }; function base64Encode(text) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; let b64 = ''; for (let i = 0; i < text.length; i += 3) { let n = (text.charCodeAt(i) << 16) | (text.charCodeAt(i + 1) << 8) | text.charCodeAt(i + 2); b64 += chars.charAt((n >> 18) & 63) + chars.charAt((n >> 12) & 63) + chars.charAt((n >> 6) & 63) + chars.charAt(n & 63); } let mod = text.length % 3; return (mod ? b64.slice(0, mod - 3) + "===".substring(mod) : b64); } function base64Decode(str) { const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; str = str.replace(/=/g, ''); let bin = ''; for (let i = 0; i < str.length; i += 4) { let n = (chars.indexOf(str.charAt(i)) << 18) | (chars.indexOf(str.charAt(i + 1)) << 12) | (chars.indexOf(str.charAt(i + 2)) << 6) | chars.indexOf(str.charAt(i + 3)); bin += String.fromCharCode((n >> 16) & 255, (n >> 8) & 255, n & 255); } return bin.replace(/\0/g, ''); } function decodeData(data) { if (!data || typeof data !== 'string') return ''; let strippedStr = data.replace(/['"]/g, '').trim(); if (!strippedStr) return ''; let segmentLength = 10; let processedBase64 = ''; for (let i = 0; i < strippedStr.length; i += segmentLength) { let segment = strippedStr.substring(i, i + segmentLength); processedBase64 += segment.split('').reverse().join(''); } processedBase64 = processedBase64.replace(/\./g, '='); try { return base64Decode(processedBase64); } catch (e) { return ''; } } function getSignedUrl(path) { const timestamp = Math.floor(Date.now() / 1000).toString(); const randomNumber = Math.floor(Math.random() * 800000001); const valueA = (randomNumber + 100000000).toString(); const valueB = (900000000 - randomNumber).toString(); const combined = valueA + valueB; let interleaved = ''; let minLen = Math.min(combined.length, timestamp.length); for (let i = 0; i < minLen; i++) { interleaved += combined[i] + timestamp[i]; } interleaved += combined.substring(minLen) + timestamp.substring(minLen); const ssid = base64Encode(interleaved).replace(/=/g, '.'); function randomStr(len) { const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let res = ''; for (let i = 0; i < len; i++) res += chars.charAt(Math.floor(Math.random() * chars.length)); return res; } const sign = randomStr(60); const token = randomStr(38); const connector = path.includes('?') ? '&' : '?'; return `${host}${path}${connector}sign=${sign}&token=${token}&ssid=${ssid}`; } async function init(cfg) {} async function home(filter) { const classes = [ { type_id: '2', type_name: '连续剧' }, { type_id: '1', type_name: '电影' }, { type_id: '3', type_name: '综艺' }, { type_id: '4', type_name: '动漫' } ]; return JSON.stringify({ class: classes }); } async function homeVod() { const url = getSignedUrl('/home'); const r = await req(url, { headers }); const json = JSON.parse(r.content); let videos = []; json.forEach(group => { (group.VodList || []).forEach(j => { videos.push({ vod_id: decodeData(j.DId || j.DuId), vod_name: j.Name, vod_pic: decodeData(j.TnId), vod_remarks: j.Tag }); }); }); return JSON.stringify({ list: videos }); } async function category(tid, pg, filter, extend = {}) { let page = pg || 1; let pageStr = page.toString() === '1' ? '' : page.toString(); let urlPath = `/vodshow/${tid}--------${pageStr}---`; const url = getSignedUrl(urlPath); const r = await req(url, { headers }); const json = JSON.parse(r.content); let videos = (json.VodList || []).map(i => ({ vod_id: decodeData(i.DId || i.DuId), vod_name: i.Name, vod_pic: decodeData(i.TnId), vod_remarks: i.Tag })); let pageCount = page; try { (json.PaginationList || []).forEach(j => { if (j.Type === 'StartEnd') { let parts = decodeData(j.PId || j.PuId).split('-'); if (parts.length > 8) pageCount = parseInt(parts[8]); } else if (j.Type === 'ShortPage') { pageCount = parseInt(j.Name.split('/')[1]); } }); } catch (e) {} return JSON.stringify({ page: parseInt(page), pagecount: pageCount || parseInt(page), list: videos }); } async function detail(id) { const url = getSignedUrl(id); const r = await req(url, { headers }); const data = JSON.parse(r.content); const playUrls = (data.Playlist || []).map(i => { return `${i.EpisodeName}$${decodeData(i.VId)}`; }).join('#'); return JSON.stringify({ list: [{ vod_id: id, vod_name: data.Name, vod_pic: decodeData(data.TnId), vod_remarks: `评分:${data.Rating}`, vod_year: data.ReleaseYear, vod_area: data.Region, vod_actor: Array.isArray(data.Actor) ? data.Actor.join(',') : data.Actor, vod_director: data.Director, vod_content: data.Description, vod_play_from: '初忆测试', vod_play_url: playUrls, type_name: `${data.Genre || ''},${data.Scenario || ''}` }] }); } async function search(wd, quick, pg = 1) { const url = getSignedUrl('/vodsearch') + `&wd=${encodeURIComponent(wd)}`; const r = await req(url, { headers }); const json = JSON.parse(r.content); const list = (json || []).map(i => ({ vod_id: decodeData(i.DId || i.DuId), vod_name: i.Name, vod_pic: decodeData(i.TnId), vod_remarks: i.Tag })); return JSON.stringify({ page: pg, list: list }); } async function play(flag, id, flags) { const url = getSignedUrl(id); const r = await req(url, { headers }); const res = JSON.parse(r.content); return JSON.stringify({ parse: 0, url: decodeData(res.HId), header: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 'Origin': 'https://w.duboku.io', 'Referer': 'https://w.duboku.io/' } }); } export default { init, home, homeVod, category, detail, search, play };