Greasy Fork is available in English.

文学社在看着你👀

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

// ==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);
        });

    });

})();