文学社在看着你👀

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

  1. // ==UserScript==
  2. // @name 文学社在看着你👀
  3. // @namespace https://world.xiaomawang.com/w/person/project/all/3267489
  4. // @version 2.0.0
  5. // @description 在你的浏览器上添加文学社所有女生的Q版形象
  6. // @author 茶铭
  7. // @match *://*/*
  8. // @icon https://ddlc.moe/images/favicon.ico
  9. // @grant GM_registerMenuCommand
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. const imageUrls = [
  19. "https://ddlc.moe/images/sticker_s.png",
  20. "https://ddlc.moe/images/sticker_y.png",
  21. "https://ddlc.moe/images/sticker_m.png",
  22. "https://ddlc.moe/images/sticker_n.png"
  23. ];
  24.  
  25. const alternativeImageUrls = [
  26. "https://img.qovv.cn/2024/04/20/66230b7098aac.png",
  27. "https://img.qovv.cn/2024/04/20/66230b748295a.png",
  28. "https://img.qovv.cn/2024/04/20/66230b6924394.png",
  29. "https://img.qovv.cn/2024/04/20/66230b6c47129.png"
  30. ];
  31.  
  32. const links = [
  33. "https://chat.monika.love/",
  34. "https://wiki.monika.love/index.php?title=%E9%A6%96%E9%A1%B5",
  35. "https://disk.monika.love/",
  36. "https://forum.monika.love/"
  37. ];
  38.  
  39. const descriptions = [
  40. "DCC chat",
  41. "DCC wiki",
  42. "莫盘",
  43. "心跳文学部中文论坛"
  44. ];
  45.  
  46. const name = [
  47. "纱世里",
  48. "优里",
  49. "莫妮卡",
  50. "夏树"
  51. ];
  52.  
  53. const characterKeywords = [
  54. {
  55. name: "纱世里",
  56. keywords: [
  57. "快乐", "悲伤", "死亡", "悲剧", "孤独", "爱情", "冒险", "甜蜜", "刺激", "烟花",
  58. "浪漫", "泪水", "压抑", "心声", "婚姻", "激情", "童年", "乐趣", "色彩", "希望",
  59. "朋友", "家庭", "聚会", "度假", "懒惰", "做白日梦", "痛苦", "假日", "床", "羽毛",
  60. "羞耻", "恐惧", "温暖", "花朵", "舒适", "跳舞", "唱歌", "哭泣", "笑", "黑暗",
  61. "晴天", "雨云", "平静", "傻傻的", "飞翔", "美妙", "单相思", "玫瑰", "在一起",
  62. "承诺", "魅力", "美丽", "欢呼", "微笑", "破碎", "珍贵", "祈祷", "笨拙", "原谅",
  63. "自然", "海洋", "耀眼", "特别", "音乐", "幸运", "不幸", "响亮", "夕阳", "萤火虫",
  64. "彩虹", "受伤", "游戏", "闪光", "伤痕", "空空如也", "了不起", "悲伤", "拥抱",
  65. "非同寻常", "令人敬畏", "失败", "绝望", "痛苦", "宝藏", "幸福", "回忆"
  66. ]
  67. },
  68. {
  69. name: "夏树",
  70. keywords: [
  71. "蓬松", "纯洁", "糖果", "购物", "小狗", "小猫咪", "云朵", "口红", "冻糕", "草莓味",
  72. "粉红色", "巧克力", "心跳", "亲吻", "旋律", "丝带", "蹦蹦跳跳", "嘟嘟嘟", "卡哇伊",
  73. "裙子", "脸颊", "电子邮件", "黏黏的", "蹦蹦跳跳", "闪闪发光", "轻咬", "幻想", "发糖",
  74. "咯咯笑", "棉花糖", "跳一跳", "跳跃", "和平", "旋转", "旋转", "棒棒糖", "噗噗", "泡泡",
  75. "耳语", "夏天", "瀑布", "泳装", "香草", "耳机", "游戏机", "袜子", "头发", "操场",
  76. "睡衣", "毛毯", "牛奶", "噘嘴", "生气", "爸爸", "情人节礼物", "老鼠", "吹口哨",
  77. "啵啵", "兔子", "动画片", "跳跃"
  78. ]
  79. },
  80. {
  81. name: "优里",
  82. keywords: [
  83. "决心", "自杀", "想象力", "秘密", "活力", "存在", "发光", "深红色", "旋风", "残影",
  84. "眩晕", "迷失方向", "本质", "氛围", "星景", "混乱", "污染", "智力", "分析", "熵",
  85. "活泼", "不可思议", "不协调", "愤怒", "天真", "屠杀", "哲学", "善变", "顽强", "灵气",
  86. "不稳定", "地狱", "无能", "命运", "无懈可击", "痛苦", "变异", "无法控制", "极端",
  87. "逃离", "梦境", "灾难", "生动", "生机勃勃", "疑问", "发酵", "审判", "牢笼", "爆炸",
  88. "快感", "欲望", "感觉", "高潮", "电流", "不承认", "鄙视", "无限", "永恒", "时间",
  89. "宇宙", "永无止境", "雨滴", "觊觎", "无拘无束", "风景", "肖像", "旅程", "微薄",
  90. "焦虑", "惊恐", "恐怖", "忧郁", "洞察力", "赎罪", "呼吸", "俘虏", "欲望", "墓地"
  91. ]
  92. },
  93. {
  94. name: "莫妮卡",
  95. keywords: ["莫妮卡"] // 没错老莫真就这一个词)
  96. }
  97. ];
  98.  
  99.  
  100. const images = [];
  101. const imagePositions = [];
  102. let isJumpPaused = false;
  103.  
  104. function toggleImageVisibility(index) {
  105. return function () {
  106. const img = images[index];
  107. img.style.display = img.style.display === 'none' ? 'block' : 'none';
  108. // 保存隐藏状态到本地存储
  109. localStorage.setItem(`imageVisibility_${index}`, img.style.display);
  110. };
  111. }
  112.  
  113. function createImage(url, link, description, x) {
  114. const a = document.createElement('a');
  115. a.href = link;
  116. a.title = `前往 ${description}`;
  117.  
  118. const img = document.createElement('img');
  119. img.src = url;
  120. img.style.position = 'fixed';
  121. img.style.bottom = '0';
  122. img.style.left = `${x}px`;
  123. img.style.zIndex = '9999';
  124.  
  125. // 从本地存储中获取隐藏状态并设置
  126. const index = images.length;
  127. const visibility = localStorage.getItem(`imageVisibility_${index}`);
  128. if (visibility === 'none') {
  129. img.style.display = 'none';
  130. }
  131.  
  132. a.appendChild(img);
  133. document.body.appendChild(a);
  134.  
  135. return img;
  136. }
  137.  
  138. function registerMenuCommands() {
  139. for (let i = 0; i < name.length; i++) {
  140. GM_registerMenuCommand(`隐藏/显示 ${name[i]}`, toggleImageVisibility(i));
  141. }
  142. }
  143.  
  144. registerMenuCommands();
  145.  
  146.  
  147.  
  148. function startJumpAnimation() {
  149. if (isJumpPaused) return;
  150. const visibleImages = images.filter(img => img.style.display !== 'none');
  151. if (visibleImages.length === 0) return; // 如果没有可见图片,则不执行跳跃动画
  152.  
  153. const randomIndex = Math.floor(Math.random() * visibleImages.length);
  154. jumpAnimation(visibleImages[randomIndex], true); // 只执行大跳事件
  155.  
  156. const randomInterval = Math.floor(Math.random() * 3000) + 3000;
  157. setTimeout(startJumpAnimation, randomInterval);
  158. }
  159.  
  160. function jumpAnimation(img, isBigJump) {
  161. const jumpHeight = isBigJump ? 100 : 50; // 调整第一次触底反弹的高度
  162. const jumpDuration = isBigJump ? 1000 : 0; // 增加跳跃速度
  163.  
  164. img.animate([
  165. { transform: 'translateY(0)', },
  166. { transform: `translateY(-${jumpHeight}px)`, offset: 0.3 }, // 触底反弹
  167. { transform: 'translateY(0)', offset: 0.6 }, // 再次落地
  168. { transform: `translateY(-${jumpHeight / 2}px)`, offset: 0.8 }, // 落地前稍微反弹一次
  169. { transform: 'translateY(0)', offset: 1 }
  170. ], {
  171. duration: jumpDuration,
  172. easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
  173. iterations: 1
  174. });
  175. }
  176.  
  177. function checkOverlap(x) {
  178. for (let i = 0; i < imagePositions.length; i++) {
  179. const position = imagePositions[i];
  180. if (Math.abs(x - position) <= 100) {
  181. return true;
  182. }
  183. }
  184. return false;
  185. }
  186.  
  187. function generateRandomX() {
  188. let x = Math.floor(Math.random() * (window.innerWidth - 100));
  189. while (checkOverlap(x)) {
  190. x = Math.floor(Math.random() * (window.innerWidth - 100));
  191. }
  192. return x;
  193. }
  194.  
  195. window.addEventListener('load', () => {
  196. imageUrls.forEach((url, index) => {
  197. const x = generateRandomX();
  198. const img = createImage(url, links[index], descriptions[index], x);
  199. images.push(img);
  200. imagePositions.push(x);
  201. });
  202.  
  203. startJumpAnimation();
  204.  
  205. function checkCopiedText(text) {
  206. for (let i = 0; i < characterKeywords.length; i++) {
  207. const character = characterKeywords[i];
  208. for (let j = 0; j < character.keywords.length; j++) {
  209. if (text.includes(character.keywords[j])) {
  210. const index = name.indexOf(character.name);
  211. if (index !== -1 && !isJumpPaused) {
  212. images[index].src = alternativeImageUrls[index];
  213. jumpAnimation(images[index], true);
  214. isJumpPaused = true;
  215. setTimeout(() => {
  216. images[index].src = imageUrls[index];
  217. isJumpPaused = false;
  218. }, 1000);
  219. }
  220. return; // 只触发一个角色的大跳事件
  221. }
  222. }
  223. }
  224. }
  225.  
  226. document.addEventListener('copy', event => {
  227. const copiedText = window.getSelection().toString();
  228. checkCopiedText(copiedText);
  229. });
  230.  
  231. });
  232.  
  233. })();
  234.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址