// YouTube 视频信息提取器

// 处理网络请求
request = async (method, url, data = null, headers = {}, requestId, platform) => {
    console.log(`request url:${url}`)
    console.log(`request data:${data}`)
    console.log(`request method:${method}`)
    console.log(`request headers:${JSON.stringify((headers))}`);
    
    if (platform === "WEB") {
        const res = await fetch(url, {
            'mode': 'cors',
            'method': method,
            'headers': headers,
            'body': data
        });
        const resData = await res.text();
        return Promise.resolve({
            'data': resData,
            'headers': res.headers
        });
    }
    
    return new Promise((resolve, reject) => {
        AF.request(url, method, data, headers, requestId, (data, headers, err) => {
            if (err) {
                console.log(`request error: ${err}`);
                reject(err);
            } else {
                console.log(`response headers: ${headers}`);
                resolve({
                    'data': data,
                    'headers': JSON.parse(headers)
                });
            }
        });
    });
}

// 解析视频编码信息
parseCodecs = (format) => {
    const mimeType = format['mimeType']
    if (!mimeType) {
        return {};
    }
    const regex = /(?<mimetype>[^/]+\/[^;]+)(?:;\s*codecs="?(?<codecs>[^"]+))?/;
    const match = mimeType.match(regex);
    if (!match) {
        return {};
    }
    const codecs = match.groups.codecs;
    if (!codecs) {
        return {};
    }

    const splitCodecs = codecs.trim().replace(/,$/, '').split(',').map(str => str.trim()).filter(Boolean);
    let vcodec = null;
    let acodec = null;

    for (const fullCodec of splitCodecs) {
        const codec = fullCodec.split('.')[0];

        if (['avc1', 'avc2', 'avc3', 'avc4', 'vp9', 'vp8', 'hev1', 'hev2', 'h263', 'h264', 'mp4v', 'hvc1', 'av01', 'theora'].includes(codec)) {
            if (!vcodec) {
                vcodec = fullCodec;
            }
        } else if (['mp4a', 'opus', 'vorbis', 'mp3', 'aac', 'ac-3', 'ec-3', 'eac3', 'dtsc', 'dtse', 'dtsh', 'dtsl'].includes(codec)) {
            if (!acodec) {
                acodec = fullCodec;
            }
        } else {
            console.log(`WARNING: Unknown codec ${fullCodec}`);
        }
    }

    if (!vcodec && !acodec) {
        if (splitCodecs.length === 2) {
            return {
                vcodec: splitCodecs[0],
                acodec: splitCodecs[1]
            };
        }
    } else {
        return {
            vcodec: vcodec,
            acodec: acodec
        };
    }

    return {};
}



// 从播放器JS中提取解密函数
async function extractDecryptFunction(playerUrl, requestId, platform) {
    // 函数内部缓存
    const cache = extractDecryptFunction.cache || (extractDecryptFunction.cache = {});
    const cacheKey = `jsFunction:${playerUrl}`;
    
    if (cache[cacheKey]) {
        console.log(`从缓存获取解密函数: ${playerUrl}`);
        return cache[cacheKey];
    }

    const playerResp = await request('GET', playerUrl, null, {}, requestId, platform);
    const playerJs = playerResp.data;

    // 提取签名函数名
    const signatureFunctionName = playerJs.match(/\bc\s*&&\s*d\.set\([^,]+\s*,\s*\([^)]*\)\s*=>\s*([a-zA-Z$_][a-zA-Z$_0-9]*)\(/)[1];
    
    // 提取ncode函数名
    const ncodeFunctionName = playerJs.match(/\bc\s*&&\s*d\.set\([^,]+\s*,\s*\([^)]*\)\s*=>\s*([a-zA-Z$_][a-zA-Z$_0-9]*)\(\))/)[1];

    // 提取函数定义
    const functionPattern = new RegExp(`${signatureFunctionName}=function\\(\\w+\\)\\{[^\\}]+\\}`);
    const signatureFunction = playerJs.match(functionPattern)[0];

    const ncodeFunctionPattern = new RegExp(`${ncodeFunctionName}=function\\(\\)\\{[^\\}]+\\}`);
    const ncodeFunction = playerJs.match(ncodeFunctionPattern)[0];

    // 存入函数内部缓存
    const result = {
        signatureFunction,
        ncodeFunction
    };
    cache[cacheKey] = result;
    return result;
}

// 解析并执行解密函数
function executeDecryptFunction(code, input) {
    const fn = new Function('a', code.replace(/^[^=]+=function/, 'return function'));
    return fn(input);
}

// 解密签名
decryptSignature = async (signatureEncrypted, playerUrl, requestId, platform) => {
    try {
        // 提取解密函数
        const {signatureFunction, ncodeFunction} = await extractDecryptFunction(playerUrl, requestId, platform);
        
        // 执行签名解密
        const decryptedSignature = executeDecryptFunction(signatureFunction, signatureEncrypted);
        
        // 执行ncode处理
        const ncode = executeDecryptFunction(ncodeFunction, '');
        
        return {
            signature: decryptedSignature,
            ncode: ncode
        };
    } catch (e) {
        console.error('签名解密失败:', e);
        return {
            signature: signatureEncrypted,
            ncode: ''
        };
    }
}

// 获取视频详情
detail = async (url, requestId, platform) => {
    try {
        // 获取视频页面 HTML
        const htmlResp = await request('GET', `${url}&bpctr=9999999999&has_verified=1`, null, {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
            'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
            'Accept-Language': 'en-us,en;q=0.5',
            'Sec-Fetch-Mode': 'navigate',
            'Accept-Encoding': 'gzip, deflate, br',

        }, requestId, platform);

        let {data: html, headers: htmlHeaders} = htmlResp;

        // 解析初始播放器响应
        const playerMatch = html.match(/var ytInitialPlayerResponse\s*=\s*({.*?});/);
        if (!playerMatch) {
            throw new Error('无法找到播放器数据');
        }

        const ytInitialPlayerResponse = JSON.parse(playerMatch[1]);
        const originVideoDetails = ytInitialPlayerResponse['videoDetails'];

        // 获取推荐视频
        const recommendInfo = [];
        const ytInitialDataMatch = html.match(/var ytInitialData\s*=\s*({.*?});/);
        if (ytInitialDataMatch) {
            const ytInitialData = JSON.parse(ytInitialDataMatch[1]);
            const recommendations = ytInitialData.contents?.twoColumnWatchNextResults?.secondaryResults?.secondaryResults?.results || [];
            
            for (const item of recommendations) {
                if (item.compactVideoRenderer) {
                    const video = item.compactVideoRenderer;
                    if (video.videoId) {
                        recommendInfo.push({
                            type: "gridVideoRenderer",
                            videoId: video.videoId,
                            title: video.title?.simpleText,
                            thumbnails: video.thumbnail?.thumbnails,
                            channelName: video.longBylineText?.runs?.[0]?.text,
                            publishedTimeText: video.publishedTimeText?.simpleText,
                            viewCountText: video.viewCountText?.simpleText,
                            shortViewCountText: video.shortViewCountText?.simpleText,
                            lengthText: video.lengthText?.simpleText
                        });
                    }
                }
            }
        }

        // 获取播放格式
        const formats = [];
        const qualities = [];

        // 从 HTML 中获取格式
        const streamingData = ytInitialPlayerResponse.streamingData;
        const allFormats = [
            ...(streamingData.formats || []),
            ...(streamingData.adaptiveFormats || [])
        ];

        for (const format of allFormats) {
            if (format.height && parseInt(format.height) >= 720) {
                continue;
            }

            if (format && !qualities.includes(format.qualityLabel)) {
                const {vcodec, acodec} = parseCodecs(format);
                
                let finalUrl = format.url;
                if (!finalUrl && format.signatureCipher) {
                    const urlParams = new URLSearchParams(format.signatureCipher);
                    const url = urlParams.get('url');
                    const s = urlParams.get('s');
                    if (url && s) {
                        const playerUrl = `https://www.youtube.com${html.match(/"(?:PLAYER_JS_URL|jsUrl)"\s*:\s*"([^"]+)"/)?.at(1)}`;
                        const {signature, ncode} = await decryptSignature(s, playerUrl, requestId, platform);
                        finalUrl = `${url}&sig=${signature}&n=${ncode}`;
                    }
                }

                if (finalUrl && vcodec && acodec) {
                    formats.push({
                        width: format.width + "",
                        height: format.height + "",
                        type: format.mimeType,
                        quality: format.qualityLabel,
                        itag: format.itag,
                        fps: format.fps + "",
                        bitrate: format.bitrate + "",
                        ext: "mp4",
                        vcodec: vcodec,
                        acodec: acodec,
                        vbr: "0",
                        abr: "0",
                        container: "mp4_dash",
                        from: "web",
                        url: format.url,
                        videoUrl: "",
                        audioUrl: ""
                    });
                    qualities.push(format.qualityLabel);
                }
            }
        }

        // 按高度排序
        formats.sort((a, b) => parseInt(a.height) - parseInt(b.height));

        // 构建缩略图列表
        const thumbnails = originVideoDetails.thumbnail.thumbnails.map(item => ({
            url: item.url,
            width: item.width + "",
            height: item.height + ""
        }));

        // 构建视频详情
        const videoDetails = {
            isLiveContent: originVideoDetails.isLiveContent,
            title: originVideoDetails.title,
            thumbnails: thumbnails,
            description: originVideoDetails.shortDescription,
            lengthSeconds: originVideoDetails.lengthSeconds,
            viewCount: originVideoDetails.viewCount,
            keywords: originVideoDetails.keywords,
            author: originVideoDetails.author,
            channelID: originVideoDetails.channelId,
            recommendInfo: recommendInfo,
            channelURL: `https://www.youtube.com/channel/${originVideoDetails.channelId}`,
            videoId: url.replace('https://www.youtube.com/watch?v=', '')
        };

        return {
            code: 200,
            msg: "",
            requestId: requestId,
            data: {
                videoDetails: videoDetails,
                streamingData: {
                    formats: formats
                }
            },
            id: "MusicDetailViewModel_detail_url"
        };

    } catch (e) {
        console.error(e);
        return {
            code: -1,
            msg: e.toString(),
            requestId: requestId
        };
    }
}