jsdelivr-auto-fallback
                                
                                 jsdelivr-auto-fallback copied to clipboard
                                
                                    jsdelivr-auto-fallback copied to clipboard
                            
                            
                            
                        The userscript won't work on firefox with greasemonkey.
Due to how firefox handle document-start,the test facility of the script won't work. See https://github.com/greasemonkey/greasemonkey/issues/2515
Here my own modified one that currently works.
// ==UserScript==
// @name Jsdelivr Auto Fallback
// @namespace https://github.com/PipecraftNet/jsdelivr-auto-fallback
// @version 0.2.2
// @author PipecraftNet&DreamOfIce
// @description 修复 cdn.jsdelivr.net 无法访问的问题
// @homepage https://github.com/PipecraftNet/jsdelivr-auto-fallback
// @supportURL https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues
// @license MIT
// @match *://*/*
// @run-at document-start
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
function act() {
  'use strict';
  let fastNode;
  let failed;
  let isRunning;
  const DEST_LIST = [
    'cdn.jsdelivr.net',
    'unpkg.com',
    'testingcf.jsdelivr.net',
    'test1.jsdelivr.net',
    'fastly.jsdelivr.net',
    'gcore.jsdelivr.net',
  ];
  const PREFIX = '//';
  const SOURCE = DEST_LIST[0];
  const starTime = Date.now();
  const TIMEOUT = 800;
  const STORE_KEY = 'jsdelivr-auto-fallback';
  const TEST_PATH = '/[email protected]/object.js?';
  const shouldReplace = (text) => text && text.includes(PREFIX + SOURCE);
  const replace = (text) => text.replace(PREFIX + SOURCE, PREFIX + fastNode);
  const setTimeout = window.setTimeout;
  const $ = document.querySelectorAll.bind(document);
  const replaceElementSrc = () => {
    let element;
    let value;
    for (element of $('link[rel="stylesheet"]')) {
      value = element.href;
      if (shouldReplace(value) && !value.includes(TEST_PATH)) {
        element.href = replace(value);
      }
    }
    for (element of $('script')) {
      value = element.src;
      if (shouldReplace(value)) {
        const newNode = document.createElement('script');
        newNode.src = replace(value);
        element.defer = true;
        element.src = '';
        element.before(newNode);
        element.remove();
      }
    }
    for (element of $('img')) {
      value = element.src;
      if (shouldReplace(value)) {
        // Used to cancel loading. Without this line it will remain pending status.
        element.src = '';
        element.src = replace(value);
      }
    }
    // All elements that have a style attribute
    for (element of $('*[style]')) {
      value = element.getAttribute('style');
      if (shouldReplace(value)) {
        element.setAttribute('style', replace(value));
      }
    }
    for (element of $('style')) {
      value = element.innerHTML;
      if (shouldReplace(value)) {
        element.innerHTML = replace(value);
      }
    }
  };
  const tryReplace = () => {
    if (!isRunning && failed && fastNode) {
      console.warn(SOURCE + ' is not available. Use ' + fastNode);
      isRunning = true;
      setTimeout(replaceElementSrc, 0);
      // Some need to wait for a while
      setTimeout(replaceElementSrc, 20);
      // Replace dynamically added elements
      setInterval(replaceElementSrc, 500);
    }else{
      console.log("Use original target.");
    }
  };
  const checkAvailable = (url, callback) => {
    let timeoutId;
    const newNode = document.createElement('link');
    const handleResult = (isSuccess) => {
      if (!timeoutId) {
        return;
      }
      clearTimeout(timeoutId);
      timeoutId = 0;
      // Used to cancel loading. Without this line it will remain pending status.
      if (!isSuccess) newNode.href = 'data:text/plain;base64,';
      newNode.remove();
      callback(isSuccess);
      console.log(url + " is Ok..");
    };
    timeoutId = setTimeout(handleResult, TIMEOUT);
    newNode.addEventListener('error', () => handleResult(false));
    newNode.addEventListener('load', () => handleResult(true));
    newNode.rel = 'prefetch';
    newNode.text = 'text/javascript';
    newNode.href = url + TEST_PATH + starTime;
    console.log("Testing .. " + url);
    if(document.head !== null) {
    document.head.insertAdjacentElement('afterbegin', newNode);
    }else{
      console.log("DOM not fully ready!");
    }
  };
  const cached = (() => {
    try {
      // eslint-disable-next-line new-cap
      return Object.assign({}, GM_getValue(STORE_KEY));
    } catch {
      return {};
    }
  })();
  const main = () => {
    cached.time = starTime;
    cached.failed = false;
    cached.fastNode = null;
    for (const url of DEST_LIST) {
      checkAvailable('https://' + url, (isAvailable) => {
        // console.log(url, Date.now() - starTime, Boolean(isAvailable));
        if (!isAvailable && url === SOURCE) {
          failed = true;
          cached.failed = true;
        }
        if (isAvailable && !fastNode) {
          fastNode = url;
        }
        if (isAvailable && !cached.fastNode) {
          cached.fastNode = url;
        }
        tryReplace();
      });
    }
    setTimeout(() => {
      // If all domains are timeout
      if (failed && !fastNode) {
        fastNode = DEST_LIST[1];
        tryReplace();
      }
      // eslint-disable-next-line new-cap
      GM_setValue(STORE_KEY, cached);
    }, TIMEOUT + 200);
  };
  if (
    cached.time &&
    starTime - cached.time < 60 * 60 * 1000 &&
    cached.failed &&
    cached.fastNode
  ) {
    failed = true;
    fastNode = cached.fastNode;
    tryReplace();
    setTimeout(main, 1000);
  } else {
    main();
  }
}
const observer = new MutationObserver(() => {
  if(document.head !== null) {
    observer.disconnect();
    act();
    console.log("Head is OK now");
  }
});
const observerOptions = {
  childList: true,
  subtree: true,
};
observer.observe(document,observerOptions);
感谢提供信息,已修改代码,使用 MutationObserver 检查 head 是否存在。
上面代码中 TEST_PATH 修改的部分因为没有时间验证,本次版本先不打算修改。
如有其他问题欢迎反馈。
@DreamOfIce 还请麻烦你在 greasyfork 更新一下脚本。 或者在 greasyfork 中添加一下我 (https://greasyfork.org/zh-CN/users/1030884-pipecraft) 为脚本作者。
谢谢。
感谢提供信息,已修改代码,使用
MutationObserver检查head是否存在。上面代码中
TEST_PATH修改的部分因为没有时间验证,本次版本先不打算修改。如有其他问题欢迎反馈。
@DreamOfIce 还请麻烦你在 greasyfork 更新一下脚本。 或者在 greasyfork 中添加一下我 (https://greasyfork.org/zh-CN/users/1030884-pipecraft) 为脚本作者。
谢谢。
GreasyFork邀请发了
GreasyFork邀请发了
谢谢,已更新脚本代码。
@PipecraftNet Your url test method may not work under firefox
GET
https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689433198847
样式表单 data:text/plain;base64, 未加载,因为它的 MIME 类型 "text/plain" 不是 "text/css"。 [uupdump.net](https://uupdump.net/)
来自“https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689433198847”的资源已被阻止,因为 MIME 类型(“text/plain”)不匹配(X-Content-Type-Options: nosniff)。
[uupdump.net](https://uupdump.net/)
样式表单 data:text/plain;base64, 未加载,因为它的 MIME 类型 "text/plain" 不是 "text/css"。
I haven't investigate if it works or not yet. Howver I think you should consider this broken on firefox since unlike chrome, the little cuty fox won't give you a chance on this.
https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689433198847
It seems that it's my mistake, this URL returns: Invalid URL. The URL structure is /gh/user/repo@version/file.js instead of null css.
I will check the reason later.
@PipecraftNet
Your url test method may not work under firefox
GET https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689433198847 样式表单 data:text/plain;base64, 未加载,因为它的 MIME 类型 "text/plain" 不是 "text/css"。 [uupdump.net](https://uupdump.net/) 来自“https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689433198847”的资源已被阻止,因为 MIME 类型(“text/plain”)不匹配(X-Content-Type-Options: nosniff)。 [uupdump.net](https://uupdump.net/) 样式表单 data:text/plain;base64, 未加载,因为它的 MIME 类型 "text/plain" 不是 "text/css"。I haven't investigate if it works or not yet. Howver I think you should consider this broken on firefox since unlike chrome, the little cuty fox won't give you a chance on this.
The problem should have been solved, can you try again?
Here are the reasons for the error:
In order to optimize the user experience, I introduced CacheFly CDN a few weeks ago and after a brief test used it as the main CDN in the direction of China Telecom.
At that time, I did not test URIs with special characters, so I did not find that CacheFly automatically encodes URIs, and jsdelivr could not recognize the @ that was converted to %40.
I've used njs to decode all request URIs, if there are any other issues, feel free to ask!
Now firefox is giving you headaches.
Content-Security-Policy:页面设置阻止读取位于 https://cdn.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://unpkg.com/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://fastly.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://gcore.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://testingcf.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://test1.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 data:text/plain;base64, 的一项资源("style-src")。
不愧是小狐狸
Now firefox is giving you headaches.
Content-Security-Policy:页面设置阻止读取位于 https://cdn.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://unpkg.com/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://fastly.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://gcore.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://testingcf.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://test1.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 data:text/plain;base64, 的一项资源("style-src")。不愧是小狐狸
Consider trying with unsafeWindow or override CSP with some magic.
Now firefox is giving you headaches.
Content-Security-Policy:页面设置阻止读取位于 https://cdn.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://unpkg.com/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://fastly.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://gcore.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://cdn.zenless.top/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://testingcf.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 https://test1.jsdelivr.net/gh/PipecraftNet/jsdelivr-auto-fallback@main/empty.css?1689519508980 的一项资源("style-src")。 [8:122:18](https://github.com/PipecraftNet/jsdelivr-auto-fallback/issues/8?notification_referrer_id=NT_kwDOAPveaLM3MDAyNTUxMTk0OjE2NTA2NDcy#issuecomment-1636996229%20line%201%20%3E%20injectedScript) Content-Security-Policy:页面设置阻止读取位于 data:text/plain;base64, 的一项资源("style-src")。不愧是小狐狸Consider trying with unsafeWindow or override CSP with some magic.
Or consider using API provided by userscript manager like "GM_addElement" See https://violentmonkey.github.io/api/gm/#gm_addelement https://www.tampermonkey.net/documentation.php#api:GM_addElement for more information
佛
Or consider using API provided by userscript manager like "GM_addElement" See https://violentmonkey.github.io/api/gm/#gm_addelement https://www.tampermonkey.net/documentation.php#api:GM_addElement for more information
这个脚本对 CSP 严格的网站无能为力,所以一开始就放弃支持这些网站了。
刚刚尝试了使用 “GM_addElement” 添加元素。用它确实可以成功添加元素,但是当改变 script, style, img 元素的 href 或 src 属性值时,依然会报 CSP 错误。
“GM_addElement” 至少有些帮助,所以用上它发布了 0.2.4 版本。
还有,Greasemonkey 不支持 “GM_addElement” API。
Or consider using API provided by userscript manager like "GM_addElement" See https://violentmonkey.github.io/api/gm/#gm_addelement https://www.tampermonkey.net/documentation.php#api:GM_addElement for more information
这个脚本对 CSP 严格的网站无能为力,所以一开始就放弃支持这些网站了。
刚刚尝试了使用 “GM_addElement” 添加元素。用它确实可以成功添加元素,但是当改变 script, style, img 元素的 href 或 src 属性值时,依然会报 CSP 错误。
“GM_addElement” 至少有些帮助,所以用上它发布了 0.2.4 版本。
还有,Greasemonkey 不支持 “GM_addElement” API。
那还挺恐怖的😂
实际上我用的是violentmonkey🌚