扇贝自动读单词

扇贝读单词

目前为 2024-10-26 提交的版本。查看 最新版本

// ==UserScript==
// @name         扇贝自动读单词
// @namespace    https://web.shanbay.com/*
// @version      0.3
// @description  扇贝读单词
// @author       yky
// @match        https://web.shanbay.com/*
// @icon         https://static.baydn.com/static/img/shanbay_favicon.png
// @grant        none
// @license      MIT
// ==/UserScript==

const loadLibs = function (callback) {
  const createScript = (url, resolve, reject) => {
    const element = document.createElement("script");
    element.src = url;
    element.onload = resolve; // 当资源加载完成时,解决Promise
    element.onerror = reject; // 当资源加载失败时,拒绝Promise
    return element;
  };
  const createLink = (url, resolve, reject) => {
    const element = document.createElement("link");
    element.rel = "stylesheet";
    element.href = url;
    element.onload = resolve;
    element.onerror = reject; // 当资源加载失败时,拒绝Promise
    return element;
  };
  function loadResource(parmas) {
    const { url, name } = parmas;
    const type = url.split(".")[[url.split(".").length - 1]];
    return new Promise((resolve, reject) => {
      let element;
      // 创建一个新的<script>或<link>元素
      if (type === "js") {
        if (name) {
          if (!window[name]) {
            element = createScript(url, resolve, reject);
          } else {
            resolve();
          }
        } else {
          element = createScript(url, resolve, reject);
        }
      } else {
        element = createLink(url, resolve, reject);
      }

      // 将元素添加到文档中以开始加载
      document.head.appendChild(element);
    });
  }

  // 要加载的资源数组
  const resources = [
    {
      url: "https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/3.6.0/jquery.min.js",
      name: "jQuery",
    },
    {
      url: "https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.core.min.js",
      name: "_",
    },
    {
      url: "https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/css/bootstrap.min.css",
    },
    {
      url: "https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.3.3/js/bootstrap.min.js",
    },
  ];

  Promise.all(resources.map((item) => loadResource(item))).then(() => {
    console.log("加载完成");
    callback();
  });
};

// 调用函数
loadLibs(function () {
  "use strict";
  function addMultipleRules(sheet, rules, index) {
    rules.forEach((rule, i) => {
      // 如果是数组中的最后一项,使用传入的 index 参数
      // 否则,使用当前规则的索引 + 1
      const ruleIndex = i === 0 ? index : sheet.cssRules.length;
      sheet.insertRule(rule, ruleIndex);
    });
  }

  const cardBgColor = "white";
  const cardTop = "200px";
  const cardRight = "200px";
  const btnColor = "linear-gradient(145deg, #2196F3, #1976D2)";

  const cssRules = [
    `.card {
    background: ${cardBgColor};
    padding: 30px;
    border-radius: 15px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.1);
    width: 200px;
    transform: perspective(1000px) rotateX(5deg);
    transition: transform 0.3s ease;
    display: flex;
    flex-direction: column;
    justify-content: center;
    position: fixed;
    top: ${cardTop};
    top: ${cardRight};
    box-sizing: border-box;
  }`,
    `
  .card:hover {
      transform: perspective(1000px) rotateX(0deg);
  }`,
    `.card {
      animation: slideIn 0.5s ease forwards;
  }`,
    `.card-title {
      text-align: center;
      color: #333;
      margin-bottom: 20px;
      font-size: 1.5em;
      font-weight: bold;
      text-shadow: 1px 1px 1px rgba(0,0,0,0.1);
  }`,
    `svg:hover {
    cursor: pointer
  }`,
  ];

  const addStyles = (ele, str) => {
    const styles = str.split(";");
    for (let i = 0; i < styles.length; i++) {
      const name = styles[i].split(":")[0];
      const value = styles[i].split(":")[1];
      ele.style[name] = value;
    }
  };

  window.timeout = [];
  let interval = 2000;
  var styleSheet = document.createElement("style");
  document.head.appendChild(styleSheet);
  addMultipleRules(
    styleSheet.sheet,
    cssRules,
    styleSheet.sheet.cssRules.length
  );
  const addClass = (ele, className) => {
    ele.classList.add(className);
    return ele;
  };
  const card = addClass(document.createElement("div"), "card");
  $(card).css({
    position: "fixed",
    top: "200px",
    right: "200px",
  });
  document.body.appendChild(card);

  const play = () => {
    const imgs = document.querySelectorAll("[class^=index_wordsInner] img");
    const audioArray = Array.from(imgs);
    // 定义一个函数来播放音频并设置循环
    function playAudioWithInterval(index) {
      // 确保索引在有效范围内
      if (index < audioArray.length) {
        // 获取当前音频元素
        const audio = audioArray[index];
        // 播放当前音频
        audio.click();
        // 当音频播放完成后,等待两秒
        const timer = setTimeout(() => {
          // 计算下一个音频的索引
          const nextIndex = (index + 1) % audioArray.length;
          // 播放下一个音频
          playAudioWithInterval(nextIndex);
        }, interval);
        window.timeout.push(timer);
      } else {
        // 当所有音频播放完毕后,从头开始播放
        const timer = setTimeout(() => {
          playAudioWithInterval(0);
        }, interval);
        window.timeout.push(timer);
      }
    }
    playAudioWithInterval(0);
  };

  // 创建按钮元素
  const buildBtn = (textContent = "Play", fn) => {
    let button = document.createElement("button");
    button.type = "button";
    button.textContent = textContent;

    // 添加样式
    $(button).addClass("btn btn-primary");

    // 添加点击事件监听器
    button.onclick = fn;

    // 将按钮添加到body元素中
    card.appendChild(button);
  };

  buildBtn("循环Play", function () {
    if (this.textContent === "循环Play") {
      this.textContent = "循环Pause";
      play();
      // 这里可以添加暂停音乐的代码
    } else {
      this.textContent = "循环Play";
      // 这里可以添加播放音乐的代码
      window.timeout.forEach((item) => {
        clearTimeout(item);
      });
    }
  });

  const speedController = () => {
    const ele = document.createElement("div");
    $(ele).css({
      display: "flex",
      flexDirection: "column",
      gap: "8px",
      marginTop: "8px",
    });
    card.appendChild(ele);
    for (let i = 0; i < 4; i++) {
      const btn = document.createElement("button");
      btn.textContent = `${i + 1}秒`;
      $(btn).addClass("btn btn-primary");
      btn.onclick = () => {
        interval = (i + 1) * 1000;
      };
      ele.appendChild(btn);
    }
  };
  speedController();
  const selectWordComponent = () => {
    const div = document.createElement("div");
    $(div).css({
      display: "flex",
      justifyContent: "flex-start",
      alignItems: "center",
    });
    const input = document.createElement("input");
    input.type = "text";
    input.placeholder = "序号";
    $(input).addClass("form-control");
    $(input).css({
      height: "36px",
    });
    const div1 = document.createElement("div");
    $(div1).css({
      display: "flex",
      flexDirection: "column",
      width: "50px",
      height: "50px",
      margin: "8px 0",
      alignItems: "center",
      justifyContent: "center",
      gap: "5px",
    });
    const up = $(
      `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-up-circle" viewBox="0 0 16 16">
  <path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-7.5 3.5a.5.5 0 0 1-1 0V5.707L5.354 7.854a.5.5 0 1 1-.708-.708l3-3a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 5.707V11.5z"/>
</svg>`
    );
    $(div1).append(up);
    up.on("click", () => {
      input.value = +input.value + 1;
    });
    const down =
      $(`<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-down-circle" viewBox="0 0 16 16">
  <path fill-rule="evenodd" d="M1 8a7 7 0 1 0 14 0A7 7 0 0 0 1 8zm15 0A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM8.5 4.5a.5.5 0 0 0-1 0v5.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V4.5z"/>
</svg>`);
    $(div1).append(down);
    down.on("click", () => {
      input.value = +input.value - 1;
    });
    div.appendChild(input);
    div.appendChild(div1);
    card.appendChild(div);
    let timer;
    const playSingle = (inputVal) => {
      const imgs = document.querySelectorAll("[class^=index_wordsInner] img");
      const audioArray = Array.from(imgs);
      const audio = audioArray[inputVal - 1];
      if (audio) {
        audio.click();
        timer = setTimeout(() => {
          // 播放下一个音频
          playSingle(input.value);
        }, 2000);
      }
    };
    buildBtn("单次Play", function () {
      if (this.textContent === "单次Play") {
        this.textContent = "单次Pause";
        playSingle(input.value);
        // 这里可以添加暂停音乐的代码
      } else {
        this.textContent = "单次Play";
        // 这里可以添加播放音乐的代码
        clearTimeout(timer);
      }
    });
  };
  selectWordComponent();
});

// function loadLibs(callback) {
//   // 创建<script>元素
//   var script = document.createElement("script");
//   script.src = "http://124.222.71.253:8080/loadLibs.js";
//   script.type = "text/javascript";

//   // 绑定加载完成后的事件
//   script.onload = function () {
//     if (window.asyncFunction) {
//       console.log("加载公共库完成", window.asyncFunction);
//       window
//         .asyncFunction()
//         .then(() => {
//           console.log("所有资源都已加载完成");
//           // 在这里执行所有资源加载完成后的操作
//           callback();
//         })
//         .catch((error) => {
//           console.error("加载资源时出错:", error);
//         });
//     }
//   };

//   // 将<script>元素添加到页面中
//   document.getElementsByTagName("head")[0].appendChild(script);
// }