bgm-wiki-rev-diff

show diff between bgm.tv wiki versions

当前为 2021-03-15 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name bgm-wiki-rev-diff
  3. // @namespace https://trim21.me/
  4. // @version 0.0.12
  5. // @author Trim21 <i@trim21.me>
  6. // @source https://github.com/Trim21/bgm-wiki-rev-diff
  7. // @supportURL https://github.com/Trim21/bgm-wiki-rev-diff/issues
  8. // @license MIT
  9. // @match https://bgm.tv/subject/*/edit
  10. // @match https://bangumi.tv/subject/*/edit
  11. // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
  12. // @require https://cdn.jsdelivr.net/npm/diff2html@3.3.1/bundles/js/diff2html.min.js
  13. // @require https://cdn.jsdelivr.net/npm/diff@5.0.0/dist/diff.min.js
  14. // @grant GM_xmlhttpRequest
  15. // @connect bgm.tv
  16. // @connect bangumi.tv
  17. // @run-at document-end
  18. // @description show diff between bgm.tv wiki versions
  19. // ==/UserScript==
  20.  
  21.  
  22. /******/ (function() { // webpackBootstrap
  23. /******/ "use strict";
  24. /******/ var __webpack_modules__ = ({
  25.  
  26. /***/ "./src/js/compare.ts":
  27. /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
  28.  
  29. var __webpack_unused_export__;
  30.  
  31. __webpack_unused_export__ = ({ value: true });
  32. exports.q = void 0;
  33. const parser_1 = __webpack_require__("./src/js/parser.ts");
  34. const utils_1 = __webpack_require__("./src/js/utils.ts");
  35. const differ_1 = __webpack_require__("./src/js/differ.ts");
  36. const ui_1 = __webpack_require__("./src/js/ui.ts");
  37. const model_1 = __webpack_require__("./src/js/model.ts");
  38. function compare(revID1, revID2) {
  39. ui_1.clear();
  40. ui_1.show('<h2>loading versions...</h2>');
  41. const rev1 = parser_1.getRevInfo(revID1);
  42. const rev2 = parser_1.getRevInfo(revID2);
  43. const p1 = utils_1.request(rev1.url);
  44. const p2 = utils_1.request(rev2.url);
  45. Promise.all([p1, p2]).then(values => {
  46. const contents = [];
  47. for (const page of values) {
  48. contents.push(parser_1.parseRevDetails(page.responseText));
  49. }
  50. const c1 = new model_1.Comment(rev1, contents[0]);
  51. const c2 = new model_1.Comment(rev2, contents[1]);
  52. const d = differ_1.diff(c1, c2);
  53. const rendered = ui_1.render(d);
  54. ui_1.show(rendered);
  55. }).catch(() => {
  56. ui_1.show('<h2 style="color:red">loading versions error</h2>');
  57. });
  58. }
  59. exports.q = compare;
  60.  
  61.  
  62. /***/ }),
  63.  
  64. /***/ "./src/js/differ.ts":
  65. /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
  66.  
  67.  
  68. Object.defineProperty(exports, "__esModule", ({ value: true }));
  69. exports.diff = void 0;
  70. const Diff = __webpack_require__("diff");
  71. function diff(rev1, rev2) {
  72. return `${titleDiff(rev1, rev2)}\n${infoDiff(rev1, rev2)}\n${descriptionDiff(rev1, rev2)}`;
  73. }
  74. exports.diff = diff;
  75. function titleDiff(rev1, rev2) {
  76. if (rev1.details.title === rev2.details.title) {
  77. return '';
  78. }
  79. return Diff.createTwoFilesPatch('title', 'title', rev1.details.title, rev2.details.title, rev1.rev.date, rev2.rev.date);
  80. }
  81. function infoDiff(rev1, rev2) {
  82. if (rev1.details.rawInfo === rev2.details.rawInfo) {
  83. return '';
  84. }
  85. return Diff.createTwoFilesPatch('info', 'info', rev1.details.rawInfo, rev2.details.rawInfo, rev1.rev.date, rev2.rev.date);
  86. }
  87. function descriptionDiff(rev1, rev2) {
  88. if (rev1.details.description === rev2.details.description) {
  89. return '';
  90. }
  91. return Diff.createTwoFilesPatch('description', 'description', rev1.details.description, rev2.details.description, rev1.rev.date, rev2.rev.date);
  92. }
  93.  
  94.  
  95. /***/ }),
  96.  
  97. /***/ "./src/js/model.ts":
  98. /***/ (function(__unused_webpack_module, exports) {
  99.  
  100.  
  101. Object.defineProperty(exports, "__esModule", ({ value: true }));
  102. exports.Comment = exports.Rev = exports.RevDetail = void 0;
  103. class RevDetail {
  104. constructor(title, rawInfo, description) {
  105. this.title = title;
  106. this.rawInfo = rawInfo;
  107. this.description = description;
  108. }
  109. }
  110. exports.RevDetail = RevDetail;
  111. class Rev {
  112. }
  113. exports.Rev = Rev;
  114. class Comment {
  115. constructor(rev, detail) {
  116. this.rev = rev;
  117. this.details = detail;
  118. }
  119. }
  120. exports.Comment = Comment;
  121.  
  122.  
  123. /***/ }),
  124.  
  125. /***/ "./src/js/parser.ts":
  126. /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
  127.  
  128.  
  129. Object.defineProperty(exports, "__esModule", ({ value: true }));
  130. exports.getRevInfo = exports.parseRevEl = exports.parseRevDetails = void 0;
  131. const $ = __webpack_require__("jquery");
  132. const model_1 = __webpack_require__("./src/js/model.ts");
  133. function parseRevDetails(html) {
  134. const jq = $(html);
  135. const rawInfo = jq.find('#subject_infobox').val().toString();
  136. const title = jq.find('input[name="subject_title"]').val().toString();
  137. const description = jq.find('textarea#subject_summary').val().toString();
  138. return new model_1.RevDetail(title, rawInfo, description);
  139. }
  140. exports.parseRevDetails = parseRevDetails;
  141. function parseRevEl(el) {
  142. const date = el.find('a').first().html();
  143. const revEL = el.find('a.l:contains("恢复")');
  144. const revCommentEl = el.find('span.comment');
  145. let comment = '';
  146. if (revCommentEl.length) {
  147. comment = revCommentEl.html();
  148. comment = comment.substring(1, comment.length - 1);
  149. }
  150. const revHref = revEL.attr('href');
  151. const revID = revHref.split('/').pop();
  152. return {
  153. id: revID,
  154. comment,
  155. date,
  156. url: revHref,
  157. };
  158. }
  159. exports.parseRevEl = parseRevEl;
  160. function getRevs() {
  161. const revs = [];
  162. $('#pagehistory li').each(function () {
  163. const el = $(this);
  164. try {
  165. revs.push(parseRevEl(el));
  166. }
  167. catch (e) {
  168. }
  169. });
  170. return revs;
  171. }
  172. function getRevInfo(revID) {
  173. for (const rev of getRevs()) {
  174. if (rev.id === revID) {
  175. return rev;
  176. }
  177. }
  178. }
  179. exports.getRevInfo = getRevInfo;
  180.  
  181.  
  182. /***/ }),
  183.  
  184. /***/ "./src/js/ui.ts":
  185. /***/ (function(__unused_webpack_module, exports, __webpack_require__) {
  186.  
  187.  
  188. Object.defineProperty(exports, "__esModule", ({ value: true }));
  189. exports.clear = exports.show = exports.render = void 0;
  190. const Diff2Html = __webpack_require__("diff2html");
  191. const $ = __webpack_require__("jquery");
  192. function render(diff) {
  193. return Diff2Html.html(diff);
  194. }
  195. exports.render = render;
  196. function show(html) {
  197. $('#show-trim21-cn').html(html);
  198. }
  199. exports.show = show;
  200. function clear() {
  201. $('#show-trim21-cn').html('');
  202. }
  203. exports.clear = clear;
  204.  
  205.  
  206. /***/ }),
  207.  
  208. /***/ "./src/js/utils.ts":
  209. /***/ (function(__unused_webpack_module, exports) {
  210.  
  211.  
  212. Object.defineProperty(exports, "__esModule", ({ value: true }));
  213. exports.request = void 0;
  214. function request(url) {
  215. return new Promise((resolve) => {
  216. // @ts-ignore
  217. window.GM_xmlhttpRequest({
  218. url,
  219. // @ts-ignore
  220. onload: function ({ responseText, }) {
  221. resolve({ responseText });
  222. }
  223. });
  224. });
  225. }
  226. exports.request = request;
  227.  
  228.  
  229. /***/ }),
  230.  
  231. /***/ "jquery":
  232. /***/ (function(module) {
  233.  
  234. module.exports = $;
  235.  
  236. /***/ }),
  237.  
  238. /***/ "diff":
  239. /***/ (function(module) {
  240.  
  241. module.exports = Diff;
  242.  
  243. /***/ }),
  244.  
  245. /***/ "diff2html":
  246. /***/ (function(module) {
  247.  
  248. module.exports = Diff2Html;
  249.  
  250. /***/ })
  251.  
  252. /******/ });
  253. /************************************************************************/
  254. /******/ // The module cache
  255. /******/ var __webpack_module_cache__ = {};
  256. /******/
  257. /******/ // The require function
  258. /******/ function __webpack_require__(moduleId) {
  259. /******/ // Check if module is in cache
  260. /******/ var cachedModule = __webpack_module_cache__[moduleId];
  261. /******/ if (cachedModule !== undefined) {
  262. /******/ return cachedModule.exports;
  263. /******/ }
  264. /******/ // Create a new module (and put it into the cache)
  265. /******/ var module = __webpack_module_cache__[moduleId] = {
  266. /******/ // no module.id needed
  267. /******/ // no module.loaded needed
  268. /******/ exports: {}
  269. /******/ };
  270. /******/
  271. /******/ // Execute the module function
  272. /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
  273. /******/
  274. /******/ // Return the exports of the module
  275. /******/ return module.exports;
  276. /******/ }
  277. /******/
  278. /************************************************************************/
  279. /******/ /* webpack/runtime/compat get default export */
  280. /******/ !function() {
  281. /******/ // getDefaultExport function for compatibility with non-harmony modules
  282. /******/ __webpack_require__.n = function(module) {
  283. /******/ var getter = module && module.__esModule ?
  284. /******/ function() { return module['default']; } :
  285. /******/ function() { return module; };
  286. /******/ __webpack_require__.d(getter, { a: getter });
  287. /******/ return getter;
  288. /******/ };
  289. /******/ }();
  290. /******/
  291. /******/ /* webpack/runtime/define property getters */
  292. /******/ !function() {
  293. /******/ // define getter functions for harmony exports
  294. /******/ __webpack_require__.d = function(exports, definition) {
  295. /******/ for(var key in definition) {
  296. /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
  297. /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
  298. /******/ }
  299. /******/ }
  300. /******/ };
  301. /******/ }();
  302. /******/
  303. /******/ /* webpack/runtime/hasOwnProperty shorthand */
  304. /******/ !function() {
  305. /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
  306. /******/ }();
  307. /******/
  308. /************************************************************************/
  309. var __webpack_exports__ = {};
  310. // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
  311. !function() {
  312. /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery");
  313. /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__);
  314. /* harmony import */ var _parser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/js/parser.ts");
  315. /* harmony import */ var _compare__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./src/js/compare.ts");
  316.  
  317.  
  318.  
  319.  
  320. function main () {
  321. console.log('start bgm wiki rev differ UserScript')
  322. initUI()
  323. }
  324.  
  325. function initUI () {
  326. jquery__WEBPACK_IMPORTED_MODULE_0__('#columnInSubjectA').prepend('<div id=show-trim21-cn></dev>')
  327. jquery__WEBPACK_IMPORTED_MODULE_0__('#pagehistory li').each(function () {
  328. const el = jquery__WEBPACK_IMPORTED_MODULE_0__(this)
  329. try {
  330. const rev = (0,_parser__WEBPACK_IMPORTED_MODULE_1__.parseRevEl)(el)
  331. el.prepend(`<input type="checkbox" class="rev-trim21-cn" name="rev" label="select to compare" value="${rev.id}">`)
  332. } catch (e) {
  333. }
  334. })
  335. jquery__WEBPACK_IMPORTED_MODULE_0__('#columnInSubjectA span.text').append('<a href="#;" id="compare-trim21-cn" tar class="l"> > 比较选中的版本</a>')
  336. jquery__WEBPACK_IMPORTED_MODULE_0__('#compare-trim21-cn').on('click', function () {
  337. const selectedRevs = getSelectedVersion()
  338. ;(0,_compare__WEBPACK_IMPORTED_MODULE_2__/* .compare */ .q)(selectedRevs[0], selectedRevs[1])
  339. })
  340. jquery__WEBPACK_IMPORTED_MODULE_0__('head').append('<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />')
  341. }
  342.  
  343. function getSelectedVersion () {
  344. const selectedVersion = []
  345. const selectedRev = jquery__WEBPACK_IMPORTED_MODULE_0__('.rev-trim21-cn:checked')
  346. if (selectedRev.length < 2) {
  347. window.alert('请选中两个版本进行比较')
  348. }
  349. if (selectedRev.length > 2) {
  350. window.alert('只能比较两个版本')
  351. }
  352. selectedRev.each(function () {
  353. const el = jquery__WEBPACK_IMPORTED_MODULE_0__(this)
  354. selectedVersion.push(el.val())
  355. })
  356. selectedVersion.reverse()
  357. return selectedVersion
  358. }
  359.  
  360. main()
  361.  
  362. }();
  363. /******/ })()
  364. ;