您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced script to track progress towards next trust level on linux.do with added search functionality, adjusted posts read limit, and a breathing icon animation.
当前为
- // ==UserScript==
- // @name Linux do Level Enhanced
- // @namespace http://tampermonkey.net/
- // @version 0.0.7
- // @description Enhanced script to track progress towards next trust level on linux.do with added search functionality, adjusted posts read limit, and a breathing icon animation.
- // @author Hua, Reno
- // @match https://linux.do/*
- // @icon https://www.google.com/s2/favicons?domain=linux.do
- // @grant none
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- const StyleManager = {
- styles: `
- @keyframes breathAnimation {
- 0%, 100% { transform: scale(1); box-shadow: 0 0 5px rgba(0,0,0,0.5); }
- 50% { transform: scale(1.1); box-shadow: 0 0 10px rgba(0,0,0,0.7); }
- }
- .breath-animation { animation: breathAnimation 4s ease-in-out infinite; }
- .minimized { border-radius: 50%; cursor: pointer; }
- .linuxDoLevelPopup { position: fixed; width: 250px; height: 150px; box-shadow: 0 0 10px rgba(0,0,0,0.5); padding: 15px; z-index: 10000; font-size: 14px; border-radius: 5px; cursor: move; }
- .linuxDoLevelPopup input, .linuxDoLevelPopup button { width: 100%; margin-top: 10px; }
- .linuxDoLevelPopup button { cursor: pointer; }
- .minimizeButton { position: absolute; top: 5px; right: 5px; background: transparent; border: none; cursor: pointer; width: 30px; height: 30px; font-size: 16px; }
- .searchButton { width: 100%; marginTop: 10px }
- .searchBox { width: 100%; marginTop: 10px }
- `,
- injectStyles: function() {
- const styleSheet = document.createElement('style');
- styleSheet.type = 'text/css';
- styleSheet.innerText = this.styles;
- document.head.appendChild(styleSheet);
- }
- };
- const DataManager = {
- ABOUT_DATA_URL: 'https://linux.do/about.json',
- USER_DATA_URL_PREFIX: 'https://linux.do/u/',
- USER_DATA_URL_SUFFIX: '/summary.json',
- FETCH_REQUEST_OPTIONS: {
- headers: { "Accept": "application/json", "User-Agent": "Mozilla/5.0" },
- method: "GET",
- },
- levelRequirements: {
- 0: { 'topics_entered': 5, 'posts_read_count': 30, 'time_read': 600 },
- 1: { 'days_visited': 15, 'likes_given': 1, 'likes_received': 1, 'post_count': 3, 'topics_entered': 20, 'posts_read_count': 100, 'time_read': 3600 },
- 2: { 'days_visited': 50, 'likes_given': 30, 'likes_received': 20, 'post_count': 10 }
- },
- levelDescriptions: {
- 0: "游客", 1: "基本用户", 2: "成员", 3: "活跃用户", 4: "领导者"
- },
- fetchAboutData: async function() {
- try {
- const response = await fetch(this.ABOUT_DATA_URL, this.FETCH_REQUEST_OPTIONS);
- if (!response.ok) throw new Error(`HTTP 错误!状态:${response.status}`);
- return await response.json();
- } catch (error) {
- UIManager.displayError("获取关于页面数据失败");
- throw error;
- }
- },
- fetchUserData: async function(username) {
- try {
- const url = `${this.USER_DATA_URL_PREFIX}${username}${this.USER_DATA_URL_SUFFIX}`;
- const response = await fetch(url, this.FETCH_REQUEST_OPTIONS);
- if (!response.ok) throw new Error(`HTTP 错误!状态:${response.status}`);
- return await response.json();
- } catch (error) {
- UIManager.displayError("获取用户数据失败");
- throw error;
- }
- }
- };
- const UIManager = {
- initPopup: function() {
- this.popup = this.createElement('div', { id: 'linuxDoLevelPopup', class: 'linuxDoLevelPopup' });
- this.content = this.createElement('div', { id: 'linuxDoLevelPopupContent' }, '欢迎使用 Linux do 等级增强插件');
- this.searchBox = this.createElement('input', { placeholder: '请输入用户名...', type: 'text', class: 'searchBox' });
- this.searchButton = this.createElement('button', { class: 'searchButton' }, '搜索');
- this.minimizeButton = this.createElement('button', { }, '隐藏');
- this.popup.style.bottom = '20px'; // 示例:距离顶部20px
- this.popup.style.right = '20px'; // 示例:距离左侧20px
- this.popup.style.width = '250px'; // 初始化宽度
- this.popup.style.height = 'auto'; // 高度自适应内容
- this.searchButton.classList.add('btn', 'btn-icon-text', 'btn-default')
- this.minimizeButton.classList.add('btn', 'btn-icon-text', 'btn-default')
- this.popup.append(this.content, this.searchBox, this.searchButton, this.minimizeButton);
- document.body.appendChild(this.popup);
- this.minimizeButton.addEventListener('click', () => this.togglePopupSize());
- this.searchButton.addEventListener('click', () => EventHandler.handleSearch());
- // 添加输入框的回车键事件监听器
- this.searchBox.addEventListener('keypress', (event) => {
- // 检查是否按下了回车键并且弹窗不处于最小化状态
- if (event.key === 'Enter' && !this.popup.classList.contains('minimized')) {
- EventHandler.handleSearch();
- }
- });
- },
- createElement: function(tag, attributes, text) {
- const element = document.createElement(tag);
- for (const attr in attributes) {
- if (attr === 'class') {
- element.classList.add(attributes[attr]);
- } else {
- element.setAttribute(attr, attributes[attr]);
- }
- }
- if (text) element.textContent = text;
- return element;
- },
- updatePopupContent: function(userSummary, user, status) {
- if (!userSummary || !user) return;
- let content = `<strong>信任等级:</strong>${DataManager.levelDescriptions[user.trust_level]}<br><strong>升级进度:</strong><br>`;
- const requirements = DataManager.levelRequirements[user.trust_level] || {};
- if (user.trust_level === 2) {
- requirements['posts_read_count'] = Math.min(parseInt(parseInt(status.posts_30_days) / 4), 20000);
- requirements['topics_entered'] = Math.min(parseInt(parseInt(status.topics_30_days) / 4), 500);
- }
- if (user.trust_level === 3) {
- content += '联系管理员以升级到领导者<br>';
- } else if (user.trust_level === 4) {
- content += '您已是最高信任等级<br>';
- } else {
- console.log(requirements)
- for (const [stat, required] of Object.entries(requirements)) {
- console.log(stat)
- console.log(required)
- const current = userSummary[stat] || 0;
- console.log(current)
- console.log(userSummary[stat])
- console.log(this.translateStat(stat))
- const color = current >= required ? "green" : "red";
- content += `${this.translateStat(stat)}: <span style="color: ${color};">${current} / ${required}</span><br>`;
- }
- }
- this.content.innerHTML = content;
- },
- togglePopupSize: function() {
- if (this.popup.classList.contains('minimized')) {
- this.popup.classList.remove('minimized');
- this.popup.style.width = '250px';
- this.popup.style.height = 'auto';
- this.content.style.display = 'block';
- this.searchBox.style.display = 'block';
- this.searchButton.style.display = 'block';
- this.minimizeButton.textContent = '隐藏';
- this.popup.classList.remove('breath-animation');
- } else {
- this.popup.classList.add('minimized');
- this.popup.style.width = '50px';
- this.popup.style.height = '50px';
- this.content.style.display = 'none';
- this.searchBox.style.display = 'none';
- this.searchButton.style.display = 'none';
- this.minimizeButton.textContent = '展开';
- this.popup.classList.add('breath-animation');
- }
- // 确保拖动时更新整个弹窗的位置而不仅是底部
- addDraggableFeature(this.popup);
- },
- displayError: function(message) {
- this.content.innerHTML = `<strong>错误:</strong>${message}`;
- },
- translateStat: function(stat) {
- const translations = {
- 'days_visited': '访问天数',
- 'likes_given': '给出的赞',
- 'likes_received': '收到的赞',
- 'post_count': '帖子数量',
- 'posts_read_count': '阅读的帖子数',
- 'topics_entered': '进入的主题数',
- 'time_read': '阅读时间(秒)'
- };
- return translations[stat] || stat;
- }
- };
- const EventHandler = {
- handleSearch: async function() {
- const username = UIManager.searchBox.value.trim();
- if (!username) return;
- try {
- const aboutData = await DataManager.fetchAboutData();
- const userData = await DataManager.fetchUserData(username);
- if (userData && aboutData) {
- UIManager.updatePopupContent(userData.user_summary, userData.users[0], aboutData.about.stats);
- }
- } catch (error) {
- console.error(error); // Already handled within data manager functions
- }
- }
- };
- // 添加拖动功能
- function addDraggableFeature(element) {
- let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
- const dragMouseDown = function(e) {
- // 检查事件的目标是否是输入框,按钮或其他可以忽略拖动逻辑的元素
- if (e.target.tagName.toUpperCase() === 'INPUT' || e.target.tagName.toUpperCase() === 'TEXTAREA' || e.target.tagName.toUpperCase() === 'BUTTON') {
- return; // 如果是,则不执行拖动逻辑
- }
- e = e || window.event;
- e.preventDefault();
- pos3 = e.clientX;
- pos4 = e.clientY;
- document.onmouseup = closeDragElement;
- document.onmousemove = elementDrag;
- };
- const elementDrag = function(e) {
- e = e || window.event;
- e.preventDefault();
- pos1 = pos3 - e.clientX;
- pos2 = pos4 - e.clientY;
- pos3 = e.clientX;
- pos4 = e.clientY;
- element.style.top = (element.offsetTop - pos2) + "px";
- element.style.left = (element.offsetLeft - pos1) + "px";
- // 为了避免与拖动冲突,在此移除bottom和right样式
- element.style.bottom = '';
- element.style.right = '';
- };
- const closeDragElement = function() {
- document.onmouseup = null;
- document.onmousemove = null;
- };
- element.onmousedown = dragMouseDown;
- }
- const init = () => {
- StyleManager.injectStyles();
- UIManager.initPopup();
- addDraggableFeature(document.getElementById('linuxDoLevelPopup')); // 确保已设置该ID
- UIManager.togglePopupSize(); // 初始最小化
- };
- init();
- })();