linux.do弹幕

快来填满我吧

  1. // ==UserScript==
  2. // @name linux.do弹幕
  3. // @namespace linux.do弹幕氛围
  4. // @version 0.6.2
  5. // @description 快来填满我吧
  6. // @author nulluser
  7. // @match https://linux.do/*
  8. // @icon https://linux.do/uploads/default/optimized/1X/3a18b4b0da3e8cf96f7eea15241c3d251f28a39b_2_180x180.png
  9. // @grant none
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function () {
  14. 'use strict';
  15.  
  16. // 创建弹幕容器
  17. const danmuContainer = document.createElement('div');
  18. danmuContainer.id = 'danmu-container';
  19. danmuContainer.style.position = 'fixed';
  20. danmuContainer.style.left = '0';
  21. danmuContainer.style.bottom = '0';
  22. danmuContainer.style.width = '260px'; // 容器宽度
  23. danmuContainer.style.height = '100%';
  24. danmuContainer.style.zIndex = '9999';
  25. danmuContainer.style.overflow = 'hidden';
  26. document.body.appendChild(danmuContainer);
  27.  
  28. // 弹幕数组
  29. let danmus = [];
  30.  
  31. // 添加弹幕
  32. function addDanmu(text) {
  33. const danmu = document.createElement('div');
  34. danmu.className = 'danmu';
  35. danmu.textContent = text;
  36. danmu.style.position = 'absolute';
  37. danmu.style.whiteSpace = 'nowrap';
  38. danmu.style.color = getRandomColor(); // 随机颜色
  39. danmu.style.fontSize = '20px';
  40. danmu.style.fontWeight = 'bold';
  41. danmu.style.left = getRandomPx();
  42. danmu.style.bottom = '0'; // 弹幕从底部进入
  43. danmu.style.writingMode = 'vertical-lr'; // 文字竖直显示
  44. danmu.style.transform = 'translateX(-100%)'; // 初始位置在容器外
  45. danmuContainer.appendChild(danmu);
  46.  
  47. // 弹幕动画
  48. const pageHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
  49. const duration = Math.random() * (pageHeight * 10) + pageHeight * 15; // 随机动画持续时间,基于页面高度
  50. danmu.animate([
  51. { transform: `translateY(-${pageHeight}px)` } // 向上移动直到消失
  52. ], {
  53. duration: duration,
  54. iterations: 1,
  55. easing: 'linear'
  56. }).finished.then(() => danmu.remove());
  57.  
  58. // 更新弹幕位置
  59. updateDanmuPositions();
  60. }
  61.  
  62. // 更新弹幕位置,防止重叠
  63. function updateDanmuPositions() {
  64. let lastBottom = 0; // 初始化上一个弹幕的底部位置
  65. danmus.forEach(danmu => {
  66. danmu.style.bottom = `${lastBottom}px`;
  67. lastBottom = parseFloat(danmu.style.bottom) + danmu.offsetHeight + 20; // 更新下一个弹幕的位置
  68. });
  69. }
  70.  
  71. // 生成随机颜色
  72. function getRandomColor() {
  73. const letters = '0123456789ABCDEF';
  74. let color = '#';
  75. for (let i = 0; i < 6; i++) {
  76. color += letters[Math.floor(Math.random() * 16)];
  77. }
  78. return color;
  79. }
  80. // 获取弹幕数据
  81. function fetchDanmuData() {
  82. const currentUrl = window.location.href;
  83. const jsonUrl = currentUrl.endsWith('.json') ? currentUrl : currentUrl + '.json';
  84. fetch(jsonUrl)
  85. .then(response => response.json())
  86. .then(data => {
  87. if (data && data.post_stream && data.post_stream.posts) {
  88. const posts = data.post_stream.posts;
  89. let postIndex = 1; // 从第二条开始
  90. function addDanmuWithDelay() {
  91. if (postIndex < posts.length) {
  92. const post = posts[postIndex++];
  93. const cookedContent = post.cooked.replace(/<[^>]*>?/gm, ''); // 移除HTML标签
  94. addDanmu(cookedContent);
  95. setTimeout(addDanmuWithDelay, 1000); // 每次添加后间隔0.2秒
  96. }
  97. }
  98. addDanmuWithDelay(); // 开始添加弹幕
  99. }
  100. })
  101. .catch(error => {
  102. console.error('Error fetching danmu data:', error);
  103. });
  104. }
  105.  
  106. // 假设 addDanmu 函数已经定义,它负责添加弹幕到页面上
  107.  
  108. // 生成随机位置
  109. function getRandomPx() {
  110. const randomNumber = Math.floor(Math.random() * 10) + 1; // 生成1到5的随机数
  111. return randomNumber * 20 + 'px'; // 添加单位px并返回
  112. }
  113.  
  114.  
  115.  
  116. // 每隔一段时间添加一个新的弹幕
  117. setInterval(() => {
  118. addDanmu('吾皇万岁!');
  119. addDanmu('欢迎来到Linux.do!');
  120. addDanmu('始皇牛牛牛!');
  121. addDanmu('快来填满我吧!');
  122. addDanmu('吾皇万睡!');
  123. }, 10000);
  124. fetchDanmuData();
  125. setInterval(() => {fetchDanmuData(); }, 20000);
  126.  
  127. function monitorTopicURLChange(callback) {
  128. const urlPattern = /^(https:\/\/linux\.do\/t\/topic\/\d+).*$/; // 正则表达式匹配基本URL
  129. let lastMatch = location.href.match(urlPattern);
  130. new MutationObserver(() => {
  131. const currentMatch = location.href.match(urlPattern);
  132. if (currentMatch && (!lastMatch || currentMatch[1] !== lastMatch[1])) {
  133. lastMatch = currentMatch;
  134. callback(currentMatch[1]);
  135. }
  136. }).observe(document, { subtree: true, childList: true });
  137. }
  138.  
  139. // 使用示例
  140. monitorTopicURLChange(newBaseURL => {
  141. fetchDanmuData();
  142. });
  143. observer.observe(document.body, { childList: true, subtree: true });
  144. window.addEventListener('load', fetchDanmuData);
  145. // 监听弹幕容器的大小变化,更新弹幕位置
  146. new ResizeObserver(updateDanmuPositions).observe(danmuContainer);
  147. })();