推特获取原图

推特在新标签页打开图片自动原图

Zanim zainstalujesz, Greasy Fork chce Cię poinformować, że ten skrypt zawiera pewne funkcjonalności mogące działać na pożytek autora, a nie twój. Upewnij się, czy na pewno chcesz kontynuować.

Ten skrypt zawiera kod, który śledzi twoje przeglądanie. Autor tego skryptu wyjaśnia: 本脚本会将您下载的图片信息(图片URL、推文链接、时间)和用户名发送到作者服务器用于个人收藏管理,不会用于其他用途

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

You will need to install an extension such as Tampermonkey to install this script.

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         推特获取原图
// @namespace    https://github.com/MuXia-0326/twitter-auto-original-picture
// @version      1.22
// @description  推特在新标签页打开图片自动原图
// @author       Mossia
// @icon         https://raw.githubusercontent.com/MuXia-0326/drawio/master/angri.png
// @match        https://pbs.twimg.com/*
// @match        https://twitter.com/*
// @match        https://x.com/*
// @grant        GM_setClipboard
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @license      MIT
// @antifeature  tracking 本脚本会将您下载的图片信息(图片URL、推文链接、时间)和用户名发送到作者服务器用于个人收藏管理,不会用于其他用途
// ==/UserScript==

(function () {
  'use strict';

  // 配置项
  const CONFIG_KEY = 'twitter_auto_like';
  const CONFIG_COPY_KEY = 'twitter_copy_replace';
  const CONFIG_SHOW_BTN_KEY = 'twitter_show_settings_btn';
  let autoLike = GM_getValue(CONFIG_KEY, true); // 默认开启自动点赞
  let copyReplace = GM_getValue(CONFIG_COPY_KEY, true); // 默认开启复制链接替换
  let showSettingsBtn = GM_getValue(CONFIG_SHOW_BTN_KEY, true); // 默认显示设置按钮

  let share_url = '';

  let userName = '';

  //载入css样式
  const css = `/* From www.lingdaima.com */
  .twitter-Btn {
    position: relative;
    display: inline-block;
    padding: 10px;
    text-align: center;
    font-size: 18px;
    letter-spacing: 1px;
    text-decoration: none;
    color: rgb(29, 155, 240);
    background: transparent;
    cursor: pointer;
    transition: ease-out 0.5s;
    border: 2px solid rgb(29, 155, 240);
    border-radius: 10px;
    box-shadow: inset 0 0 0 0 rgb(29, 155, 240);
  }

  .twitter-Btn:hover {
    color: white;
    box-shadow: inset 0 -100px 0 0 rgb(29, 155, 240);
  }

  .twitter-Btn:active {
    transform: scale(0.9);
  }

  .twitter-Btn:hover svg {
    fill: white;
  }
  .twitter-Btn:active svg,
  .twitter-Btn svg {
    fill: rgb(29, 155, 240);
  }

  .Btn {
    position: absolute;
    top: 2px;
    right: 2px;
  }
  .svgClass {
    display: flex;
  }

  .share-btn {
    display:none;
  }

  /* 配置面板样式 */
  .config-modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(0, 0, 0, 0.5);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 10000;
  }

  .config-panel {
    background: white;
    border-radius: 16px;
    padding: 24px;
    min-width: 400px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
  }

  .config-header {
    font-size: 20px;
    font-weight: bold;
    margin-bottom: 20px;
    color: #0f1419;
  }

  .config-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 0;
    border-bottom: 1px solid #eff3f4;
  }

  .config-label {
    font-size: 15px;
    color: #0f1419;
  }

  .config-description {
    font-size: 13px;
    color: #536471;
    margin-top: 4px;
  }

  .toggle-switch {
    position: relative;
    width: 44px;
    height: 24px;
    background: #cfd9de;
    border-radius: 12px;
    cursor: pointer;
    transition: background 0.3s;
  }

  .toggle-switch.active {
    background: rgb(29, 155, 240);
  }

  .toggle-slider {
    position: absolute;
    top: 2px;
    left: 2px;
    width: 20px;
    height: 20px;
    background: white;
    border-radius: 50%;
    transition: transform 0.3s;
  }

  .toggle-switch.active .toggle-slider {
    transform: translateX(20px);
  }

  .config-buttons {
    display: flex;
    justify-content: flex-end;
    gap: 12px;
    margin-top: 20px;
  }

  .config-btn {
    padding: 8px 16px;
    border-radius: 20px;
    border: none;
    font-size: 15px;
    font-weight: bold;
    cursor: pointer;
    transition: background 0.2s;
  }

  .config-btn-primary {
    background: rgb(29, 155, 240);
    color: white;
  }

  .config-btn-primary:hover {
    background: rgb(26, 140, 216);
  }

  .config-btn-secondary {
    background: #eff3f4;
    color: #0f1419;
  }

  .config-btn-secondary:hover {
    background: #d7dbdc;
  }

  /* 设置按钮样式 */
  .settings-btn {
    position: fixed;
    bottom: 20px;
    left: 20px;
    width: 56px;
    height: 56px;
    background: rgb(29, 155, 240);
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    cursor: pointer;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
    z-index: 9999;
    transition: transform 0.2s, box-shadow 0.2s;
  }

  .settings-btn:hover {
    transform: scale(1.1);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  }

  .settings-btn svg {
    fill: white;
  }
  `;

  let styleTag = document.createElement('style');
  styleTag.innerText = css;
  document.head.append(styleTag);

  // 创建配置面板
  function createConfigPanel() {
    const modal = document.createElement('div');
    modal.className = 'config-modal';
    modal.innerHTML = `
      <div class="config-panel">
        <div class="config-header">推特获取原图 - 设置</div>
        <div class="config-item">
          <div>
            <div class="config-label">下载时自动点赞</div>
            <div class="config-description">下载图片时自动为该推文点赞</div>
          </div>
          <div class="toggle-switch ${autoLike ? 'active' : ''}" id="autoLikeToggle">
            <div class="toggle-slider"></div>
          </div>
        </div>
        <div class="config-item">
          <div>
            <div class="config-label">复制链接时替换域名</div>
            <div class="config-description">复制推文链接时将 x.com 替换为 fixupx.com</div>
          </div>
          <div class="toggle-switch ${copyReplace ? 'active' : ''}" id="copyReplaceToggle">
            <div class="toggle-slider"></div>
          </div>
        </div>
        <div class="config-item">
          <div>
            <div class="config-label">显示设置按钮</div>
            <div class="config-description">在页面左下角显示设置按钮(关闭后可通过油猴菜单打开设置)</div>
          </div>
          <div class="toggle-switch ${showSettingsBtn ? 'active' : ''}" id="showBtnToggle">
            <div class="toggle-slider"></div>
          </div>
        </div>
        <div class="config-buttons">
          <button class="config-btn config-btn-secondary" id="configCancel">取消</button>
          <button class="config-btn config-btn-primary" id="configSave">保存</button>
        </div>
      </div>
    `;

    document.body.appendChild(modal);

    // 切换自动点赞开关
    const likeToggle = modal.querySelector('#autoLikeToggle');
    let tempAutoLike = autoLike;
    likeToggle.addEventListener('click', () => {
      tempAutoLike = !tempAutoLike;
      likeToggle.classList.toggle('active', tempAutoLike);
    });

    // 切换复制替换开关
    const copyToggle = modal.querySelector('#copyReplaceToggle');
    let tempCopyReplace = copyReplace;
    copyToggle.addEventListener('click', () => {
      tempCopyReplace = !tempCopyReplace;
      copyToggle.classList.toggle('active', tempCopyReplace);
    });

    // 切换显示按钮开关
    const showBtnToggle = modal.querySelector('#showBtnToggle');
    let tempShowSettingsBtn = showSettingsBtn;
    showBtnToggle.addEventListener('click', () => {
      tempShowSettingsBtn = !tempShowSettingsBtn;
      showBtnToggle.classList.toggle('active', tempShowSettingsBtn);
    });

    // 取消按钮
    modal.querySelector('#configCancel').addEventListener('click', () => {
      modal.remove();
    });

    // 保存按钮
    modal.querySelector('#configSave').addEventListener('click', () => {
      autoLike = tempAutoLike;
      copyReplace = tempCopyReplace;
      const oldShowSettingsBtn = showSettingsBtn;
      showSettingsBtn = tempShowSettingsBtn;

      GM_setValue(CONFIG_KEY, autoLike);
      GM_setValue(CONFIG_COPY_KEY, copyReplace);
      GM_setValue(CONFIG_SHOW_BTN_KEY, showSettingsBtn);

      // 如果设置按钮显示状态改变,更新按钮显示
      if (oldShowSettingsBtn !== showSettingsBtn) {
        const existingBtn = document.querySelector('.settings-btn');
        if (showSettingsBtn && !existingBtn) {
          createSettingsButton();
        } else if (!showSettingsBtn && existingBtn) {
          existingBtn.remove();
        }
      }

      alert('设置已保存!');
      modal.remove();
    });

    // 点击背景关闭
    modal.addEventListener('click', (e) => {
      if (e.target === modal) {
        modal.remove();
      }
    });
  }

  // 创建设置按钮
  function createSettingsButton() {
    const settingsBtn = document.createElement('div');
    settingsBtn.className = 'settings-btn';
    settingsBtn.innerHTML = `
      <svg width="24" height="24" viewBox="0 0 24 24">
        <path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/>
      </svg>
    `;
    settingsBtn.addEventListener('click', createConfigPanel);
    document.body.appendChild(settingsBtn);
  }

  // 注册油猴菜单命令
  GM_registerMenuCommand('⚙️ 设置', createConfigPanel);

  // 获取当前页面的URL
  if (window.location.hostname === 'pbs.twimg.com') {
    let newUrl = replaceImageSizeName(window.location.href);
    if (newUrl !== window.location.href) {
      window.location.href = newUrl;
    }
  } else if (window.location.hostname === 'twitter.com' || window.location.hostname === 'x.com') {
    document.js_nsfw = setInterval(main, 100);
    // 页面加载完成后根据配置决定是否添加设置按钮
    if (showSettingsBtn) {
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', createSettingsButton);
      } else {
        createSettingsButton();
      }
    }
  }

  let url = '';
  let createDate = '';

  function main() {
    if (userName === '') {
      getUserName();
    }

    tweetAdd();
    imageDetailsAdd();
    copy();
    tweetAltAdd();
  }

  function getUserName() {
    let divs = document.querySelectorAll('button[aria-label="账号菜单"]');

    if (divs.length === 0) {
      let mobileDivs = document.querySelectorAll('button[data-testid="DashButton_ProfileIcon_Link"]');
      for (let mobileDiv of mobileDivs) {
        let mobileName = mobileDiv.getAttribute('aria-label');
        userName = mobileName.split(' ')[1];
      }
    }

    for (let div of divs) {
      if (div.children.length === 3) {
        let secondDiv = div.children[1];
        if (secondDiv === null) {
          continue;
        }

        let oneDiv = secondDiv.children[0].children[0];
        let twoDiv = secondDiv.children[0].children[1];

        let likeName = oneDiv.children[0].children[0].children[0].textContent;
        let name = twoDiv.children[0].children[0].children[0].textContent;

        userName = likeName + '(' + name + ')';
      } else if (div.children.length === 1) {
        let oneDiv = div.children[0];
        if (oneDiv === null) {
          continue;
        }

        let nameDiv =
          oneDiv.children[0].children[1].children[0].children[1].children[0].children[0].children[2].children[0].children[1]
            .children[0];
        userName = nameDiv.getAttribute('aria-label');
      }
    }
  }

  function tweetAltAdd() {
    let tweets = document.querySelectorAll('[data-testid="cellInnerDiv"]');

    for (let tweet of tweets) {
      let className = 'div.css-175oi2r.r-rki7wi.r-u8s1d.r-14fd9ze';

      let div = tweet.querySelector(className);
      if (div === null) {
        continue;
      }

      let parent = div.parentNode;
      let links = parent.querySelector('a');
      if (links === null) {
        continue;
      }

      let imageDiv = links.querySelector('img.css-9pa8cd');
      if (imageDiv === null) {
        continue;
      }

      let temp = [...new Set(baseSelectorAlt(parent, 'img.css-9pa8cd'))];
      let like = queryLikeBtn(tweet);

      for (let i = 0; i < temp.length; i++) {
        setAltBtn([temp[i]], like);
      }
    }
  }

  function copy() {
    if (copyReplace) {
      // 替换复制按钮的url
      let firstChildDiv = document.querySelector('div[data-testid="Dropdown"] > div:first-child');

      // 确保第一个子元素是一个 div
      if (firstChildDiv) {
        firstChildDiv.addEventListener('click', function (e) {
          navigator.clipboard
            .readText()
            .then((text) => {
              // console.log('剪贴板的内容:', text);
              if (text.indexOf('fixupx') === -1) {
                // 修改剪贴板的内容
                GM_setClipboard(text.replace(/x/g, 'fixupx'), 'text');
              }
            })
            .catch((err) => {
              console.log('无法读取剪贴板的内容:', err);
            });
        });
      }
    }
  }

  function imageDetailsAdd() {
    // 图片详情页的按钮
    let classDetailsName = 'div[data-testid="swipe-to-dismiss"] div[aria-label="图像"]';

    let tempDetails = [...new Set(baseSelector(document, classDetailsName))];

    for (let i = 0; i < tempDetails.length; i++) {
      setDetailsBtn([tempDetails[i]]);
    }
  }

  function tweetAdd() {
    let tweets = document.querySelectorAll('[data-testid="cellInnerDiv"]');

    for (let tweet of tweets) {
      let time = tweet.querySelector('time');

      let className = 'div[data-testid="tweetPhoto"]';

      let imageDiv = tweet.querySelector(className);
      if (imageDiv === null) {
        continue;
      }

      let temp = [...new Set(baseSelector(tweet, className))];
      let like = queryLikeBtn(tweet);

      for (let i = 0; i < temp.length; i++) {
        setBtn([temp[i]], like, time);
      }
    }
  }

  function queryLikeBtn(tweet) {
    let like = null;
    if (tweet.querySelector('div.css-175oi2r.r-16y2uox.r-1wbh5a2.r-1ny4l3l')) {
      let divs = tweet.querySelector('div.css-175oi2r.r-16y2uox.r-1wbh5a2.r-1ny4l3l');

      let childCount = divs.children.length;
      if (childCount === 3) {
        let div = divs.children[2];
        let lastNum = 3;
        like = div.children[lastNum].querySelector('div').querySelector('div').children[2];
      } else if (childCount === 2) {
        let div = divs.children[1].children[1];
        if (div.children.length === 4) {
          like = div.children[3].querySelector('div').querySelector('div').children[2];
        } else if (div.children.length === 5) {
          like = div.children[4].querySelector('div').querySelector('div').children[2];
        }
      }
    } else if (tweet.querySelector('div.css-175oi2r.r-1iusvr4.r-16y2uox.r-1777fci.r-kzbkwu')) {
      like = tweet
        .querySelector('div.css-175oi2r.r-1iusvr4.r-16y2uox.r-1777fci.r-kzbkwu')
        .children[3].querySelector('div')
        .querySelector('div').children[2];
    }

    return like;
  }

  function baseSelector(parentEle, selector) {
    let items = parentEle.querySelectorAll(selector);
    return Array.from(items).filter((item) => {
      let node = getParentByNum(item, 5).querySelectorAll('div[data-nsfw]');
      return !(node && node.length > 0);
    });
  }

  function baseSelectorAlt(parentEle, selector) {
    let items = parentEle.querySelectorAll(selector);
    return Array.from(items).filter((item) => {
      let node = getParentByNum(item, 5).querySelectorAll('div[data-nsfw]');
      return !(node && node.length > 0);
    });
  }

  function setBtn(node, like, time) {
    for (let container of node) {
      let images = container.querySelectorAll('img');

      for (let image of images) {
        let imageUrl = image.getAttribute('src');
        let classText = image.getAttribute('class') + getRandomIntExclusive(10);

        let buttonHtml = getBtnHtml(classText);

        let parentElement = getParentByNum(image, 5);

        let newUrl = replaceImageSizeName(imageUrl);
        appendBtn(parentElement, newUrl, buttonHtml, classText, like, time);
      }
    }
  }

  function setAltBtn(node, like) {
    for (let images of node) {
      let imageUrl = images.getAttribute('src');
      let classText = images.getAttribute('class') + getRandomIntExclusive(10);

      let buttonHtml = getBtnHtml(classText);

      let parentElement = getParentByNum(images, 5);

      let newUrl = replaceImageSizeName(imageUrl);
      appendBtn(parentElement, newUrl, buttonHtml, classText, like);
    }
  }

  function setDetailsBtn(node) {
    for (let container of node) {
      let images = container.querySelectorAll('img');

      for (let image of images) {
        let imageUrl = image.getAttribute('src');
        let classText = image.getAttribute('class') + getRandomIntExclusive(10);

        let buttonHtml = getBtnHtml(classText);

        let like = getParentByNum(container, 4).nextElementSibling.querySelector('div').querySelector('div').querySelector('div')
          .children[2];

        let newUrl = replaceImageSizeName(imageUrl);
        appendBtn(container, newUrl, buttonHtml, classText, like);
      }
    }
  }

  function getBtnHtml(classText) {
    const buttonHtml = `<div class="Btn">
                <button class="twitter-Btn" id="copy-${classText}">
                    <div class="svgClass">
                        <svg t="1694962361717" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5412" width="20" height="20">
                            <path d="M761.088 715.3152a38.7072 38.7072 0 0 1 0-77.4144 37.4272 37.4272 0 0 0 37.4272-37.4272V265.0112a37.4272 37.4272 0 0 0-37.4272-37.4272H425.6256a37.4272 37.4272 0 0 0-37.4272 37.4272 38.7072 38.7072 0 1 1-77.4144 0 115.0976 115.0976 0 0 1 114.8416-114.8416h335.4624a115.0976 115.0976 0 0 1 114.8416 114.8416v335.4624a115.0976 115.0976 0 0 1-114.8416 114.8416z" p-id="5413" ></path>
                            <path d="M589.4656 883.0976H268.1856a121.1392 121.1392 0 0 1-121.2928-121.2928v-322.56a121.1392 121.1392 0 0 1 121.2928-121.344h321.28a121.1392 121.1392 0 0 1 121.2928 121.2928v322.56c1.28 67.1232-54.1696 121.344-121.2928 121.344zM268.1856 395.3152a43.52 43.52 0 0 0-43.8784 43.8784v322.56a43.52 43.52 0 0 0 43.8784 43.8784h321.28a43.52 43.52 0 0 0 43.8784-43.8784v-322.56a43.52 43.52 0 0 0-43.8784-43.8784z" p-id="5414" ></path>
                        </svg>
                    </div>
                </button>
                <button class="twitter-Btn" id="download-${classText}">
                    <div class="svgClass">
                        <svg t="1694962091616" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4129" id="mx_n_1694962091617" width="20" height="20">
                            <path d="M160 579.2a28.8 28.8 0 0 1 28.8 28.8v170.672c0 30.4 25.664 56.528 59.2 56.528h528c33.536 0 59.2-26.144 59.2-56.528V608a28.8 28.8 0 0 1 57.6 0v170.672c0 63.856-53.12 114.128-116.8 114.128h-528c-63.68 0-116.8-50.272-116.8-114.128V608a28.8 28.8 0 0 1 28.8-28.8z"  p-id="4130"></path><path d="M540.8 176l0 464a28.8 28.8 0 0 1-57.6 0L483.2 176a28.8 28.8 0 0 1 57.6 0z"  p-id="4131"></path>
                            <path d="M331.632 459.632a28.8 28.8 0 0 1 40.736 0l160 160a28.8 28.8 0 0 1-40.736 40.736l-160-160a28.8 28.8 0 0 1 0-40.736z" p-id="4132"></path><path d="M692.368 459.632a28.8 28.8 0 0 0-40.736 0l-160 160a28.8 28.8 0 0 0 40.736 40.736l160-160a28.8 28.8 0 0 0 0-40.736z" p-id="4133"></path>
                        </svg>
                    </div>
                </button>
                <button class="twitter-Btn share-btn" id="share-${classText}">
                    <div class="svgClass">
                        <svg t="1713618483987" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2790" width="20" height="20">
                            <path d="M720.020242 809.16812c0-49.233308 39.919175-89.151459 89.151459-89.151459s89.150436 39.918151 89.150436 89.151459c0 49.227168-39.918151 89.159646-89.150436 89.159646S720.020242 858.397335 720.020242 809.16812zM571.433112 214.824717c0-49.234331 39.919175-89.152483 89.151459-89.152483 49.234331 0 89.152483 39.918151 89.152483 89.152483 0 49.232285-39.918151 89.151459-89.152483 89.151459C611.352287 303.976176 571.433112 264.057001 571.433112 214.824717zM125.674792 675.441443c0-82.07018 66.530252-148.586107 148.585083-148.586107 82.056877 0 148.58713 66.515926 148.58713 148.586107 0 82.071204-66.531276 148.58713-148.58713 148.58713C192.205045 824.028573 125.674792 757.511623 125.674792 675.441443zM66.240145 675.441443c0 114.89375 93.142353 208.027917 208.019731 208.027917 81.402985 0 151.8525-46.752814 186.03809-114.870214l200.360284 35.288714-0.073678 5.28026c0 82.07632 66.531276 148.594293 148.58713 148.594293s148.586107-66.517973 148.586107-148.594293c0-82.072227-66.530252-148.586107-148.586107-148.586107-59.507302 0-110.815875 34.927487-134.554532 85.436858l-195.454554-34.403554c2.059915-11.738345 3.119037-23.839965 3.119037-36.174897 0-54.311976-20.822235-103.748922-54.892191-140.779304l180.740434-180.755784c16.309454 6.152117 33.983999 9.503445 52.454676 9.503445 82.056877 0 148.58713-66.514903 148.58713-148.586107 0-82.07018-66.530252-148.58713-148.58713-148.58713-82.055854 0-148.585083 66.51695-148.585083 148.58713 0 41.674145 17.165961 79.32772 44.792159 106.317421L381.013225 496.92056c-31.211862-18.71934-67.703985-29.499871-106.753349-29.499871C159.382499 467.421712 66.240145 560.549739 66.240145 675.441443z" p-id="2791"></path>
                        </svg>
                    </div>
                </button>
            </div>`;
    return buttonHtml;
  }

  function appendBtn(parentElement, newUrl, buttonHtml, classText, like, time) {
    // 创建按钮元素
    let button = document.createElement('div');
    button.setAttribute('data-nsfw', 'x');
    button.innerHTML = buttonHtml;

    // 按钮点击事件处理程序
    button.querySelector(`#copy-${classText}`).addEventListener('click', () => navigator.clipboard.writeText(newUrl));

    // 发起fetch请求获取图片内容
    button.querySelector(`#download-${classText}`).addEventListener('click', () => {
      // 根据配置决定是否自动点赞
      if (autoLike) {
        let likeDiv = like.querySelector('[data-testid="like"]');
        if (likeDiv) {
          likeDiv.click();
        }
      }

      let url = parentElement.querySelector('a').href.replace(/\/photo\/\d+$/, '');

      let date = new Date(time.getAttribute('datetime'));
      let formattedDate =
        date.getFullYear() +
        '-' +
        String(date.getMonth() + 1).padStart(2, '0') +
        '-' + // 月份从 0 开始,需要加 1
        String(date.getDate()).padStart(2, '0') +
        ' ' +
        String(date.getHours()).padStart(2, '0') +
        ':' +
        String(date.getMinutes()).padStart(2, '0') +
        ':' +
        String(date.getSeconds()).padStart(2, '0');

      fetch(newUrl)
        .then(function (response) {
          if (response.ok) {
            return response.blob(); // 以Blob形式解析响应内容
          } else {
            throw new Error('下载失败');
          }
        })
        .then(function (imageBlob) {
          // 创建一个Blob URL,用于保存图片内容
          var imageUrl = URL.createObjectURL(imageBlob);

          let urlParams = new URL(newUrl);
          // 创建一个下载链接
          var downloadLink = document.createElement('a');
          downloadLink.href = imageUrl;
          downloadLink.download =
            urlParams.pathname.substring(urlParams.pathname.lastIndexOf('/') + 1) + '.' + urlParams.searchParams.get('format');

          // 模拟用户点击下载链接
          downloadLink.click();

          // 释放Blob URL以节省内存
          URL.revokeObjectURL(imageUrl);
        })
        .catch(function (error) {
          console.error('下载失败:', error);
        });

      GM_xmlhttpRequest({
        method: 'POST',
        url: 'https://api.mossia.top/add/xPicture',
        headers: {
          'Content-Type': 'application/json',
        },
        data: JSON.stringify({
          url: url,
          pictureUrl: newUrl,
          xCreateDate: formattedDate,
          createBy: userName,
        }),
        onload: function (response) {
          let result = JSON.parse(response.responseText);
        },
        onerror: function (error) {
          console.error('Request failed:', error);
        },
      });
    });

    // 发起分享图片
    button.querySelector(`#share-${classText}`).addEventListener('click', () => {
      GM_xmlhttpRequest({
        method: 'POST',
        url: share_url, // 目标 URL
        headers: {
          'Content-Type': 'application/json',
        },
        data: JSON.stringify({
          type: 1,
          imageUrl: newUrl,
        }),
        onload: function (response) {
          var responseData = JSON.parse(response.responseText);
          console.log('Received response:', responseData);
        },
        onerror: function (error) {
          console.error('Request failed:', error);
        },
      });
    });

    parentElement.appendChild(button);
  }

  function getParentByNum(element, number) {
    let ancestor = element;
    for (let i = 0; i < number; i++) {
      if (ancestor.parentElement) {
        ancestor = ancestor.parentElement;
      } else {
        break;
      }
    }
    return ancestor;
  }

  /**
   * @param {string} urlString
   */
  function replaceImageSizeName(urlString) {
    // 替换name参数的值为"orig"
    const url = new URL(urlString);
    url.searchParams.set('name', 'orig');
    return url.toString();
  }

  /**
   * @param {number} max
   */
  function getRandomIntExclusive(max) {
    return Math.floor(Math.random() * max);
  }
})();