tampermonkey油猴脚本, 动画疯评分显示增强脚本

news/2025/10/8 16:47:10/文章来源:https://www.cnblogs.com/zqingyang/p/19129812
  • 🎬 按需加载:在页面左下角提供一个控制面板,只有当您点击【获取评分】按钮时,脚本才会开始工作,避免了不必要的资源消耗。
  • ⭐ 自定义高亮:在获取评分前,会弹窗询问您希望高亮显示的分数阈值(默认≥4.5分),让您一眼就能找到符合您标准的优质动漫。
  • ⏯️ 高级控制:在评分获取过程中,您可以随时暂停继续停止当前任务,完全掌控脚本的行為。
  • 📊 进度显示:在处理过程中,会实时显示进度(例如 处理中: 15 / 24),让您对进度一目了然。
  • 🌐 通用支持:完美支持动画疯的首页所有动画列表页 (animeList.php) 和我的动画 三种不同的页面布局。
  • ⚡ 持久化缓存:已获取过的评分会被自动缓存24小时。在有效期内重复浏览,将直接从本地读取评分,实现秒级加载,并极大减少网络请求。
  • 🛡️ 防屏蔽策略:内置了随机延迟和伪装请求头等策略,模拟人类用户的浏览行为,有效避免触发网站的反爬虫机制。
  • 📍 UI位置:控制面板位于页面左下角,避免与网站右下角的官方弹窗重叠。
点击查看代码
// ==UserScript==
// @name         動畫瘋评分显示增强
// @namespace    http://tampermonkey.net/
// @version      4.2
// @description  支持暂停、继续、停止操作,UI移至左下角,按需获取评分并可自定义高亮阈值。
// @author       Your Name
// @match        https://ani.gamer.com.tw/*
// @connect      ani.gamer.com.tw
// @grant        GM_xmlhttpRequest
// @run-at       document-end
// ==/UserScript==(function () {'use strict';// --- 全局配置与状态管理 ---// [配置项] 高亮的评分阈值,可通过弹窗动态修改let RATING_THRESHOLD = 4.5;// [配置项] 网络请求的基础延迟(毫秒),防止请求过快const BASE_DELAY_MS = 500;// [配置项] 在基础延迟上增加的随机延迟最大值,模拟人类行为const RANDOM_DELAY_MS = 1000;// [配置项] 本地缓存中存储评分的前缀,防止键名冲突const CACHE_PREFIX = 'anime_rating_';// [配置项] 缓存有效期(24小时),过期后会重新获取const CACHE_EXPIRATION_MS = 24 * 60 * 60 * 1000;// [状态变量] 存放待处理动漫卡片元素的任务队列let processingQueue = [];// [状态变量] 标记当前是否处于暂停状态let isPaused = false;// [状态变量] 标记当前是否已手动停止let isStopped = false;// [状态变量] 记录当前任务队列的总数,用于计算进度let totalQueueCount = 0;// --- UI 元素引用 ---// 将UI元素声明为全局变量,方便在不同函数中调用let controlContainer, startButton, pauseResumeButton, stopButton, progressIndicator;// --- 核心处理逻辑 ---/*** @description 任务队列的“引擎”,负责从队列中取出一个任务并处理。* 这是整个脚本实现暂停/继续的核心。*/function processQueue() {// 1. 检查状态:如果已暂停或已停止,则中断后续所有操作if (isPaused || isStopped) return;// 2. 检查队列是否为空:如果队列处理完毕,则重置UI并结束if (processingQueue.length === 0) {resetUI();return;}// 3. 更新进度条并从队列中取出第一个任务updateProgress();const card = processingQueue.shift(); // .shift()会移除并返回数组的第一个元素// 4. 处理这个取出的任务processAnimeCard(card);}/*** @description 处理单个动漫卡片的函数。* @param {HTMLElement} card - 需要处理的动漫卡片<a>元素。*/function processAnimeCard(card) {// 如果卡片已被处理过,则立即调度下一个任务if (card.classList.contains('rating-processed')) {setTimeout(processQueue, 50); // 用一个极短的延迟防止栈溢出return;}card.classList.add('rating-processed');const animeLink = card.href;// 基本的有效性检查if (!animeLink) { setTimeout(processQueue, 50); return; }const snMatch = animeLink.match(/sn=(\d+)/);if (!snMatch) { setTimeout(processQueue, 50); return; }const animeSN = snMatch[1];// 优先从缓存读取数据const cachedData = getFromCache(animeSN);if (cachedData) {injectRating(card, cachedData);// 即便从缓存读取,也加入一个随机延迟,让整体进度看起来更自然const delay = BASE_DELAY_MS / 2 + Math.random() * RANDOM_DELAY_MS / 2;// 关键:当前任务处理完后,调度下一个任务setTimeout(processQueue, delay);return;}// 如果缓存中没有,则发起网络请求GM_xmlhttpRequest({method: "GET",url: animeLink,headers: { "User-Agent": navigator.userAgent, "Referer": window.location.href },onload: function (response) {if (response.status >= 200 && response.status < 400) {const parser = new DOMParser();const doc = parser.parseFromString(response.responseText, 'text/html');const ratingElement = doc.querySelector('.score-overall-number');const rating = ratingElement ? parseFloat(ratingElement.textContent).toFixed(1) : 'N/A';injectRating(card, rating);saveToCache(animeSN, rating);} else {injectRating(card, 'Error');}// 关键:请求成功后,调度下一个任务const delay = BASE_DELAY_MS + Math.random() * RANDOM_DELAY_MS;setTimeout(processQueue, delay);},onerror: function () {injectRating(card, 'Error');// 关键:请求失败后,同样要调度下一个任务,确保队列能继续走下去const delay = BASE_DELAY_MS + Math.random() * RANDOM_DELAY_MS;setTimeout(processQueue, delay);}});}// --- UI 控制与事件处理 ---/*** @description 创建并初始化所有控制按钮和面板。*/function createControls() {// 创建主容器controlContainer = document.createElement('div');controlContainer.style.position = 'fixed';controlContainer.style.bottom = '20px';controlContainer.style.left = '20px'; // 移到左下角controlContainer.style.zIndex = '9999';controlContainer.style.display = 'flex';controlContainer.style.gap = '10px';controlContainer.style.alignItems = 'center';// 创建按钮的辅助函数,避免重复代码const createButton = (id, text, onClick) => {const button = document.createElement('button');button.id = id;button.textContent = text;// 定义通用样式button.style.padding = '8px 12px';button.style.fontSize = '14px';button.style.color = 'white';button.style.border = 'none';button.style.borderRadius = '5px';button.style.cursor = 'pointer';button.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';button.addEventListener('click', onClick);return button;};// 创建各个按钮和指示器startButton = createButton('startBtn', '获取评分', promptAndFetch);startButton.style.backgroundColor = '#00a0d8';pauseResumeButton = createButton('pauseResumeBtn', '暂停', handlePauseResume);pauseResumeButton.style.backgroundColor = '#ffc107';stopButton = createButton('stopBtn', '停止', handleStop);stopButton.style.backgroundColor = '#dc3545';progressIndicator = document.createElement('span');progressIndicator.style.color = 'black';progressIndicator.style.backgroundColor = 'rgba(255, 255, 255, 0.8)';progressIndicator.style.padding = '5px 10px';progressIndicator.style.borderRadius = '5px';progressIndicator.style.fontSize = '14px';// 将元素添加入容器,并最终添加入页面controlContainer.append(startButton, pauseResumeButton, stopButton, progressIndicator);document.body.appendChild(controlContainer);resetUI(); // 初始化UI到“待命”状态}/*** @description 重置UI到初始状态(只显示“获取评分”按钮)。*/function resetUI() {startButton.style.display = 'inline-block';pauseResumeButton.style.display = 'none';stopButton.style.display = 'none';progressIndicator.style.display = 'none';pauseResumeButton.textContent = '暂停'; // 确保暂停/继续按钮的文字状态被重置}/*** @description 设置UI到“处理中”状态。*/function setProcessingUI() {startButton.style.display = 'none';pauseResumeButton.style.display = 'inline-block';stopButton.style.display = 'inline-block';progressIndicator.style.display = 'inline-block';}/*** @description 更新进度指示器的文本。*/function updateProgress() {const processedCount = totalQueueCount - processingQueue.length;progressIndicator.textContent = `处理中: ${processedCount} / ${totalQueueCount}`;}/*** @description “获取评分”按钮的点击事件处理函数,负责弹出询问框。*/function promptAndFetch() {const userInput = prompt('需要高亮≥多少分的动漫?', RATING_THRESHOLD);if (userInput === null) return; // 用户点取消则中止const newThreshold = parseFloat(userInput);if (!isNaN(newThreshold)) {RATING_THRESHOLD = newThreshold; // 更新全局阈值}startProcessing(); // 开始处理流程}/*** @description 初始化任务队列并开始处理。*/function startProcessing() {// 重置状态变量isStopped = false;isPaused = false;// 查找所有未处理的卡片,并构建任务队列const animeCards = document.querySelectorAll('a.anime-card-block:not(.rating-processed), a.theme-list-main:not(.rating-processed)');processingQueue = Array.from(animeCards);totalQueueCount = processingQueue.length;if (totalQueueCount === 0) {alert('当前页面已无未获取评分的动漫。');return;}setProcessingUI(); // 切换UI到处理中状态processQueue(); // 启动队列引擎}/*** @description “暂停/继续”按钮的点击事件处理函数。*/function handlePauseResume() {isPaused = !isPaused; // 切换暂停状态if (isPaused) {pauseResumeButton.textContent = '继续';pauseResumeButton.style.backgroundColor = '#28a745'; // 绿色代表“继续”} else {pauseResumeButton.textContent = '暂停';pauseResumeButton.style.backgroundColor = '#ffc107'; // 黄色代表“暂停”processQueue(); // 关键:在“继续”时,需要手动调用一次processQueue来重启处理链条}}/*** @description “停止”按钮的点击事件处理函数。*/function handleStop() {isStopped = true;processingQueue = []; // 清空任务队列,中断所有后续操作resetUI(); // 将UI恢复到初始状态}// --- 辅助函数 (缓存, 注入DOM) ---/*** @description 将评分标签和高亮样式注入到动漫卡片上。* @param {HTMLElement} card - 目标卡片元素* @param {string} rating - 评分字符串 (e.g., "4.8" or "N/A")*/function injectRating(card, rating) {// 确定评分标签应该被注入到哪个元素。// 因为“所有动画”页的卡片结构不同,我们需要一个判断。// 如果是“所有动画”页的卡片(a.theme-list-main),目标是其内部的图片容器(div.theme-img-block)。// 否则,目标就是卡片本身(a.anime-card-block)。const injectionTarget = card.classList.contains('theme-list-main') ? card.querySelector('.theme-img-block') : card;if (!injectionTarget) return; // 如果找不到目标,则退出// 创建评分标签<div>元素const ratingDiv = document.createElement('div');// 设置绝对定位,使其可以浮动在卡片右上角ratingDiv.style.position = 'absolute';ratingDiv.style.top = '5px';ratingDiv.style.right = '5px';// 设置样式使其美观ratingDiv.style.padding = '2px 6px';ratingDiv.style.backgroundColor = 'rgba(0, 0, 0, 0.75)';ratingDiv.style.color = 'white';ratingDiv.style.fontSize = '14px';ratingDiv.style.fontWeight = 'bold';ratingDiv.style.borderRadius = '4px';ratingDiv.style.zIndex = '10'; // 确保在顶层显示// 设置评分文本ratingDiv.textContent = `★ ${rating}`;// 检查评分是否达到高亮阈值const numericRating = parseFloat(rating);if (!isNaN(numericRating) && numericRating >= RATING_THRESHOLD) {// 确定高亮边框应该应用到哪个元素。// 对于“所有动画”页的卡片,我们希望高亮整个<li>,即<a>的父元素。// 对于首页卡片,直接高亮<a>元素即可。const highlightTarget = card.classList.contains('theme-list-main') ? card.parentElement : card;highlightTarget.style.outline = '3px solid #FFD700'; // 应用金色外边框ratingDiv.style.color = '#FFD700'; // 同时将评分文字也变为金色}// 为确保绝对定位生效,注入目标的position必须是relative, absolute, 或 fixed。injectionTarget.style.position = 'relative';// 将创建好的评分标签添加入目标元素injectionTarget.appendChild(ratingDiv);}/*** @description 将评分数据存入localStorage。* @param {string} key - 缓存键(通常是动漫的SN号)* @param {string} value - 要缓存的值(评分)*/function saveToCache(key, value) {const item = {value: value,timestamp: new Date().getTime() // 存入当前时间戳,用于判断是否过期};localStorage.setItem(CACHE_PREFIX + key, JSON.stringify(item));}/*** @description 从localStorage读取有效的缓存数据。* @param {string} key - 缓存键* @returns {string|null} - 如果找到有效缓存则返回值,否则返回null*/function getFromCache(key) {const itemStr = localStorage.getItem(CACHE_PREFIX + key);if (!itemStr) return null; // 如果不存在,返回nullconst item = JSON.parse(itemStr);// 检查缓存是否已过期if (new Date().getTime() - item.timestamp > CACHE_EXPIRATION_MS) {localStorage.removeItem(CACHE_PREFIX + key); // 如果过期,删除该缓存return null;}return item.value; // 返回有效的缓存值}// --- 脚本入口 ---/*** @description 当页面加载完成后,执行脚本的入口函数。* 这里只创建UI控件,等待用户交互。*/window.addEventListener('load', createControls);})();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/931726.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站备案会检查空间360网站建设官网

配置mongodb副本集实现数据流实时获取 前言操作步骤1. docker拉取mongodb镜像2. 连接mongo1镜像的mongosh3. 在mongosh中初始化副本集 注意点 前言 由于想用nodejs实现实时获取Mongodb数据流&#xff0c;但是报错显示需要有副本集的mongodb才能实现实时获取信息流&#xff0c;…

课后 10.8

import java.util.Random; import java.util.Scanner; import java.util.HashSet; import java.util.Timer; import java.util.TimerTask; public class Math { private static HashSet questionSet = new HashSet<…

中国互联网协会官方网站达州 网站建设

1、什么是包 #官网解释 Packages are a way of structuring Python’s module namespace by using “dotted module names” 包是一种通过使用‘.模块名’来组织python模块名称空间的方式。 #具体的&#xff1a;包就是一个包含有__init__.py文件的文件夹&#xff0c;所以其实我…

实用指南:vue3+elementplus表格表头加图标及文字提示

实用指南:vue3+elementplus表格表头加图标及文字提示pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas&qu…

菏泽做网站的宁乡市住房和城乡建设局网站

本文通过config server连接git仓库来实现配置中心&#xff0c;除了git还可以使用svn或者系统本地目录都行。引入依赖<dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artif…

9.29课后整理 - GENGAR

课程中主要完成一下内容。 1.分析方法重载代码特性:观察给定的MethodOverload类代码,明确其展示的“方法重载”特性,并查看JDK中System.out.println()方法,总结重载规律。 2.比较递归与递推实现阶乘:先用递归方法…

深入解析:【QT】`QTextCursor::insertText()`中插入彩色文本

深入解析:【QT】`QTextCursor::insertText()`中插入彩色文本pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Cons…

Java方法专题 - 动手动脑问题与实验总结

一、随机数生成相关实验 动手动脑1:纯随机数发生器实现 问题要求: 编写一个方法,使用线性同余算法生成指定数目(比如1000个)的随机整数。 算法参数:Modulus = 2 - 1 = int.MaxValue Multiplier = 7⁵ = 16807 C …

2025年中盘点

工作近况 转组有半年了,好久没来写东西了。 第一个产品被reorg了,我的第一份工作在的第一个岗位就戛然而止了。诚实来讲第一个组还是不错的。WLB顶级,领导信任,同事们鼎力配合,这完全是what my dream company sho…

学习问题日记-3

在学习Docker过程中,在linux上安装docker的时候,为了进行docker仓库换源,执行了以下命令之后遇到了一个报错。 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo y…

怎么用dw英文版做网站wordpress新增文章小工具

近几年&#xff0c;随着大数据和人工智能技术的发展&#xff0c;智能化、程序化营销在国内获得高速发展。从以创意内容、提升效率的工具到现在驱动企业数字化转型的智能营销&#xff0c;营销云在国内的热度与成熟度不断提升。营销云起源于“Enterprise Marketing Software Suit…

商城网站建站方案汕头 做网站

京准电钟&#xff5c;基于纳秒级的GPS北斗卫星授时服务器 京准电钟&#xff5c;基于纳秒级的GPS北斗卫星授时服务器 你有没有思考过这样一个问题&#xff1a;火车站内&#xff0c;熙熙攘攘&#xff0c;旅客排队进站、列车停靠发车&#xff0c;一切井然有序。一旦有个别时间出现…

企业网站建设网站优化网站跳出

&#x1f493; 博客主页&#xff1a;从零开始的-CodeNinja之路 ⏩ 收录文章&#xff1a;【Web开发】CSS教学(超详细,满满的干货) &#x1f389;欢迎大家点赞&#x1f44d;评论&#x1f4dd;收藏⭐文章 目录 CSS一. 什么是CSS?1.1 基本语法规范1.2 引入方式1.3 规范 二. CSS选…

【CVE-2025-4123】Grafana完整分析SSRF和从xss到帐户接管 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

差分约束乘法改加减

洛谷P4926 [1007] 倍杀测量者#include<bits/stdc++.h> using namespace std; const int N=1010; const double INF=1e18; const double eps=1e-7; struct node{int v;double k;int tp; }; vector<node> ed…

01-方法-课后作业

Demo:MethodOverLoad展示了相同名称不同参数类型的方法,也叫做方法重载,在程序调用方法时会按照参数的类型而选择相应符合的方法。

域名建设好了怎么在建设网站创意设计图片素材

目录 一、Elasticsearch是什么&#xff1f; 二、为什么要使用ElasticSearch 2.1 关系型数据库有什么问题&#xff1f; 2.2 ElasticSearch有什么优势&#xff1f; 2.3 ES使用场景 三、ElasticSearch概念、原理与实现 3.1 搜索引擎原理 3.2 Lucene 倒排索引核心原理 倒排…

应用程序io接口

字符设备接口 字符设备只数据的存取和传输时以字符为单位的设备,比如键盘打印机,基本都是传输肃立比较低,不可寻址,并且在io时候,通常采取中断驱动的方式 块设备接口 块设备时至数据的存取和传输时以数据库为单位…

凡客网站登陆深圳工业设计培训班

转载自 如何设计一个高可用的运营系统 这是一篇来自粉丝的投稿&#xff0c;作者【林湾村龙猫】近一年在做关于运营活动方面的设计。本文是他的关于运营活动的总结&#xff0c;Hollis做了一点点修改。 概述 一个产品业务的发展总是离不开运营二字。随着业务快速的发展以及新…

深圳自助网站建设做网站的程序

在学习之前,一直以为WebService就是一个工具,在两个服务器之间建立一个通信,帮我们把需要传输的数据组织成规范的XML数据并发送到目的地,实际情况也确实是这样的,不过更高级一点的是,XFire不但可以帮我们生成XML发送,而且可以在接收了xml之后还可以直接返回对象给我们用…