Greasy Fork

来自缓存

Greasy Fork is available in English.

文学社在看着你👀

在你的浏览器上添加文学社所有女生的Q版形象

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         文学社在看着你👀
// @namespace    https://world.xiaomawang.com/w/person/project/all/3267489
// @version      2.0.0
// @description  在你的浏览器上添加文学社所有女生的Q版形象
// @author       茶铭
// @match        *://*/*
// @icon           https://ddlc.moe/images/favicon.ico
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const imageUrls = [
        "https://ddlc.moe/images/sticker_s.png",
        "https://ddlc.moe/images/sticker_y.png",
        "https://ddlc.moe/images/sticker_m.png",
        "https://ddlc.moe/images/sticker_n.png"
    ];

    const alternativeImageUrls = [
        "https://img.qovv.cn/2024/04/20/66230b7098aac.png",
        "https://img.qovv.cn/2024/04/20/66230b748295a.png",
        "https://img.qovv.cn/2024/04/20/66230b6924394.png",
        "https://img.qovv.cn/2024/04/20/66230b6c47129.png"
    ];

    const links = [
        "https://chat.monika.love/",
        "https://wiki.monika.love/index.php?title=%E9%A6%96%E9%A1%B5",
        "https://disk.monika.love/",
        "https://forum.monika.love/"
    ];

const descriptions = [
    "DCC chat",
    "DCC wiki",
    "莫盘",
    "心跳文学部中文论坛"
];

const name = [
    "纱世里",
    "优里",
    "莫妮卡",
    "夏树"
];

const characterKeywords = [
    {
        name: "纱世里",
        keywords: [
            "快乐", "悲伤", "死亡", "悲剧", "孤独", "爱情", "冒险", "甜蜜", "刺激", "烟花",
            "浪漫", "泪水", "压抑", "心声", "婚姻", "激情", "童年", "乐趣", "色彩", "希望",
            "朋友", "家庭", "聚会", "度假", "懒惰", "做白日梦", "痛苦", "假日", "床", "羽毛",
            "羞耻", "恐惧", "温暖", "花朵", "舒适", "跳舞", "唱歌", "哭泣", "笑", "黑暗",
            "晴天", "雨云", "平静", "傻傻的", "飞翔", "美妙", "单相思", "玫瑰", "在一起",
            "承诺", "魅力", "美丽", "欢呼", "微笑", "破碎", "珍贵", "祈祷", "笨拙", "原谅",
            "自然", "海洋", "耀眼", "特别", "音乐", "幸运", "不幸", "响亮", "夕阳", "萤火虫",
            "彩虹", "受伤", "游戏", "闪光", "伤痕", "空空如也", "了不起", "悲伤", "拥抱",
            "非同寻常", "令人敬畏", "失败", "绝望", "痛苦", "宝藏", "幸福", "回忆"
        ]
    },
    {
        name: "夏树",
        keywords: [
            "蓬松", "纯洁", "糖果", "购物", "小狗", "小猫咪", "云朵", "口红", "冻糕", "草莓味",
            "粉红色", "巧克力", "心跳", "亲吻", "旋律", "丝带", "蹦蹦跳跳", "嘟嘟嘟", "卡哇伊",
            "裙子", "脸颊", "电子邮件", "黏黏的", "蹦蹦跳跳", "闪闪发光", "轻咬", "幻想", "发糖",
            "咯咯笑", "棉花糖", "跳一跳", "跳跃", "和平", "旋转", "旋转", "棒棒糖", "噗噗", "泡泡",
            "耳语", "夏天", "瀑布", "泳装", "香草", "耳机", "游戏机", "袜子", "头发", "操场",
            "睡衣", "毛毯", "牛奶", "噘嘴", "生气", "爸爸", "情人节礼物", "老鼠", "吹口哨",
            "啵啵", "兔子", "动画片", "跳跃"
        ]
    },
    {
        name: "优里",
        keywords: [
            "决心", "自杀", "想象力", "秘密", "活力", "存在", "发光", "深红色", "旋风", "残影",
            "眩晕", "迷失方向", "本质", "氛围", "星景", "混乱", "污染", "智力", "分析", "熵",
            "活泼", "不可思议", "不协调", "愤怒", "天真", "屠杀", "哲学", "善变", "顽强", "灵气",
            "不稳定", "地狱", "无能", "命运", "无懈可击", "痛苦", "变异", "无法控制", "极端",
            "逃离", "梦境", "灾难", "生动", "生机勃勃", "疑问", "发酵", "审判", "牢笼", "爆炸",
            "快感", "欲望", "感觉", "高潮", "电流", "不承认", "鄙视", "无限", "永恒", "时间",
            "宇宙", "永无止境", "雨滴", "觊觎", "无拘无束", "风景", "肖像", "旅程", "微薄",
            "焦虑", "惊恐", "恐怖", "忧郁", "洞察力", "赎罪", "呼吸", "俘虏", "欲望", "墓地"
        ]
    },
    {
        name: "莫妮卡",
        keywords: ["莫妮卡"] // 没错老莫真就这一个词)
    }
];


const images = [];
const imagePositions = [];
let isJumpPaused = false;

function toggleImageVisibility(index) {
    return function () {
        const img = images[index];
        img.style.display = img.style.display === 'none' ? 'block' : 'none';
        // 保存隐藏状态到本地存储
        localStorage.setItem(`imageVisibility_${index}`, img.style.display);
    };
}

function createImage(url, link, description, x) {
    const a = document.createElement('a');
    a.href = link;
    a.title = `前往 ${description}`;

    const img = document.createElement('img');
    img.src = url;
    img.style.position = 'fixed';
    img.style.bottom = '0';
    img.style.left = `${x}px`;
    img.style.zIndex = '9999';

    // 从本地存储中获取隐藏状态并设置
    const index = images.length;
    const visibility = localStorage.getItem(`imageVisibility_${index}`);
    if (visibility === 'none') {
        img.style.display = 'none';
    }

    a.appendChild(img);
    document.body.appendChild(a);

    return img;
}

function registerMenuCommands() {
    for (let i = 0; i < name.length; i++) {
        GM_registerMenuCommand(`隐藏/显示 ${name[i]}`, toggleImageVisibility(i));
    }
}

registerMenuCommands();



function startJumpAnimation() {
    if (isJumpPaused) return;
    const visibleImages = images.filter(img => img.style.display !== 'none');
    if (visibleImages.length === 0) return; // 如果没有可见图片,则不执行跳跃动画

    const randomIndex = Math.floor(Math.random() * visibleImages.length);
    jumpAnimation(visibleImages[randomIndex], true); // 只执行大跳事件

    const randomInterval = Math.floor(Math.random() * 3000) + 3000;
    setTimeout(startJumpAnimation, randomInterval);
}

function jumpAnimation(img, isBigJump) {
    const jumpHeight = isBigJump ? 100 : 50; // 调整第一次触底反弹的高度
    const jumpDuration = isBigJump ? 1000 : 0; // 增加跳跃速度

    img.animate([
        { transform: 'translateY(0)', },
        { transform: `translateY(-${jumpHeight}px)`, offset: 0.3 }, // 触底反弹
        { transform: 'translateY(0)', offset: 0.6 }, // 再次落地
        { transform: `translateY(-${jumpHeight / 2}px)`, offset: 0.8 }, // 落地前稍微反弹一次
        { transform: 'translateY(0)', offset: 1 }
    ], {
        duration: jumpDuration,
        easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
        iterations: 1
    });
}

    function checkOverlap(x) {
        for (let i = 0; i < imagePositions.length; i++) {
            const position = imagePositions[i];
            if (Math.abs(x - position) <= 100) {
                return true;
            }
        }
        return false;
    }

    function generateRandomX() {
        let x = Math.floor(Math.random() * (window.innerWidth - 100));
        while (checkOverlap(x)) {
            x = Math.floor(Math.random() * (window.innerWidth - 100));
        }
        return x;
    }

    window.addEventListener('load', () => {
        imageUrls.forEach((url, index) => {
            const x = generateRandomX();
            const img = createImage(url, links[index], descriptions[index], x);
            images.push(img);
            imagePositions.push(x);
        });

        startJumpAnimation();

        function checkCopiedText(text) {
            for (let i = 0; i < characterKeywords.length; i++) {
                const character = characterKeywords[i];
                for (let j = 0; j < character.keywords.length; j++) {
                    if (text.includes(character.keywords[j])) {
                        const index = name.indexOf(character.name);
                        if (index !== -1 && !isJumpPaused) {
                            images[index].src = alternativeImageUrls[index];
                            jumpAnimation(images[index], true);
                            isJumpPaused = true;
                            setTimeout(() => {
                                images[index].src = imageUrls[index];
                                isJumpPaused = false;
                            }, 1000);
                        }
                        return; // 只触发一个角色的大跳事件
                    }
                }
            }
        }

        document.addEventListener('copy', event => {
            const copiedText = window.getSelection().toString();
            checkCopiedText(copiedText);
        });

    });

})();