* AutoPagerize LazyLoad Assistant

修复某些 AutoPagerize 脚本、扩展和附加中出现的第二页或更高版本的延迟加载图像问题。

  1. // ==UserScript==
  2. // @name * AutoPagerize LazyLoad Assistant
  3. // @name:ja * AutoPagerize LazyLoad Assistant
  4. // @name:zh-CN * AutoPagerize LazyLoad Assistant
  5. // @namespace knoa.jp
  6. // @description It fixes the lazy load image problem of some AutoPagerize scripts, extensions or add-ons, occuring on second or latter pages.
  7. // @description:ja 一部の AutoPagerize スクリプト、拡張機能、アドオンで発生する、2ページ目以降の遅延読み込み画像の問題を修正します。
  8. // @description:zh-CN 修复某些 AutoPagerize 脚本、扩展和附加中出现的第二页或更高版本的延迟加载图像问题。
  9. // @include *
  10. // @version 2.0.0
  11. // @grant GM.xmlHttpRequest
  12. // ==/UserScript==
  13.  
  14. /*
  15. [update]
  16. 2025-05-18 2.0.0 サイト指定制御対応(togetter/posfie対応)
  17. */
  18. (function() {
  19. const SCRIPTID = 'AutoPagerizeLazyLoadAssistant';
  20. const FLAGNAME = 'lazyLoadAssistant';
  21. const DATASETS = [
  22. 'src',
  23. 'lazySrc',
  24. 'original',
  25. 'delay',
  26. 'img',
  27. ];
  28. const CALLBACKS = {
  29. id: async () => {},
  30. togetter: async () => {
  31. // togetter/posfie は img の data-s 属性の数字が head 内 script 要素の usedImages 配列に対応する。
  32. // 画像ギャラリー表示の際には https://togetter.com/api/getImageList にPOSTを投げて全画像を取得しているようだが活用しづらいしプロフィールアイコンなども含まれない。
  33. // autopazerizeはスクリプトに対して2ページ目以降のdocumentを取得させてくれないので、独自に取得しに行くしかない。
  34. console.log(SCRIPTID, 'callback: togetter');
  35. const as = document.querySelectorAll('a.autopagerize_link[href]');
  36. if(as.length === 0) return console.log(SCRIPTID, 'autopagerize_link not found.');
  37. const a = Array.from(as).at(-1);
  38. const r = await GM.xmlHttpRequest({url: a.href}).catch(e => console.error(SCRIPTID, e));
  39. const scripts = r.responseXML.querySelectorAll('head > script[type="text/javascript"]:not([src])'); //usedImages配列見込みを絞っているがセレクタとしては脆い。
  40. if(scripts.length === 0) return console.log(SCRIPTID, 'script not found.');
  41. const script = Array.from(scripts).find(s => s.textContent.includes(' usedImages = ')); //判定としてはやや弱い
  42. if(script === undefined) return console.log(SCRIPTID, 'usedImages not found.');
  43. const srcs = script.textContent.match(/"[^"]+?"/g).map(s => s.slice(1, -1).replace(/\\/g, '').replace(/^p/, 'https://pbs.twimg.com/profile_images/')); //profileはサイト解析で確認した処理。
  44. const imgs = document.querySelectorAll('hr.autopagerize_page_separator ~ * img[data-s]'); //対象となる2ページ目以降をシンプルに取得してあとから適用済みを除外する
  45. imgs.forEach(img => {
  46. if(img.dataset[FLAGNAME]) return; //本スクリプトが適用済
  47. if(img.dataset.s.startsWith('https:')) img.dataset.src = img.dataset.s;//動画サムネの場合はdata.sにURLが直接入っている
  48. else img.dataset.src = srcs[parseInt(img.dataset.s)];//通常はdata.sに数字のみが入っている
  49. //※実際のimg.srcに入れるのは後の共通処理で
  50. });
  51. },
  52. };
  53. const SITES = {
  54. 'host': CALLBACKS.id,
  55. 'togetter.com': CALLBACKS.togetter,
  56. 'posfie.com': CALLBACKS.togetter,
  57. };
  58. let dataset = undefined; //サイトで使われている lazyload dataset名。一度確定したら変わらない。
  59. let callback = SITES[location.host]; //サイト指定制御が存在していれば。
  60. document.addEventListener('GM_AutoPagerizeNextPageLoaded', async e => {
  61. console.log(SCRIPTID, 'event:', e.type);
  62. if(callback) await callback();
  63. const imgs = document.querySelectorAll('img'); //ここで FLAGNAME 付きを除外する処理は重いのでシンプルに全取得する
  64. for(let i = 0; imgs[i]; i++){
  65. // 画像srcが入ったdataset名を判定する
  66. if(dataset === undefined){
  67. dataset = DATASETS.find(n => imgs[i].dataset[n]);
  68. if(dataset) console.log(SCRIPTID, 'dataset:', dataset);
  69. else continue;
  70. }
  71. // 処理済ならスキップ
  72. if(imgs[i].dataset[FLAGNAME]) continue;
  73. // 画像src処理
  74. if(imgs[i].dataset[dataset]){
  75. imgs[i].src = imgs[i].dataset[dataset];
  76. imgs[i].style.opacity = 1; //一部のサイトに必要
  77. imgs[i].style.visibility = 'visible'; //一部のサイトに必要
  78. imgs[i].dataset[FLAGNAME] = 'true';
  79. }
  80. }
  81. });
  82. })();