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