auto-read 自动阅读的稍加改进

基于该大佬的油猴代码修改,改进内容:

  • 使用 $.ajax() 请求 https://linux.do/latest.json?no_definitions=true&page=1 分页获取文章列表。
  • 筛选未阅读文章以及评论数较少的文章,将筛选结果存入 localStorage。
  • 文章阅读完成后读取 localStorage 中未阅读文章列表,直接进入下一篇文章,并更新 localStorage 中未阅读文章列表,即删除列表中第一个元素。
  • 当 localStorage 中未阅读文章列表为空时,请求获取下一页文章列表。
油猴代码
// ==UserScript==
// @name         Auto Read
// @namespace    http://tampermonkey.net/
// @version      1.3.1
// @description  自动刷linuxdo文章
// @author       liuweiqing
// @match        https://meta.discourse.org/*
// @match        https://linux.do/*
// @match        https://meta.appinn.net/*
// @match        https://community.openai.com/
// @grant        none
// @license      MIT
// @icon         https://www.google.com/s2/favicons?domain=linux.do
// @downloadURL https://update.greasyfork.org/scripts/489464/Auto%20Read.user.js
// @updateURL https://update.greasyfork.org/scripts/489464/Auto%20Read.meta.js
// ==/UserScript==

(function () {
  ("use strict");
  // 定义可能的基本URL
  const possibleBaseURLs = [
    "https://meta.discourse.org",
    "https://linux.do",
    "https://meta.appinn.net",
    "https://community.openai.com",
  ];

  // 获取当前页面的URL
  const currentURL = window.location.href;

  // 确定当前页面对应的BASE_URL
  let BASE_URL = possibleBaseURLs.find((url) => currentURL.startsWith(url));

  // 环境变量:阅读网址,如果没有找到匹配的URL,则默认为第一个
  if (!BASE_URL) {
    BASE_URL = possibleBaseURLs[0];
    console.log("默认BASE_URL设置为: " + BASE_URL);
  } else {
    console.log("当前BASE_URL是: " + BASE_URL);
  }

  // 以下是脚本的其余部分
  console.log("脚本正在运行在: " + BASE_URL);
  //1.进入网页 https://linux.do/t/topic/数字(1,2,3,4)
  //2.使滚轮均衡的往下移动模拟刷文章
  // 检查是否是第一次运行脚本
  function checkFirstRun() {
    if (localStorage.getItem("isFirstRun") === null) {
      // 是第一次运行,执行初始化操作
      console.log("脚本第一次运行,执行初始化操作...");
      updateInitialData();

      // 设置 isFirstRun 标记为 false
      localStorage.setItem("isFirstRun", "false");
    } else {
      // 非第一次运行
      console.log("脚本非第一次运行");
    }
  }

  // 更新初始数据的函数
  function updateInitialData() {
    localStorage.setItem("read", "false"); // 开始时自动滚动关闭
    localStorage.setItem("autoLikeEnabled", "false"); //默认关闭自动点赞
    console.log("执行了初始数据更新操作");
  }
  const delay = 2000; // 滚动检查的间隔(毫秒)
  let scrollInterval = null;
  let checkScrollTimeout = null;
  let autoLikeInterval = null;

  function scrollToBottomSlowly(
    stopDistance = 9999999999,
    callback = undefined,
    distancePerStep = 20,
    delayPerStep = 50
  ) {
    if (scrollInterval !== null) {
      clearInterval(scrollInterval);
    }
    scrollInterval = setInterval(() => {
      if (
        window.innerHeight + window.scrollY >=
        document.body.offsetHeight - 100 ||
        window.innerHeight + window.scrollY >= stopDistance
      ) {
        clearInterval(scrollInterval);
        scrollInterval = null;
        if (typeof callback === "function") {
          callback(); // 当滚动结束时调用回调函数
        }
      } else {
        window.scrollBy(0, distancePerStep);
      }
    }, delayPerStep);
  }

  // 获取最新文章列表
  function getLatestTopic() {
    let latestPage = 0;
    const latestPageStr = localStorage.getItem("latestPage");
    if (latestPageStr) {
      latestPage = Number(latestPageStr);
    }
    latestPage++;

    const url = `${BASE_URL}/latest.json?no_definitions=true&page=${latestPage}`;
    $.ajax({
      url: url,
      async: false,
      success: function (result) {
        if (result) {
          const topicList = [];
          result.topic_list.topics.forEach((topic) => {
            // 未读以及评论数小于50
            if (!topic.unseen && 50 > topic.posts_count) {
              topicList.push(topic);
            }
          });

          localStorage.setItem("latestPage", latestPage);
          localStorage.setItem("topicList", JSON.stringify(topicList));
        }
      },
      error: function (XMLHttpRequest, textStatus, errorThrown) {
        console.error(XMLHttpRequest, textStatus, errorThrown)
      }
    })
  }

  // 打开新的文章
  function openNewTopic() {
    const topicListStr = localStorage.getItem("topicList");
    if (topicListStr) {
      const topicList = JSON.parse(topicListStr);
      if (topicList && 0 < topicList.length) {
        // 从未读列表中取出第一个
        const topic = topicList.shift();
        localStorage.setItem("topicList", JSON.stringify(topicList));
        window.location.href = `${BASE_URL}/t/topic/${topic.id}`;
      } else {
        // 获取最新文章列表
        getLatestTopic();
        // 打开新的文章
        openNewTopic();
      }
    } else {
      // 获取最新文章列表
      getLatestTopic();
      // 打开新的文章
      openNewTopic();
    }
  }

  // 功能:跳转到下一个话题

  function navigateToNextTopic() {
    // 定义包含文章列表的数组
    const urls = [
      `${BASE_URL}/latest`,
      `${BASE_URL}/top`,
      `${BASE_URL}/latest?ascending=false&order=posts`,
      // `${BASE_URL}/unread`, // 示例:如果你想将这个URL启用,只需去掉前面的注释
    ];

    // 生成一个随机索引
    const randomIndex = Math.floor(Math.random() * urls.length);

    // 根据随机索引选择一个URL
    const nextTopicURL = urls[randomIndex]; // 在跳转之前,标记即将跳转到下一个话题
    localStorage.setItem("navigatingToNextTopic", "true");
    // 尝试导航到下一个话题
    window.location.href = nextTopicURL;
  }

  // 检查是否已滚动到底部(不断重复执行)
  function checkScroll() {
    if (localStorage.getItem("read")) {
      if (
        window.innerHeight + window.scrollY >=
        document.body.offsetHeight - 100
      ) {
        console.log("已滚动到底部");
        openNewTopic();
      } else {
        scrollToBottomSlowly();
        if (checkScrollTimeout !== null) {
          clearTimeout(checkScrollTimeout);
        }
        checkScrollTimeout = setTimeout(checkScroll, delay);
      }
    }
  }

  // 入口函数
  window.addEventListener("load", () => {
    checkFirstRun();
    console.log(
      "autoRead",
      localStorage.getItem("read"),
      "autoLikeEnabled",
      localStorage.getItem("autoLikeEnabled")
    );
    if (localStorage.getItem("read") === "true") {
      // 检查是否正在导航到下一个话题
      if (localStorage.getItem("navigatingToNextTopic") === "true") {
        console.log("正在导航到下一个话题");
        // 等待一段时间或直到页面完全加载
        // 页面加载完成后,移除标记
        localStorage.removeItem("navigatingToNextTopic");
        // 使用setTimeout延迟执行
        setTimeout(() => {
          openNewTopic();
        }, 2000); // 延迟2000毫秒(即2秒)
      } else {
        console.log("执行正常的滚动和检查逻辑");
        // 执行正常的滚动和检查逻辑
        checkScroll();
        if (isAutoLikeEnabled()) {
          //自动点赞
          autoLike();
        }
      }
    }
  });
  // 创建一个控制滚动的按钮
  function searchLinkClick() {
    // 在新页面加载后执行检查
    // 使用CSS属性选择器寻找href属性符合特定格式的<a>标签
    const links = document.querySelectorAll('a[href^="/t/"]');
    // const alreadyReadLinks = JSON.parse(
    //   localStorage.getItem("alreadyReadLinks") || "[]"
    // ); // 获取已阅读链接列表

    // 筛选出未阅读的链接
    const unreadLinks = Array.from(links).filter((link) => {
      // 检查链接是否已经被读过
      // const isAlreadyRead = alreadyReadLinks.includes(link.href);
      // if (isAlreadyRead) {
      //   return false; // 如果链接已被读过,直接排除
      // }

      // 向上遍历DOM树,查找包含'visited'类的父级元素,最多查找三次
      let parent = link.parentElement;
      let times = 0; // 查找次数计数器
      while (parent && times < 3) {
        if (parent.classList.contains("visited")) {
          // 如果找到包含'visited'类的父级元素,中断循环
          return false; // 父级元素包含'visited'类,排除这个链接
        }
        parent = parent.parentElement; // 继续向上查找
        times++; // 增加查找次数
      }

      // 如果链接未被读过,且在向上查找三次内,其父级元素中没有包含'visited'类,则保留这个链接
      return true;
    });

    // 如果找到了这样的链接
    if (unreadLinks.length > 0) {
      // 从所有匹配的链接中随机选择一个
      const randomIndex = Math.floor(Math.random() * unreadLinks.length);
      const link = unreadLinks[randomIndex];
      // 打印找到的链接(可选)
      console.log("Found link:", link.href);
      // // 模拟点击该链接
      // setTimeout(() => {
      //   link.click();
      // }, delay);
      // 将链接添加到已阅读列表并更新localStorage
      // alreadyReadLinks.push(link.href);
      // localStorage.setItem(
      //   "alreadyReadLinks",
      //   JSON.stringify(alreadyReadLinks)
      // );

      // 导航到该链接
      window.location.href = link.href;
    } else {
      // 如果没有找到符合条件的链接,打印消息(可选)
      console.log("No link with the specified format was found.");
      scrollToBottomSlowly(
        Math.random() * document.body.offsetHeight * 3,
        searchLinkClick
      );
    }
  }
  // 获取当前时间戳
  const currentTime = Date.now();
  // 获取存储的时间戳
  const defaultTimestamp = new Date("1999-01-01T00:00:00Z").getTime(); //默认值为1999年
  const storedTime = parseInt(
    localStorage.getItem("clickCounterTimestamp") ||
    defaultTimestamp.toString(),
    10
  );

  // 获取当前的点击计数,如果不存在则初始化为0
  let clickCounter = parseInt(localStorage.getItem("clickCounter") || "0", 10);
  // 检查是否超过24小时(24小时 = 24 * 60 * 60 * 1000 毫秒)
  if (currentTime - storedTime > 24 * 60 * 60 * 1000) {
    // 超过24小时,清空点击计数器并更新时间戳
    clickCounter = 0;
    localStorage.setItem("clickCounter", "0");
    localStorage.setItem("clickCounterTimestamp", currentTime.toString());
  }

  console.log(`Initial clickCounter: ${clickCounter}`);
  function triggerClick(button) {
    const event = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      view: window,
    });
    button.dispatchEvent(event);
  }

  function autoLike() {
    console.log(`Initial clickCounter: ${clickCounter}`);
    // 寻找所有的discourse-reactions-reaction-button
    const buttons = document.querySelectorAll(
      ".discourse-reactions-reaction-button"
    );
    if (buttons.length === 0) {
      console.error(
        "No buttons found with the selector '.discourse-reactions-reaction-button'"
      );
      return;
    }
    console.log(`Found ${buttons.length} buttons.`); // 调试信息

    // 逐个点击找到的按钮
    buttons.forEach((button, index) => {
      if (
        (button.title !== "点赞此帖子" && button.title !== "Like this post") ||
        clickCounter >= 50
      ) {
        return;
      }

      // 使用setTimeout来错开每次点击的时间,避免同时触发点击
      autoLikeInterval = setTimeout(() => {
        // 模拟点击
        triggerClick(button); // 使用自定义的触发点击方法
        console.log(`Clicked like button ${index + 1}`);
        clickCounter++; // 更新点击计数器
        // 将新的点击计数存储到localStorage
        localStorage.setItem("clickCounter", clickCounter.toString());
        // 如果点击次数达到50次,则设置点赞变量为false
        if (clickCounter === 50) {
          console.log("Reached 50 likes, setting the like variable to false.");
          localStorage.setItem("autoLikeEnabled", "false"); // 使用localStorage存储点赞变量状态
        } else {
          console.log("clickCounter:", clickCounter);
        }
      }, index * 1000); // 这里的1000毫秒是两次点击之间的间隔,可以根据需要调整
    });
  }
  const button = document.createElement("button");
  // 初始化按钮文本基于当前的阅读状态
  button.textContent =
    localStorage.getItem("read") === "true" ? "停止阅读" : "开始阅读";
  button.style.position = "fixed";
  button.style.bottom = "10px"; // 之前是 top
  button.style.left = "10px"; // 之前是 right
  button.style.zIndex = 1000;
  button.style.backgroundColor = "#f0f0f0"; // 浅灰色背景
  button.style.color = "#000"; // 黑色文本
  button.style.border = "1px solid #ddd"; // 浅灰色边框
  button.style.padding = "5px 10px"; // 内边距
  button.style.borderRadius = "5px"; // 圆角
  document.body.appendChild(button);

  button.onclick = function () {
    const currentlyReading = localStorage.getItem("read") === "true";
    const newReadState = !currentlyReading;
    localStorage.setItem("read", newReadState.toString());
    button.textContent = newReadState ? "停止阅读" : "开始阅读";
    if (!newReadState) {
      if (scrollInterval !== null) {
        clearInterval(scrollInterval);
        scrollInterval = null;
      }
      if (checkScrollTimeout !== null) {
        clearTimeout(checkScrollTimeout);
        checkScrollTimeout = null;
      }
      localStorage.removeItem("navigatingToNextTopic");
    } else {
      // 如果是Linuxdo,就导航到我的帖子
      if (BASE_URL == "https://linux.do") {
        window.location.href = "https://linux.do/t/topic/13716/191";
      } else {
        window.location.href = `${BASE_URL}/t/topic/1`;
      }
      checkScroll();
    }
  };

  //自动点赞按钮
  // 在页面上添加一个控制自动点赞的按钮
  const toggleAutoLikeButton = document.createElement("button");
  toggleAutoLikeButton.textContent = isAutoLikeEnabled()
    ? "禁用自动点赞"
    : "启用自动点赞";
  toggleAutoLikeButton.style.position = "fixed";
  toggleAutoLikeButton.style.bottom = "50px"; // 之前是 top,且与另一个按钮错开位置
  toggleAutoLikeButton.style.left = "10px"; // 之前是 right
  toggleAutoLikeButton.style.zIndex = "1000";
  toggleAutoLikeButton.style.backgroundColor = "#f0f0f0"; // 浅灰色背景
  toggleAutoLikeButton.style.color = "#000"; // 黑色文本
  toggleAutoLikeButton.style.border = "1px solid #ddd"; // 浅灰色边框
  toggleAutoLikeButton.style.padding = "5px 10px"; // 内边距
  toggleAutoLikeButton.style.borderRadius = "5px"; // 圆角
  document.body.appendChild(toggleAutoLikeButton);

  // 为按钮添加点击事件处理函数
  toggleAutoLikeButton.addEventListener("click", () => {
    const isEnabled = !isAutoLikeEnabled();
    setAutoLikeEnabled(isEnabled);
    toggleAutoLikeButton.textContent = isEnabled
      ? "禁用自动点赞"
      : "启用自动点赞";
  });
  // 判断是否启用自动点赞
  function isAutoLikeEnabled() {
    // 从localStorage获取autoLikeEnabled的值,如果未设置,默认为"true"
    return localStorage.getItem("autoLikeEnabled") !== "false";
  }

  // 设置自动点赞的启用状态
  function setAutoLikeEnabled(enabled) {
    localStorage.setItem("autoLikeEnabled", enabled ? "true" : "false");
  }
})();
8 Likes

太强了

好厉害

thalassa 通过 LINUX DO <[email protected]> 于 2024年6月7日周五 上午10:07写道:

我也来分享一个
修改的动机主要是我的使用情境是我常常做其他事,用另一个银幕滑L站,如果自动阅读新文章,可能会遗漏一些重要内容。
而推荐阅读通常都是从已读/已回覆的文章推荐,读的比较多是回帖的水楼,可以降低影响。
实际保级只需要每天200楼,故追加阈值的设计(预设350),可以减少论坛开销,同时某种程度上避免触发CF盾。

主要修改如下

  1. 由于本帖比较新,基于本帖修改
  2. 主要差别如下:
  • 新增「跳转阅读进度」当右方提示上次阅读时,从该楼开始
  • 新增阈值,可设定读多少帖停止,避免暴走
  • 新增计算已读帖数(随点赞计数重置)
  • 新增归零按钮(当你不想等点赞重置时)
  • 修改阅读完毕判断(从右侧楼层)
  • 新增选择,是否从下方建议帖子跳转
    为了降低原作运作的改变,可以直接从最上方的 readSuggestPost 变数决定。
    (更新备注:这是比较适合我的模式,如果你平常阅读的帖子不够多,请改为 false 来阅读新文章。)
    image
  • 之后预计大改版一下
  1. 详细修改项目:新增以下变数
摘要
  • readCounter
    已读数量
  • stopLimit
    读取停止阈值,代码预设 350
  • readSuggestPost
    是否使用推荐文章进入下一篇帖
  • defaultPost
    执行时预设连结,找了一篇封存文,原因是不会增加楼层,执行脚本后可以在不影响记录的前提很快触发下一篇(首篇)阅读
  • startFloor, endFloor, lastFloor
    文章右侧的楼层记录,用来计算滑了几楼,以及修改阅读完毕的判断。
  1. 新增以下函式
摘要
  • checkLastRead() => return: true / false
    检查右侧是否有回到上次阅读进度,有的话会点击。
    返回是否存在。
  • setFloor(refresh=false)
    给 startFloor endFloor 赋值,若 true 则 null,用于页面载入时正确计算已读数量。
  • setBtnText_readToday()
    按钮显示已读数量
  • check_read_limit()
    检查是否已达设定阈值,如达到则停止阅读


留意 // @version 1.3.2-fork-b

代码
// ==UserScript==
// @name         Auto Read new
// @namespace    http://tampermonkey.net/
// @version      1.3.2-fork-b
// @description  自动刷linuxdo文章
// @author       liuweiqing
// @match        https://meta.discourse.org/*
// @match        https://linux.do/*
// @match        https://meta.appinn.net/*
// @match        https://community.openai.com/
// @grant        none
// @license      MIT
// @icon         https://www.google.com/s2/favicons?domain=linux.do
// @downloadURL https://update.greasyfork.org/scripts/489464/Auto%20Read.user.js
// @updateURL https://update.greasyfork.org/scripts/489464/Auto%20Read.meta.js
// ==/UserScript==

// original post https://linux.do/t/topic/29808
// base of this fork https://linux.do/t/topic/106471

(function () {
  ("use strict");
  //set stop limit
  const stopLimit = 350;
  const readSuggestPost = true;
  const defaultPost = "https://linux.do/t/topic/53589/1501";
  const postCommentsCount = 50;// filter post under this comments, over this will PASS
  // 定义可能的基本URL
  const possibleBaseURLs = [
    "https://meta.discourse.org",
    "https://linux.do",
    "https://meta.appinn.net",
    "https://community.openai.com",
  ];

  // 获取当前页面的URL
  const currentURL = window.location.href;

  // 确定当前页面对应的BASE_URL
  let BASE_URL = possibleBaseURLs.find((url) => currentURL.startsWith(url));

  // 环境变量:阅读网址,如果没有找到匹配的URL,则默认为第一个
  if (!BASE_URL) {
    BASE_URL = possibleBaseURLs[0];
    console.log("默认BASE_URL设置为: " + BASE_URL);
  } else {
    console.log("当前BASE_URL是: " + BASE_URL);
  }

  // 以下是脚本的其余部分
  console.log("脚本正在运行在: " + BASE_URL);
  //1.进入网页 https://linux.do/t/topic/数字(1,2,3,4)
  //2.使滚轮均衡的往下移动模拟刷文章
  // 检查是否是第一次运行脚本
  function checkFirstRun() {
    if (localStorage.getItem("isFirstRun") === null) {
      // 是第一次运行,执行初始化操作
      console.log("脚本第一次运行,执行初始化操作...");
      updateInitialData();

      // 设置 isFirstRun 标记为 false
      localStorage.setItem("isFirstRun", "false");
    } else {
      // 非第一次运行
      console.log("脚本非第一次运行");
    }
  }

  // 更新初始数据的函数
  function updateInitialData() {
    localStorage.setItem("read", "false"); // 开始时自动滚动关闭
    localStorage.setItem("autoLikeEnabled", "false"); //默认关闭自动点赞
    console.log("执行了初始数据更新操作");
  }
  const delay = 2000; // 滚动检查的间隔(毫秒)
  let scrollInterval = null;
  let checkScrollTimeout = null;
  let autoLikeInterval = null;
  let lastFloor = null;
  let startFloor = null;
  let endFloor = null;

  function scrollToBottomSlowly(
    stopDistance = 9999999999,
    callback = undefined,
    distancePerStep = 20,
    delayPerStep = 50
  ) {
    if (scrollInterval !== null) {
      clearInterval(scrollInterval);
    }
    scrollInterval = setInterval(() => {
      checkLastRead() ? null : setFloor() ;
      if (
        startFloor &&
        startFloor === endFloor
        /*window.innerHeight + window.scrollY >=
        document.body.offsetHeight - 100 ||
        window.innerHeight + window.scrollY >= stopDistance*/
      ) {
        console.log("==end==");
        clearInterval(scrollInterval);
        scrollInterval = null;
        setFloor(true);
        if (typeof callback === "function") {
          callback(); // 当滚动结束时调用回调函数
        }
      } else {
        console.log("==>");
        setBtnText_readToday();
        window.scrollBy(0, distancePerStep);
        check_read_limit();
      }
    }, delayPerStep);
  }
    function checkLastRead(){
        let buttonLastRead = document.querySelector('.timeline-last-read .btn');
        if (buttonLastRead) {
            buttonLastRead.click();
            return true;
        }
        return false;
    };
    function setFloor(refresh=false){
        if(refresh){
            lastFloor = null;
            startFloor = null;
            endFloor = null;
        } else {
            let element_floor = document.querySelector('.timeline-replies');
            let floor_numbers = element_floor.textContent.trim().split(' / ');
            if(!lastFloor){
                lastFloor = startFloor;
            } else {
                readCounter += startFloor - lastFloor;
                localStorage.setItem("readCounter", readCounter.toString());
                //console.log("add read",startFloor - lastFloor," ==> ", readCounter);
                lastFloor = startFloor;
            };
            startFloor = floor_numbers[0].replace(" ","");
            endFloor = floor_numbers[1].replace(" ","");
        }

    };
    function setBtnText_readToday(){
        let btnAutoRead = document.getElementById("btnAutoRead");
        btnAutoRead.textContent = localStorage.getItem("read") === "true" ? `停止阅读 ( ${readCounter} )` : `开始阅读 ( ${readCounter} )`;
    }
    function check_read_limit(){
        if(readCounter>stopLimit){
            document.getElementById('btnAutoRead').click();
        }
    }

  // 获取最新文章列表
  function getLatestTopic() {
    let latestPage = 0;
    const latestPageStr = localStorage.getItem("latestPage");
    if (latestPageStr) {
      latestPage = Number(latestPageStr);
    }
    latestPage++;

    const url = `${BASE_URL}/latest.json?no_definitions=true&page=${latestPage}`;
    $.ajax({
      url: url,
      async: false,
      success: function (result) {
        if (result) {
          const topicList = [];
          result.topic_list.topics.forEach((topic) => {
            // 未读以及评论数小于50
            if (!topic.unseen && postCommentsCount > topic.posts_count) {
              topicList.push(topic);
            }
          });

          localStorage.setItem("latestPage", latestPage);
          localStorage.setItem("topicList", JSON.stringify(topicList));
        }
      },
      error: function (XMLHttpRequest, textStatus, errorThrown) {
        console.error(XMLHttpRequest, textStatus, errorThrown)
      }
    })
  }

  // 打开新的文章
  function openNewTopic() {
    const topicListStr = localStorage.getItem("topicList");
    let suggestPost = document.querySelector('a.raw-topic-link');//document.querySelector('.badge.badge-notification.unread-posts');
    if (suggestPost && readSuggestPost) {
        let suggestPostHerf = suggestPost.getAttribute('href');
        //suggestPost.click();
        window.location.href = suggestPostHerf;
    } else if (topicListStr) {
      const topicList = JSON.parse(topicListStr);
      if (topicList && 0 < topicList.length) {
        // 从未读列表中取出第一个
        const topic = topicList.shift();
        localStorage.setItem("topicList", JSON.stringify(topicList));
        window.location.href = `${BASE_URL}/t/topic/${topic.id}`;
      } else {
        // 获取最新文章列表
        getLatestTopic();
        // 打开新的文章
        openNewTopic();
      }
    } else {
      // 获取最新文章列表
      getLatestTopic();
      // 打开新的文章
      openNewTopic();
    }
  }

  // 功能:跳转到下一个话题

  function navigateToNextTopic() {
    // 定义包含文章列表的数组
    const urls = [
      `${BASE_URL}/latest`,
      `${BASE_URL}/top`,
      `${BASE_URL}/latest?ascending=false&order=posts`,
      // `${BASE_URL}/unread`, // 示例:如果你想将这个URL启用,只需去掉前面的注释
    ];

    // 生成一个随机索引
    const randomIndex = Math.floor(Math.random() * urls.length);

    // 根据随机索引选择一个URL
    const nextTopicURL = urls[randomIndex]; // 在跳转之前,标记即将跳转到下一个话题
    localStorage.setItem("navigatingToNextTopic", "true");
    // 尝试导航到下一个话题
    window.location.href = nextTopicURL;
  }

  // 检查是否已滚动到底部(不断重复执行)
  function checkScroll() {
    if (localStorage.getItem("read")) {
      setFloor();
      if (
        startFloor &&
        startFloor === endFloor
        /*window.innerHeight + window.scrollY >=
        document.body.offsetHeight - 100*/
      ) {
        console.log("已滚动到底部");
        openNewTopic();
      } else {
        scrollToBottomSlowly();
        if (checkScrollTimeout !== null) {
          clearTimeout(checkScrollTimeout);
        }
        checkScrollTimeout = setTimeout(checkScroll, delay);
      }
    }
  }

  // 入口函数
  window.addEventListener("load", () => {
    checkFirstRun();
    console.log(
      "autoRead",
      localStorage.getItem("read"),
      "autoLikeEnabled",
      localStorage.getItem("autoLikeEnabled")
    );
    if (localStorage.getItem("read") === "true") {
      // 检查是否正在导航到下一个话题
      if (localStorage.getItem("navigatingToNextTopic") === "true") {
        console.log("正在导航到下一个话题");
        // 等待一段时间或直到页面完全加载
        // 页面加载完成后,移除标记
        localStorage.removeItem("navigatingToNextTopic");
        // 使用setTimeout延迟执行
        setTimeout(() => {
          openNewTopic();
        }, 2000); // 延迟2000毫秒(即2秒)
      } else {
        console.log("执行正常的滚动和检查逻辑");
        // 执行正常的滚动和检查逻辑
        checkScroll();
        if (isAutoLikeEnabled()) {
          //自动点赞
          autoLike();
        }
      }
    }
  });
  // 创建一个控制滚动的按钮
  function searchLinkClick() {
    // 在新页面加载后执行检查
    // 使用CSS属性选择器寻找href属性符合特定格式的<a>标签
    const links = document.querySelectorAll('a[href^="/t/"]');
    // const alreadyReadLinks = JSON.parse(
    //   localStorage.getItem("alreadyReadLinks") || "[]"
    // ); // 获取已阅读链接列表

    // 筛选出未阅读的链接
    const unreadLinks = Array.from(links).filter((link) => {
      // 检查链接是否已经被读过
      // const isAlreadyRead = alreadyReadLinks.includes(link.href);
      // if (isAlreadyRead) {
      //   return false; // 如果链接已被读过,直接排除
      // }

      // 向上遍历DOM树,查找包含'visited'类的父级元素,最多查找三次
      let parent = link.parentElement;
      let times = 0; // 查找次数计数器
      while (parent && times < 3) {
        if (parent.classList.contains("visited")) {
          // 如果找到包含'visited'类的父级元素,中断循环
          return false; // 父级元素包含'visited'类,排除这个链接
        }
        parent = parent.parentElement; // 继续向上查找
        times++; // 增加查找次数
      }

      // 如果链接未被读过,且在向上查找三次内,其父级元素中没有包含'visited'类,则保留这个链接
      return true;
    });

    // 如果找到了这样的链接
    if (unreadLinks.length > 0) {
      // 从所有匹配的链接中随机选择一个
      const randomIndex = Math.floor(Math.random() * unreadLinks.length);
      const link = unreadLinks[randomIndex];
      // 打印找到的链接(可选)
      console.log("Found link:", link.href);
      // // 模拟点击该链接
      // setTimeout(() => {
      //   link.click();
      // }, delay);
      // 将链接添加到已阅读列表并更新localStorage
      // alreadyReadLinks.push(link.href);
      // localStorage.setItem(
      //   "alreadyReadLinks",
      //   JSON.stringify(alreadyReadLinks)
      // );

      // 导航到该链接
      window.location.href = link.href;
    } else {
      // 如果没有找到符合条件的链接,打印消息(可选)
      console.log("No link with the specified format was found.");
      scrollToBottomSlowly(
        Math.random() * document.body.offsetHeight * 3,
        searchLinkClick
      );
    }
  }
  // 获取当前时间戳
  const currentTime = Date.now();
  // 获取存储的时间戳
  const defaultTimestamp = new Date("1999-01-01T00:00:00Z").getTime(); //默认值为1999年
  const storedTime = parseInt(
    localStorage.getItem("clickCounterTimestamp") ||
    defaultTimestamp.toString(),
    10
  );

  // 获取当前的点击计数,如果不存在则初始化为0
  let clickCounter = parseInt(localStorage.getItem("clickCounter") || "0", 10);
  let readCounter = parseInt(localStorage.getItem("readCounter") || "0", 10);
  // 检查是否超过24小时(24小时 = 24 * 60 * 60 * 1000 毫秒)
  if (currentTime - storedTime > 24 * 60 * 60 * 1000) {
    // 超过24小时,清空点击计数器并更新时间戳
    clickCounter = 0;
    localStorage.setItem("clickCounter", "0");
    localStorage.setItem("readCounter", "0");
    localStorage.setItem("clickCounterTimestamp", currentTime.toString());
  }

  console.log(`Initial clickCounter: ${clickCounter},readCounter: ${readCounter}`);
  function triggerClick(button) {
    const event = new MouseEvent("click", {
      bubbles: true,
      cancelable: true,
      view: window,
    });
    button.dispatchEvent(event);
  }

  function autoLike() {
    console.log(`Initial clickCounter: ${clickCounter}`);
    // 寻找所有的discourse-reactions-reaction-button
    const buttons = document.querySelectorAll(
      ".discourse-reactions-reaction-button"
    );
    if (buttons.length === 0) {
      console.error(
        "No buttons found with the selector '.discourse-reactions-reaction-button'"
      );
      return;
    }
    console.log(`Found ${buttons.length} buttons.`); // 调试信息

    // 逐个点击找到的按钮
    buttons.forEach((button, index) => {
      if (
        (button.title !== "点赞此帖子" && button.title !== "Like this post") ||
        clickCounter >= 50
      ) {
        return;
      }

      // 使用setTimeout来错开每次点击的时间,避免同时触发点击
      autoLikeInterval = setTimeout(() => {
        // 模拟点击
        triggerClick(button); // 使用自定义的触发点击方法
        console.log(`Clicked like button ${index + 1}`);
        clickCounter++; // 更新点击计数器
        // 将新的点击计数存储到localStorage
        localStorage.setItem("clickCounter", clickCounter.toString());
        // 如果点击次数达到50次,则设置点赞变量为false
        if (clickCounter === 50) {
          console.log("Reached 50 likes, setting the like variable to false.");
          localStorage.setItem("autoLikeEnabled", "false"); // 使用localStorage存储点赞变量状态
        } else {
          console.log("clickCounter:", clickCounter);
        }
      }, index * 1000); // 这里的1000毫秒是两次点击之间的间隔,可以根据需要调整
    });
  }
  const button = document.createElement("button");
  // 初始化按钮文本基于当前的阅读状态
  button.textContent =
    localStorage.getItem("read") === "true" ? `停止阅读 ( ${readCounter} )` : `开始阅读 ( ${readCounter} )`;
  button.style.position = "fixed";
  button.style.bottom = "10px"; // 之前是 top
  button.style.left = "10px"; // 之前是 right
  button.style.zIndex = 1000;
  button.style.backgroundColor = "#f0f0f0"; // 浅灰色背景
  button.style.color = "#000"; // 黑色文本
  button.style.border = "1px solid #ddd"; // 浅灰色边框
  button.style.padding = "5px 10px"; // 内边距
  button.style.borderRadius = "5px"; // 圆角
  button.id = "btnAutoRead";
  document.body.appendChild(button);

  button.onclick = function () {
    const currentlyReading = localStorage.getItem("read") === "true";
    const newReadState = !currentlyReading;
    localStorage.setItem("read", newReadState.toString());
    button.textContent = newReadState ? `停止阅读 ( ${readCounter} )` : `开始阅读 ( ${readCounter} )`;
    if (!newReadState) {
      if (scrollInterval !== null) {
        clearInterval(scrollInterval);
        scrollInterval = null;
      }
      if (checkScrollTimeout !== null) {
        clearTimeout(checkScrollTimeout);
        checkScrollTimeout = null;
      }
      localStorage.removeItem("navigatingToNextTopic");
    } else {
      // 如果是Linuxdo,就导航到我的帖子
      if (BASE_URL == "https://linux.do") {
        window.location.href = defaultPost;
      } else {
        window.location.href = `${BASE_URL}/t/topic/1`;
      }
      checkScroll();
    }
  };

  const buttonRead = document.createElement("button");
  // 初始化按钮文本基于当前的阅读状态
  buttonRead.textContent = `清0`;
  buttonRead.style.position = "fixed";
  buttonRead.style.bottom = "90px"; // 之前是 top
  buttonRead.style.left = "10px"; // 之前是 right
  buttonRead.style.zIndex = 1000;
  buttonRead.style.backgroundColor = "#f0f0f0"; // 浅灰色背景
  buttonRead.style.color = "#000"; // 黑色文本
  buttonRead.style.border = "1px solid #ddd"; // 浅灰色边框
  buttonRead.style.padding = "5px 10px"; // 内边距
  buttonRead.style.borderRadius = "5px"; // 圆角
  buttonRead.id = "btnAutoReadReset";
  document.body.appendChild(buttonRead);

  buttonRead.onclick = function () {
      readCounter = 0;
      localStorage.setItem("readCounter", readCounter.toString());
      button.textContent =
          localStorage.getItem("read") === "true" ? `停止阅读 ( ${readCounter} )` : `开始阅读 ( ${readCounter} )`;
  };

  //自动点赞按钮
  // 在页面上添加一个控制自动点赞的按钮
  const toggleAutoLikeButton = document.createElement("button");
  toggleAutoLikeButton.textContent = isAutoLikeEnabled()
    ? "禁用自动点赞"
    : "启用自动点赞";
  toggleAutoLikeButton.style.position = "fixed";
  toggleAutoLikeButton.style.bottom = "50px"; // 之前是 top,且与另一个按钮错开位置
  toggleAutoLikeButton.style.left = "10px"; // 之前是 right
  toggleAutoLikeButton.style.zIndex = "1000";
  toggleAutoLikeButton.style.backgroundColor = "#f0f0f0"; // 浅灰色背景
  toggleAutoLikeButton.style.color = "#000"; // 黑色文本
  toggleAutoLikeButton.style.border = "1px solid #ddd"; // 浅灰色边框
  toggleAutoLikeButton.style.padding = "5px 10px"; // 内边距
  toggleAutoLikeButton.style.borderRadius = "5px"; // 圆角
  toggleAutoLikeButton.id = "btnAutoLike";
  document.body.appendChild(toggleAutoLikeButton);

  // 为按钮添加点击事件处理函数
  toggleAutoLikeButton.addEventListener("click", () => {
    const isEnabled = !isAutoLikeEnabled();
    setAutoLikeEnabled(isEnabled);
    toggleAutoLikeButton.textContent = isEnabled
      ? "禁用自动点赞"
      : "启用自动点赞";
  });
  // 判断是否启用自动点赞
  function isAutoLikeEnabled() {
    // 从localStorage获取autoLikeEnabled的值,如果未设置,默认为"true"
    return localStorage.getItem("autoLikeEnabled") !== "false";
  }

  // 设置自动点赞的启用状态
  function setAutoLikeEnabled(enabled) {
    localStorage.setItem("autoLikeEnabled", enabled ? "true" : "false");
  }
})();
4 Likes

牛(:+1:ᐛ)

好棒棒哦:heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes::heart_eyes:

1 Like

mark

666