pixiv コメントを展開

Expands pixiv comments. Always shows all comments (and replies).

  1. // ==UserScript==
  2. // @name pixiv コメントを展開
  3. // @name:ja pixiv コメントを展開
  4. // @name:en pixiv Comment Expander
  5. // @description Expands pixiv comments. Always shows all comments (and replies).
  6. // @description:ja コメント (+ 返信) を常に全件表示します。
  7. // @namespace http://userscripts.org/users/347021
  8. // @version 2.8.0
  9. // @match https://www.pixiv.net/*
  10. // @require https://gf.qytechs.cn/scripts/19616/code/utilities.js?version=895049
  11. // @require https://gf.qytechs.cn/scripts/17896/code/start-script.js?version=112958
  12. // @license MPL-2.0
  13. // @contributionURL https://www.amazon.co.jp/registry/wishlist/E7PJ5C3K7AM2
  14. // @compatible Edge
  15. // @compatible Firefox Firefoxを推奨 / Firefox is recommended
  16. // @compatible Opera
  17. // @compatible Chrome
  18. // @grant dummy
  19. // @noframes
  20. // @run-at document-start
  21. // @icon https://s.pximg.net/common/images/apple-touch-icon.png
  22. // @author 100の人
  23. // @homepageURL https://gf.qytechs.cn/scripts/266
  24. // ==/UserScript==
  25.  
  26. new class CommentExpander
  27. {
  28. /**
  29. * 1回のコメント取得数制限。
  30. * @constant {number}
  31. */
  32. static get LIMIT() {return 200;}
  33.  
  34. constructor()
  35. {
  36. startScript(
  37. () => GreasemonkeyUtils.executeOnUnsafeContext(this.changeLimit, [CommentExpander.LIMIT]),
  38. parent => parent.localName === 'html',
  39. target => target.localName === 'head',
  40. () => document.head
  41. );
  42.  
  43. document.addEventListener('DOMContentLoaded', () => {
  44. this.expandReplies();
  45. }, {once: true});
  46. }
  47.  
  48. /*globals fetch:true */
  49. /**
  50. * ページ側のコンテキストで実行してコメント取得数を変更する関数。
  51. * @param {number} limit
  52. */
  53. changeLimit(limit)
  54. {
  55. let offset;
  56. fetch = new Proxy(fetch, {
  57. apply(fetch, thisArgument, argumentList)
  58. {
  59. if (!(argumentList[0] instanceof Request)) {
  60. argumentList[0] = new URL(argumentList[0], location);
  61. if (argumentList[0].pathname.endsWith('/comments/roots')) {
  62. const params = argumentList[0].searchParams;
  63. if (Number.parseInt(params.get('offset')) === 0) {
  64. offset = 0;
  65. }
  66. params.set('offset', offset);
  67. params.set('limit', limit);
  68. offset += limit;
  69. }
  70. }
  71. return Reflect.apply(fetch, thisArgument, argumentList);
  72. },
  73. });
  74. }
  75.  
  76. /**
  77. * すべての返信を展開します。
  78. * @access private
  79. */
  80. async expandReplies()
  81. {
  82. const root = document.getElementById('root');
  83. if (!root) {
  84. return;
  85. }
  86.  
  87. new MutationObserver(mutations => {
  88. for (const mutation of mutations) {
  89. if (mutation.target.parentElement.matches('main h2 ~ div:nth-of-type(2) > ul [role="button"] *')) {
  90. // 「以前の返信を見る」の展開
  91. mutation.target.parentElement.closest('[role="button"]').click();
  92. }
  93. }
  94. }).observe(root, {characterData: true, subtree: true});
  95.  
  96. new MutationObserver(mutations => {
  97. for (const mutation of mutations) {
  98. if (!mutation.target.matches('main h2 ~ div:nth-of-type(2)')) {
  99. continue;
  100. }
  101.  
  102. const list = Array.from(mutation.addedNodes).find(node => node.localName === 'ul');
  103. if (list) {
  104. this.watchAndClickButtons(list);
  105. return;
  106. }
  107. }
  108. }).observe(root, {childList: true, subtree: true});
  109. }
  110.  
  111. /**
  112. * 指定された要素の子の追加を監視し、要素内のすべてのボタンを押します。
  113. * @access private
  114. * @param {HTMLUListElement} element
  115. */
  116. watchAndClickButtons(element)
  117. {
  118. this.clickButtons(element);
  119. new MutationObserver(mutations => {
  120. for (const mutation of mutations) {
  121. for (const element of mutation.addedNodes) {
  122. this.clickButtons(element);
  123. }
  124. }
  125. }).observe(element, {childList: true});
  126. }
  127.  
  128. /**
  129. * 指定された要素内のすべてのボタンを押します。
  130. * @access private
  131. * @param {(HTMLUListElement|HTMLLIElement)} element
  132. */
  133. clickButtons(element)
  134. {
  135. for (const button of element.querySelectorAll('[role="button"]')) {
  136. button.click();
  137. }
  138. }
  139. }();

QingJ © 2025

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