// ==UserScript== // @name bgm-wiki-rev-diff // @namespace https://trim21.me/ // @version 0.0.12 // @author Trim21 // @source https://github.com/Trim21/bgm-wiki-rev-diff // @supportURL https://github.com/Trim21/bgm-wiki-rev-diff/issues // @license MIT // @match https://bgm.tv/subject/*/edit // @match https://bangumi.tv/subject/*/edit // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js // @require https://cdn.jsdelivr.net/npm/diff2html@3.3.1/bundles/js/diff2html.min.js // @require https://cdn.jsdelivr.net/npm/diff@5.0.0/dist/diff.min.js // @grant GM_xmlhttpRequest // @connect bgm.tv // @connect bangumi.tv // @run-at document-end // @description show diff between bgm.tv wiki versions // @downloadURL none // ==/UserScript== /******/ (function() { // webpackBootstrap /******/ "use strict"; /******/ var __webpack_modules__ = ({ /***/ "./src/js/compare.ts": /***/ (function(__unused_webpack_module, exports, __webpack_require__) { var __webpack_unused_export__; __webpack_unused_export__ = ({ value: true }); exports.q = void 0; const parser_1 = __webpack_require__("./src/js/parser.ts"); const utils_1 = __webpack_require__("./src/js/utils.ts"); const differ_1 = __webpack_require__("./src/js/differ.ts"); const ui_1 = __webpack_require__("./src/js/ui.ts"); const model_1 = __webpack_require__("./src/js/model.ts"); function compare(revID1, revID2) { ui_1.clear(); ui_1.show('

loading versions...

'); const rev1 = parser_1.getRevInfo(revID1); const rev2 = parser_1.getRevInfo(revID2); const p1 = utils_1.request(rev1.url); const p2 = utils_1.request(rev2.url); Promise.all([p1, p2]).then(values => { const contents = []; for (const page of values) { contents.push(parser_1.parseRevDetails(page.responseText)); } const c1 = new model_1.Comment(rev1, contents[0]); const c2 = new model_1.Comment(rev2, contents[1]); const d = differ_1.diff(c1, c2); const rendered = ui_1.render(d); ui_1.show(rendered); }).catch(() => { ui_1.show('

loading versions error

'); }); } exports.q = compare; /***/ }), /***/ "./src/js/differ.ts": /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.diff = void 0; const Diff = __webpack_require__("diff"); function diff(rev1, rev2) { return `${titleDiff(rev1, rev2)}\n${infoDiff(rev1, rev2)}\n${descriptionDiff(rev1, rev2)}`; } exports.diff = diff; function titleDiff(rev1, rev2) { if (rev1.details.title === rev2.details.title) { return ''; } return Diff.createTwoFilesPatch('title', 'title', rev1.details.title, rev2.details.title, rev1.rev.date, rev2.rev.date); } function infoDiff(rev1, rev2) { if (rev1.details.rawInfo === rev2.details.rawInfo) { return ''; } return Diff.createTwoFilesPatch('info', 'info', rev1.details.rawInfo, rev2.details.rawInfo, rev1.rev.date, rev2.rev.date); } function descriptionDiff(rev1, rev2) { if (rev1.details.description === rev2.details.description) { return ''; } return Diff.createTwoFilesPatch('description', 'description', rev1.details.description, rev2.details.description, rev1.rev.date, rev2.rev.date); } /***/ }), /***/ "./src/js/model.ts": /***/ (function(__unused_webpack_module, exports) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.Comment = exports.Rev = exports.RevDetail = void 0; class RevDetail { constructor(title, rawInfo, description) { this.title = title; this.rawInfo = rawInfo; this.description = description; } } exports.RevDetail = RevDetail; class Rev { } exports.Rev = Rev; class Comment { constructor(rev, detail) { this.rev = rev; this.details = detail; } } exports.Comment = Comment; /***/ }), /***/ "./src/js/parser.ts": /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.getRevInfo = exports.parseRevEl = exports.parseRevDetails = void 0; const $ = __webpack_require__("jquery"); const model_1 = __webpack_require__("./src/js/model.ts"); function parseRevDetails(html) { const jq = $(html); const rawInfo = jq.find('#subject_infobox').val().toString(); const title = jq.find('input[name="subject_title"]').val().toString(); const description = jq.find('textarea#subject_summary').val().toString(); return new model_1.RevDetail(title, rawInfo, description); } exports.parseRevDetails = parseRevDetails; function parseRevEl(el) { const date = el.find('a').first().html(); const revEL = el.find('a.l:contains("恢复")'); const revCommentEl = el.find('span.comment'); let comment = ''; if (revCommentEl.length) { comment = revCommentEl.html(); comment = comment.substring(1, comment.length - 1); } const revHref = revEL.attr('href'); const revID = revHref.split('/').pop(); return { id: revID, comment, date, url: revHref, }; } exports.parseRevEl = parseRevEl; function getRevs() { const revs = []; $('#pagehistory li').each(function () { const el = $(this); try { revs.push(parseRevEl(el)); } catch (e) { } }); return revs; } function getRevInfo(revID) { for (const rev of getRevs()) { if (rev.id === revID) { return rev; } } } exports.getRevInfo = getRevInfo; /***/ }), /***/ "./src/js/ui.ts": /***/ (function(__unused_webpack_module, exports, __webpack_require__) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.clear = exports.show = exports.render = void 0; const Diff2Html = __webpack_require__("diff2html"); const $ = __webpack_require__("jquery"); function render(diff) { return Diff2Html.html(diff); } exports.render = render; function show(html) { $('#show-trim21-cn').html(html); } exports.show = show; function clear() { $('#show-trim21-cn').html(''); } exports.clear = clear; /***/ }), /***/ "./src/js/utils.ts": /***/ (function(__unused_webpack_module, exports) { Object.defineProperty(exports, "__esModule", ({ value: true })); exports.request = void 0; function request(url) { return new Promise((resolve) => { // @ts-ignore window.GM_xmlhttpRequest({ url, // @ts-ignore onload: function ({ responseText, }) { resolve({ responseText }); } }); }); } exports.request = request; /***/ }), /***/ "jquery": /***/ (function(module) { module.exports = $; /***/ }), /***/ "diff": /***/ (function(module) { module.exports = Diff; /***/ }), /***/ "diff2html": /***/ (function(module) { module.exports = Diff2Html; /***/ }) /******/ }); /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ var cachedModule = __webpack_module_cache__[moduleId]; /******/ if (cachedModule !== undefined) { /******/ return cachedModule.exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = __webpack_module_cache__[moduleId] = { /******/ // no module.id needed /******/ // no module.loaded needed /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ !function() { /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function() { return module['default']; } : /******/ function() { return module; }; /******/ __webpack_require__.d(getter, { a: getter }); /******/ return getter; /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/define property getters */ /******/ !function() { /******/ // define getter functions for harmony exports /******/ __webpack_require__.d = function(exports, definition) { /******/ for(var key in definition) { /******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); /******/ } /******/ } /******/ }; /******/ }(); /******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ !function() { /******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } /******/ }(); /******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. !function() { /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("jquery"); /* harmony import */ var jquery__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jquery__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var _parser__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__("./src/js/parser.ts"); /* harmony import */ var _compare__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__("./src/js/compare.ts"); function main () { console.log('start bgm wiki rev differ UserScript') initUI() } function initUI () { jquery__WEBPACK_IMPORTED_MODULE_0__('#columnInSubjectA').prepend('
') jquery__WEBPACK_IMPORTED_MODULE_0__('#pagehistory li').each(function () { const el = jquery__WEBPACK_IMPORTED_MODULE_0__(this) try { const rev = (0,_parser__WEBPACK_IMPORTED_MODULE_1__.parseRevEl)(el) el.prepend(``) } catch (e) { } }) jquery__WEBPACK_IMPORTED_MODULE_0__('#columnInSubjectA span.text').append(' > 比较选中的版本') jquery__WEBPACK_IMPORTED_MODULE_0__('#compare-trim21-cn').on('click', function () { const selectedRevs = getSelectedVersion() ;(0,_compare__WEBPACK_IMPORTED_MODULE_2__/* .compare */ .q)(selectedRevs[0], selectedRevs[1]) }) jquery__WEBPACK_IMPORTED_MODULE_0__('head').append('') } function getSelectedVersion () { const selectedVersion = [] const selectedRev = jquery__WEBPACK_IMPORTED_MODULE_0__('.rev-trim21-cn:checked') if (selectedRev.length < 2) { window.alert('请选中两个版本进行比较') } if (selectedRev.length > 2) { window.alert('只能比较两个版本') } selectedRev.each(function () { const el = jquery__WEBPACK_IMPORTED_MODULE_0__(this) selectedVersion.push(el.val()) }) selectedVersion.reverse() return selectedVersion } main() }(); /******/ })() ;