写完了不知道该发哪里,就发这里吧,有需要自取 xhj010

脚本能禁止使用clearkey然后就会回落到熟悉的wv,因为pssh需要拼凑才能得到很麻烦,直接通过脚本在控制台输出,方便快速拿key,主要是用来破dcv档不用下那破播放器还要捣鼓抓包了

只在火狐上测试过能用

无论是clearkey还是wv,只要是相同的文件用的就是相同的key,只是加密技术不同而已所以通过clearkey拿到的key一样可以用来破dcv不需要回落wv

脚本只适用于普通视频,4k和vr这种的话卖这么贵根本连测试片源都没有好吧应该是用不了的

wasm真是好方便,看下以后有没可能直接脚本拿key yct010

// ==UserScript==
// @name         Disable ClearKey & Get PSSH
// @namespace    http://tampermonkey.net/
// @version      0.0.1
// @description  Disable ClearKey & Get PSSH
// @author       You
// @match        https://www.dmm.co.jp/digital/-/player/=/player=html5/act=playlist/pid=*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=dmm.co.jp
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 禁用 ClearKey
    const originalRequestMediaKeySystemAccess = navigator.requestMediaKeySystemAccess;
    navigator.requestMediaKeySystemAccess = function(keySystem, configs) {
        if (keySystem === 'org.w3.clearkey') {
            return Promise.reject(new Error('ClearKey not supported'));
        }
        return originalRequestMediaKeySystemAccess.call(this, keySystem, configs);
    };

    let mpdKid = null;
    let contentId = null;
    let licenseURL = null;
    let psshBase64 = null;
    let licenseCookie = null;
    let manifestURL = null;

    // 提取 licenseUID 的正则表达式
    function extractLicenseUID(cookieString) {
        const match = cookieString.match(/licenseUID=([^;]+)/);
        return match ? match[1] : null;
    }

    // 获取所有 cookies
    const allCookies = document.cookie;

    // 提取并输出 licenseUID
    const licenseUID = extractLicenseUID(allCookies);
    if (licenseUID) {
        console.log('Extracted licenseUID:', licenseUID);
        licenseCookie = `headers = { 'Cookie': 'licenseUID=${licenseUID}' }`;
    } else {
        console.log('licenseUID not found in cookies.');
    }

    // 保存原始 fetch
    const originalFetch = window.fetch;

    let mpdRequestCount = 0;
    let licRequestCount = 0;

    window.fetch = async function(...args) {
        const request = args[0];
        const options = args[1] || {};

        // 判断 URL 是否以 manifest.mpd 结尾
        if (typeof request === 'string' && request.endsWith('manifest.mpd')) {
            mpdRequestCount++;
            if (mpdRequestCount === 1) {
                // console.log('Intercepted manifest.mpd URL:', request);
                manifestURL = request;

                // 获取响应
                const response = await originalFetch.apply(this, args);

                // 读取响应的内容
                const responseText = await response.text();

                // 正则表达式匹配 default_KID
                const regex = /default_KID="([A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12})"/g;
                let match;
                let count = 0;

                // 使用 while 循环来匹配所有匹配项
                while ((match = regex.exec(responseText)) !== null) {
                    console.log('Matched default_KID:', match[1]); // match[1] 为捕获的 KID 值
                    count++;
                     if (count === 1) {
                         mpdKid = match[1].replace(/-/g, '').toLowerCase();
                     }
                }

                if (count === 0) {
                    console.log('No default_KID found.');
                }

                // 返回原始的响应
                return response;
            }
        }

        // 检查 URL 是否符合条件
        if (typeof request === 'string' && request.startsWith('https://mlic.dmm')) {
            licRequestCount++;
            if (licRequestCount === 2) {
                const url = new URL(request); // 使用 URL 对象解析 URL
                licenseURL = request;

                // 检查请求体是否存在并符合条件
                if (options.body) {
                    const decoder = new TextDecoder(); // 解码器将字节转为字符串
                    const bodyText = decoder.decode(options.body).match(/{"v":.*?"}/);; // 解码为字符串
                    if (bodyText) {
                        contentId = bodyText[0];
                    } else {
                        console.log('%cNo matching content found in body.', 'color: red; font-weight: bold;');
                    }
                } else {
                    console.log('%cNo body content in request.', 'color: red; font-weight: bold;');
                }

                // 如果 mpdKid 和 contentId 都已获取到,生成 PSSH
                if (mpdKid && contentId) {

                    const encoder = new TextEncoder();
                    const contentIdBytes = encoder.encode(contentId);
                    const contentIdHex = Array.from(contentIdBytes)
                    .map(byte => byte.toString(16).padStart(2, '0'))
                    .join('');

                    (async () => {
                        const initModule = await import('https://emarsden.github.io/pssh-box-wasm/pkg/pssh_box_wasm.js');
                        await initModule.default();
                        psshBase64 = initModule.generate_widevine_pssh_b64(0, [mpdKid], '', contentIdHex, '', null, '', null);
                    })();
                }

                // 通过 setInterval 检查是否已经被赋值
                const checkValue = setInterval(() => {

                    if (mpdKid) {
                        console.log('%cRequest Kid:\n', 'color: green; font-weight: bold;', mpdKid);
                    }

                    if (contentId) {
                        console.log('%cRequest contentId:\n', 'color: green; font-weight: bold;', contentId);
                    }

                    if (licenseURL) {
                        console.log('%cRequest License URL:\n', 'color: green; font-weight: bold;', request);
                    }

                    if (psshBase64) {
                        console.log('%cRequest PSSH:', 'color: green; font-weight: bold;', psshBase64);
                    }

                    if (licenseCookie) {
                        console.log('%cRequest Cookie:\n', 'color: green; font-weight: bold;', licenseCookie);
                    }

                    if (manifestURL) {
                        console.log('%cRequest Manifest URL:\n', 'color: green; font-weight: bold;', manifestURL);
                    }

                    // 全都有值时,停止检查
                    if (mpdKid && contentId && licenseURL && psshBase64 && licenseCookie && manifestURL) {
                        clearInterval(checkValue); // 清除定时器
                    }
                }, 2000); // 每 2000 毫秒检查一次
            }
        }

        // 调用原始 fetch
        return originalFetch.apply(this, args);
    };

})();