/**
 * 咪咕视频直播流 m3u8 获取脚本
 * 用法: node migu_stream.js <content_id> [rate_type]
 * 输出: 加密后的 m3u8 URL (stdout)
 * 
 * 基于: https://github.com/jiarandiana0307/migu-video-crack
 */

let wasmInstance = null;
let memory_p = null;
let memory_h = null;
let CallInterface1, CallInterface2, CallInterface3, CallInterface4,
    CallInterface6, CallInterface7, CallInterface8, CallInterface9,
    CallInterface10, CallInterface11, CallInterface14, malloc;
let memory = null;

const p = '+6e7/UkVh9XuFSTC5k08Qw==';
const h = '10012';

function stringToUTF8(string, offset, length) {
    const encoded = new TextEncoder().encode(string);
    for (let i = 0; i < encoded.length && i < length - 1; i++) {
        memory_p[offset + i] = encoded[i];
    }
    memory_p[offset + encoded.length] = 0;
    return encoded.length;
}

function UTF8ToString(offset) {
    let s = '';
    let i = 0;
    while (memory_p[offset + i]) {
        s += String.fromCharCode(memory_p[offset + i]);
        i++;
    }
    return s;
}

function a(e, t, r, n) {
    let s = 0;
    for (let i = 0; i < r; i++) {
        s += memory_h[(t + 4) >> 2];
        t += 8;
    }
    memory_h[n >> 2] = s;
    return 0;
}
function b(e, t, r, n) {}
function c(e) {}
function d() { return 1; }

async function initWasm() {
    const playerVersion = 'v_20251124155500_63c16e66';
    const wasmUrl = `https://www.miguvideo.com/mgs/player/prd/${playerVersion}/dist/mgprtcl.wasm`;
    const response = await fetch(wasmUrl);
    const wasmBinary = await response.arrayBuffer();
    const importObject = { a: { b, c, a, d } };
    const { instance } = await WebAssembly.instantiate(wasmBinary, importObject);
    wasmInstance = instance;
    memory = wasmInstance.exports.e;
    memory_p = new Uint8Array(memory.buffer);
    memory_h = new Uint32Array(memory.buffer);
    CallInterface1 = wasmInstance.exports.i;
    CallInterface2 = wasmInstance.exports.j;
    CallInterface3 = wasmInstance.exports.k;
    CallInterface4 = wasmInstance.exports.l;
    CallInterface6 = wasmInstance.exports.n;
    CallInterface7 = wasmInstance.exports.o;
    CallInterface8 = wasmInstance.exports.p;
    CallInterface9 = wasmInstance.exports.q;
    CallInterface10 = wasmInstance.exports.r;
    CallInterface11 = wasmInstance.exports.s;
    CallInterface14 = wasmInstance.exports.u;
    malloc = wasmInstance.exports.v;
}

function encrypt(url) {
    const parsedUrl = new URL(url);
    const query = Object.fromEntries(new URLSearchParams(parsedUrl.search));
    const o = query.userid || '';
    const aa = query.timestamp || '';
    const s = query.ProgramID || '';
    const l = query.Channel_ID || '';
    const g = query.puData || '';

    const f = malloc(o.length + 1);
    const dd = malloc(aa.length + 1);
    const v = malloc(s.length + 1);
    const m = malloc(l.length + 1);
    const bb = malloc(g.length + 1);
    const _ = malloc(p.length + 1);
    const E = malloc(64);
    const T = malloc(128);
    const w = malloc(128);

    stringToUTF8(o, f, o.length + 1);
    stringToUTF8(aa, dd, aa.length + 1);
    stringToUTF8(s, v, s.length + 1);
    stringToUTF8(l, m, l.length + 1);
    stringToUTF8(g, bb, g.length + 1);
    stringToUTF8(p, _, p.length + 1);

    const S = CallInterface6();
    CallInterface1(S, v, s.length);
    CallInterface10(S, dd, aa.length);
    CallInterface9(S, f, o.length);
    CallInterface3(S, 0, 0);
    CallInterface11(S, 0, 0);
    CallInterface8(S, bb, g.length);
    CallInterface2(S, m, l.length);
    CallInterface14(S, _, p.length, w, 128);

    const I = UTF8ToString(w);
    const O = malloc(I.length + 1);
    stringToUTF8(I, O, I.length + 1);
    CallInterface7(S, O, I.length);
    CallInterface4(S, T, 128);
    const k = UTF8ToString(T);
    return url + '&ddCalcu=' + encodeURIComponent(k) + '&sv=' + h;
}

async function getUrl(vid, rateType = 3) {
    const channelId = '0132_10010001005';
    const headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/125.0.0.0 Safari/537.36',
        'Appcode': 'miguvideo_default_www',
        'Appid': 'miguvideo',
        'Channel': 'H5',
        'x-up-client-channel-id': channelId,
    };
    const url = `https://webapi.miguvideo.com/gateway/playurl/v3/play/playurl?contId=${vid}&rateType=${rateType}&xh265=true&chip=mgwww&channelId=${channelId}`;
    const response = await fetch(url, { headers });
    const data = await response.json();
    if (data.code !== '200' && data.playCode) {
        throw new Error(`Migu API: ${data.message || data.playCode} (${data.code})`);
    }
    if (!data.body || !data.body.urlInfo || !data.body.urlInfo.url) {
        throw new Error(`节目未开播或已下线 (code: ${data.code})`);
    }
    return data.body.urlInfo.url;
}

(async () => {
    const vid = process.argv[2] || '120000575503';
    const rateType = parseInt(process.argv[3] || '3');
    try {
        await initWasm();
        const rawUrl = await getUrl(vid, rateType);
        const encryptedUrl = encrypt(rawUrl);
        console.log(encryptedUrl);
    } catch (e) {
        console.error('ERROR:', e.message);
        process.exit(1);
    }
})();
