bgm-hover-subject-info

鼠标指向条目链接时弹出一个悬浮窗显示条目信息

当前为 2022-10-02 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name bgm-hover-subject-info
  3. // @name:zh 鼠标指向条目链接时显示更多信息
  4. // @namespace https://trim21.me/
  5. // @description 鼠标指向条目链接时弹出一个悬浮窗显示条目信息
  6. // @version 0.2.3
  7. // @source https://github.com/trim21/bgm-tv-userscripts
  8. // @supportURL https://github.com/trim21/bgm-tv-userscripts/issues
  9. // @license MIT
  10. // @match https://bgm.tv/group/topic/*
  11. // @match https://bangumi.tv/group/topic/*
  12. // @match https://chii.in/group/topic/*
  13. // @match https://bgm.tv/index/*
  14. // @match https://bangumi.tv/index/*
  15. // @match https://chii.in/index/*
  16. // @match https://bgm.tv/rakuen/topiclist
  17. // @match https://bangumi.tv/rakuen/topiclist
  18. // @match https://chii.in/rakuen/topiclist
  19. // @require https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js
  20. // @run-at document-end
  21. // @author Trim21 <i@trim21.me>
  22. // ==/UserScript==
  23.  
  24.  
  25. /******/ (() => { // webpackBootstrap
  26. /******/ "use strict";
  27. var __webpack_exports__ = {};
  28.  
  29. ;// CONCATENATED MODULE: external "$"
  30. const external_$_namespaceObject = $;
  31. ;// CONCATENATED MODULE: ./src/utils.ts
  32.  
  33. function getSubjectID(s) {
  34. if (!(s == null ? void 0 : s.length))
  35. return void 0;
  36. if (s.startsWith("/")) {
  37. s = "https://bgm.tv" + s;
  38. }
  39. const u = new URL(s);
  40. const path = u.pathname;
  41. const split = path.split("/");
  42. if (split.length >= 4) {
  43. return void 0;
  44. }
  45. if (split[1] === "subject") {
  46. return parseInt(split[2], 10);
  47. }
  48. return void 0;
  49. }
  50.  
  51. ;// CONCATENATED MODULE: ./src/index.ts
  52.  
  53.  
  54.  
  55. const style = `
  56. <style>
  57. .d-block {
  58. display: block;
  59. }
  60. .d-flex {
  61. display: flex;
  62. }
  63.  
  64. #popup {
  65. width: 30em;
  66. /*height: 15em;*/
  67. flex: auto;
  68. background: white;
  69. border: solid 1px black;
  70. position: absolute;
  71. padding: 0.5em;
  72. border-radius: 0.2em;
  73. }
  74. .tag .name {
  75. /*background-color: dodgerblue;*/
  76. /*color: white;*/
  77. }
  78.  
  79. .popup-tags{
  80. display: block;
  81. }
  82.  
  83. .tag {
  84. border-radius: 0.2em;
  85. border: solid 1px gray;
  86. padding: 0 0.3em;
  87. }
  88.  
  89. .image {
  90. padding-right: 2px;
  91. }
  92.  
  93. </style>
  94. `;
  95. function createPopup(subject) {
  96. var _a;
  97. let rank = "";
  98. if (subject.rating.rank) {
  99. rank = `<p class='rateInfo'>
  100. <span class='starstop-s'><span class='starlight stars${Math.round(subject.rating.score)}'></span></span>
  101. <small class='fade'>${subject.rating.score}</small> <span class='tip_j'>(${subject.rating.total}人评分)</span>
  102. </p>`;
  103. }
  104. let tags = "";
  105. if (subject.tags.length) {
  106. tags = "<div class='popup-tags'>" + subject.tags.sort((a, b) => b.count - a.count).slice(0, 10).map(
  107. (value) => `<span class='tag'><span class='name'>${value.name}</span> <small>${value.count}</small></span>`
  108. ).join("\n");
  109. tags += "</div>";
  110. }
  111. return `
  112. <div class='d-flex'>
  113. <span class='image d-block'>
  114. <img src='${(_a = subject.images) == null ? void 0 : _a.small}' class='cover' alt='${subject.name}'>
  115. </span>
  116. <div class='d-block'>
  117. <h3>${subject.name}</h3>
  118. <small class='grey'>${subject.name_cn}</small>
  119. <p class='info tip'> ${subject.summary} </p>
  120. </div>
  121. </div>
  122.  
  123. ${rank}
  124.  
  125. ${tags}
  126. `;
  127. }
  128. function main() {
  129. console.log(GM.info.script.name);
  130. external_$_namespaceObject("head").append(style);
  131. external_$_namespaceObject("a").each((i, e) => {
  132. if (getSubjectID(external_$_namespaceObject(e).attr("href"))) {
  133. external_$_namespaceObject(e).on("mouseover", hoverHandler).on("mouseleave", leaveHandler);
  134. }
  135. });
  136. }
  137. function leaveHandler() {
  138. external_$_namespaceObject("#popup").remove();
  139. console.log("leave");
  140. }
  141. function hoverHandler() {
  142. const e = external_$_namespaceObject(this);
  143. const href = e.attr("href");
  144. if (!href) {
  145. return;
  146. }
  147. const offset = e.offset() ?? { left: 0, top: 0 };
  148. external_$_namespaceObject("body").append('<div id="popup"> loading </div>');
  149. const popup = external_$_namespaceObject("#popup").css({
  150. left: offset.left,
  151. top: offset.top + 40,
  152. position: "absolute",
  153. "z-index": 1e3
  154. });
  155. const subjectID = getSubjectID(href);
  156. if (!subjectID) {
  157. return;
  158. }
  159. (async function() {
  160. const res = await fetch(`https://api.bgm.tv/v0/subjects/${subjectID}`);
  161. if (res.status > 400) {
  162. popup.html("not found");
  163. return;
  164. }
  165. const data = await res.json();
  166. let html = createPopup(data);
  167. if (res.redirected) {
  168. html = "条目被合并到此条目" + html;
  169. }
  170. popup.html(html);
  171. })().catch(console.error);
  172. }
  173. main();
  174.  
  175. /******/ })()
  176. ;