Skip to content

Instantly share code, notes, and snippets.

@wjx0912
Created October 12, 2024 07:55
Show Gist options
  • Save wjx0912/b7c433db17a3bffee0732e9b6f77ec35 to your computer and use it in GitHub Desktop.
Save wjx0912/b7c433db17a3bffee0732e9b6f77ec35 to your computer and use it in GitHub Desktop.
dump_eme.js
//dump eme代码:放到preload或者cp.js等最前面都行:
//dump_eme.js 代码参考:https://greasyfork.org/en/scripts/373903-eme-logger/code
//shaka也有个eme logger,作为chrome extension,vd里面loadExtension成功了,但是界面不知道怎么操作(https://github.com/shaka-project/eme_logger) 也可以考虑移植这个代码
// ================================================================================================
// from: https://greasyfork.org/en/scripts/373903-eme-logger/code
// ==UserScript==
// @name EME Logger
// @namespace http://greasyfork.org/
// @version 2.0
// @description Inject EME interface and log its function calls.
// @author cramer
// @match *://*/*
// @run-at document-start
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// ==/UserScript==
(async () => {
function isKeySystemDisabled(keySystem) {
return false
}
// Color constants
const $ = {
INFO: '#66d9ef',
VALUE: '#4ec9a4',
METHOD: '#569cd6',
SUCCESS: '#a6e22e',
FAILURE: '#6d1212',
WARNING: '#fd971f',
};
const indent = (s,n=4) => s.split('\n').map(l=>Array(n).fill(' ').join('')+l).join('\n');
const b64 = {
decode: s => Uint8Array.from(atob(s), c => c.charCodeAt(0)),
encode: b => btoa(String.fromCharCode(...new Uint8Array(b)))
};
const fnproxy = (object, func) => new Proxy(object, { apply: func });
const proxy = (object, key, func) => Object.hasOwnProperty.call(object, key) && Object.defineProperty(object, key, {
value: fnproxy(object[key], func)
});
function messageHandler(event) {
const keySession = event.target;
const {sessionId} = keySession;
const {message, messageType} = event;
const msgs = keySession.getEventListeners('message');
console.log('messageHandler msgs: ', msgs)
const listeners = keySession.getEventListeners('message').filter(l => l !== messageHandler);
console.groupCollapsed(
`%c[EME] (EVENT)%c MediaKeySession::message%c\n` +
`Session ID: %c%s%c\n` +
`Message Type: %c%s%c\n` +
`Message: %c%s%c\n` +
`Listeners:`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, sessionId || '(not available)', `color: inherit; font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, messageType, `color: inherit; font-weight: normal;`,
`font-weight: bold;`, b64.encode(message), `font-weight: normal;`,
listeners,
);
console.trace();
console.groupEnd();
}
function keyStatusColor(status) {
switch(status.toLowerCase()) {
case 'usable':
return $.SUCCESS;
case 'output-restricted':
case 'output-downscaled':
case 'usable-in-future':
case 'status-pending':
return $.WARNING;
case 'expired':
case 'released':
case 'internal-error':
default:
return $.FAILURE;
}
}
function keystatuseschangeHandler(event) {
const keySession = event.target;
const {sessionId} = keySession;
const listeners = keySession.getEventListeners('keystatuseschange').filter(l => l !== keystatuseschangeHandler);
let keysFmt = '';
const keysText = [];
keySession.keyStatuses.forEach((status, keyId) => {
keysFmt += ` %c[%s]%c %s%c\n`;
keysText.push(
`color: ${keyStatusColor(status)}; font-weight: bold;`,
status.toUpperCase(),
`color: ${$.VALUE};`,
b64.encode(keyId),
`color: inherit; font-weight: normal;`,
);
});
console.groupCollapsed(
`%c[EME] (EVENT)%c MediaKeySession::keystatuseschange%c\n` +
`Session ID: %c%s%c\n` +
`Key Statuses:\n` + keysFmt +
'Listeners:',
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, sessionId || '(not available)', `color: inherit; font-weight: normal;`,
...keysText,
listeners,
);
console.trace();
console.groupEnd();
}
function getEventListeners(type) {
if (this == null) return [];
const store = this[Symbol.for(getEventListeners)];
if (store == null || store[type] == null) return [];
return store[type];
}
EventTarget.prototype.getEventListeners = getEventListeners;
typeof Navigator !== 'undefined' && proxy(Navigator.prototype, 'requestMediaKeySystemAccess', async (_target, _this, _args) => {
const [keySystem, supportedConfigurations] = _args;
const enterMessage = [
`%c[EME] (CALL)%c Navigator::requestMediaKeySystemAccess%c\n` +
`Key System: %c%s%c\n` +
`Supported Configurations:\n`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, keySystem, `color: inherit; font-weight: normal;`,
indent(JSON.stringify(supportedConfigurations, null, ' ')),
];
let result, err;
try {
if (isKeySystemDisabled(keySystem)) {
throw new DOMException(`Unsupported keySystem or supportedConfigurations.`, `NotSupportedError`);
}
result = await _target.apply(_this, _args);
return result;
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`, result);
}
console.trace();
console.groupEnd();
}
});
typeof MediaKeySystemAccess !== 'undefined' && proxy(MediaKeySystemAccess.prototype, 'createMediaKeys', async (_target, _this, _args) => {
const enterMessage = [
`%c[EME] (CALL)%c MediaKeySystemAccess::createMediaKeys%c\n` +
`Key System: %c%s%c\n` +
`Configurations:\n`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, _this.keySystem, `color: inherit; font-weight: normal;`,
indent(JSON.stringify(_this.getConfiguration(), null, ' ')),
];
let result, err;
try {
result = await _target.apply(_this, _args);
return result;
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`, result);
}
console.trace();
console.groupEnd();
}
});
if (typeof MediaKeys !== 'undefined') {
proxy(MediaKeys.prototype, 'setServerCertificate', async (_target, _this, _args) => {
const [serverCertificate] = _args;
const enterMessage = [
`%c[EME] (CALL)%c MediaKeys::setServerCertificate%c\n` +
`Server Certificate:`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
b64.encode(serverCertificate),
];
let result, err;
try {
result = await _target.apply(_this, _args);
return result;
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`, result);
}
console.trace();
console.groupEnd();
}
});
proxy(MediaKeys.prototype, 'createSession', (_target, _this, _args) => {
const [sessionType] = _args;
const enterMessage = [
`%c[EME] (CALL)%c MediaKeys::createSession%c\n` +
`Session Type: %c%s`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, sessionType || 'temporary (default)',
];
let session, err;
try {
session = _target.apply(_this, _args);
session.addEventListener('message', messageHandler);
session.addEventListener('keystatuseschange', keystatuseschangeHandler);
return session;
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`, session);
}
console.trace();
console.groupEnd();
}
});
}
if (typeof EventTarget !== 'undefined') {
proxy(EventTarget.prototype, 'addEventListener', async (_target, _this, _args) => {
if (_this != null) {
const [type, listener] = _args;
const storeKey = Symbol.for(getEventListeners);
if (!(storeKey in _this)) _this[storeKey] = {};
const store = _this[storeKey];
if (!(type in store)) store[type] = [];
const listeners = store[type];
if (listeners.indexOf(listener) < 0) {
listeners.push(listener);
}
}
return _target.apply(_this, _args);
});
proxy(EventTarget.prototype, 'removeEventListener', async (_target, _this, _args) => {
if (_this != null) {
const [type, listener] = _args;
const storeKey = Symbol.for(getEventListeners);
if (!(storeKey in _this)) return;
const store = _this[storeKey];
if (!(type in store)) return;
const listeners = store[type];
const index = listeners.indexOf(listener);
if (index >= 0) {
if (listeners.length === 1) {
delete store[type];
} else {
listeners.splice(index, 1);
}
}
}
return _target.apply(_this, _args);
});
}
if (typeof MediaKeySession !== 'undefined') {
proxy(MediaKeySession.prototype, 'generateRequest', async (_target, _this, _args) => {
const [initDataType, initData] = _args;
const enterMessage = [
`%c[EME] (CALL)%c MediaKeySession::generateRequest%c\n` +
`Session ID: %c%s%c\n` +
`Init Data Type: %c%s%c\n` +
`Init Data:`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, _this.sessionId || '(not available)', `color: inherit; font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, initDataType, `color: inherit; font-weight: normal;`,
b64.encode(initData),
];
let result, err;
try {
result = await _target.apply(_this, _args);
return result;
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`, result);
}
console.trace();
console.groupEnd();
}
});
proxy(MediaKeySession.prototype, 'load', async (_target, _this, _args) => {
const [sessionId] = _args;
const enterMessage = [
`%c[EME] (CALL)%c MediaKeySession::load%c\n` +
`Session ID: %c%s`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, _this.sessionId || '(not available)',
];
let result, err;
try {
result = await _target.apply(_this, _args);
return result;
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`, result);
}
console.trace();
console.groupEnd();
}
});
proxy(MediaKeySession.prototype, 'update', async (_target, _this, _args) => {
const [response] = _args;
const enterMessage = [
`%c[EME] (CALL)%c MediaKeySession::update%c\n` +
`Session ID: %c%s%c\n` +
`Response:`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, _this.sessionId || '(not available)', `color: inherit; font-weight: normal;`,
b64.encode(response),
];
let err;
try {
return await _target.apply(_this, _args);
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`);
}
console.trace();
console.groupEnd();
}
});
proxy(MediaKeySession.prototype, 'close', async (_target, _this, _args) => {
const enterMessage = [
`%c[EME] (CALL)%c MediaKeySession::close%c\n` +
`Session ID: %c%s`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, _this.sessionId || '(not available)',
];
let err;
try {
return await _target.apply(_this, _args);
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`);
}
console.trace();
console.groupEnd();
}
});
proxy(MediaKeySession.prototype, 'remove', async (_target, _this, _args) => {
const enterMessage = [
`%c[EME] (CALL)%c MediaKeySession::remove%c\n` +
`Session ID: %c%s`,
`color: ${$.INFO}; font-weight: bold;`, `color: ${$.METHOD};`, `font-weight: normal;`,
`color: ${$.VALUE}; font-weight: bold;`, _this.sessionId || '(not available)',
];
let err;
try {
return await _target.apply(_this, _args);
} catch(e) {
err = e;
throw e;
} finally {
console.groupCollapsed(...enterMessage);
if (err) {
console.error(`%c[FAILURE]`, `color: ${$.FAILURE}; font-weight: bold;`, err);
} else {
console.log(`%c[SUCCESS]`, `color: ${$.SUCCESS}; font-weight: bold;`);
}
console.trace();
console.groupEnd();
}
});
}
})();
// ================================================================================================
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment