Greasy Fork

文学社在看着你👀

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

目前为 2024-04-20 提交的版本。查看 最新版本

// ==UserScript==
// @name         文学社在看着你👀
// @namespace    https://world.xiaomawang.com/w/person/project/all/3267489
// @version      1.9
// @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 images = [];
    const imagePositions = [];

    let isJumpPaused = false;

    function toggleImageVisibility(index) {
        return function() {
            const img = images[index];
            img.style.display = img.style.display === 'none' ? 'block' : 'none';
        };
    }

    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';
        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;
    }

    function startJumpAnimation() {
        if (isJumpPaused) return;
        const randomIndex = Math.floor(Math.random() * images.length);
        jumpAnimation(images[randomIndex], true); // 只执行大跳事件

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

    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();

        document.addEventListener('keydown', event => {
            if (event.key === '1' && !isJumpPaused) {
                images[0].src = alternativeImageUrls[0];
                jumpAnimation(images[0], true);
                isJumpPaused = true;
                setTimeout(() => {
                    images[0].src = imageUrls[0];
                    isJumpPaused = false;
                }, 1000);
            }
            if (event.key === '2' && !isJumpPaused) {
                images[1].src = alternativeImageUrls[1];
                jumpAnimation(images[1], true);
                isJumpPaused = true;
                setTimeout(() => {
                    images[1].src = imageUrls[1];
                    isJumpPaused = false;
                }, 1000);
            }
            if (event.key === '3' && !isJumpPaused) {
                images[2].src = alternativeImageUrls[2];
                jumpAnimation(images[2], true);
                isJumpPaused = true;
                setTimeout(() => {
                    images[2].src = imageUrls[2];
                    isJumpPaused = false;
                }, 1000);
            }
            if (event.key === '4' && !isJumpPaused) {
                images[3].src = alternativeImageUrls[3];
                jumpAnimation(images[3], true);
                isJumpPaused = true;
                setTimeout(() => {
                    images[3].src = imageUrls[3];
                    isJumpPaused = false;
                }, 1000);
            }
            if (event.key === 'n' || event.key === 'N') {
                toggleImagesVisibility();
            }
        });
    });

})();