有没有可能使用cf反代new站并注入油猴脚本

现在oaifree被大削,几乎没法用了
在站里找到了这些油猴来辅助使用,不知道能不能直接反代注入页面里
一个脚本解决 oaifree 点击发送按钮卡顿问题 - 开发调优 / 开发调优, Lv2 - LINUX DO

6 个赞

如果我没猜错,@pengzhile 马老师已经在写了把 :tieba_087:

4 个赞

@pengzhile 马老师加油 :joy:

1 个赞

这个挺简单的啊,就是把 js 直接注入就行了。我其实昨天就已经实现了,下面是我整合了一下常用的脚本。env 中添加 REDIRECT_URL 环境变量,作为跳转登录的自定义域名。

const PROXY_HOST = 'new.oaifree.com';

// 注入的脚本
const INJECT_SCRIPT = `
(function(){
    'use strict';
    // 脚本1:解除模型切换限制
    (function(){
        const classesToRemove = ['pointer-events-none', 'text-token-text-quaternary'];
        function processSpan(span){
          if(span.getAttribute('data-state') !== 'closed') return;
          const firstDiv = span.querySelector('div');
          if(!firstDiv) return;
          let classChanged = false;
          classesToRemove.forEach(cls => {
            if(firstDiv.classList.contains(cls)){
              firstDiv.classList.remove(cls);
              classChanged = true;
            }
          });
          if(classChanged){
            unwrapElement(span);
          }
        }

        function unwrapElement(element){
          const parent = element.parentNode;
          if(!parent) return;
          while(element.firstChild){
            parent.insertBefore(element.firstChild, element);
          }
          parent.removeChild(element);
        }

        function processExistingSpans(){
          const spans = document.querySelectorAll('span[data-state="closed"]');
          spans.forEach(span => {
            processSpan(span);
          });
        }

        function setupMutationObserver(){
          const observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
              mutation.addedNodes.forEach(node => {
                if(node.nodeType !== Node.ELEMENT_NODE) return;
                if(node.matches && node.matches('span[data-state="closed"]')){
                  processSpan(node);
                }
                const spans = node.querySelectorAll && node.querySelectorAll('span[data-state="closed"]');
                if(spans && spans.length > 0){
                  spans.forEach(span => processSpan(span));
                }
              });
              if(mutation.type === 'attributes' && mutation.target.matches('span[data-state="closed"]')){
                processSpan(mutation.target);
              }
            });
          });
          observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-state'] });
        }

        function init(){
          processExistingSpans();
          setupMutationObserver();
        }

        if(document.readyState === 'loading'){
          document.addEventListener('DOMContentLoaded', init);
        } else {
          init();
        }
    })();

    // 脚本2:自动发送图片到ChatGPT
    (function() {
      'use strict';
    
      // 图片URL
      const imageUrl = "https://image.lolimi.cn/2024/11/15/673738bd893d1.webp";
      let autoSendEnabled = localStorage.getItem('autoSendEnabled') === 'true';
      let imageSent = false; // 用于标记图片是否已发送
    
      // 创建样式元素并添加到文档头部
      const style = document.createElement('style');
      style.textContent = \`
          .control-button {
              position: fixed;
              border-radius: 50%;
              border: 2px solid #ccc;
              cursor: pointer;
              z-index: 9999;
              display: flex;
              align-items: center;
              justify-content: center;
              transition: all 0.3s ease;
              background-color: #ccc;
              border-color: #ccc;
              opacity: 0.3;
              top: 12px;
              right: 70px;
              width: 30px;
              height: 30px;
          }
          .control-button .inner-circle {
              border-radius: 50%;
              background-color: #999;
              width: 20px;
              height: 20px;
              transition: all 0.3s ease;
          }
          .control-button.active {
              background-color: rgba(255, 255, 0, 0.7);
              border-color: #FFD700;
              opacity: 1;
          }
          .control-button.active .inner-circle {
              background-color: #FFD700;
          }
          .control-button:hover {
              opacity: 1;
          }
          /* 手机端样式 */
          @media (max-width: 768px) {
              .control-button {
                  width: 25px;
                  height: 25px;
                  top: 16.5px;
                  right: 80px;
              }
              .control-button .inner-circle {
                  width: 18px;
                  height: 18px;
              }
          }
          .tooltip {
              position: fixed;
              padding: 10px 20px;
              background-color: rgba(0, 0, 0, 0.7);
              color: #fff;
              border-radius: 5px;
              font-size: 14px;
              z-index: 10000;
              transition: opacity 0.3s ease;
              opacity: 0;
          }
      \`;
      document.head.appendChild(style);
    
      // 创建控制按钮
      const controlButton = document.createElement('div');
      controlButton.classList.add('control-button');
    
      const innerCircle = document.createElement('div');
      innerCircle.classList.add('inner-circle');
    
      controlButton.appendChild(innerCircle);
      document.body.appendChild(controlButton);
    
      // 提示信息
      controlButton.title = '点击切换自动发送图片功能';
    
      // 点击事件
      controlButton.addEventListener('click', (e) => {
          autoSendEnabled = !autoSendEnabled;
          localStorage.setItem('autoSendEnabled', autoSendEnabled);
          updateButtonState();
          showTooltip(e.clientX, e.clientY);
      });
    
      function updateButtonState() {
          if (autoSendEnabled) {
              controlButton.classList.add('active');
          } else {
              controlButton.classList.remove('active');
          }
      }
    
      // 显示提示弹窗
      function showTooltip(x, y) {
          const tooltip = document.createElement('div');
          tooltip.classList.add('tooltip');
          tooltip.style.top = \`\${y + 20}px\`;
          tooltip.style.left = \`\${x - 180}px\`;
    
          tooltip.innerText = autoSendEnabled
              ? '您已开启自动发送图片防降智,当使用ChatGPT对话时,脚本会在gpt-4o模型对话前发送一张图片,稍等片刻然后您可以切换到其他模型'
              : '您已关闭自动发送图片';
    
          document.body.appendChild(tooltip);
    
          // 过渡效果
          setTimeout(() => {
              tooltip.style.opacity = '1';
          }, 0);
    
          // 自动消失
          setTimeout(() => {
              tooltip.style.opacity = '0';
              setTimeout(() => {
                  if (tooltip.parentNode) {
                      tooltip.parentNode.removeChild(tooltip);
                  }
              }, 300);
          }, 2000);
      }
    
      // 检查聊天界面并发送图片
      function checkChatReady() {
          if (!autoSendEnabled || imageSent) return; // 添加了对 imageSent 的检查
          const chatInput = document.querySelector('#prompt-textarea');
          const chatContainer = document.querySelector('main');
    
          if (chatInput && chatContainer) {
              sendImage(chatInput);
          } else {
              setTimeout(checkChatReady, 1000);
          }
      }
    
      // 发送图片
      function sendImage(chatInput) {
          imageSent = true; // 确保图片只发送一次
          fetch(imageUrl)
              .then(response => response.blob())
              .then(blob => {
                  const file = new File([blob], "image.png", { type: blob.type });
                  const dataTransfer = new DataTransfer();
                  dataTransfer.items.add(file);
    
                  const event = new DragEvent('drop', {
                      bubbles: true,
                      cancelable: true,
                      dataTransfer: dataTransfer
                  });
    
                  chatInput.dispatchEvent(event);
    
                  // 尝试点击发送按钮
                  let attempts = 0;
                  const maxAttempts = 10;
    
                  const tryClickSend = () => {
                      const sendButton = findSendButton();
                      if (sendButton && !sendButton.disabled) {
                          sendButton.click();
                      } else if (attempts < maxAttempts) {
                          attempts++;
                          setTimeout(tryClickSend, 1000);
                      }
                  };
    
                  setTimeout(tryClickSend, 2000);
              })
              .catch(error => {
                  console.error('图片下载失败:', error);
              });
      }
    
      // 查找发送按钮
      function findSendButton() {
          const possibleSelectors = [
              'button[data-testid="send-button"]',
              'form button[type="submit"]',
              'button.absolute.p-1.rounded-md',
              'button[aria-label="Send message"]',
              'main form button:last-child'
          ];
    
          for (let selector of possibleSelectors) {
              const button = document.querySelector(selector);
              if (button) {
                  return button;
              }
          }
          return null;
      }
    
      // 初始化按钮状态
      updateButtonState();
    
      // 页面加载后检查
      window.addEventListener('load', () => {
          if (autoSendEnabled) {
              setTimeout(checkChatReady, 3000);
          }
      });
    })();
    

    // 脚本3:保存markdown和html
    (function() {
      'use strict';
      window.addEventListener('load', () => {
        createExportButton();
        setInterval(() => {
          if (!document.getElementById('export-chat')) {
              createExportButton();
          }
        }, 1000);
      });
      function createExportButton() {
          const exportButton = document.createElement('button');
          exportButton.id = 'export-chat';
          function updateButtonText() {
            if (window.innerWidth <= 768) {
              exportButton.textContent = '导';
            } else {
              exportButton.textContent = '导出聊天';
            }
          }
          window.addEventListener('resize', updateButtonText);
          updateButtonText();
          const style = document.createElement('style');
          style.textContent = \`
            #export-chat {
              position: fixed;
              height: 36px;
              bottom: 80px;
              right: 15px;
              z-index: 10000;
              padding: 10px;
              background-color: #4cafa3;
              color: white;
              border: none;
              border-radius: 5px;
              cursor: pointer;
              text-align: center;
              line-height: 16px;
              box-shadow: 0 2px 6px rgba(0,0,0,0.3);
            }
            #export-options {
              position: fixed;
              bottom: 70px;
              right: 100px;
              backgroundColor: #fff;
              border: 1px solid #ccc;
              borderRadius: 5px;
              boxShadow: 0 2px 6px rgba(0,0,0,0.3);
              padding: 10px;
              zIndex: 1000;
            }
            @media (max-width: 768px) {
              #export-chat {
                width: 25px;
                height: 25px;
                right: 14%;
                padding: 0;
                font-size: 10px;
                line-height: 25px;
                text-align: center;
                border-radius: 50%;
                top: 16px;
              }
              #export-options {
                position: fixed;
                top: 50px;
                right: 8%;
                backgroundColor: #fff;
                border: 1px solid #ccc;
                borderRadius: 5px;
                boxShadow: 0 2px 6px rgba(0,0,0,0.3);
                padding: 10px;
                zIndex: 1000;
              }
            }
        \`;
        document.head.appendChild(style);
        document.body.appendChild(exportButton);
        exportButton.addEventListener('click', showExportOptions);
      }
      function showExportOptions() {
        if (document.getElementById('export-options')) return;
        const optionsContainer = document.createElement('div');
        optionsContainer.id = 'export-options';
        const buttonsContainer = document.createElement('div');
        Object.assign(buttonsContainer.style, {
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'stretch',
          gap: '5px'
        });
        const mdButton = document.createElement('button');
        mdButton.textContent = '导出为 Markdown';
        Object.assign(mdButton.style, {
          padding: '8px 12px',
          backgroundColor: '#4cafa3',
          color: 'white',
          border: 'none',
          borderRadius: '3px',
          cursor: 'pointer'
        });
        mdButton.addEventListener('click', async () => {
          await exportChatAsMarkdown();
          document.body.removeChild(optionsContainer);
        });
        const htmlButton = document.createElement('button');
        htmlButton.textContent = '导出为 HTML';
        Object.assign(htmlButton.style, {
          padding: '8px 12px',
          backgroundColor: '#4cafa3',
          color: 'white',
          border: 'none',
          borderRadius: '3px',
          cursor: 'pointer'
        });
        htmlButton.addEventListener('click', async () => {
          await exportChatAsHTML();
          document.body.removeChild(optionsContainer);
        });
        buttonsContainer.appendChild(mdButton);
        buttonsContainer.appendChild(htmlButton);
        const autoSendContainer = document.createElement('div');
        Object.assign(autoSendContainer.style, {
            display: 'flex',
            alignItems: 'center',
            gap: '5px'
        });
    
        const autoSendCheckbox = document.createElement('input');
        autoSendCheckbox.type = 'checkbox';
        autoSendCheckbox.id = 'auto-send-checkbox';
    
        // 从本地存储读取状态,默认开启
        const autoSendEnabled = localStorage.getItem('autoSendEnabled');
        autoSendCheckbox.checked = autoSendEnabled === null || autoSendEnabled === 'true';
    
        const autoSendLabel = document.createElement('label');
        autoSendLabel.htmlFor = 'auto-send-checkbox';
        autoSendLabel.textContent = '开启自动发送图片';
    
        // 监听复选框状态变化,保存到本地存储
        autoSendCheckbox.addEventListener('change', () => {
            localStorage.setItem('autoSendEnabled', autoSendCheckbox.checked);
        });
    
        autoSendContainer.appendChild(autoSendCheckbox);
        autoSendContainer.appendChild(autoSendLabel);
    
        // 将新选项添加到按钮容器中
        buttonsContainer.appendChild(autoSendContainer);
    
        // 关闭按钮
        const closeButton = document.createElement('span');
        closeButton.textContent = '✖';
        Object.assign(closeButton.style, {
            position: 'absolute',
            top: '5px',
            right: '10px',
            cursor: 'pointer',
            fontWeight: 'bold'
        });
        closeButton.addEventListener('click', () => {
            document.body.removeChild(optionsContainer);
        });
    
        optionsContainer.appendChild(closeButton);
        optionsContainer.appendChild(buttonsContainer);
        document.body.appendChild(optionsContainer);
      }
      async function exportChatAsMarkdown() {
        let date = new Date();
        let year = date.getFullYear();
        let month = date.getMonth() + 1;
        let day = date.getDate();
        let formattedDate = \`\${year}年\${month}月\${day}日\`;
        let markdownContent = \`# \${formattedDate} ChatGPT对话记录\\n\`;
        let allElements = document.querySelectorAll('div.flex.flex-grow.flex-col.max-w-full');
        for (let i = 0; i < allElements.length; i += 2) {
          let userElement = allElements[i];
          let answerElement = allElements[i + 1];
          if (!userElement || !answerElement) continue;
          let userText = userElement.innerHTML.trim();
          let answerText = answerElement.innerHTML.trim();
          let tempDivUser = document.createElement('div');
          tempDivUser.innerHTML = userText;
          removeEditButtons(tempDivUser);
          await convertImagesToBase64(tempDivUser);
          userText = tempDivUser.innerHTML;
          let tempDivAnswer = document.createElement('div');
          tempDivAnswer.innerHTML = answerText;
          removeEditButtons(tempDivAnswer);
          await convertImagesToBase64(tempDivAnswer);
          answerText = tempDivAnswer.innerHTML;
          let modelSlug = answerElement?.childNodes[0]?.getAttribute('data-message-model-slug') || '';
          let roleName = extractRoleName(modelSlug);
          userText = await htmlToMarkdown(userText);
          answerText = await htmlToMarkdown(answerText);
          markdownContent += \`\\n## User\\n\${userText}\\n## \${roleName}\\n\${answerText}\\n\`;
        }
        markdownContent = markdownContent.replace(/&amp;/g, '&');
        if (markdownContent) {
          download(markdownContent, 'chat-export.md', 'text/markdown');
        } else {
          alert("未找到任何问题或答案。");
        }
      }
      async function exportChatAsHTML() {
        let htmlContent = "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Chat Export</title></head><body>";
        let allElements = document.querySelectorAll('div.flex.flex-grow.flex-col.max-w-full');
        for (let i = 0; i < allElements.length; i += 2) {
          let userElement = allElements[i];
          let answerElement = allElements[i + 1];
          if (!userElement || !answerElement) continue;
          let userText = userElement.innerHTML.trim();
          let answerText = answerElement.innerHTML.trim();
          let tempDivUser = document.createElement('div');
          tempDivUser.innerHTML = userText;
          removeEditButtons(tempDivUser);
          await convertImagesToBase64(tempDivUser);
          userText = tempDivUser.innerHTML;
          let tempDivAnswer = document.createElement('div');
          tempDivAnswer.innerHTML = answerText;
          removeEditButtons(tempDivAnswer);
          await convertImagesToBase64(tempDivAnswer);
          answerText = tempDivAnswer.innerHTML;
          let modelSlug = answerElement?.childNodes[0]?.getAttribute('data-message-model-slug') || '';
          let roleName = extractRoleName(modelSlug);
          htmlContent += \`<h2>User</h2><div>\${userText}</div>\`;
          htmlContent += \`<h2>\${roleName}</h2><div>\${answerText}</div>\`;
        }
        htmlContent += "</body></html>";
        if (htmlContent !== "<!DOCTYPE html><html><head><meta charset='UTF-8'><title>Chat Export</title></head><body></body></html>") {
          download(htmlContent, 'chat-export.html', 'text/html');
        } else {
          alert("未找到任何问题或答案。");
        }
      }
      function removeEditButtons(container) {
        container.querySelectorAll('button[aria-label="编辑消息"]').forEach(button => {
          let parentDiv = button.closest('div');
          if (parentDiv) parentDiv.remove();
        });
      }
      function extractRoleName(modelSlug) {
        var role = "";
        if (!modelSlug) role = 'Assistant';
        if (modelSlug.includes("gpt")) {
            role = 'GPT' + modelSlug.split('gpt')[1];
        } else {
            role = 'Assistant';
        }
        return role;
      }
      function download(data, filename, type) {
        const blob = new Blob([data], {type: type});
        if (window.navigator.msSaveOrOpenBlob) {
          window.navigator.msSaveOrOpenBlob(blob, filename);
        } else {
          const a = document.createElement('a');
          const url = URL.createObjectURL(blob);
          a.href = url;
          a.download = filename;
          document.body.appendChild(a);
          a.click();
          setTimeout(() => {
              document.body.removeChild(a);
              window.URL.revokeObjectURL(url);
          }, 0);
        }
      }
      async function convertImagesToBase64(container) {
        const imgElements = container.querySelectorAll('img');
        for (let img of imgElements) {
          let src = img.src;
          try {
            let base64 = await getBase64FromImageUrl(src);
            img.src = base64;
          } catch (error) {
            console.error(\`图片转换为Base64失败,使用原始链接: \${src}\`, error);
          }
        }
      }
      function getBase64FromImageUrl(url) {
        return fetch(url)
          .then(response => {
              if (!response.ok) {
                throw new Error(\`网络响应失败,状态码: \${response.status}\`);
              }
              return response.blob();
          })
          .then(blob => new Promise((resolve, reject) => {
              let reader = new FileReader();
              reader.onloadend = function() {
                resolve(reader.result);
              };
              reader.onerror = function(error) {
                reject(error);
              };
              reader.readAsDataURL(blob);
          }))
          .catch(error => {
            throw error;
          });
      }
    
      async function htmlToMarkdown(html) {
          const parser = new DOMParser();
          const doc = parser.parseFromString(html, 'text/html');
          removeEditButtons(doc.body);
          doc.querySelectorAll('span.katex-html').forEach(element => element.remove());
          doc.querySelectorAll('mrow').forEach(mrow => mrow.remove());
          doc.querySelectorAll('annotation[encoding="application/x-tex"]').forEach(element => {
              if (element.closest('.katex-display')) {
                  const latex = element.textContent;
                  element.replaceWith(\`\\n\$\$\\n\${latex}\\n\$\$\\n\`);
              } else {
                  const latex = element.textContent;
                  element.replaceWith(\`\$\${latex}$ \`);
                }
              });
          doc.querySelectorAll('strong, b').forEach(bold => {
              const markdownBold = \`**\${bold.textContent}**\`;
              const boldTextNode = document.createTextNode(markdownBold);
              bold.parentNode.replaceChild(boldTextNode, bold);
          });
          doc.querySelectorAll('em, i').forEach(italic => {
              const markdownItalic = \`*\${italic.textContent}*\`;
              const italicTextNode = document.createTextNode(markdownItalic);
              italic.parentNode.replaceChild(italicTextNode, italic);
          });
          doc.querySelectorAll('p code, li code, span code').forEach(code => {
              const markdownCode = \`\\\`\${code.textContent}\\\`\`;
              const codeTextNode = document.createTextNode(markdownCode);
              code.parentNode.replaceChild(codeTextNode, code);
          });
          doc.querySelectorAll('a').forEach(link => {
              const markdownLink = \`[\${link.textContent}](\${link.href})\`;
              const linkTextNode = document.createTextNode(markdownLink);
              link.parentNode.replaceChild(linkTextNode, link);
          });
          doc.querySelectorAll('img').forEach(img => {
              const markdownImage = \`![\${img.alt}](\${img.src})\`;
              const imgTextNode = document.createTextNode(markdownImage);
              img.parentNode.replaceChild(imgTextNode, img);
          });
          doc.querySelectorAll('pre').forEach(pre => {
              const codeTypeElement = pre.querySelector('div > div:first-child');
              const codeType = codeTypeElement ? codeTypeElement.textContent.trim() : '';
              const codeElement = pre.querySelector('div > div:nth-child(3) > code');
              const codeContent = codeElement ? codeElement.textContent : '';
              pre.innerHTML = \`\\n\\\`\\\`\\\`\${codeType}\\n\${codeContent}\\n\\\`\\\`\\\`\\n\`;
          });
          doc.querySelectorAll('ul').forEach(ul => {
              let markdown = '';
              ul.querySelectorAll(':scope > li').forEach(li => {
                  markdown += \`- \${li.textContent.trim()}\\n\`;
              });
              const markdownTextNode = document.createTextNode('\\n' + markdown.trim());
              ul.parentNode.replaceChild(markdownTextNode, ul);
          });
          doc.querySelectorAll('ol').forEach(ol => {
              let markdown = '';
              ol.querySelectorAll(':scope > li').forEach((li, index) => {
                  markdown += \`\${index + 1}. \${li.textContent.trim()}\\n\`;
              });
              const markdownTextNode = document.createTextNode('\\n' + markdown.trim());
              ol.parentNode.replaceChild(markdownTextNode, ol);
          });
          for (let i = 1; i <= 6; i++) {
              doc.querySelectorAll(\`h\${i}\`).forEach(header => {
                  const markdownHeader = \`\\n\${'#'.repeat(i)} \${header.textContent}\\n\`;
                  const headerTextNode = document.createTextNode(markdownHeader);
                  header.parentNode.replaceChild(headerTextNode, header);
              });
          }
          doc.querySelectorAll('p').forEach(p => {
              const markdownParagraph = \`\\n\${p.textContent}\\n\`;
              const paragraphTextNode = document.createTextNode(markdownParagraph);
              p.parentNode.replaceChild(paragraphTextNode, p);
          });
          doc.querySelectorAll('table').forEach(table => {
              let markdown = '';
              table.querySelectorAll('thead tr').forEach(tr => {
                  tr.querySelectorAll('th').forEach(th => {
                      markdown += \`| \${th.textContent} \`;
                  });
                  markdown += '|\\n';
                  tr.querySelectorAll('th').forEach(() => {
                      markdown += '| ---- ';
                  });
                  markdown += '|\\n';
              });
              table.querySelectorAll('tbody tr').forEach(tr => {
                  tr.querySelectorAll('td').forEach(td => {
                      markdown += \`| \${td.textContent} \`;
                  });
                  markdown += '|\\n';
              });
              const markdownTextNode = document.createTextNode('\\n' + markdown.trim() + '\\n');
              table.parentNode.replaceChild(markdownTextNode, table);
          });
          let markdown = doc.body.innerHTML.replace(/<[^>]*>/g, '');
          return markdown.trim();
      }
    })();

    // 脚本4:oaifree自动重试pow
    (function() {
      'use strict';
      const TARGET_PATH = '/backend-api/sentinel/chat-requirements';
      const MAX_RETRIES = 20;
      const PREFIX = '0000';
      function startsWith(str, prefix) {
          return str.startsWith(prefix);
      }
      function delay(ms) {
          return new Promise(resolve => setTimeout(resolve, ms));
      }
      const originalFetch = window.fetch;
      window.fetch = async function(input, init) {
          const url = typeof input === 'string' ? input : input.url;
          const method = (init && init.method) || (input && input.method) || 'GET';
  
          if (method.toUpperCase() === 'POST' && url.includes(TARGET_PATH)) {
              for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
                  const response = await originalFetch(input, init);
                  const clonedResponse = response.clone();
                  try {
                      const data = await clonedResponse.json();
                      if (data?.proofofwork?.difficulty && startsWith(data.proofofwork.difficulty, PREFIX)) {
                          if (attempt < MAX_RETRIES) {
                              await delay(200);
                              continue;
                          }
                      }
                      return response;
                  } catch {
                      return response;
                  }
              }
          }
          return originalFetch.apply(this, arguments);
      };
  
      const originalOpen = XMLHttpRequest.prototype.open;
      const originalSend = XMLHttpRequest.prototype.send;
  
      XMLHttpRequest.prototype.open = function(method, url) {
          this._method = method;
          this._url = url;
          originalOpen.apply(this, arguments);
      };
  
      XMLHttpRequest.prototype.send = function(body) {
          if (this._method.toUpperCase() === 'POST' && this._url.includes(TARGET_PATH)) {
              let attempt = 0;
              const xhr = this;
              const sendRequest = () => {
                  attempt++;
                  xhr.addEventListener('load', function onLoad() {
                      xhr.removeEventListener('load', onLoad);
                      try {
                          const data = JSON.parse(xhr.responseText);
                          if (data?.proofofwork?.difficulty && startsWith(data.proofofwork.difficulty, PREFIX)) {
                              if (attempt < MAX_RETRIES) {
                                  delay(200).then(sendRequest);
                              }
                          }
                      } catch {}
                  });
                  originalOpen.call(xhr, this._method, this._url, true);
                  originalSend.call(xhr, body);
              };
              sendRequest();
          } else {
              originalSend.apply(this, arguments);
          }
      };
  })();
})();
`;

export default {
    async fetch(request, env, ctx) {
      const REDIRECT_URL = env.REDIRECT_URL;
        try {
            const url = new URL(request.url);

            // 处理 /auth/login 路径
            if (url.pathname === '/auth/login') {
                const token = url.searchParams.get('token');
                if (!token) {
                    return Response.redirect(REDIRECT_URL, 301);
                }
                url.host = PROXY_HOST;
                const modifiedRequest = new Request(url, request);
                return await fetch(modifiedRequest);
            }

            // 对所有其他请求进行代理
            url.host = PROXY_HOST;
            const modifiedRequest = new Request(url, request);

            // 检查缓存
            const cache = caches.default;
            // let cachedResponse = await cache.match(modifiedRequest);
            // if (cachedResponse) {
            //     return cachedResponse;
            // }

            const response = await fetch(modifiedRequest);
            const contentType = response.headers.get('Content-Type') || '';

            // 仅对 HTML 内容注入脚本
            if (contentType.includes('text/html')) {
                let body = await response.text();
                body = body.replace('</body>', `<script>${INJECT_SCRIPT}</script></body>`);

                // 处理响应头
                const newHeaders = new Headers(response.headers);
                newHeaders.delete('Content-Length');
                if (newHeaders.get('Content-Type') && !newHeaders.get('Content-Type').includes('charset')) {
                    newHeaders.set('Content-Type', `${newHeaders.get('Content-Type')}; charset=utf-8`);
                }

                const newResponse = new Response(body, {
                    status: response.status,
                    statusText: response.statusText,
                    headers: newHeaders
                });

                // 缓存响应
                ctx.waitUntil(cache.put(modifiedRequest, newResponse.clone()));

                return newResponse;
            }

            // 缓存非HTML响应
            ctx.waitUntil(cache.put(modifiedRequest, response.clone()));
            return response;
        } catch (error) {
            console.error('Worker error:', error);
            return new Response('Internal Server Error', { status: 500 });
        }
    }
};
7 个赞

大佬好,如果没有用CF反代,用了nginx反代的话,这个代码需要怎么改才可以呢??

好的,谢谢大佬

部署之后访问报错Internal Server Error是我设置的有什么问题吗 :melting_face:

我直接套的别的佬的一个模板,不好意思没细看,把redirect删掉就好了。我已经修改了,请重写复制。

好的好的,多谢

mark:new站注入油猴脚本