Greasy Fork

来自缓存

Greasy Fork is available in English.

迁移豆瓣收藏到 Bangumi

迁移豆瓣动画收藏到 Bangumi.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        migrate douban collection to bangumi
// @name:zh-CN  迁移豆瓣收藏到 Bangumi
// @namespace   https://github.com/22earth
// @description migrate douban collection to bangumi and export douban collection
// @description:zh-cn 迁移豆瓣动画收藏到 Bangumi.
// @include     /^https?:\/\/(bangumi|bgm|chii)\.(tv|in)\/?$/
// @include     https://movie.douban.com/mine
// @include     https://search.douban.com/movie/subject_search*
// @author      22earth
// @homepage    https://github.com/22earth/gm_scripts
// @version     0.0.9
// @run-at      document-end
// @grant       GM_registerMenuCommand
// @grant       GM_xmlhttpRequest
// @grant       GM_addStyle
// @grant       GM_setValue
// @grant       GM_getValue
// @grant       GM_getResourceText
// @require     https://cdnjs.cloudflare.com/ajax/libs/fuse.js/6.4.0/fuse.min.js
// @resource    bangumiDataURL https://unpkg.com/[email protected]/dist/data.json
// ==/UserScript==

(function () {
  'use strict';

  function sleep(num) {
      return new Promise((resolve) => {
          setTimeout(resolve, num);
      });
  }
  function randomSleep(max = 400, min = 200) {
      return sleep(randomNum(max, min));
  }
  function randomNum(max, min) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  // support GM_XMLHttpRequest
  let retryCounter = 0;
  let USER_SITE_CONFIG = {};
  function getSiteConfg(url, host) {
      let hostname = host;
      if (!host) {
          hostname = new URL(url)?.hostname;
      }
      const config = USER_SITE_CONFIG[hostname] || {};
      return config;
  }
  function mergeOpts(opts, config) {
      return {
          ...opts,
          ...config,
          headers: {
              ...opts?.headers,
              ...config?.headers,
          },
      };
  }
  function fetchInfo(url, type, opts = {}, TIMEOUT = 10 * 1000) {
      const method = opts?.method?.toUpperCase() || 'GET';
      opts = mergeOpts(opts, getSiteConfg(url));
      // @ts-ignore
      {
          const gmXhrOpts = { ...opts };
          if (method === 'POST' && gmXhrOpts.body) {
              gmXhrOpts.data = gmXhrOpts.body;
          }
          if (opts.decode) {
              type = 'arraybuffer';
          }
          return new Promise((resolve, reject) => {
              // @ts-ignore
              GM_xmlhttpRequest({
                  method,
                  timeout: TIMEOUT,
                  url,
                  responseType: type,
                  onload: function (res) {
                      if (res.status === 404) {
                          retryCounter = 0;
                          reject(404);
                      }
                      else if (res.status === 302 && retryCounter < 5) {
                          retryCounter++;
                          resolve(fetchInfo(res.finalUrl, type, opts, TIMEOUT));
                      }
                      if (opts.decode && type === 'arraybuffer') {
                          retryCounter = 0;
                          let decoder = new TextDecoder(opts.decode);
                          resolve(decoder.decode(res.response));
                      }
                      else {
                          retryCounter = 0;
                          resolve(res.response);
                      }
                  },
                  onerror: (e) => {
                      retryCounter = 0;
                      reject(e);
                  },
                  ...gmXhrOpts,
              });
          });
      }
  }
  function fetchText(url, opts = {}, TIMEOUT = 10 * 1000) {
      return fetchInfo(url, 'text', opts, TIMEOUT);
  }
  function fetchJson(url, opts = {}) {
      return fetchInfo(url, 'json', opts);
  }

  var SubjectTypeId;
  (function (SubjectTypeId) {
      SubjectTypeId[SubjectTypeId["book"] = 1] = "book";
      SubjectTypeId[SubjectTypeId["anime"] = 2] = "anime";
      SubjectTypeId[SubjectTypeId["music"] = 3] = "music";
      SubjectTypeId[SubjectTypeId["game"] = 4] = "game";
      SubjectTypeId[SubjectTypeId["real"] = 6] = "real";
      SubjectTypeId["all"] = "all";
  })(SubjectTypeId || (SubjectTypeId = {}));

  function formatDate(time, fmt = 'yyyy-MM-dd') {
      const date = new Date(time);
      var o = {
          'M+': date.getMonth() + 1,
          'd+': date.getDate(),
          'h+': date.getHours(),
          'm+': date.getMinutes(),
          's+': date.getSeconds(),
          'q+': Math.floor((date.getMonth() + 3) / 3),
          S: date.getMilliseconds(), //毫秒
      };
      if (/(y+)/i.test(fmt)) {
          fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));
      }
      for (var k in o) {
          if (new RegExp('(' + k + ')', 'i').test(fmt)) {
              fmt = fmt.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length));
          }
      }
      return fmt;
  }
  function dealDate(dataStr) {
      // 2019年12月19
      let l = [];
      if (/\d{4}年\d{1,2}月(\d{1,2}日?)?/.test(dataStr)) {
          l = dataStr
              .replace('日', '')
              .split(/年|月/)
              .filter((i) => i);
      }
      else if (/\d{4}\/\d{1,2}(\/\d{1,2})?/.test(dataStr)) {
          l = dataStr.split('/');
      }
      else if (/\d{4}-\d{1,2}(-\d{1,2})?/.test(dataStr)) {
          return dataStr;
      }
      else {
          return dataStr;
      }
      return l
          .map((i) => {
          if (i.length === 1) {
              return `0${i}`;
          }
          return i;
      })
          .join('-');
  }
  function isEqualDate(d1, d2, type = 'd') {
      const resultDate = new Date(d1);
      const originDate = new Date(d2);
      if (type === 'y') {
          return resultDate.getFullYear() === originDate.getFullYear();
      }
      if (type === 'm') {
          return resultDate.getFullYear() === originDate.getFullYear() && resultDate.getMonth() === originDate.getMonth();
      }
      if (resultDate.getFullYear() === originDate.getFullYear() &&
          resultDate.getMonth() === originDate.getMonth() &&
          resultDate.getDate() === originDate.getDate()) {
          return true;
      }
      return false;
  }
  function getShortenedQuery(query) {
      let newQuery = query;
      let parts = newQuery.split(' ');
      let englishWordCount = 0;
      let nonEnglishDetected = false;
      let japaneseWordCount = 0;
      let isJapaneseWord = false;
      for (let i = 0; i < parts.length; i++) {
          let isEnglishWord = /^[a-zA-Z]+$/.test(parts[i]);
          if (isEnglishWord || /^\d+$/.test(parts[i])) {
              englishWordCount++;
          }
          else {
              isJapaneseWord = /[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}ーa-zA-Z0-9a-zA-Z0-9々〆〤]/u.test(parts[i]);
              if (isJapaneseWord) {
                  nonEnglishDetected = true;
                  japaneseWordCount++;
              }
          }
          if (nonEnglishDetected && englishWordCount < 2 && parts[i].length > 2) {
              parts = [parts[i]];
              break;
          }
          if (isEnglishWord && englishWordCount >= 2 && parts.slice(0, i + 1).join('').length > 2) {
              parts = parts.slice(0, i + 1);
              break;
          }
          if (isJapaneseWord && japaneseWordCount == 2) {
              for (let j = 0; j <= i; j++) {
                  if (parts[j].length <= 1 && j < i) {
                      continue;
                  }
                  else {
                      parts = parts.slice(0, j + 1);
                      break;
                  }
              }
              break;
          }
      }
      newQuery = parts.join(' ');
      // xxx1  bb2, cc3 ----> xx1, bb, cc
      if (/[^\d]+\d+$/.test(newQuery)) {
          return newQuery.replace(/\d+$/, '').trim();
      }
      return newQuery;
  }

  // TinySegmenter 0.2 -- Super compact Japanese tokenizer in Javascript
  // (c) 2008 Taku Kudo <[email protected]>
  // TinySegmenter is freely distributable under the terms of a new BSD licence.
  // For details, see http://chasen.org/~taku/software/TinySegmenter/LICENCE.txt

  function TinySegmenter() {
      var patterns = {
          "[一二三四五六七八九十百千万億兆]":"M",
          "[一-龠々〆ヵヶ]":"H",
          "[ぁ-ん]":"I",
          "[ァ-ヴーア-ン゙ー]":"K",
          "[a-zA-Za-zA-Z]":"A",
          "[0-90-9]":"N"
      };
      this.chartype_ = [];
      for (var i in patterns) {
          var regexp = new RegExp;
          regexp.compile(i);
          this.chartype_.push([regexp, patterns[i]]);
      }

      this.BIAS__ = -332;
      this.BC1__ = {"HH":6,"II":2461,"KH":406,"OH":-1378};
      this.BC2__ = {"AA":-3267,"AI":2744,"AN":-878,"HH":-4070,"HM":-1711,"HN":4012,"HO":3761,"IA":1327,"IH":-1184,"II":-1332,"IK":1721,"IO":5492,"KI":3831,"KK":-8741,"MH":-3132,"MK":3334,"OO":-2920};
      this.BC3__ = {"HH":996,"HI":626,"HK":-721,"HN":-1307,"HO":-836,"IH":-301,"KK":2762,"MK":1079,"MM":4034,"OA":-1652,"OH":266};
      this.BP1__ = {"BB":295,"OB":304,"OO":-125,"UB":352};
      this.BP2__ = {"BO":60,"OO":-1762};
      this.BQ1__ = {"BHH":1150,"BHM":1521,"BII":-1158,"BIM":886,"BMH":1208,"BNH":449,"BOH":-91,"BOO":-2597,"OHI":451,"OIH":-296,"OKA":1851,"OKH":-1020,"OKK":904,"OOO":2965};
      this.BQ2__ = {"BHH":118,"BHI":-1159,"BHM":466,"BIH":-919,"BKK":-1720,"BKO":864,"OHH":-1139,"OHM":-181,"OIH":153,"UHI":-1146};
      this.BQ3__ = {"BHH":-792,"BHI":2664,"BII":-299,"BKI":419,"BMH":937,"BMM":8335,"BNN":998,"BOH":775,"OHH":2174,"OHM":439,"OII":280,"OKH":1798,"OKI":-793,"OKO":-2242,"OMH":-2402,"OOO":11699};
      this.BQ4__ = {"BHH":-3895,"BIH":3761,"BII":-4654,"BIK":1348,"BKK":-1806,"BMI":-3385,"BOO":-12396,"OAH":926,"OHH":266,"OHK":-2036,"ONN":-973};
      this.BW1__ = {",と":660,",同":727,"B1あ":1404,"B1同":542,"、と":660,"、同":727,"」と":1682,"あっ":1505,"いう":1743,"いっ":-2055,"いる":672,"うし":-4817,"うん":665,"から":3472,"がら":600,"こう":-790,"こと":2083,"こん":-1262,"さら":-4143,"さん":4573,"した":2641,"して":1104,"すで":-3399,"そこ":1977,"それ":-871,"たち":1122,"ため":601,"った":3463,"つい":-802,"てい":805,"てき":1249,"でき":1127,"です":3445,"では":844,"とい":-4915,"とみ":1922,"どこ":3887,"ない":5713,"なっ":3015,"など":7379,"なん":-1113,"にし":2468,"には":1498,"にも":1671,"に対":-912,"の一":-501,"の中":741,"ませ":2448,"まで":1711,"まま":2600,"まる":-2155,"やむ":-1947,"よっ":-2565,"れた":2369,"れで":-913,"をし":1860,"を見":731,"亡く":-1886,"京都":2558,"取り":-2784,"大き":-2604,"大阪":1497,"平方":-2314,"引き":-1336,"日本":-195,"本当":-2423,"毎日":-2113,"目指":-724,"B1あ":1404,"B1同":542,"」と":1682};
      this.BW2__ = {"..":-11822,"11":-669,"――":-5730,"−−":-13175,"いう":-1609,"うか":2490,"かし":-1350,"かも":-602,"から":-7194,"かれ":4612,"がい":853,"がら":-3198,"きた":1941,"くな":-1597,"こと":-8392,"この":-4193,"させ":4533,"され":13168,"さん":-3977,"しい":-1819,"しか":-545,"した":5078,"して":972,"しな":939,"その":-3744,"たい":-1253,"たた":-662,"ただ":-3857,"たち":-786,"たと":1224,"たは":-939,"った":4589,"って":1647,"っと":-2094,"てい":6144,"てき":3640,"てく":2551,"ては":-3110,"ても":-3065,"でい":2666,"でき":-1528,"でし":-3828,"です":-4761,"でも":-4203,"とい":1890,"とこ":-1746,"とと":-2279,"との":720,"とみ":5168,"とも":-3941,"ない":-2488,"なが":-1313,"など":-6509,"なの":2614,"なん":3099,"にお":-1615,"にし":2748,"にな":2454,"によ":-7236,"に対":-14943,"に従":-4688,"に関":-11388,"のか":2093,"ので":-7059,"のに":-6041,"のの":-6125,"はい":1073,"はが":-1033,"はず":-2532,"ばれ":1813,"まし":-1316,"まで":-6621,"まれ":5409,"めて":-3153,"もい":2230,"もの":-10713,"らか":-944,"らし":-1611,"らに":-1897,"りし":651,"りま":1620,"れた":4270,"れて":849,"れば":4114,"ろう":6067,"われ":7901,"を通":-11877,"んだ":728,"んな":-4115,"一人":602,"一方":-1375,"一日":970,"一部":-1051,"上が":-4479,"会社":-1116,"出て":2163,"分の":-7758,"同党":970,"同日":-913,"大阪":-2471,"委員":-1250,"少な":-1050,"年度":-8669,"年間":-1626,"府県":-2363,"手権":-1982,"新聞":-4066,"日新":-722,"日本":-7068,"日米":3372,"曜日":-601,"朝鮮":-2355,"本人":-2697,"東京":-1543,"然と":-1384,"社会":-1276,"立て":-990,"第に":-1612,"米国":-4268,"11":-669};
      this.BW3__ = {"あた":-2194,"あり":719,"ある":3846,"い.":-1185,"い。":-1185,"いい":5308,"いえ":2079,"いく":3029,"いた":2056,"いっ":1883,"いる":5600,"いわ":1527,"うち":1117,"うと":4798,"えと":1454,"か.":2857,"か。":2857,"かけ":-743,"かっ":-4098,"かに":-669,"から":6520,"かり":-2670,"が,":1816,"が、":1816,"がき":-4855,"がけ":-1127,"がっ":-913,"がら":-4977,"がり":-2064,"きた":1645,"けど":1374,"こと":7397,"この":1542,"ころ":-2757,"さい":-714,"さを":976,"し,":1557,"し、":1557,"しい":-3714,"した":3562,"して":1449,"しな":2608,"しま":1200,"す.":-1310,"す。":-1310,"する":6521,"ず,":3426,"ず、":3426,"ずに":841,"そう":428,"た.":8875,"た。":8875,"たい":-594,"たの":812,"たり":-1183,"たる":-853,"だ.":4098,"だ。":4098,"だっ":1004,"った":-4748,"って":300,"てい":6240,"てお":855,"ても":302,"です":1437,"でに":-1482,"では":2295,"とう":-1387,"とし":2266,"との":541,"とも":-3543,"どう":4664,"ない":1796,"なく":-903,"など":2135,"に,":-1021,"に、":-1021,"にし":1771,"にな":1906,"には":2644,"の,":-724,"の、":-724,"の子":-1000,"は,":1337,"は、":1337,"べき":2181,"まし":1113,"ます":6943,"まっ":-1549,"まで":6154,"まれ":-793,"らし":1479,"られ":6820,"るる":3818,"れ,":854,"れ、":854,"れた":1850,"れて":1375,"れば":-3246,"れる":1091,"われ":-605,"んだ":606,"んで":798,"カ月":990,"会議":860,"入り":1232,"大会":2217,"始め":1681,"市":965,"新聞":-5055,"日,":974,"日、":974,"社会":2024,"カ月":990};
      this.TC1__ = {"AAA":1093,"HHH":1029,"HHM":580,"HII":998,"HOH":-390,"HOM":-331,"IHI":1169,"IOH":-142,"IOI":-1015,"IOM":467,"MMH":187,"OOI":-1832};
      this.TC2__ = {"HHO":2088,"HII":-1023,"HMM":-1154,"IHI":-1965,"KKH":703,"OII":-2649};
      this.TC3__ = {"AAA":-294,"HHH":346,"HHI":-341,"HII":-1088,"HIK":731,"HOH":-1486,"IHH":128,"IHI":-3041,"IHO":-1935,"IIH":-825,"IIM":-1035,"IOI":-542,"KHH":-1216,"KKA":491,"KKH":-1217,"KOK":-1009,"MHH":-2694,"MHM":-457,"MHO":123,"MMH":-471,"NNH":-1689,"NNO":662,"OHO":-3393};
      this.TC4__ = {"HHH":-203,"HHI":1344,"HHK":365,"HHM":-122,"HHN":182,"HHO":669,"HIH":804,"HII":679,"HOH":446,"IHH":695,"IHO":-2324,"IIH":321,"III":1497,"IIO":656,"IOO":54,"KAK":4845,"KKA":3386,"KKK":3065,"MHH":-405,"MHI":201,"MMH":-241,"MMM":661,"MOM":841};
      this.TQ1__ = {"BHHH":-227,"BHHI":316,"BHIH":-132,"BIHH":60,"BIII":1595,"BNHH":-744,"BOHH":225,"BOOO":-908,"OAKK":482,"OHHH":281,"OHIH":249,"OIHI":200,"OIIH":-68};
      this.TQ2__ = {"BIHH":-1401,"BIII":-1033,"BKAK":-543,"BOOO":-5591};
      this.TQ3__ = {"BHHH":478,"BHHM":-1073,"BHIH":222,"BHII":-504,"BIIH":-116,"BIII":-105,"BMHI":-863,"BMHM":-464,"BOMH":620,"OHHH":346,"OHHI":1729,"OHII":997,"OHMH":481,"OIHH":623,"OIIH":1344,"OKAK":2792,"OKHH":587,"OKKA":679,"OOHH":110,"OOII":-685};
      this.TQ4__ = {"BHHH":-721,"BHHM":-3604,"BHII":-966,"BIIH":-607,"BIII":-2181,"OAAA":-2763,"OAKK":180,"OHHH":-294,"OHHI":2446,"OHHO":480,"OHIH":-1573,"OIHH":1935,"OIHI":-493,"OIIH":626,"OIII":-4007,"OKAK":-8156};
      this.TW1__ = {"につい":-4681,"東京都":2026};
      this.TW2__ = {"ある程":-2049,"いった":-1256,"ころが":-2434,"しょう":3873,"その後":-4430,"だって":-1049,"ていた":1833,"として":-4657,"ともに":-4517,"もので":1882,"一気に":-792,"初めて":-1512,"同時に":-8097,"大きな":-1255,"対して":-2721,"社会党":-3216};
      this.TW3__ = {"いただ":-1734,"してい":1314,"として":-4314,"につい":-5483,"にとっ":-5989,"に当た":-6247,"ので,":-727,"ので、":-727,"のもの":-600,"れから":-3752,"十二月":-2287};
      this.TW4__ = {"いう.":8576,"いう。":8576,"からな":-2348,"してい":2958,"たが,":1516,"たが、":1516,"ている":1538,"という":1349,"ました":5543,"ません":1097,"ようと":-4258,"よると":5865};
      this.UC1__ = {"A":484,"K":93,"M":645,"O":-505};
      this.UC2__ = {"A":819,"H":1059,"I":409,"M":3987,"N":5775,"O":646};
      this.UC3__ = {"A":-1370,"I":2311};
      this.UC4__ = {"A":-2643,"H":1809,"I":-1032,"K":-3450,"M":3565,"N":3876,"O":6646};
      this.UC5__ = {"H":313,"I":-1238,"K":-799,"M":539,"O":-831};
      this.UC6__ = {"H":-506,"I":-253,"K":87,"M":247,"O":-387};
      this.UP1__ = {"O":-214};
      this.UP2__ = {"B":69,"O":935};
      this.UP3__ = {"B":189};
      this.UQ1__ = {"BH":21,"BI":-12,"BK":-99,"BN":142,"BO":-56,"OH":-95,"OI":477,"OK":410,"OO":-2422};
      this.UQ2__ = {"BH":216,"BI":113,"OK":1759};
      this.UQ3__ = {"BA":-479,"BH":42,"BI":1913,"BK":-7198,"BM":3160,"BN":6427,"BO":14761,"OI":-827,"ON":-3212};
      this.UW1__ = {",":156,"、":156,"「":-463,"あ":-941,"う":-127,"が":-553,"き":121,"こ":505,"で":-201,"と":-547,"ど":-123,"に":-789,"の":-185,"は":-847,"も":-466,"や":-470,"よ":182,"ら":-292,"り":208,"れ":169,"を":-446,"ん":-137,"・":-135,"主":-402,"京":-268,"区":-912,"午":871,"国":-460,"大":561,"委":729,"市":-411,"日":-141,"理":361,"生":-408,"県":-386,"都":-718,"「":-463,"・":-135};
      this.UW2__ = {",":-829,"、":-829,"〇":892,"「":-645,"」":3145,"あ":-538,"い":505,"う":134,"お":-502,"か":1454,"が":-856,"く":-412,"こ":1141,"さ":878,"ざ":540,"し":1529,"す":-675,"せ":300,"そ":-1011,"た":188,"だ":1837,"つ":-949,"て":-291,"で":-268,"と":-981,"ど":1273,"な":1063,"に":-1764,"の":130,"は":-409,"ひ":-1273,"べ":1261,"ま":600,"も":-1263,"や":-402,"よ":1639,"り":-579,"る":-694,"れ":571,"を":-2516,"ん":2095,"ア":-587,"カ":306,"キ":568,"ッ":831,"三":-758,"不":-2150,"世":-302,"中":-968,"主":-861,"事":492,"人":-123,"会":978,"保":362,"入":548,"初":-3025,"副":-1566,"北":-3414,"区":-422,"大":-1769,"天":-865,"太":-483,"子":-1519,"学":760,"実":1023,"小":-2009,"市":-813,"年":-1060,"強":1067,"手":-1519,"揺":-1033,"政":1522,"文":-1355,"新":-1682,"日":-1815,"明":-1462,"最":-630,"朝":-1843,"本":-1650,"東":-931,"果":-665,"次":-2378,"民":-180,"気":-1740,"理":752,"発":529,"目":-1584,"相":-242,"県":-1165,"立":-763,"第":810,"米":509,"自":-1353,"行":838,"西":-744,"見":-3874,"調":1010,"議":1198,"込":3041,"開":1758,"間":-1257,"「":-645,"」":3145,"ッ":831,"ア":-587,"カ":306,"キ":568};
      this.UW3__ = {",":4889,"1":-800,"−":-1723,"、":4889,"々":-2311,"〇":5827,"」":2670,"〓":-3573,"あ":-2696,"い":1006,"う":2342,"え":1983,"お":-4864,"か":-1163,"が":3271,"く":1004,"け":388,"げ":401,"こ":-3552,"ご":-3116,"さ":-1058,"し":-395,"す":584,"せ":3685,"そ":-5228,"た":842,"ち":-521,"っ":-1444,"つ":-1081,"て":6167,"で":2318,"と":1691,"ど":-899,"な":-2788,"に":2745,"の":4056,"は":4555,"ひ":-2171,"ふ":-1798,"へ":1199,"ほ":-5516,"ま":-4384,"み":-120,"め":1205,"も":2323,"や":-788,"よ":-202,"ら":727,"り":649,"る":5905,"れ":2773,"わ":-1207,"を":6620,"ん":-518,"ア":551,"グ":1319,"ス":874,"ッ":-1350,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278,"・":-3794,"一":-1619,"下":-1759,"世":-2087,"両":3815,"中":653,"主":-758,"予":-1193,"二":974,"人":2742,"今":792,"他":1889,"以":-1368,"低":811,"何":4265,"作":-361,"保":-2439,"元":4858,"党":3593,"全":1574,"公":-3030,"六":755,"共":-1880,"円":5807,"再":3095,"分":457,"初":2475,"別":1129,"前":2286,"副":4437,"力":365,"動":-949,"務":-1872,"化":1327,"北":-1038,"区":4646,"千":-2309,"午":-783,"協":-1006,"口":483,"右":1233,"各":3588,"合":-241,"同":3906,"和":-837,"員":4513,"国":642,"型":1389,"場":1219,"外":-241,"妻":2016,"学":-1356,"安":-423,"実":-1008,"家":1078,"小":-513,"少":-3102,"州":1155,"市":3197,"平":-1804,"年":2416,"広":-1030,"府":1605,"度":1452,"建":-2352,"当":-3885,"得":1905,"思":-1291,"性":1822,"戸":-488,"指":-3973,"政":-2013,"教":-1479,"数":3222,"文":-1489,"新":1764,"日":2099,"旧":5792,"昨":-661,"時":-1248,"曜":-951,"最":-937,"月":4125,"期":360,"李":3094,"村":364,"東":-805,"核":5156,"森":2438,"業":484,"氏":2613,"民":-1694,"決":-1073,"法":1868,"海":-495,"無":979,"物":461,"特":-3850,"生":-273,"用":914,"町":1215,"的":7313,"直":-1835,"省":792,"県":6293,"知":-1528,"私":4231,"税":401,"立":-960,"第":1201,"米":7767,"系":3066,"約":3663,"級":1384,"統":-4229,"総":1163,"線":1255,"者":6457,"能":725,"自":-2869,"英":785,"見":1044,"調":-562,"財":-733,"費":1777,"車":1835,"軍":1375,"込":-1504,"通":-1136,"選":-681,"郎":1026,"郡":4404,"部":1200,"金":2163,"長":421,"開":-1432,"間":1302,"関":-1282,"雨":2009,"電":-1045,"非":2066,"駅":1620,"1":-800,"」":2670,"・":-3794,"ッ":-1350,"ア":551,"グ":1319,"ス":874,"ト":521,"ム":1109,"ル":1591,"ロ":2201,"ン":278};
      this.UW4__ = {",":3930,".":3508,"―":-4841,"、":3930,"。":3508,"〇":4999,"「":1895,"」":3798,"〓":-5156,"あ":4752,"い":-3435,"う":-640,"え":-2514,"お":2405,"か":530,"が":6006,"き":-4482,"ぎ":-3821,"く":-3788,"け":-4376,"げ":-4734,"こ":2255,"ご":1979,"さ":2864,"し":-843,"じ":-2506,"す":-731,"ず":1251,"せ":181,"そ":4091,"た":5034,"だ":5408,"ち":-3654,"っ":-5882,"つ":-1659,"て":3994,"で":7410,"と":4547,"な":5433,"に":6499,"ぬ":1853,"ね":1413,"の":7396,"は":8578,"ば":1940,"ひ":4249,"び":-4134,"ふ":1345,"へ":6665,"べ":-744,"ほ":1464,"ま":1051,"み":-2082,"む":-882,"め":-5046,"も":4169,"ゃ":-2666,"や":2795,"ょ":-1544,"よ":3351,"ら":-2922,"り":-9726,"る":-14896,"れ":-2613,"ろ":-4570,"わ":-1783,"を":13150,"ん":-2352,"カ":2145,"コ":1789,"セ":1287,"ッ":-724,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637,"・":-4371,"ー":-11870,"一":-2069,"中":2210,"予":782,"事":-190,"井":-1768,"人":1036,"以":544,"会":950,"体":-1286,"作":530,"側":4292,"先":601,"党":-2006,"共":-1212,"内":584,"円":788,"初":1347,"前":1623,"副":3879,"力":-302,"動":-740,"務":-2715,"化":776,"区":4517,"協":1013,"参":1555,"合":-1834,"和":-681,"員":-910,"器":-851,"回":1500,"国":-619,"園":-1200,"地":866,"場":-1410,"塁":-2094,"士":-1413,"多":1067,"大":571,"子":-4802,"学":-1397,"定":-1057,"寺":-809,"小":1910,"屋":-1328,"山":-1500,"島":-2056,"川":-2667,"市":2771,"年":374,"庁":-4556,"後":456,"性":553,"感":916,"所":-1566,"支":856,"改":787,"政":2182,"教":704,"文":522,"方":-856,"日":1798,"時":1829,"最":845,"月":-9066,"木":-485,"来":-442,"校":-360,"業":-1043,"氏":5388,"民":-2716,"気":-910,"沢":-939,"済":-543,"物":-735,"率":672,"球":-1267,"生":-1286,"産":-1101,"田":-2900,"町":1826,"的":2586,"目":922,"省":-3485,"県":2997,"空":-867,"立":-2112,"第":788,"米":2937,"系":786,"約":2171,"経":1146,"統":-1169,"総":940,"線":-994,"署":749,"者":2145,"能":-730,"般":-852,"行":-792,"規":792,"警":-1184,"議":-244,"谷":-1000,"賞":730,"車":-1481,"軍":1158,"輪":-1433,"込":-3370,"近":929,"道":-1291,"選":2596,"郎":-4866,"都":1192,"野":-1100,"銀":-2213,"長":357,"間":-2344,"院":-2297,"際":-2604,"電":-878,"領":-1659,"題":-792,"館":-1984,"首":1749,"高":2120,"「":1895,"」":3798,"・":-4371,"ッ":-724,"ー":-11870,"カ":2145,"コ":1789,"セ":1287,"ト":-403,"メ":-1635,"ラ":-881,"リ":-541,"ル":-856,"ン":-3637};
      this.UW5__ = {",":465,".":-299,"1":-514,"E2":-32768,"]":-2762,"、":465,"。":-299,"「":363,"あ":1655,"い":331,"う":-503,"え":1199,"お":527,"か":647,"が":-421,"き":1624,"ぎ":1971,"く":312,"げ":-983,"さ":-1537,"し":-1371,"す":-852,"だ":-1186,"ち":1093,"っ":52,"つ":921,"て":-18,"で":-850,"と":-127,"ど":1682,"な":-787,"に":-1224,"の":-635,"は":-578,"べ":1001,"み":502,"め":865,"ゃ":3350,"ょ":854,"り":-208,"る":429,"れ":504,"わ":419,"を":-1264,"ん":327,"イ":241,"ル":451,"ン":-343,"中":-871,"京":722,"会":-1153,"党":-654,"務":3519,"区":-901,"告":848,"員":2104,"大":-1296,"学":-548,"定":1785,"嵐":-1304,"市":-2991,"席":921,"年":1763,"思":872,"所":-814,"挙":1618,"新":-1682,"日":218,"月":-4353,"査":932,"格":1356,"機":-1508,"氏":-1347,"田":240,"町":-3912,"的":-3149,"相":1319,"省":-1052,"県":-4003,"研":-997,"社":-278,"空":-813,"統":1955,"者":-2233,"表":663,"語":-1073,"議":1219,"選":-1018,"郎":-368,"長":786,"間":1191,"題":2368,"館":-689,"1":-514,"E2":-32768,"「":363,"イ":241,"ル":451,"ン":-343};
      this.UW6__ = {",":227,".":808,"1":-270,"E1":306,"、":227,"。":808,"あ":-307,"う":189,"か":241,"が":-73,"く":-121,"こ":-200,"じ":1782,"す":383,"た":-428,"っ":573,"て":-1014,"で":101,"と":-105,"な":-253,"に":-149,"の":-417,"は":-236,"も":-206,"り":187,"る":-135,"を":195,"ル":-673,"ン":-496,"一":-277,"中":201,"件":-800,"会":624,"前":302,"区":1792,"員":-1212,"委":798,"学":-960,"市":887,"広":-695,"後":535,"業":-697,"相":753,"社":-507,"福":974,"空":-822,"者":1811,"連":463,"郎":1082,"1":-270,"E1":306,"ル":-673,"ン":-496};

      return this;
  }

  TinySegmenter.prototype.ctype_ = function(str) {
      for (var i in this.chartype_) {
          if (str.match(this.chartype_[i][0])) {
              return this.chartype_[i][1];
          }
      }
      return "O";
  };

  TinySegmenter.prototype.ts_ = function(v) {
      if (v) { return v; }
      return 0;
  };

  TinySegmenter.prototype.segment = function(input) {
      if (input == null || input == undefined || input == "") {
          return [];
      }
      var result = [];
      var seg = ["B3","B2","B1"];
      var ctype = ["O","O","O"];
      var o = input.split("");
      for (i = 0; i < o.length; ++i) {
          seg.push(o[i]);
          ctype.push(this.ctype_(o[i]));
      }
      seg.push("E1");
      seg.push("E2");
      seg.push("E3");
      ctype.push("O");
      ctype.push("O");
      ctype.push("O");
      var word = seg[3];
      var p1 = "U";
      var p2 = "U";
      var p3 = "U";
      for (var i = 4; i < seg.length - 3; ++i) {
          var score = this.BIAS__;
          var w1 = seg[i-3];
          var w2 = seg[i-2];
          var w3 = seg[i-1];
          var w4 = seg[i];
          var w5 = seg[i+1];
          var w6 = seg[i+2];
          var c1 = ctype[i-3];
          var c2 = ctype[i-2];
          var c3 = ctype[i-1];
          var c4 = ctype[i];
          var c5 = ctype[i+1];
          var c6 = ctype[i+2];
          score += this.ts_(this.UP1__[p1]);
          score += this.ts_(this.UP2__[p2]);
          score += this.ts_(this.UP3__[p3]);
          score += this.ts_(this.BP1__[p1 + p2]);
          score += this.ts_(this.BP2__[p2 + p3]);
          score += this.ts_(this.UW1__[w1]);
          score += this.ts_(this.UW2__[w2]);
          score += this.ts_(this.UW3__[w3]);
          score += this.ts_(this.UW4__[w4]);
          score += this.ts_(this.UW5__[w5]);
          score += this.ts_(this.UW6__[w6]);
          score += this.ts_(this.BW1__[w2 + w3]);
          score += this.ts_(this.BW2__[w3 + w4]);
          score += this.ts_(this.BW3__[w4 + w5]);
          score += this.ts_(this.TW1__[w1 + w2 + w3]);
          score += this.ts_(this.TW2__[w2 + w3 + w4]);
          score += this.ts_(this.TW3__[w3 + w4 + w5]);
          score += this.ts_(this.TW4__[w4 + w5 + w6]);
          score += this.ts_(this.UC1__[c1]);
          score += this.ts_(this.UC2__[c2]);
          score += this.ts_(this.UC3__[c3]);
          score += this.ts_(this.UC4__[c4]);
          score += this.ts_(this.UC5__[c5]);
          score += this.ts_(this.UC6__[c6]);
          score += this.ts_(this.BC1__[c2 + c3]);
          score += this.ts_(this.BC2__[c3 + c4]);
          score += this.ts_(this.BC3__[c4 + c5]);
          score += this.ts_(this.TC1__[c1 + c2 + c3]);
          score += this.ts_(this.TC2__[c2 + c3 + c4]);
          score += this.ts_(this.TC3__[c3 + c4 + c5]);
          score += this.ts_(this.TC4__[c4 + c5 + c6]);
  //  score += this.ts_(this.TC5__[c4 + c5 + c6]);
          score += this.ts_(this.UQ1__[p1 + c1]);
          score += this.ts_(this.UQ2__[p2 + c2]);
          score += this.ts_(this.UQ3__[p3 + c3]);
          score += this.ts_(this.BQ1__[p2 + c2 + c3]);
          score += this.ts_(this.BQ2__[p2 + c3 + c4]);
          score += this.ts_(this.BQ3__[p3 + c2 + c3]);
          score += this.ts_(this.BQ4__[p3 + c3 + c4]);
          score += this.ts_(this.TQ1__[p2 + c1 + c2 + c3]);
          score += this.ts_(this.TQ2__[p2 + c2 + c3 + c4]);
          score += this.ts_(this.TQ3__[p3 + c1 + c2 + c3]);
          score += this.ts_(this.TQ4__[p3 + c2 + c3 + c4]);
          var p = "O";
          if (score > 0) {
              result.push(word);
              word = "";
              p = "B";
          }
          p1 = p2;
          p2 = p3;
          p3 = p;
          word += seg[i];
      }
      result.push(word);

      return result;
  };

  var lib = TinySegmenter;

  const SEARCH_RESULT = 'search_result';

  /**
   * 过滤搜索结果: 通过名称以及日期
   * @param items
   * @param subjectInfo
   * @param opts
   */
  function filterResults(items, subjectInfo, opts) {
      if (!items)
          return;
      // 只有一个结果时直接返回, 不再比较日期
      if (items.length === 1 && opts.uniqueSearch) {
          return items[0];
      }
      // 使用发行日期过滤
      if (subjectInfo.releaseDate && opts.dateFirst) {
          const list = items
              .filter((item) => isEqualDate(item.releaseDate, subjectInfo.releaseDate))
              .sort((a, b) => +b.count - +a.count);
          if (opts.sameName) {
              return list.find((item) => item.name === subjectInfo.name);
          }
          if (list && list.length > 0) {
              return list[0];
          }
      }
      var results = new Fuse(items, { ...opts, includeScore: true }).search(subjectInfo.name);
      // 去掉括号包裹的,再次模糊查询
      if (!results.length && /<|<|\(|(/.test(subjectInfo.name)) {
          results = new Fuse(items, { ...opts, includeScore: true }).search(subjectInfo.name
              .replace(/<.+>/g, '')
              .replace(/<.+>/g, '')
              .replace(/(.+)/g, '')
              .replace(/\(.+\)/g, ''));
      }
      if (!results.length) {
          return;
      }
      if (opts.score) {
          results = results.filter((item) => {
              if (item.score > opts.score) {
                  return false;
              }
              return true;
          });
      }
      if (opts.sortCount) {
          results.sort((a, b) => {
              return +b.item.count - +a.item.count;
          });
      }
      // 有参考的发布时间
      if (subjectInfo.releaseDate) {
          const sameDateResults = [];
          const sameYearResults = [];
          const sameMonthResults = [];
          for (const obj of results) {
              const result = obj.item;
              if (result.releaseDate) {
                  // 只有年的时候
                  if (result.releaseDate.length === 4) {
                      if (result.releaseDate === subjectInfo.releaseDate.slice(0, 4)) {
                          return result;
                      }
                  }
                  if (isEqualDate(result.releaseDate, subjectInfo.releaseDate)) {
                      sameDateResults.push(obj);
                      continue;
                  }
                  if (isEqualDate(result.releaseDate, subjectInfo.releaseDate, 'm')) {
                      sameMonthResults.push(obj);
                      continue;
                  }
                  if (isEqualDate(result.releaseDate, subjectInfo.releaseDate, 'y')) {
                      sameYearResults.push(obj);
                  }
              }
          }
          if (opts.sameDate) {
              return sameDateResults[0]?.item;
          }
          if (sameDateResults.length) {
              return sameDateResults[0].item;
          }
          if (sameMonthResults.length) {
              return sameMonthResults[0].item;
          }
          if (sameYearResults.length && opts.sameYear) {
              return sameYearResults[0].item;
          }
      }
      return results[0]?.item;
  }
  const typeIdDict$1 = {
      dropped: {
          name: '抛弃',
          id: '5',
      },
      on_hold: {
          name: '搁置',
          id: '4',
      },
      do: {
          name: '在看',
          id: '3',
      },
      collect: {
          name: '看过',
          id: '2',
      },
      wish: {
          name: '想看',
          id: '1',
      },
  };
  function findInterestStatusById(id) {
      for (let key in typeIdDict$1) {
          const obj = typeIdDict$1[key];
          if (obj.id === id) {
              return {
                  key: key,
                  ...obj,
              };
          }
      }
  }
  async function getSearchSubjectByGM() {
      return new Promise((resolve, reject) => {
          const listenId = window.gm_val_listen_id;
          if (listenId) {
              GM_removeValueChangeListener(listenId);
          }
          window.gm_val_listen_id = GM_addValueChangeListener(
          // const listenId = GM_addValueChangeListener(
          SEARCH_RESULT, (n, oldValue, newValue) => {
              console.log('enter promise');
              const now = +new Date();
              if (newValue.type === SEARCH_RESULT && newValue.timestamp && newValue.timestamp < now) {
                  // GM_removeValueChangeListener(listenId);
                  resolve(newValue.data);
              }
              reject('mismatch timestamp');
          });
      });
  }
  async function setSearchResultByGM(data) {
      const res = {
          type: SEARCH_RESULT,
          timestamp: +new Date(),
          data,
      };
      GM_setValue(SEARCH_RESULT, res);
  }
  function isSingleJpSegment(name) {
      const segmenter = new lib();
      const segs = segmenter.segment(name);
      if (segs.length === 1) {
          if (/^\p{Script=Katakana}+$/u.test(name)) {
              return true;
          }
          if (/^\p{Script=Hiragana}+$/u.test(name)) {
              return true;
          }
      }
      return false;
  }

  function getBgmHost() {
      return `${location.protocol}//${location.host}`;
  }
  function getSubjectId$1(url) {
      const m = url.match(/(?:subject|character)\/(\d+)/);
      if (!m)
          return '';
      return m[1];
  }
  function getUserId$1(url) {
      // https://bgm.tv/user/a_little
      const m = url.match(/user\/(.*)/);
      if (!m)
          return '';
      return m[1];
  }
  function insertLogInfo($sibling, txt) {
      const $log = document.createElement('div');
      $log.classList.add('e-wiki-log-info');
      // $log.setAttribute('style', 'color: tomato;');
      $log.innerHTML = txt;
      $sibling.parentElement.insertBefore($log, $sibling);
      $sibling.insertAdjacentElement('afterend', $log);
      return $log;
  }
  function convertItemInfo$1($item) {
      let $subjectTitle = $item.querySelector('h3>a.l');
      let itemSubject = {
          name: $subjectTitle.textContent.trim(),
          rawInfos: $item.querySelector('.info').textContent.trim(),
          // url 没有协议和域名
          url: $subjectTitle.getAttribute('href'),
          greyName: $item.querySelector('h3>.grey')
              ? $item.querySelector('h3>.grey').textContent.trim()
              : '',
      };
      let matchDate = $item
          .querySelector('.info')
          .textContent.match(/\d{4}[\-\/\年]\d{1,2}[\-\/\月]\d{1,2}/);
      if (matchDate) {
          itemSubject.releaseDate = dealDate(matchDate[0]);
      }
      const $rateInfo = $item.querySelector('.rateInfo');
      if ($rateInfo) {
          const rateInfo = {};
          if ($rateInfo.querySelector('.fade')) {
              rateInfo.score = $rateInfo.querySelector('.fade').textContent;
              rateInfo.count = $rateInfo
                  .querySelector('.tip_j')
                  .textContent.replace(/[^0-9]/g, '');
          }
          else {
              rateInfo.score = '0';
              rateInfo.count = '少于10';
          }
          itemSubject.rateInfo = rateInfo;
      }
      const $rank = $item.querySelector('.rank');
      if ($rank) {
          itemSubject.rank = $rank.textContent.replace('Rank', '').trim();
      }
      const $collectInfo = $item.querySelector('.collectInfo');
      const collectInfo = {};
      const $comment = $item.querySelector('#comment_box');
      if ($comment) {
          collectInfo.comment = $comment.textContent.trim();
      }
      if ($collectInfo) {
          const textArr = $collectInfo.textContent.split('/');
          collectInfo.date = textArr[0].trim();
          textArr.forEach((str) => {
              if (str.match('标签')) {
                  collectInfo.tags = str.replace(/标签:/, '').trim();
              }
          });
          const $starlight = $collectInfo.querySelector('.starlight');
          if ($starlight) {
              $starlight.classList.forEach((s) => {
                  if (/stars\d/.test(s)) {
                      collectInfo.score = s.replace('stars', '');
                  }
              });
          }
      }
      if (Object.keys(collectInfo).length) {
          collectInfo.tags = collectInfo.tags || '';
          collectInfo.comment = collectInfo.comment || '';
          itemSubject.collectInfo = collectInfo;
      }
      const $cover = $item.querySelector('.subjectCover img');
      if ($cover && $cover.tagName.toLowerCase() === 'img') {
          // 替换 cover/s --->  cover/l 是大图
          const src = $cover.getAttribute('src') || $cover.getAttribute('data-cfsrc');
          if (src) {
              itemSubject.cover = src.replace('pic/cover/s', 'pic/cover/l');
          }
      }
      return itemSubject;
  }
  function getItemInfos$1($doc = document) {
      const items = $doc.querySelectorAll('#browserItemList>li');
      const res = [];
      for (const item of Array.from(items)) {
          res.push(convertItemInfo$1(item));
      }
      return res;
  }
  function getTotalPageNum$2($doc = document) {
      const $multipage = $doc.querySelector('#multipage');
      let totalPageNum = 1;
      const pList = $multipage?.querySelectorAll('.page_inner>.p');
      if (pList && pList.length) {
          let tempNum = parseInt(pList[pList.length - 2].getAttribute('href').match(/page=(\d*)/)[1]);
          totalPageNum = parseInt(pList[pList.length - 1].getAttribute('href').match(/page=(\d*)/)[1]);
          totalPageNum = totalPageNum > tempNum ? totalPageNum : tempNum;
      }
      return totalPageNum;
  }
  function genCollectionURL$1(userId, subjectType, interestType) {
      const dict = {
          movie: 'anime',
          music: 'music',
          book: 'book',
      };
      return `https://bgm.tv/${dict[subjectType]}/list/${userId}/${interestType}`;
  }
  async function getAllPageInfo$1(userId, subjectType, interestType) {
      const url = genCollectionURL$1(userId, subjectType, interestType);
      console.info('bgm collection page: ', url);
      const rawText = await fetchText(url);
      const $doc = new DOMParser().parseFromString(rawText, 'text/html');
      const totalPageNum = getTotalPageNum$2($doc);
      const res = [...getItemInfos$1($doc)];
      let page = 2;
      while (page <= totalPageNum) {
          let reqUrl = url;
          const m = url.match(/page=(\d*)/);
          if (m) {
              reqUrl = reqUrl.replace(m[0], `page=${page}`);
          }
          else {
              reqUrl = `${reqUrl}?page=${page}`;
          }
          await sleep(500);
          console.info('fetch info: ', reqUrl);
          const rawText = await fetchText(reqUrl);
          const $doc = new DOMParser().parseFromString(rawText, 'text/html');
          res.push(...getItemInfos$1($doc));
          page += 1;
      }
      return res;
  }
  function loadIframe$1($iframe, subjectId) {
      return new Promise((resolve, reject) => {
          $iframe.src = `/update/${subjectId}`;
          let timer = setTimeout(() => {
              timer = null;
              reject('bangumi iframe timeout');
          }, 5000);
          $iframe.onload = () => {
              clearTimeout(timer);
              $iframe.onload = null;
              resolve(null);
          };
      });
  }
  async function getUpdateForm(subjectId) {
      const iframeId = 'e-userjs-update-interest';
      let $iframe = document.querySelector(`#${iframeId}`);
      if (!$iframe) {
          $iframe = document.createElement('iframe');
          $iframe.style.display = 'none';
          $iframe.id = iframeId;
          document.body.appendChild($iframe);
      }
      await loadIframe$1($iframe, subjectId);
      const $form = $iframe.contentDocument.querySelector('#collectBoxForm');
      return $form;
      // return $form.action;
  }
  /**
   * 更新用户收藏
   * @param subjectId 条目 id
   * @param data 更新数据
   */
  async function updateInterest$1(subjectId, data) {
      // gh 暂时不知道如何获取,直接拿 action 了
      const $form = await getUpdateForm(subjectId);
      const formData = new FormData($form);
      const obj = Object.assign({ referer: 'ajax', tags: '', comment: '', update: '保存' }, data);
      for (let [key, val] of Object.entries(obj)) {
          if (!formData.has(key)) {
              formData.append(key, val);
          }
          else {
              // 标签和吐槽可以直接清空
              if (['tags', 'comment', 'rating'].includes(key)) {
                  formData.set(key, val);
              }
              else if (!formData.get(key) && val) {
                  formData.set(key, val);
              }
          }
      }
      await fetch($form.action, {
          method: 'POST',
          body: formData,
      });
  }

  const SUB_TITLE_PAIRS = ['--', '──', '~~', '~~', '--', '<>', '<>'];
  function getAliasByName(name) {
      const opens = SUB_TITLE_PAIRS.map(pair => pair[0]);
      const closes = SUB_TITLE_PAIRS.map(pair => pair[1]);
      const len = name.length;
      if (closes.includes(name[len - 1])) {
          let i = len - 1;
          const c = name[len - 1];
          let idx = closes.indexOf(c);
          const openChar = opens[idx];
          const j = name.lastIndexOf(openChar, i - 1);
          if (j >= 0) {
              return [name.slice(0, j).trim(), name.slice(j + 1, i)];
          }
      }
      return [];
  }
  function removePairs(str, pairs = []) {
      for (let i = 0; i < pairs.length; i++) {
          if (pairs.length < 2) {
              continue;
          }
          const [open, close] = pairs[i];
          str = str.replace(new RegExp(open + '.+?' + close, 'g'), '');
      }
      return str
          .replace(/\(.*?\)/g, '')
          .replace(/\(.*?\)/g, '')
          .replace(/<.+?>/, '')
          .replace(/<.+?>/, '');
  }
  function removeSubTitle(str) {
      return removePairs(str, SUB_TITLE_PAIRS).trim();
  }
  function unique(str) {
      var result = '';
      for (var i = 0; i < str.length; i++) {
          if (result.indexOf(str[i]) < 0) {
              result += str[i];
          }
      }
      return result;
  }
  function charsToSpace(originStr, chars) {
      return originStr.replace(new RegExp(`[${chars}]`, 'g'), ' ').replace(/\s{2,}/g, ' ');
  }
  function replaceCharsToSpace(str, excludes = '', extra = '') {
      const fullwidthPair = '~-<>';
      // @TODO 需要更多测试
      var symbolString = '―〜━『』~\'…!?。♥☆/♡★‥○【】◆×▼’'"*?' + '.・ ' + fullwidthPair;
      if (excludes) {
          symbolString = symbolString.replace(new RegExp(`[${excludes}]`, 'g'), '');
      }
      symbolString = symbolString + extra;
      let output = charsToSpace(str, unique(symbolString));
      // output =  output.replace(/[&,\[\]]/g, ' ');
      return output;
  }
  function pairCharsToSpace(str) {
      return charsToSpace(str, unique(SUB_TITLE_PAIRS.join(''))).trim();
  }
  function replaceToASCII(str) {
      return str
          .replace(/=|=/g, ' ')
          .replace(/ /g, ' ')
          .replace(/0/g, '0')
          .replace(/1/g, '1')
          .replace(/2/g, '2')
          .replace(/3/g, '3')
          .replace(/4/g, '4')
          .replace(/5/g, '5')
          .replace(/6/g, '6')
          .replace(/7/g, '7')
          .replace(/8/g, '8')
          .replace(/9/g, '9')
          .replace(/Ⅰ/g, 'I')
          .replace(/Ⅱ/g, 'II')
          .replace(/Ⅲ/g, 'III')
          .replace(/Ⅳ/g, 'IV')
          .replace(/Ⅴ/g, 'V')
          .replace(/Ⅵ/g, 'VI')
          .replace(/Ⅶ/g, 'VII')
          .replace(/Ⅷ/g, 'VIII')
          .replace(/Ⅸ/g, 'IX')
          .replace(/Ⅹ/g, 'X');
  }
  function isEnglishName(name) {
      return /^[a-zA-Z][a-zA-Z\s.-]*[a-zA-Z]$/.test(name);
  }
  function isKatakanaName(name) {
      // ァ-ン
      return /^[ァ-ヶ][ァ-ヶー・\s]*[ァ-ヶー]?$/.test(name);
  }

  /**
   * 为页面添加样式
   * @param style
   */
  /**
   * 下载内容
   * https://stackoverflow.com/questions/14964035/how-to-export-javascript-array-info-to-csv-on-client-side
   * @example
   * download(csvContent, 'dowload.csv', 'text/csv;encoding:utf-8');
   * BOM: data:text/csv;charset=utf-8,\uFEFF
   * @param content 内容
   * @param fileName 文件名
   * @param mimeType 文件类型
   */
  function downloadFile(content, fileName, mimeType = 'application/octet-stream') {
      var a = document.createElement('a');
      a.href = URL.createObjectURL(new Blob([content], {
          type: mimeType,
      }));
      a.style.display = 'none';
      a.setAttribute('download', fileName);
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
  }
  /**
   * @param {String} HTML 字符串
   * @return {Element}
   */
  function htmlToElement(html) {
      var template = document.createElement('template');
      html = html.trim();
      template.innerHTML = html;
      // template.content.childNodes;
      return template.content.firstChild;
  }
  /**
   * 载入 iframe
   * @param $iframe iframe DOM
   * @param src iframe URL
   * @param TIMEOUT time out
   */
  function loadIframe($iframe, src, TIMEOUT = 5000) {
      return new Promise((resolve, reject) => {
          $iframe.src = src;
          let timer = setTimeout(() => {
              timer = null;
              $iframe.onload = undefined;
              reject('iframe timeout');
          }, TIMEOUT);
          $iframe.onload = () => {
              clearTimeout(timer);
              $iframe.onload = null;
              resolve(null);
          };
      });
  }

  function getSearchItem($item) {
      let $subjectTitle = $item.querySelector('h3>a.l');
      let info = {
          name: $subjectTitle.textContent.trim(),
          // url 没有协议和域名
          url: $subjectTitle.getAttribute('href'),
          greyName: $item.querySelector('h3>.grey') ? $item.querySelector('h3>.grey').textContent.trim() : '',
      };
      let matchDate = $item.querySelector('.info').textContent.match(/\d{4}[\-\/\年]\d{1,2}[\-\/\月]\d{1,2}/);
      if (matchDate) {
          info.releaseDate = dealDate(matchDate[0]);
      }
      let $rateInfo = $item.querySelector('.rateInfo');
      if ($rateInfo) {
          if ($rateInfo.querySelector('.fade')) {
              info.score = $rateInfo.querySelector('.fade').textContent;
              info.count = $rateInfo.querySelector('.tip_j').textContent.replace(/[^0-9]/g, '');
          }
          else {
              info.score = '0';
              info.count = '少于10';
          }
      }
      else {
          info.score = '0';
          info.count = '0';
      }
      return info;
  }
  function extractInfoList($doc) {
      return [...$doc.querySelectorAll('#browserItemList>li')].map(($item) => {
          return getSearchItem($item);
      });
  }
  function getTotalPageNum$1($doc = document) {
      const $multipage = $doc.querySelector('#multipage');
      let totalPageNum = 1;
      const pList = $multipage?.querySelectorAll('.page_inner>.p');
      if (pList && pList.length) {
          let tempNum = parseInt(pList[pList.length - 2].getAttribute('href').match(/page=(\d*)/)[1]);
          totalPageNum = parseInt(pList[pList.length - 1].getAttribute('href').match(/page=(\d*)/)[1]);
          totalPageNum = totalPageNum > tempNum ? totalPageNum : tempNum;
      }
      return totalPageNum;
  }
  function filterSubjectByNameAndDate(items, subjectInfo) {
      const list = items.filter((item) => isEqualDate(item.releaseDate, subjectInfo.releaseDate));
      if (list.length === 0)
          return;
      let res = list.find((item) => item.name === subjectInfo.name);
      if (res) {
          return res;
      }
      return list.find((item) => item.greyName === subjectInfo.name);
  }

  var BangumiDomain;
  (function (BangumiDomain) {
      BangumiDomain["chii"] = "chii.in";
      BangumiDomain["bgm"] = "bgm.tv";
      BangumiDomain["bangumi"] = "bangumi.tv";
  })(BangumiDomain || (BangumiDomain = {}));
  var Protocol;
  (function (Protocol) {
      Protocol["http"] = "http";
      Protocol["https"] = "https";
  })(Protocol || (Protocol = {}));
  function normalizeQueryBangumi(query) {
      query = replaceToASCII(query);
      query = removePairs(query);
      query = pairCharsToSpace(query);
      // fix いつまでも僕だけのママのままでいて!
      query = replaceCharsToSpace(query, '', '!');
      return query.trim();
  }
  /**
   * 搜索条目并过滤出搜索结果
   * @param subjectInfo
   * @param type
   * @param uniqueQueryStr
   */
  async function searchSubject(subjectInfo, bgmHost = 'https://bgm.tv', type = SubjectTypeId.all, uniqueQueryStr = '', opts = {}) {
      // fuse options
      const fuseOptions = {
          uniqueSearch: false,
          keys: ['name', 'greyName'],
      };
      let query = normalizeQueryBangumi((subjectInfo.name || '').trim());
      if (type === SubjectTypeId.book) {
          // 去掉末尾的括号并加上引号
          query = query.replace(/([^0-9]+?)|\([^0-9]+?\)$/, '');
          query = `"${query}"`;
      }
      if (opts.query) {
          query = opts.query;
      }
      // for example: book's ISBN
      if (uniqueQueryStr) {
          query = `"${uniqueQueryStr || ''}"`;
          fuseOptions.uniqueSearch = true;
      }
      if (!query || query === '""') {
          console.info('Query string is empty');
          return;
      }
      const url = `${bgmHost}/subject_search/${encodeURIComponent(query)}?cat=${type}`;
      console.info('search bangumi subject URL: ', url);
      const content = await fetchText(url);
      const $doc = new DOMParser().parseFromString(content, 'text/html');
      const rawInfoList = extractInfoList($doc);
      // 使用指定搜索字符串如 ISBN 搜索时, 并且结果只有一条时,不再使用名称过滤
      if (uniqueQueryStr && rawInfoList && rawInfoList.length === 1) {
          return rawInfoList[0];
      }
      if (type === SubjectTypeId.game) {
          const name = subjectInfo.name;
          if (getAliasByName(name).length > 0) {
              // fix: グリザイアの楽園 -LE EDEN DE LA GRISAIA-
              const changedName = removeSubTitle(name);
              const info = { ...subjectInfo, name: changedName };
              let res = filterResults(rawInfoList, info, {
                  ...fuseOptions,
                  score: 0.1,
                  sameDate: true,
              });
              if (res) {
                  return res;
              }
          }
          if (isSingleJpSegment(subjectInfo.name) && rawInfoList.length >= 6) {
              return filterSubjectByNameAndDate(rawInfoList, subjectInfo);
          }
          // fix: "ソード(同人フリー版)"
          if (name.startsWith(query) && /[))>>]$/.test(name)) {
              return filterResults(rawInfoList, {
                  ...subjectInfo,
                  name: query,
              }, {
                  ...fuseOptions,
                  score: 0.1,
                  sameDate: true,
              });
          }
      }
      if (type === SubjectTypeId.anime) ;
      return filterResults(rawInfoList, subjectInfo, fuseOptions);
  }
  /**
   * 通过时间查找条目
   * @param subjectInfo 条目信息
   * @param pageNumber 页码
   * @param type 条目类型
   */
  async function findSubjectByDate(subjectInfo, bgmHost = 'https://bgm.tv', pageNumber = 1, type) {
      if (!subjectInfo || !subjectInfo.releaseDate || !subjectInfo.name) {
          throw new Error('invalid subject info');
      }
      const releaseDate = new Date(subjectInfo.releaseDate);
      if (isNaN(releaseDate.getTime())) {
          throw `invalid releasedate: ${subjectInfo.releaseDate}`;
      }
      const sort = releaseDate.getDate() > 15 ? 'sort=date' : '';
      const page = pageNumber ? `page=${pageNumber}` : '';
      let query = '';
      if (sort && page) {
          query = '?' + sort + '&' + page;
      }
      else if (sort) {
          query = '?' + sort;
      }
      else if (page) {
          query = '?' + page;
      }
      const url = `${bgmHost}/${type}/browser/airtime/${releaseDate.getFullYear()}-${releaseDate.getMonth() + 1}${query}`;
      console.info('find subject by date: ', url);
      const rawText = await fetchText(url);
      const $doc = new DOMParser().parseFromString(rawText, 'text/html');
      const rawInfoList = extractInfoList($doc);
      const numOfPage = getTotalPageNum$1($doc);
      const options = {
          threshold: 0.3,
          keys: ['name', 'greyName'],
      };
      let result = filterResults(rawInfoList, subjectInfo, options);
      if (!result) {
          if (pageNumber < numOfPage) {
              await sleep(300);
              return await findSubjectByDate(subjectInfo, bgmHost, pageNumber + 1, type);
          }
          else {
              throw 'notmatched';
          }
      }
      return result;
  }
  function isUniqueQuery(info) {
      // fix: ヴァージン・トリガー
      if (isKatakanaName(info.name) || isEnglishName(info.name)) {
          return true;
      }
      // fix いろとりどりのセカイ
      if (/^[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Han}ー々\s]+$/u.test(info.name)) {
          return true;
      }
  }
  /**
   * 查找条目是否存在: 通过名称搜索或者日期加上名称的过滤查询
   * @param subjectInfo 条目基本信息
   * @param bgmHost bangumi 域名
   * @param type 条目类型
   */
  async function checkExist(subjectInfo, bgmHost = 'https://bgm.tv', type, opts) {
      const subjectTypeDict = {
          [SubjectTypeId.game]: 'game',
          [SubjectTypeId.anime]: 'anime',
          [SubjectTypeId.music]: 'music',
          [SubjectTypeId.book]: 'book',
          [SubjectTypeId.real]: 'real',
          [SubjectTypeId.all]: 'all',
      };
      let searchOpts = {};
      if (typeof opts === 'object') {
          searchOpts = opts;
      }
      const normalizedStr = normalizeQueryBangumi((subjectInfo.name || '').trim());
      // fix long name
      if (subjectInfo.name.length > 50) {
          let query = normalizeQueryBangumi(subjectInfo.name.split(' ')[0]);
          return await searchSubject(subjectInfo, bgmHost, type, '', {
              ...searchOpts,
              shortenQuery: true,
              query,
          });
      }
      if (isUniqueQuery(subjectInfo)) {
          return await searchSubject(subjectInfo, bgmHost, type, subjectInfo.name.trim(), searchOpts);
      }
      let searchResult = await searchSubject(subjectInfo, bgmHost, type, '', searchOpts);
      console.info(`First: search result of bangumi: `, searchResult);
      if (searchResult && searchResult.url) {
          return searchResult;
      }
      if (searchOpts.enableShortenQuery) {
          await sleep(300);
          const shortenedQuery = getShortenedQuery(normalizedStr);
          if (shortenedQuery === normalizedStr) {
              return;
          }
          searchResult = await searchSubject(subjectInfo, bgmHost, type, '', {
              ...searchOpts,
              shortenQuery: true,
              query: shortenedQuery,
          });
          if (searchResult && searchResult.url) {
              return searchResult;
          }
      }
      // disableDate
      if ((typeof opts === 'boolean' && opts) || (typeof opts === 'object' && opts.disableDate)) {
          return;
      }
      searchResult = await findSubjectByDate(subjectInfo, bgmHost, 1, subjectTypeDict[type]);
      console.info(`Second: search result by date: `, searchResult);
      return searchResult;
  }
  async function checkAnimeSubjectExist$1(subjectInfo) {
      const result = await checkExist(subjectInfo, getBgmHost(), SubjectTypeId.anime, true);
      return result;
  }
  const siteUtils$1 = {
      name: 'Bangumi',
      contanerSelector: '#columnHomeB',
      getUserId: getUserId$1,
      getSubjectId: getSubjectId$1,
      updateInterest: updateInterest$1,
      checkSubjectExist: checkAnimeSubjectExist$1,
      getAllPageInfo: getAllPageInfo$1,
  };

  function genCollectionURL(userId, interestType, subjectType = 'movie', start = 1) {
      const baseURL = `https://${subjectType}.douban.com/people/${userId}/${interestType}`;
      if (start === 1) {
          return baseURL;
      }
      else {
          return `${baseURL}?start=${start}&sort=time&rating=all&filter=all&mode=grid`;
      }
  }
  function convertBangumiScore(num) {
      return Math.ceil(num / 2);
      // if (num < 4) {
      //   return 1;
      // }
      // if (num < 6) {
      //   return 2;
      // }
      // if (num < 8) return 3;
      // if (num < 9) return 4;
      // if (num === 10) return 5;
      // return 0;
  }
  function getSubjectId(url) {
      const m = url.match(/movie\.douban\.com\/subject\/(\d+)/);
      if (m) {
          return m[1];
      }
      return '';
  }
  function getUserId(homeURL) {
      let m = homeURL.match(/douban.com\/people\/([^\/]*)\//);
      if (m) {
          return m[1];
      }
      return '';
  }
  function convertItemInfo($item) {
      let $subjectTitle = $item.querySelector('.info .title a');
      // 默认第二项为日文名
      const titleArr = $subjectTitle.textContent
          .trim()
          .split('/')
          .map((str) => str.trim());
      const rawInfos = $item.querySelector('.info .intro').textContent.trim();
      let itemSubject = {
          name: titleArr[1],
          rawInfos,
          url: $subjectTitle.getAttribute('href'),
          greyName: titleArr[0],
      };
      const $cover = $item.querySelector('.pic img');
      if ($cover && $cover.tagName.toLowerCase() === 'img') {
          const src = $cover.getAttribute('src');
          if (src) {
              itemSubject.cover = src;
          }
      }
      const jpDateReg = /(\d+-\d\d\-\d\d)(?:\(日本\))/;
      const dateReg = /\d+-\d\d\-\d\d/;
      let m;
      if ((m = rawInfos.match(jpDateReg))) {
          itemSubject.releaseDate = m[1];
      }
      else if ((m = rawInfos.match(dateReg))) {
          itemSubject.releaseDate = m[0];
      }
      const $collectInfo = $item.querySelector('.info');
      if ($collectInfo) {
          const collectInfo = {};
          collectInfo.date = $collectInfo
              .querySelector('li .date')
              ?.textContent.trim();
          collectInfo.tags = $collectInfo
              .querySelector('li .tags')
              ?.textContent.replace('标签: ', '')
              .trim() ?? '';
          collectInfo.comment = $collectInfo
              .querySelector('li .comment')
              ?.textContent.trim() ?? '';
          const $rating = $collectInfo.querySelector('[class^=rating]');
          if ($rating) {
              const m = $rating.getAttribute('class').match(/\d/);
              if (m) {
                  // 十分制
                  collectInfo.score = +m[0] * 2;
              }
          }
          itemSubject.collectInfo = collectInfo;
      }
      return itemSubject;
  }
  function getTotalPageNum($doc = document) {
      const numStr = $doc.querySelector('.mode > .subject-num').textContent.trim();
      return Number(numStr.split('/')[1].trim());
  }
  /**
   * 拿到当前页面豆瓣用户收藏信息列表
   * @param $doc DOM
   */
  function getItemInfos($doc = document) {
      const items = $doc.querySelectorAll('#content .grid-view > .item');
      const res = [];
      for (const item of Array.from(items)) {
          res.push(convertItemInfo(item));
      }
      return res;
  }
  /**
   * 获取所有分页的条目数据
   * @param userId 用户id
   * @param subjectType 条目类型
   * @param interestType 条目状态
   */
  async function getAllPageInfo(userId, subjectType = 'movie', interestType) {
      let res = [];
      const url = genCollectionURL(userId, interestType, subjectType);
      const rawText = await fetchText(url);
      const $doc = new DOMParser().parseFromString(rawText, 'text/html');
      const totalPageNum = getTotalPageNum($doc);
      res = [...getItemInfos($doc)];
      // 16 分割
      let page = 16;
      while (page <= totalPageNum) {
          let reqUrl = genCollectionURL(userId, interestType, subjectType, page);
          await sleep(500);
          console.info('fetch info: ', reqUrl);
          const rawText = await fetchText(reqUrl);
          const $doc = new DOMParser().parseFromString(rawText, 'text/html');
          res.push(...getItemInfos($doc));
          page += 15;
      }
      return res;
  }
  function convertHomeSearchItem($item) {
      const dealHref = (href) => {
          if (/^https:\/\/movie\.douban\.com\/subject\/\d+\/$/.test(href)) {
              return href;
          }
          const urlParam = href.split('?url=')[1];
          if (urlParam) {
              return decodeURIComponent(urlParam.split('&')[0]);
          }
          else {
              throw 'invalid href';
          }
      };
      const $title = $item.querySelector('.title h3 > a');
      const href = dealHref($title.getAttribute('href'));
      const $ratingNums = $item.querySelector('.rating-info > .rating_nums');
      let ratingsCount = '';
      let averageScore = '';
      if ($ratingNums) {
          const $count = $ratingNums.nextElementSibling;
          const m = $count.innerText.match(/\d+/);
          if (m) {
              ratingsCount = m[0];
          }
          averageScore = $ratingNums.innerText;
      }
      let greyName = '';
      const $greyName = $item.querySelector('.subject-cast');
      if ($greyName) {
          greyName = $greyName.innerText;
      }
      return {
          name: $title.textContent.trim(),
          greyName: greyName.split('/')[0].replace('原名:', '').trim(),
          releaseDate: (greyName.match(/\d{4}$/) || [])[0],
          url: href,
          score: averageScore,
          count: ratingsCount,
      };
  }
  /**
   * 通过首页搜索的结果
   * @param query 搜索字符串
   */
  async function getHomeSearchResults(query, cat = '1002') {
      const url = `https://www.douban.com/search?cat=${cat}&q=${encodeURIComponent(query)}`;
      console.info('Douban search URL: ', url);
      const rawText = await fetchText(url);
      const $doc = new DOMParser().parseFromString(rawText, 'text/html');
      const items = $doc.querySelectorAll('.search-result > .result-list > .result > .content');
      return Array.prototype.slice
          .call(items)
          .map(($item) => convertHomeSearchItem($item));
  }
  /**
   * 提取所有 search.douban.com 的条目信息
   * @param $doc 页面容器
   */
  function getAllSearchResult($doc = document) {
      let items = $doc.querySelectorAll('#root .item-root');
      return Array.prototype.slice
          .call(items)
          .map(($item) => convertSubjectSearchItem($item));
  }
  /**
   * 提取 search.douban.com 的条目信息
   * @param $item 单项搜索结果容器 DOM
   */
  function convertSubjectSearchItem($item) {
      // item-root
      const $title = $item.querySelector('.title a');
      let name = '';
      let releaseDate = '';
      let rawName = '';
      if ($title) {
          const rawText = $title.textContent.trim();
          rawName = rawText;
          const yearRe = /\((\d{4})\)$/;
          releaseDate = (rawText.match(yearRe) || ['', ''])[1];
          let arr = rawText.split(/ (?!-)/);
          if (arr && arr.length === 2) {
              name = arr[0];
              arr[1].replace(yearRe, '');
          }
          else {
              arr = rawText.split(/ (?!(-|\w))/);
              name = arr[0];
              rawText.replace(name, '').trim().replace(yearRe, '').trim();
          }
      }
      let ratingsCount = '';
      let averageScore = '';
      const $ratingNums = $item.querySelector('.rating_nums');
      if ($ratingNums) {
          const $count = $ratingNums.nextElementSibling;
          const m = $count.textContent.match(/\d+/);
          if (m) {
              ratingsCount = m[0];
          }
          averageScore = $ratingNums.textContent;
      }
      return {
          name,
          rawName,
          url: $title.getAttribute('href'),
          score: averageScore,
          count: ratingsCount,
          releaseDate,
      };
  }
  /**
   * 单独类型搜索入口
   * @param query 搜索字符串
   * @param cat 搜索类型
   * @param type 获取传递数据的类型: gm 通过 GM_setValue, message 通过 postMessage
   */
  async function getSubjectSearchResults(query, cat = '1002') {
      const url = `https://search.douban.com/movie/subject_search?search_text=${encodeURIComponent(query)}&cat=${cat}`;
      console.info('Douban search URL: ', url);
      const iframeId = 'e-userjs-search-subject';
      let $iframe = document.querySelector(`#${iframeId}`);
      if (!$iframe) {
          $iframe = document.createElement('iframe');
          $iframe.setAttribute('sandbox', 'allow-forms allow-same-origin allow-scripts');
          $iframe.style.display = 'none';
          $iframe.id = iframeId;
          document.body.appendChild($iframe);
      }
      // 这里不能使用 await 否则数据加载完毕了监听器还没有初始化
      loadIframe($iframe, url, 1000 * 10);
      return await getSearchSubjectByGM();
  }
  async function sendSearchResults() {
      const searchItems = getAllSearchResult();
      setSearchResultByGM(searchItems);
  }
  async function updateInterest(subjectId, data) {
      const interestObj = findInterestStatusById(data.interest);
      let query = '';
      if (data.interest !== undefined) {
          query = 'interest=' + interestObj.key;
      }
      let url = `https://movie.douban.com/j/subject/${subjectId}/interest?${query}`;
      const collectInfo = await fetchJson(url);
      const interestStatus = collectInfo.interest_status;
      const tags = collectInfo.tags;
      const $doc = new DOMParser().parseFromString(collectInfo.html, 'text/html');
      const $form = $doc.querySelector('form');
      const formData = new FormData($form);
      const sendData = {
          interest: interestObj.key,
          tags: data.tags,
          comment: data.comment,
          rating: convertBangumiScore(+data.rating) + '',
      };
      if (tags && tags.length) {
          sendData.tags = tags.join(' ');
      }
      if (interestStatus) {
          sendData.interest = interestStatus;
      }
      if (data.privacy === '1') {
          // @ts-ignore
          sendData.privacy = 'on';
      }
      for (let [key, val] of Object.entries(sendData)) {
          if (!formData.has(key)) {
              formData.append(key, val);
          }
          else if (formData.has(key) && !formData.get(key) && val) {
              formData.set(key, val);
          }
      }
      // share-shuo: douban  删除分享广播
      if (formData.has('share-shuo')) {
          formData.delete('share-shuo');
      }
      await fetch($form.action, {
          method: 'POST',
          headers: {
              'X-Requested-With': 'XMLHttpRequest',
          },
          body: formData,
      });
  }
  /**
   *
   * @param subjectInfo 条目信息
   * @param type 默认使用主页搜索
   * @returns 搜索结果
   */
  async function checkAnimeSubjectExist(subjectInfo, type = 'home_search') {
      let query = (subjectInfo.name || '').trim();
      if (!query) {
          console.info('Query string is empty');
          return Promise.reject();
      }
      let rawInfoList;
      let searchResult;
      const options = {
          sameYear: true,
          keys: ['name', 'greyName'],
      };
      if (type === 'home_search') {
          rawInfoList = await getHomeSearchResults(query);
      }
      else {
          rawInfoList = await getSubjectSearchResults(query);
      }
      searchResult = filterResults(rawInfoList, subjectInfo, options);
      console.info(`Search result of ${query} on Douban: `, searchResult);
      if (searchResult && searchResult.url) {
          return searchResult;
      }
  }
  const siteUtils = {
      name: '豆瓣',
      contanerSelector: '#content .aside',
      getUserId,
      getSubjectId,
      getAllPageInfo,
      updateInterest,
      checkSubjectExist: checkAnimeSubjectExist,
  };

  function insertControl(contanerSelector, name) {
      GM_addStyle(`
  .e-userjs-export-tool-container input {
    margin-bottom: 12px;
  }
  .e-userjs-export-tool-container .title {
    color: #F09199;
    font-weight: bold;
    font-size: 14px;
    margin: 12px 0;
    display: inline-block;
  }
  .e-userjs-export-tool-container .import-btn{
    margin-top: 12px;
  }
  .e-userjs-export-tool-container .export-btn {
    display: none;
  }
  .e-userjs-export-tool-container .retry-btn {
    display: none;
  }
  .ui-button {
    display: inline-block;
    line-height: 20px;
    font-size: 14px;
    text-align: center;
    color: #4c5161;
    border-radius: 4px;
    border: 1px solid #d0d0d5;
    padding: 9px 15px;
    min-width: 80px;
    background-color: #fff;
    background-repeat: no-repeat;
    background-position: center;
    text-decoration: none;
    box-sizing: border-box;
    transition: border-color .15s, box-shadow .15s, opacity .15s;
    font-family: inherit;
    cursor: pointer;
    overflow: visible;

    background-color: #2a80eb;
    color: #fff;
  }
`);
      const $parent = document.querySelector(contanerSelector);
      const $container = htmlToElement(`
<div class="e-userjs-export-tool-container">
<div>
  <span class="title">${name}主页 URL: </span><br/>
  <input placeholder="输入${name}主页的 URL" class="inputtext" autocomplete="off" type="text" size="30" name="tags" value="">
</div>
  <div>
<label for="movie-type-select">选择同步类型:</label>
<select name="movieType" id="movie-type-select">
    <option value="">所有</option>
    <option value="do">在看</option>
    <option value="wish">想看</option>
    <option value="collect">看过</option>
</select>
  </div>
  <button class="ui-button import-btn" type="submit">
导入${name}动画收藏
  </button>
  <br/>
  <button class="ui-button export-btn" type="submit">
导出${name}动画的收藏同步信息
  </button>
  <button class="ui-button retry-btn" type="submit">
重新同步失败的条目
  </button>
</div>
  `);
      $parent.appendChild($container);
      return $container;
  }

  let bangumiData = null;
  const typeIdDict = {
      dropped: {
          name: '抛弃',
          id: '5',
      },
      on_hold: {
          name: '搁置',
          id: '4',
      },
      do: {
          name: '在看',
          id: '3',
      },
      collect: {
          name: '看过',
          id: '2',
      },
      wish: {
          name: '想看',
          id: '1',
      },
  };
  function getBangumiSubjectId(name = '', greyName = '') {
      if (!bangumiData)
          return;
      const obj = bangumiData.items.find((item) => {
          let cnNames = [];
          if (item.titleTranslate && item.titleTranslate['zh-Hans']) {
              cnNames = item.titleTranslate['zh-Hans'];
          }
          return (item.title === name ||
              item.title === greyName ||
              cnNames.includes(greyName));
      });
      return obj?.sites?.find((item) => item.site === 'bangumi').id;
  }
  function genCSVContent(infos) {
      const header = '\ufeff名称,别名,发行日期,地址,封面地址,收藏日期,我的评分,标签,吐槽,其它信息,类别,同步情况,搜索结果信息';
      let csvContent = '';
      const keys = Object.keys(infos);
      keys.forEach((key) => {
          infos[key].forEach((item) => {
              csvContent += `\r\n${item.name || ''},${item.greyName || ''},${item.releaseDate || ''}`;
              const subjectUrl = item.url;
              csvContent += `,${subjectUrl}`;
              const cover = item.cover || '';
              csvContent += `,${cover}`;
              const collectInfo = item.collectInfo || {};
              const collectDate = collectInfo.date || '';
              csvContent += `,${collectDate}`;
              const score = collectInfo.score || '';
              csvContent += `,${score}`;
              const tag = collectInfo.tags || '';
              csvContent += `,${tag}`;
              const comment = collectInfo.comment || '';
              csvContent += `,"${comment}"`;
              const rawInfos = item.rawInfos || '';
              csvContent += `,"${rawInfos}"`;
              csvContent += `,"${typeIdDict[key].name}"`;
              csvContent += `,${item.syncStatus || ''}`;
              // 新增搜索结果信息
              let searchResultStr = '';
              if (item.syncSubject) {
                  const obj = item.syncSubject;
                  searchResultStr = `${obj.name};${obj.greyName || ''};${obj.url || ''};${obj.rawName || ''}`;
              }
              // 同步信息
              csvContent += `,"${searchResultStr}"`;
          });
      });
      return header + csvContent;
  }
  // 区分是否为动画
  function isJpMovie(item) {
      return item.rawInfos.indexOf('日本') !== -1;
  }
  function clearLogInfo($container) {
      $container
          .querySelectorAll('.e-wiki-log-info')
          .forEach((node) => node.remove());
  }
  function init(site) {
      let targetUtils;
      let originUtils;
      if (site === 'bangumi') {
          targetUtils = siteUtils;
          originUtils = siteUtils$1;
      }
      else {
          targetUtils = siteUtils$1;
          originUtils = siteUtils;
      }
      const $container = insertControl(originUtils.contanerSelector, targetUtils.name);
      const $input = $container.querySelector('input');
      const $importBtn = $container.querySelector('.import-btn');
      const $exportBtn = $container.querySelector('.export-btn');
      const $retryBtn = $container.querySelector('.retry-btn');
      const interestInfos = {
          do: [],
          collect: [],
          wish: [],
          dropped: [],
          on_hold: [],
      };
      $exportBtn.addEventListener('click', async (e) => {
          const $text = e.target;
          $text.value = '导出中...';
          let name = 'Bangumi';
          if (site === 'bangumi') {
              name = '豆瓣';
          }
          let strName = `${name}动画的收藏`;
          const csv = genCSVContent(interestInfos);
          // $text.value = '导出完成';
          $text.style.display = 'none';
          downloadFile(csv, `${strName}-${formatDate(new Date())}.csv`);
      });
      $retryBtn.addEventListener('click', async (e) => {
          try {
              bangumiData = JSON.parse(GM_getResourceText('bangumiDataURL'));
          }
          catch (e) {
              console.log('parse JSON:', e);
          }
          const userId = getUserIdFromInput($input.value, targetUtils.getUserId);
          if (!userId)
              return;
          const arr = getInterestTypeArr();
          for (let type of arr) {
              const res = interestInfos[type];
              for (let i = 0; i < res.length; i++) {
                  let item = res[i];
                  if (!item.syncStatus) {
                      item = await migrateCollection(originUtils, item, site, type);
                  }
                  res[i] = item;
              }
          }
          clearLogInfo($container);
          $exportBtn.style.display = 'inline-block';
          $retryBtn.style.display = 'inline-block';
      });
      $importBtn.addEventListener('click', async (e) => {
          try {
              bangumiData = JSON.parse(GM_getResourceText('bangumiDataURL'));
          }
          catch (e) {
              console.log('parse JSON:', e);
          }
          const userId = getUserIdFromInput($input.value, targetUtils.getUserId);
          if (!userId)
              return;
          const arr = getInterestTypeArr();
          for (let type of arr) {
              try {
                  const res = (await targetUtils.getAllPageInfo(userId, 'movie', type));
                  for (let i = 0; i < res.length; i++) {
                      let item = res[i];
                      item = await migrateCollection(originUtils, item, site, type);
                      res[i] = item;
                  }
                  interestInfos[type] = [...res];
              }
              catch (error) {
                  console.error(error);
              }
          }
          clearLogInfo($container);
          $exportBtn.style.display = 'inline-block';
          $retryBtn.style.display = 'inline-block';
      });
  }
  function getUserIdFromInput(val, fn) {
      if (!val) {
          alert(`请输入${name}主页地址`);
          return '';
      }
      const userId = fn(val);
      if (!userId) {
          alert(`无效${name}主页地址`);
          return '';
      }
      return userId;
  }
  function getInterestTypeArr() {
      const $container = document.querySelector('.e-userjs-export-tool-container');
      const $select = $container.querySelector('#movie-type-select');
      // const arr: InterestType[] = ['wish'];
      let arr = ['do', 'collect', 'wish'];
      if ($select && $select.value) {
          arr = [$select.value];
      }
      return arr;
  }
  async function migrateCollection(siteUtils, item, site, type) {
      const subjectItem = { ...item };
      const $container = document.querySelector('.e-userjs-export-tool-container');
      const $btn = $container.querySelector('.import-btn');
      // 在 Bangumi 上 非日语的条目跳过
      if (site === 'bangumi' && !isJpMovie(subjectItem)) {
          return subjectItem;
      }
      let subjectId = '';
      // 使用 bangumi data
      if (site === 'bangumi') {
          subjectId = getBangumiSubjectId(subjectItem.name, subjectItem.greyName);
      }
      if (!subjectId) {
          try {
              await randomSleep(1000, 400);
              const result = await siteUtils.checkSubjectExist({
                  name: subjectItem.name,
                  releaseDate: subjectItem.releaseDate,
              });
              if (result && result.url) {
                  subjectId = siteUtils.getSubjectId(result.url);
                  subjectItem.syncSubject = result;
              }
          }
          catch (error) {
              console.error(error);
          }
      }
      if (subjectId) {
          clearLogInfo($container);
          const nameStr = `<span style="color:tomato">《${subjectItem.name}》</span>`;
          insertLogInfo($btn, `更新收藏 ${nameStr} 中...`);
          await siteUtils.updateInterest(subjectId, {
              interest: typeIdDict[type].id,
              ...subjectItem.collectInfo,
              rating: subjectItem.collectInfo.score || '',
          });
          subjectItem.syncStatus = '成功';
          await randomSleep(2000, 1000);
          insertLogInfo($btn, `更新收藏 ${nameStr} 成功`);
      }
      return subjectItem;
  }
  if (location.href.match(/bgm.tv|bangumi.tv|chii.in/)) {
      init('bangumi');
  }
  if (location.href.match(/movie.douban.com/)) {
      init('douban');
  }
  if (location.href.match(/search\.douban\.com\/movie\/subject_search/)) {
      if (window.top !== window.self) {
          sendSearchResults();
      }
  }

})();