MSE Dump Tools

Media Source Extensions API 数据 Dump 工具

当前为 2021-11-30 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name MSE Dump Tools
  3. // @namespace CloudMoeMediaSourceExtensionsAPIDataDumper
  4. // @version 1.4.0
  5. // @description Media Source Extensions API 数据 Dump 工具
  6. // @author TGSAN
  7. // @include /.*/
  8. // @run-at document-start
  9. // @grant GM_unregisterMenuCommand
  10. // @grant GM_registerMenuCommand
  11. // @grant unsafeWindow
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. GM_registerMenuCommand(`视频 - 最快播放速度`, function () { document.getElementsByTagName("video")[0].playbackRate = 16 });
  18. GM_registerMenuCommand(`视频 - 恢复播放速度`, function () { document.getElementsByTagName("video")[0].playbackRate = 1 });
  19. GM_registerMenuCommand(`音频 - 最快播放速度`, function () { document.getElementsByTagName("audio")[0].playbackRate = 16 });
  20. GM_registerMenuCommand(`音频 - 恢复播放速度`, function () { document.getElementsByTagName("audio")[0].playbackRate = 1 });
  21. GM_registerMenuCommand(`结束Dump`, EndAllDumpTasks);
  22.  
  23. var dumpEndTasks = [];
  24.  
  25. function dateFormat(dataObj, fmt) {
  26. var o = {
  27. "M+": dataObj.getMonth() + 1, //月份
  28. "d+": dataObj.getDate(), //日
  29. "h+": dataObj.getHours(), //小时
  30. "m+": dataObj.getMinutes(), //分
  31. "s+": dataObj.getSeconds(), //秒
  32. "q+": Math.floor((dataObj.getMonth() + 3) / 3), //季度
  33. "S": dataObj.getMilliseconds() //毫秒
  34. };
  35. if (/(y+)/.test(fmt)) {
  36. fmt = fmt.replace(RegExp.$1, (dataObj.getFullYear() + "").substr(4 - RegExp.$1.length));
  37. }
  38. for (var k in o) {
  39. if (new RegExp("(" + k + ")").test(fmt)) {
  40. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
  41. }
  42. }
  43. return fmt;
  44. }
  45.  
  46. function EndAllDumpTasks() {
  47. while (dumpEndTasks.length > 0) {
  48. let endTask = dumpEndTasks.shift();
  49. endTask();
  50. }
  51. }
  52.  
  53. unsafeWindow.SavedDataList = [];
  54.  
  55. unsafeWindow.DownloadData = function (dataKey, fileName) {
  56. const link = document.createElement('a');
  57. link.href = URL.createObjectURL(new Blob([unsafeWindow.SavedDataList[dataKey]]));
  58. link.download = fileName;
  59. link.click();
  60. window.URL.revokeObjectURL(link.href);
  61. }
  62.  
  63. function DownloadDataCmd(key, type, date) {
  64. var ext = "bin";
  65. if (type == "audio") {
  66. ext = "m4a";
  67. } else if (type == "video") {
  68. ext = "mp4";
  69. }
  70. DownloadData(key, "dumped_" + type + "_" + dateFormat(date, "yyyyMMddhhmmss") + "." + ext);
  71. }
  72.  
  73. function Uint8ArrayConcat(a, b) {
  74. var c = new Uint8Array(a.length + b.length);
  75. c.set(a);
  76. c.set(b, a.length);
  77. return c;
  78. }
  79.  
  80. function BytesToSize(bytes) {
  81. if (bytes === 0) return '0 B';
  82. var k = 1024;
  83. var sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  84. var i = Math.floor(Math.log(bytes) / Math.log(k));
  85. return (bytes / Math.pow(k, i)).toPrecision(3) + ' ' + sizes[i];
  86. }
  87.  
  88. var _addSourceBuffer = unsafeWindow.MediaSource.prototype.addSourceBuffer;
  89. unsafeWindow.MediaSource.prototype.addSourceBuffer = function (mime) {
  90. console.log("MediaSource addSourceBuffer Type: ", mime);
  91. var sourceBuffer = _addSourceBuffer.call(this, mime);
  92. var _append = sourceBuffer.appendBuffer;
  93. var endToSave = false;
  94. var sourceBufferData = new Uint8Array();
  95. var isVideo = (mime.startsWith("audio") ? false : true);
  96. var type = (isVideo ? "video" : "audio");
  97. var key = type + "_" + window.performance.now().toString();
  98. var startDate = new Date();
  99. dumpEndTasks.push(() => {
  100. endToSave = true;
  101. console.warn(`轨道: ${mime} 已结束保存。`);
  102. unsafeWindow.SavedDataList[key] = sourceBufferData;
  103. let downloadCaption = `下载${(isVideo ? "视频" : "音频")}数据 (${BytesToSize(sourceBufferData.length)}, at ${dateFormat(startDate, "yyyy/MM/dd hh:mm:ss")})`;
  104. GM_registerMenuCommand(downloadCaption, () => { DownloadDataCmd(key, type, startDate); });
  105. });
  106. sourceBuffer.appendBuffer = function (buffer) {
  107. if (!endToSave) {
  108. sourceBufferData = Uint8ArrayConcat(sourceBufferData, new Uint8Array(buffer));
  109. }
  110. _append.call(this, buffer);
  111. }
  112. return sourceBuffer;
  113. }
  114.  
  115. })();