動畫瘋工具箱

取得動畫的 m3u8 網址,下載彈幕為 json,去除擋廣告的警告訊息

目前为 2018-06-15 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 動畫瘋工具箱
  3. // @namespace https://blog.maple3142.net/
  4. // @description 取得動畫的 m3u8 網址,下載彈幕為 json,去除擋廣告的警告訊息
  5. // @version 0.7.3
  6. // @author maple3142
  7. // @match https://ani.gamer.com.tw/animeVideo.php?sn=*
  8. // @connect home.gamer.com.tw
  9. // @require https://cdn.jsdelivr.net/npm/m3u8-parser@4.2.0/dist/m3u8-parser.min.js
  10. // @grant GM_xmlhttpRequest
  11. // @grant unsafeWindow
  12. // ==/UserScript==
  13.  
  14. (function () {
  15. 'use strict';
  16.  
  17. function hookSetter(obj, prop, cb) {
  18. var value,
  19. canceled = false;
  20. Object.defineProperty(obj, prop, {
  21. set: function set(v) {
  22. value = v;
  23. if (!canceled) cb(v);
  24. },
  25. get: function get() {
  26. return value;
  27. }
  28. });
  29. return function () {
  30. return canceled = true;
  31. };
  32. }
  33. function cvtM3U8_to_playlist(baseurl) {
  34. return function (m3u8) {
  35. var parser = new m3u8Parser.Parser();
  36. parser.push(m3u8);
  37. parser.end();
  38. var pls = parser.manifest.playlists.map(function (pl) {
  39. return {
  40. url: 'https:' + baseurl + pl.uri,
  41. res: pl.attributes.RESOLUTION
  42. };
  43. });
  44. return pls;
  45. };
  46. }
  47. function triggerDownload(url, fname) {
  48. var a = document.createElement('a');
  49. a.href = url;
  50. a.download = fname;
  51. document.body.appendChild(a);
  52. a.click();
  53. a.remove();
  54. }
  55. function saveTextAsFile(text, fname) {
  56. var blob = new Blob([text]);
  57. var url = URL.createObjectURL(blob);
  58. triggerDownload(url, fname);
  59. URL.revokeObjectURL(url);
  60. }
  61. function getCORS(url) {
  62. return new Promise(function (res, rej) {
  63. GM_xmlhttpRequest({
  64. method: 'GET',
  65. url: url,
  66. responseType: 'text',
  67. onload: function onload(r) {
  68. return res(r.response);
  69. },
  70. onerror: rej
  71. });
  72. });
  73. }
  74. var $ = jQuery;
  75.  
  76. requirejs.config({
  77. baseUrl: '//i2.bahamut.com.tw',
  78. waitSeconds: 0,
  79. paths: {
  80. order: 'js/order'
  81. },
  82. shim: {
  83. vastvpaid: {
  84. deps: ['videojs']
  85. }
  86. }
  87. });
  88. requirejs(['order!videojs'], function (videojs) {
  89. return hookSetter(videojs.players, 'ani_video', function (vid) {
  90. unsafeWindow.ani_video = vid; //EXPOSE
  91.  
  92. hookSetter(vid.K, 'src', onPlaylistUrl);
  93. });
  94. });
  95.  
  96. function render(pls) {
  97. var html = pls.map(function (pl) {
  98. return "<div><label for=\"".concat(pl.res.height, "p\">").concat(pl.res.height, "P: </label><input id=\"").concat(pl.res.height, "p\" value=\"").concat(pl.url, "\" style=\"width: 500px;\"></div>");
  99. }).join('');
  100. $('.anime_name').append("<div id=\"anigamer_m3u8_warpper\">".concat(html, "</div>"));
  101. }
  102.  
  103. function onPlaylistUrl(playlisturl) {
  104. if (playlisturl.indexOf('gamer_ad') !== -1) {
  105. //is ad
  106. return;
  107. }
  108.  
  109. var baseurl = playlisturl.replace(/playlist\.m3u8.*/, '');
  110. fetch(playlisturl).then(function (r) {
  111. return r.text();
  112. }).then(cvtM3U8_to_playlist(baseurl)).then(function (pls) {
  113. return window.unsafeWindow = pls;
  114. }) //EXPOSE
  115. .then(render);
  116. }
  117.  
  118. var restore = hookSetter(animefun, 'danmu', function (danmu) {
  119. var text = JSON.stringify(danmu);
  120. var title = $('.anime_name h1').text();
  121. $('.anime_name').append($('<a>').on('click', function (e) {
  122. e.preventDefault();
  123. saveTextAsFile(text, "".concat(title, "_\u5F48\u5E55.json"));
  124. }).text('把彈幕存成檔案').css('display', 'block'));
  125. restore();
  126. });
  127.  
  128. //extra: block anti adblock alert
  129. var orig_alert = alert;
  130.  
  131. unsafeWindow.alert = function (t) {
  132. if (t.includes('由於擋廣告插件會影響播放器運作')) return;
  133. orig_alert(t);
  134. };
  135.  
  136. var hurl = 'https://home.gamer.com.tw/creationCategory.php?owner=blackxblue&c=370818';
  137. $('.anime_name').append($('<a>').on('click', function (e) {
  138. e.preventDefault();
  139. ani_video.total_time = 1000;
  140. ani_video.currentTime(ani_video.duration());
  141. }).text('直接顯示動漫通問題').css('display', 'block')).append($('<a>').on('click', function (e) {
  142. getCORS(hurl).then(function (ht) {
  143. var $h = $(ht);
  144. var url = $h.find('.TS1').toArray().filter(function (x) {
  145. return new RegExp('\\d{2}/' + new Date().getDate().toString().padStart(2, '0')).test(x.textContent);
  146. }).map(function (x) {
  147. return x.getAttribute('href');
  148. })[0];
  149. if (!url) throw new Error('No url found.');
  150. return getCORS('https://home.gamer.com.tw/' + url);
  151. }).then(function (ht) {
  152. var $h = $(ht);
  153. return /A:(\d)/.exec($h.find('.MSG-list8C').find('div').text())[1];
  154. }).then(function (ans) {
  155. alert('答案可能是 ' + ans);
  156. }).catch(function (err) {
  157. console.error(err);
  158. alert('抓取答案失敗,建議去官方粉絲團尋找答案');
  159. });
  160. }).text('試著從 blackxblue 小屋中抓取答案(實驗性)').css('display', 'block'));
  161.  
  162. }());

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址