cd ..
root@paste:~/kUCxJx_Jy$cat paste
paste://kUCxJx_JyPUBLIC
public paste

kUCxJx_Jy

—1 views18,318 chars19.0 KB

stdout

Paste content

>_javascriptauto-detected
// ==UserScript==
// @name         图集连续看图与广告跳转拦截
// @namespace    local.gallery.reader
// @version      1.0.0
// @description  连续看图、逐张保存整套,并拦截常见广告跳转。
// @match        https://aouq7273oo.gcliuchu7.cyou/*
// @run-at       document-start
// @grant        GM_download
// @grant        GM.download
// @grant        unsafeWindow
// @connect      imgclh.com
// ==/UserScript==

(function () {
  'use strict';
  if (window.top !== window.self) return;
  var origin = location.origin;
  if (location.hostname !== 'aouq7273oo.gcliuchu7.cyou') return;
  var albumPath = location.pathname;
  var albumPage = /^\/detail\/id\/\d+\.html$/.test(albumPath);
  var cache = new Map(), current = null, index = 0, overlay = null, picture = null, info = null;
  var prevButton = null, nextButton = null, entry = null, active = false, loading = false, controller = null, generation = 0, imageFolder = '', basePage = 0;
  var pageWindow=typeof unsafeWindow!=='undefined' && unsafeWindow ? unsafeWindow : window;
  var downloadButton=null,stopButton=null,downloadStatus=null,downloading=false,downloadGeneration=0,downloadController=null,downloadHandle=null,preloadedImage=null;

  function siteUrl(raw, base) {
    try { var url = new URL(raw, base || location.href);return url.protocol === 'https:' && url.origin === origin && !url.username && !url.password ? url : null; }
    catch (_) { return null; }
  }
  function outbound(raw) {
    if (!raw || /^\s*(?:#|mailto:|tel:)/i.test(raw) || /^\s*javascript:\s*(?:void\s*\(\s*0\s*\)\s*;?|;)\s*$/i.test(raw)) return false;
    if (/^\s*javascript:/i.test(raw)) return true;
    try {var u = new URL(raw, location.href);return /^(?:https?:)$/.test(u.protocol) && (u.origin !== origin || /^\/link\/go\/?$/.test(u.pathname));}
    catch (_) {return true;}
  }
  function mediaUrl(raw, base) {
    try {
      var u = new URL(raw, base);
      if (u.protocol !== 'https:' || u.username || u.password || !/^(?:[a-z0-9-]+\.)*imgclh\.com$/i.test(u.hostname) ||
          !/^\/contents\/albums\/sources\/.+\.(?:jpe?g|png|webp|gif)$/i.test(u.pathname)) return null;
      return u.href;
    } catch (_) { return null; }
  }
  function pageNumber(url) {
    var text = url.searchParams.get('page');if (text === null) return 1;
    return /^[1-9]\d{0,4}$/.test(text) ? Number(text) : 0;
  }
  function parsePage(doc, url) {
    if (!siteUrl(url.href) || url.pathname !== albumPath || !pageNumber(url)) throw new Error('图集地址不匹配');
    if (doc.querySelector('input[name="GOEDGE_WAF_CAPTCHA_CODE"], #loginForm')) throw new Error('下一页需要验证或登录');
    var images = Array.from(doc.querySelectorAll('.thumb-item a[href]')).map(function (a) { return mediaUrl(a.getAttribute('href'), url.href); }).filter(Boolean);
    if (!images.length) throw new Error('下一页没有找到可用的图集图片');
    var folder = new URL(images[0]);folder = folder.origin + folder.pathname.slice(0,folder.pathname.lastIndexOf('/') + 1);
    if (!imageFolder) imageFolder=folder;
    if (folder !== imageFolder || images.some(function(src){var img=new URL(src);return img.origin + img.pathname.slice(0,img.pathname.lastIndexOf('/')+1)!==imageFolder;})) throw new Error('图片地址与当前图集不一致');
    var number = pageNumber(url), previous = null, next = null;
    doc.querySelectorAll('.pagination a[href]').forEach(function (a) {
      var candidate = siteUrl(a.getAttribute('href'), url.href);
      if (!candidate || candidate.pathname !== albumPath) return;
      var n = pageNumber(candidate);
      if (n === number - 1) previous = candidate.href;
      if (n === number + 1) next = candidate.href;
    });
    return { number:number, images:images, previous:previous, next:next };
  }
  function createStyle() {
    if (document.getElementById('bm-gallery-style')) return;
    if (!document.head && !document.documentElement) {document.addEventListener('DOMContentLoaded',createStyle,{once:true});return;}
    var style=document.createElement('style');style.id='bm-gallery-style';
    style.textContent='a[href^="/link/go"],.links-grid{display:none!important}' +
      '#bm-gallery-entry{position:fixed;z-index:2147482000;left:12px;top:calc(100vh - 72px);top:calc(100dvh - 72px);border:0;border-radius:25px;padding:12px 18px;background:#266d5d;color:#fff;font:600 15px sans-serif;box-shadow:0 3px 12px #0005;touch-action:manipulation}' +
      '#bm-gallery{position:fixed;top:0;left:0;width:100vw;max-width:100vw;height:100vh;height:100dvh;z-index:2147483647;background:#111;color:#fff;display:flex;flex-direction:column;align-items:center;justify-content:space-between;box-sizing:border-box;font:15px/1.4 sans-serif;padding:env(safe-area-inset-top) 0 env(safe-area-inset-bottom)}' +
      '#bm-gallery[hidden]{display:none!important}#bm-gallery *{box-sizing:border-box}' +
      '#bm-gallery .bm-top{width:100%;display:flex;align-items:center;justify-content:space-between;padding:8px 12px;gap:8px;min-height:52px}' +
      '#bm-gallery .bm-stage{flex:1;min-height:0;width:100%;display:flex;align-items:center;justify-content:center;overflow:auto;touch-action:pan-y}' +
      '#bm-gallery img{display:block;max-width:100%;max-height:100%;object-fit:contain}' +
      '#bm-gallery .bm-controls{width:100%;max-width:100%;min-width:0;display:flex;align-items:center;justify-content:center;gap:8px;padding:10px 8px 16px;flex-wrap:wrap}' +
      '#bm-gallery button{min-height:44px;min-width:72px;border:1px solid #ffffff66;border-radius:10px;background:#2b2b2b;color:#fff;padding:8px 14px;font:15px sans-serif;touch-action:manipulation}' +
      '#bm-gallery button:disabled{opacity:.35}#bm-gallery [data-bm-gallery-status]{font-size:13px;color:#ddd;text-align:center;overflow-wrap:anywhere}';
    (document.head || document.documentElement).appendChild(style);
  }
  createStyle();

  // Block confirmed outbound ad links and the site's own redirect endpoint.
  // Browser-level rules are still needed for redirects not caused by a click or window.open.
  var originalOpen=pageWindow.open;
  try {pageWindow.open=function(url){var destination=url && siteUrl(String(url));if(!destination || /^\/link\/go\/?$/.test(destination.pathname))return null;return originalOpen.apply(pageWindow,arguments);};} catch (_) {}
  function intercept(event) {
    var target=event.target;if (!target || !target.closest) return;
    var a=target.closest('a[href]');if (!a) return;
    if (albumPage && a.closest('.thumb-item') && mediaUrl(a.getAttribute('href'),location.href)) {
      event.preventDefault();event.stopImmediatePropagation();
      if(event.type==='click')openFromAnchor(a);return;
    }
    if (outbound(a.getAttribute('href'))) {event.preventDefault();event.stopImmediatePropagation();}
  }
  document.addEventListener('click',intercept,true);
  document.addEventListener('auxclick',intercept,true);

  function button(text, label, action) {
    var b=document.createElement('button');b.type='button';b.textContent=text;b.setAttribute('aria-label',label);b.addEventListener('click',action);return b;
  }
  function installViewer() {
    if (overlay) return;
    overlay=document.createElement('div');overlay.id='bm-gallery';overlay.hidden=true;overlay.setAttribute('role','dialog');overlay.setAttribute('aria-label','连续看图');overlay.setAttribute('aria-modal','true');
    var top=document.createElement('div');top.className='bm-top';info=document.createElement('span');info.setAttribute('data-bm-gallery-status','');top.appendChild(info);
    top.appendChild(button('关闭','关闭看图',closeViewer));overlay.appendChild(top);
    var stage=document.createElement('div');stage.className='bm-stage';picture=document.createElement('img');picture.alt='图集图片';stage.appendChild(picture);overlay.appendChild(stage);
    var controls=document.createElement('div');controls.className='bm-controls';prevButton=button('上一张','上一张',function(){step(-1);});nextButton=button('下一张','下一张',function(){step(1);});
    controls.appendChild(prevButton);controls.appendChild(nextButton);
    downloadButton=button('保存整套','逐张保存整套图片',startDownload);stopButton=button('停止保存','停止保存图片',stopDownload);stopButton.disabled=true;
    controls.appendChild(downloadButton);controls.appendChild(stopButton);overlay.appendChild(controls);
    downloadStatus=document.createElement('div');downloadStatus.setAttribute('data-bm-gallery-download-status','');downloadStatus.style.cssText='font-size:12px;color:#ddd;text-align:center;padding:0 12px 6px;';overlay.appendChild(downloadStatus);document.body.appendChild(overlay);
    picture.addEventListener('error',function(){if(active)info.textContent='图片加载失败,可尝试下一张或检查网络。';});
    var start=null;stage.addEventListener('touchstart',function(e){if(e.touches.length===1)start={x:e.touches[0].clientX,y:e.touches[0].clientY};},{passive:true});
    stage.addEventListener('touchend',function(e){if(!start || e.changedTouches.length!==1)return;var dx=e.changedTouches[0].clientX-start.x,dy=e.changedTouches[0].clientY-start.y;start=null;if(Math.abs(dx)>65&&Math.abs(dx)>Math.abs(dy)*1.5)step(dx<0?1:-1);},{passive:true});
  }
  function paint() {
    if (!active || !current) return;
    picture.src=current.images[index];info.textContent='网页 '+current.number+' · 本页 '+(index+1)+' / '+current.images.length;
    if(index+1<current.images.length){preloadedImage=new Image();preloadedImage.src=current.images[index+1];}else preloadedImage=null;
    prevButton.disabled=loading || (index===0 && !current.previous);
    nextButton.disabled=loading || (index===current.images.length-1 && !current.next);
  }
  var oldOverflow='';
  function openViewer(start) {
    if (!current || !current.images.length) return;
    installViewer();index=Math.max(0,Math.min(start,current.images.length-1));
    if (!active) oldOverflow=document.body.style.overflow;
    active=true;overlay.hidden=false;document.body.style.overflow='hidden';paint();
  }
  function closeViewer() {
    generation++;active=false;loading=false;if(controller){controller.abort();controller=null;}
    if(overlay)overlay.hidden=true;if(picture)picture.removeAttribute('src');document.body.style.overflow=oldOverflow;
    if(cache.has(basePage))current=cache.get(basePage);
  }
  function openFromAnchor(anchor) {
    var url=mediaUrl(anchor.getAttribute('href'),location.href);if(!url || !current)return;
    var at=current.images.indexOf(url);if(at>=0)openViewer(at);
  }
  async function loadPage(raw, previousPage, token) {
    var url=siteUrl(raw);if(!url || url.pathname!==albumPath)throw new Error('下一页地址不属于当前图集');
    var wanted=pageNumber(url);if(!wanted || Math.abs(wanted-previousPage.number)!==1)throw new Error('分页顺序异常');
    if(cache.has(wanted))return cache.get(wanted);
    var requestController=new AbortController();controller=requestController;var timeout=setTimeout(function(){requestController.abort();},15000);
    try {
      var response=await fetch(url.href,{credentials:'same-origin',redirect:'manual',signal:requestController.signal});
      if(!response.ok || response.type==='opaqueredirect')throw new Error('网页加载失败,可能需要登录或验证');
      var final=siteUrl(response.url || url.href);if(!final || final.pathname!==albumPath || pageNumber(final)!==wanted)throw new Error('网站返回了其他页面');
      var contentType=response.headers.get('content-type') || '';if(contentType && !/text\/html|application\/xhtml\+xml/i.test(contentType))throw new Error('网站返回的不是图集网页');
      var html=await response.text();if(!active || generation!==token)throw new Error('已关闭');
      var doc=new DOMParser().parseFromString(html,'text/html'),page=parsePage(doc,final);
      if(page.images.length===previousPage.images.length && page.images.every(function(v,i){return v===previousPage.images[i];}))throw new Error('下一页与当前页重复,已停止翻页');
      cache.set(wanted,page);return page;
    } finally {clearTimeout(timeout);if(controller===requestController)controller=null;}
  }
  async function step(direction) {
    if (!active || loading || !current) return;
    var n=index+direction;if(n>=0 && n<current.images.length){index=n;paint();return;}
    var url=direction>0?current.next:current.previous;if(!url){info.textContent=direction>0?'已经是最后一张。':'已经是第一张。';return;}
    var previous=current,token=generation;loading=true;prevButton.disabled=nextButton.disabled=true;info.textContent='正在加载'+(direction>0?'下一':'上一')+'网页…';
    try {var page=await loadPage(url,previous,token);if(!active || generation!==token)return;current=page;index=direction>0?0:page.images.length-1;}
    catch(error){if(active && generation===token)info.textContent=error.name==='AbortError'?'网页加载超时,请重试。':(error.message || '网页加载失败,请重试。');return;}
    finally {if(active && generation===token){loading=false;prevButton.disabled=index===0&&!current.previous;nextButton.disabled=index===current.images.length-1&&!current.next;}}
    paint();
  }
  function downloadApi() {
    if(typeof GM_download==='function')return function(options){return GM_download(options);};
    if(typeof GM!=='undefined' && GM && typeof GM.download==='function')return function(options){return GM.download(options);};
    return null;
  }
  function updateDownload(message) {
    if(downloadStatus)downloadStatus.textContent=message;
    if(downloadButton)downloadButton.disabled=downloading;
    if(stopButton)stopButton.disabled=!downloading;
    if(entry)entry.textContent=downloading?'保存中 · 看图':'开始看图';
  }
  function stopDownload() {
    downloadGeneration++;downloading=false;
    if(downloadController){try{downloadController.abort();}catch(_){}downloadController=null;}
    if(downloadHandle && typeof downloadHandle.abort==='function'){try{downloadHandle.abort();}catch(_){}}downloadHandle=null;
    updateDownload('已停止后续保存;已保存的图片保留。');
  }
  async function downloadPage(raw, from, token) {
    var url=siteUrl(raw);if(!url || url.pathname!==albumPath || Math.abs(pageNumber(url)-from.number)!==1)throw new Error('分页地址不属于当前图集');
    var wanted=pageNumber(url);if(cache.has(wanted))return cache.get(wanted);
    var own=new AbortController();downloadController=own;var timer=setTimeout(function(){own.abort();},15000);
    try {
      var response=await fetch(url.href,{credentials:'same-origin',redirect:'manual',signal:own.signal});
      if(!response.ok || response.type==='opaqueredirect')throw new Error('网页加载失败,可能需要登录或验证');
      var final=siteUrl(response.url || url.href);if(!final || final.pathname!==albumPath || pageNumber(final)!==wanted)throw new Error('网站返回了其他页面');
      var type=response.headers.get('content-type')||'';if(type&&!/text\/html|application\/xhtml\+xml/i.test(type))throw new Error('网站返回的不是图集网页');
      var body=await response.text();if(!downloading || token!==downloadGeneration)throw new Error('已停止');
      var page=parsePage(new DOMParser().parseFromString(body,'text/html'),final);
      if(page.images.length===from.images.length&&page.images.every(function(v,i){return v===from.images[i];}))throw new Error('相邻网页图片重复,已停止');
      cache.set(wanted,page);return page;
    } finally {clearTimeout(timer);if(downloadController===own)downloadController=null;}
  }
  function downloadOne(api,src,name,tag,token) {
    return new Promise(function(resolve,reject){
      var settled=false,timer=setTimeout(function(){finish(new Error('下载器没有返回结果,请检查浏览器下载设置。'));},30000);
      function finish(error){if(settled)return;settled=true;clearTimeout(timer);if(token===downloadGeneration)downloadHandle=null;if(error)reject(error);else resolve();}
      try {
        var handle=api({url:src,name:name,tag:tag,headers:{Referer:origin+'/'},onload:function(){if(token===downloadGeneration&&downloading)finish();else finish(new Error('已停止'));},onerror:function(){finish(new Error('图片保存失败,请检查网络或下载权限。'));},ontimeout:function(){finish(new Error('图片保存超时。'));}});
        downloadHandle=handle;if(handle&&typeof handle.then==='function')handle.then(function(){if(token===downloadGeneration&&downloading)finish();},function(){finish(new Error('图片保存失败,请检查网络或下载权限。'));});
      } catch(_){finish(new Error('浏览器下载接口调用失败。'));}
    });
  }
  async function startDownload() {
    if(downloading || !current)return;
    var api=downloadApi();if(!api){updateDownload('当前脚本环境没有下载接口;可长按当前图片保存。');return;}
    downloading=true;var token=++downloadGeneration,page=current,count=0,seen=new Set(),album=(albumPath.match(/\/id\/(\d+)/)||[])[1] || 'images',tag='图集_'+album;
    updateDownload('正在准备整套图片;请保持此网页打开。');
    try {
      while(page.number>1){if(!page.previous)throw new Error('找不到第一页,已停止。');page=await downloadPage(page.previous,page,token);if(!downloading||token!==downloadGeneration)return;}
      while(page){
        if(seen.has(page.number)||seen.size>=1000)throw new Error('分页重复或超过上限,已停止。');seen.add(page.number);
        for(var i=0;i<page.images.length;i++){
          if(!downloading||token!==downloadGeneration)return;
          var path=new URL(page.images[i]).pathname,ext=(path.match(/\.(jpe?g|png|webp|gif)$/i)||[])[1]||'jpg';
          updateDownload('正在保存第 '+(count+1)+' 张 · 网页 '+page.number+',请保持此网页打开。');
          await downloadOne(api,page.images[i],album+'-'+String(page.number).padStart(3,'0')+'-'+String(i+1).padStart(3,'0')+'.'+ext,tag,token);
          if(!downloading||token!==downloadGeneration)return;count++;
        }
        page=page.next?await downloadPage(page.next,page,token):null;
      }
      if(downloading&&token===downloadGeneration){downloading=false;updateDownload('已收到 '+count+' 张图片的下载完成回调,请在浏览器下载目录查看。');}
    } catch(error){if(downloading&&token===downloadGeneration){downloading=false;updateDownload((error.name==='AbortError'?'网页加载超时。':error.message||'保存失败。')+' 已完成 '+count+' 张。');}}
  }
  function start() {
    createStyle();if(!albumPage)return;
    try {var url=new URL(location.href);current=parsePage(document,url);basePage=current.number;cache.set(current.number,current);}catch(_){return;}
    entry=button('开始看图','从本页第一张开始看图',function(){openViewer(0);});entry.id='bm-gallery-entry';document.body.appendChild(entry);
  }
  document.addEventListener('keydown',function(e){if(!active)return;if(e.key==='Escape'){e.preventDefault();closeViewer();}else if(e.key==='ArrowRight'){e.preventDefault();step(1);}else if(e.key==='ArrowLeft'){e.preventDefault();step(-1);}},true);
  window.addEventListener('pagehide',function(){if(active)closeViewer();if(downloading)stopDownload();});
  if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',start,{once:true});else start();
})();

$ tail -f comments.log

Comments [0]

// no comments yet