Bangumi帖子收藏到日志

在Bangumi帖子页面添加收藏按钮,自动收藏到指定日志

  1. // ==UserScript==
  2. // @name Bangumi帖子收藏到日志
  3. // @version 1.2.1
  4. // @description 在Bangumi帖子页面添加收藏按钮,自动收藏到指定日志
  5. // @author age_anime
  6. // @match https://bgm.tv/group/topic/*
  7. // @match https://chii.in/group/topic/*
  8. // @match https://bangumi.tv/group/topic/*
  9. // @match https://bgm.tv/blog/*
  10. // @match https://chii.in/blog/*
  11. // @match https://bangumi.tv/blog/*
  12. // @license MIT
  13. // @namespace https://gf.qytechs.cn/users/1426310
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. const BASE_URL = window.location.hostname;
  20. const path = window.location.pathname;
  21.  
  22. if (path.startsWith('/blog/')) {
  23. handleBlogPage();
  24. return;
  25. }
  26.  
  27. let TARGET_BLOG_ID = localStorage.getItem('UserTargetBlogID') || '填纯数字!';
  28. const UserConIDT = JSON.parse(localStorage.getItem('UserConIDT') || '{}');
  29.  
  30. function addCollectButton() {
  31. const header = document.querySelector('#pageHeader h1');
  32. if (!header) return;
  33.  
  34. const btnContainer = document.createElement('div');
  35. btnContainer.style.display = 'inline-flex';
  36. btnContainer.style.alignItems = 'center';
  37. btnContainer.style.gap = '8px';
  38. btnContainer.style.marginLeft = '10px';
  39.  
  40. const collectBtn = createButton(UserConIDT[getPostIdFromUrl()] ? '🔴 再次收藏' : '⭐ 收藏本帖', handleCollect);
  41. const modifyLogBtn = createButton('修改日志地址', handleModifyLog);
  42. const openLogBtn = createButton('打开收藏地址', handleOpenLog);
  43.  
  44. btnContainer.appendChild(collectBtn);
  45. btnContainer.appendChild(modifyLogBtn);
  46. btnContainer.appendChild(openLogBtn);
  47.  
  48. header.parentNode.insertBefore(btnContainer, header.nextSibling);
  49. }
  50.  
  51. function createButton(text, onClick) {
  52. const button = document.createElement('button');
  53. button.innerHTML = text;
  54. button.style.cssText = 'padding: 2px 6px; font-size: 12px; background: transparent; border: 1px solid #ccc; border-radius: 3px; cursor: pointer;';
  55. button.addEventListener('click', onClick);
  56.  
  57. // 根据当前模式设置按钮文字颜色
  58. setButtonColor(button);
  59.  
  60. return button;
  61. }
  62.  
  63. function setButtonColor(button) {
  64. const theme = document.documentElement.getAttribute('data-theme');
  65. if (theme === 'dark') {
  66. button.style.color = '#cccccc'; // 深色模式
  67. } else {
  68. button.style.color = 'black'; // 浅色模式
  69. }
  70. }
  71.  
  72. function handleCollect() {
  73. try {
  74. const postId = getPostIdFromUrl();
  75. if (!UserConIDT[postId]) {
  76. UserConIDT[postId] = true;
  77. localStorage.setItem('UserConIDT', JSON.stringify(UserConIDT));
  78. } else {
  79. alert('再次收藏成功!');
  80. }
  81.  
  82. const postUrl = window.location.href;
  83. const postTitle = document.title.replace(' - Bangumi', '');
  84. const groupName = document.querySelector('#pageHeader h1 a')?.textContent.trim() || '未知小组';
  85. const postAuthorScript = document.querySelector('.post_actions .dropdown ul li a');
  86. const authorNameMatch = postAuthorScript?.getAttribute('onclick')?.match(/ignoreUser\('([^']+)'/);
  87. const authorUsername = authorNameMatch ? authorNameMatch[1] : '未知用户';
  88. const authorDisplayName = document.querySelector('.postTopic .inner strong a')?.textContent.trim() || '未知用户';
  89.  
  90. // 获取目标日志的formhash
  91. getBlogFormData().then(formData => {
  92. const postUrlLink = `https://${BASE_URL}/group/topic/${window.location.pathname.split('/')[3]}`;
  93. const authorLink = `https://${BASE_URL}/user/${authorUsername}`;
  94. const bbcode = `[url=${postUrlLink}]${postTitle}[/url]\n${groupName}\n${authorDisplayName}(${authorLink});`;
  95.  
  96. submitComment(formData, bbcode).then(success => {
  97. if (success) {
  98. console.log('收藏成功');
  99. } else {
  100. throw new Error('提交失败');
  101. }
  102. }).catch(err => console.error('错误:', err.message || '操作失败'));
  103. });
  104.  
  105. } catch (err) {
  106. console.error('错误:', err.message || '操作失败');
  107. }
  108. }
  109.  
  110. function handleModifyLog() {
  111. const newBlogId = prompt('请输入新的日志ID:', TARGET_BLOG_ID);
  112. if (newBlogId) {
  113. TARGET_BLOG_ID = newBlogId;
  114. localStorage.setItem('UserTargetBlogID', TARGET_BLOG_ID);
  115. alert('日志地址已修改为: ' + TARGET_BLOG_ID);
  116. }
  117. }
  118.  
  119. function handleOpenLog() {
  120. window.open(`https://${BASE_URL}/blog/${TARGET_BLOG_ID}`, '_blank');
  121. }
  122.  
  123. function getPostIdFromUrl() {
  124. const urlParts = window.location.pathname.split('/');
  125. return urlParts[urlParts.length - 1];
  126. }
  127.  
  128. async function getBlogFormData() {
  129. try {
  130. const response = await fetch(`https://${BASE_URL}/blog/${TARGET_BLOG_ID}`);
  131. if (!response.ok) throw new Error('无法获取日志');
  132.  
  133. const text = await response.text();
  134. const doc = new DOMParser().parseFromString(text, 'text/html');
  135. const formhash = doc.querySelector('input[name="formhash"]')?.value;
  136. const lastview = doc.querySelector('input[name="lastview"]')?.value;
  137.  
  138. if (!formhash || !lastview) throw new Error('找不到日志信息');
  139. return { formhash, lastview };
  140. } catch (error) {
  141. console.error('获取日志失败:', error.message);
  142. throw error;
  143. }
  144. }
  145.  
  146. async function submitComment(formData, content) {
  147. try {
  148. const response = await fetch(`https://${BASE_URL}/blog/entry/${TARGET_BLOG_ID}/new_reply`, {
  149. method: 'POST',
  150. headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  151. body: new URLSearchParams({
  152. formhash: formData.formhash,
  153. lastview: formData.lastview,
  154. content: content,
  155. submit: '加上去'
  156. })
  157. });
  158. return response.ok || response.status === 302;
  159. } catch (error) {
  160. console.error('提交失败:', error.message);
  161. return false;
  162. }
  163. }
  164.  
  165. function handleBlogPage() {
  166. const TARGET_BLOG_ID = localStorage.getItem('UserTargetBlogID');
  167. const currentBlogId = path.split('/')[2];
  168.  
  169. if (currentBlogId === TARGET_BLOG_ID) {
  170. extractTopicIDs();
  171. }
  172.  
  173. function extractTopicIDs() {
  174. const extractedIDs = {};
  175.  
  176. const comments = document.querySelectorAll('.light_even.row.row_reply.clearit, .light_odd.row.row_reply.clearit');
  177. comments.forEach(comment => {
  178. const links = comment.querySelectorAll('.message a[href*="/group/topic/"]');
  179. links.forEach(link => {
  180. const href = link.href;
  181. const topicID = href.match(/group\/topic\/(\d+)/)?.[1];
  182. if (topicID) {
  183. extractedIDs[topicID] = true;
  184. }
  185. });
  186. });
  187.  
  188. localStorage.setItem('UserConIDT', JSON.stringify(extractedIDs));
  189.  
  190. const notice = document.createElement('div');
  191. notice.textContent = `已提取 ${Object.keys(extractedIDs).length} 个主题帖`;
  192. notice.style.cssText = `
  193. position: fixed;
  194. top: 20px;
  195. right: 20px;
  196. padding: 10px;
  197. background: #40E0D0;
  198. color: white;
  199. border-radius: 5px;
  200. z-index: 9999;
  201. box-shadow: 0 2px 5px rgba(0,0,0,0.2);
  202. `;
  203. document.body.appendChild(notice);
  204.  
  205. setTimeout(() => {
  206. notice.style.transition = 'opacity 1s';
  207. notice.style.opacity = '0';
  208. setTimeout(() => notice.remove(), 1000);
  209. }, 3000);
  210. }
  211. }
  212.  
  213. // 初始化
  214. addCollectButton();
  215. })();

QingJ © 2025

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