bgm-wiki-rev-diff

show diff between bgm.tv wiki versions

当前为 2020-04-25 提交的版本,查看 最新版本

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