Greasy Fork

Greasy Fork is available in English.

Bangumi 标签批量管理

Bangumi 标签批量管理和修改自己可见

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        Bangumi 标签批量管理
// @description Bangumi 标签批量管理和修改自己可见
// @namespace   org.upsuper.bangumi
// @include     /^https?://(bgm\.tv|chii\.in|bangumi\.tv)/(anime|book|music|game|real)/list/.+$/
// @version     2.4
// @grant       GM_addStyle
// ==/UserScript==

var TIMEOUT = 3000,
    RETRY_INTERVAL = 1000;

function $(q, e) { return (e ? e : document).querySelector(q); }
function $a(q, e) { return (e ? e : document).querySelectorAll(q); }
function $c(t) { return document.createElement(t); }
String.prototype.u$format = function () {
  var args = arguments;
  return this.replace(/{(\d+)}/g, function (match, i) {
    return args[i] !== undefined ? args[i] : match;
  });
};

// check username
var username = $('.idBadgerNeue a.avatar').href.split('/').pop();
var urlPieces = location.href.split(/[\/\?]/);
if (username !== urlPieces[5])
  return;
var urlBase = urlPieces.slice(0, 7).join('/');

// insert style
GM_addStyle('\
#userTagList>li>a.l { margin-right: 32px; } \
#userTagList>li>a.__u_edit, #userTagList>li>a.__u_del { \
  width: 16px; height: 16px; \
  padding: 4px 0; float: right; \
  text-align: center; color: #aaa; \
  line-height: 16px; font-size: 10px; \
} \
a.__u_add { \
  width: 16px; height: 16px; \
  padding: 3px 0; float: right; \
  text-align: center; color: #fff; \
  line-height: 16px; font-size: 10px; \
} \
#__u_pb { \
  position: fixed; \
  top: 0; \
  width: 100%; \
} \
#__u_pb[max="0"] { \
  display: none; \
} \
');

// add progress bar
var $pb = $c('progress');
var workingJobs = 0;
$pb.id = '__u_pb';
$pb.max = $pb.value = 0;
document.body.appendChild($pb);

// update tag list
var $tags = $a('#userTagList>li');
for (var i = 0; i < $tags.length; i++) {
  var $tag = $tags[i],
  $anchor = $tag.getElementsByTagName('a')[0];
  var $button;

  $button = $c('a');
  $button.href = '#';
  $button.className = '__u_del';
  $button.title = '删除';
  $button.textContent = 'x';
  $tag.insertBefore($button, $anchor);

  $button = $c('a');
  $button.href = '#';
  $button.className = '__u_edit';
  $button.title = '编辑';
  $button.textContent = '#';
  $tag.insertBefore($button, $anchor);
}

// add checkboxes to item list
var $items = $a('#browserItemList>li');
for (var i = 0; i < $items.length; i++) {
  var $item = $items[i],
  $modify = $('.collectModify', $item);

  var $checkbox = $c('input');
  $checkbox.type = 'checkbox';
  $modify.insertBefore($checkbox, $modify.firstChild);
}

// add new tag button
var $panel = $('#userTagList').parentNode;
var $newtag = $c('a');
$newtag.href = '#';
$newtag.className = '__u_add';
$newtag.title = '添加';
$newtag.textContent = '+';
$newtag.addEventListener('click', function (evt) {
  var ids = [];
  evt.preventDefault();

  var $items = $a('#browserItemList>li');
  for (var i = 0; i < $items.length; i++) {
    var $item = $items[i],
    $chk = $('input[type=checkbox]', $item);
    if ($chk.checked)
      ids.push($item.id.substr(5));
  }

  if (!ids.length) {
    alert('请先选择条目');
    return;
  }

  var newTag = prompt('请输入新标签名:');
  if (!newTag) return;
  batchChangeTag(ids, null, newTag, function (id) {
    //$('#item_{0} input[type=checkbox]'.u$format(id)).checked = false;
  });
});
$panel.insertBefore($newtag, $panel.firstChild);

// add a button for making subject privacy  2016/08/04
function add_btn(class_name, title, text, callback) {
  var $panel = $('#userTagList').parentNode;
  var $newtag = $c('a');
  $newtag.href = '#';
  $newtag.className = class_name;
  $newtag.title = title;
  $newtag.textContent = text;
  $panel.insertBefore($newtag, $panel.firstChild);
  $newtag.addEventListener('click', function (evt) {
    var ids = [];
    evt.preventDefault();

    var $items = $a('#browserItemList>li');
    for (var i = 0; i < $items.length; i++) {
      var $item = $items[i],
      $chk = $('input[type=checkbox]', $item);
      if ($chk.checked)
        ids.push($item.id.substr(5));
    }

    if (!ids.length) {
      alert('请先选择条目');
      return;
    }

    var flag_privacy = 1;
    if (text === 'c')
      flag_privacy = 0;
    callback(ids, flag_privacy, function (id) {
      //$('#item_{0} input[type=checkbox]'.u$format(id)).checked = false;
    });
  });
}

add_btn('__u_add', '自己可见', 'p', batch_make_privacy);
add_btn('__u_add', '取消自己可见', 'c', batch_make_privacy);

// bind event
$('#userTagList').addEventListener('click', function (evt) {
  var className = evt.target.className;
  if (className != '__u_edit' && className != '__u_del')
    return;

  var $li = evt.target.parentNode;
  var oldTag = decodeURIComponent($('a.l', $li).href.split('=')[1]);
  var newTag;
  evt.preventDefault();
  if (className == '__u_del') {
    if (!confirm('确认要删除标签“{0}”吗?'.u$format(oldTag)))
    return;
    newTag = '';
  } else {
    newTag = prompt('请输入新的标签名:');
    if (!newTag) return;
  }

  changeTagName(oldTag, newTag, $li);
}, true);

// process
function changeTagName(oldTag, newTag, $li) {
  var $anchor = $('a.l', $li);
  var num = parseInt($('small', $anchor).textContent),
      pageNum = Math.ceil(num / 24);
  var ids = [];
  var url = urlBase + '?tag=' + encodeURIComponent(oldTag) + '&page=';
  $pb.max += num + pageNum;
  workingJobs++;

  getListPage(1, function () {
    batchChangeTag(ids, oldTag, newTag, updateProcessBar);
  });

  function updateProcessBar() {
    $pb.value++;
  }

  function getListPage(page, callback) {
    var xhr = new XMLHttpRequest();
    var received = false;

    var watchdog = setTimeout(function () {
      watchdog = 0;
      if (received) return;
      xhr.abort();
      getListPage(page, callback);
    }, TIMEOUT);

    xhr.open('GET', url + page, true);
    xhr.send(null);
    xhr.onreadystatechange = function () {
      if (this.readyState != 4 || this.status != 200)
        return;
      received = true;
      if (watchdog) {
        clearTimeout(watchdog);
        watchdog = 0;
      }

      var content = this.responseText;
      var regx = /<li id="item_(\d+)"/g, match;
      while (match = regx.exec(content))
        ids.push(match[1]);

      updateProcessBar();
      if (page < pageNum)
        getListPage(page + 1, callback);
      else
        callback();
    };
  }
}

function batchChangeTag(ids, oldTag, newTag, updateProcessBar) {
  var $iframe = $c('iframe');
  $iframe.style.display = 'none';
  document.body.appendChild($iframe);

  function nextItem() {
    var id = ids.shift();
    if (id) {
      changeTag(id, oldTag, newTag,
                $iframe, updateProcessBar, nextItem);
    } else {
      workingJobs--;
      if (workingJobs == 0)
        location.reload();
    }
  }
  nextItem();
}

function changeTag(id, oldTag, newTag,
                   $iframe, updateProcessBar, callback) {
  var url = '/update/' + id;
  var watchdog;
  stage0();

  function stage0() {
    $iframe.src = url;
    $iframe.onload = stage1;
    finished = false;
    watchdog = setTimeout(function () {
      if ($iframe.onload != stage1)
        return;
      url += '?';
      stage0();
    }, TIMEOUT);
  }
  function stage1() {
    if (watchdog) {
      clearTimeout(watchdog);
      watchdog = 0;
    }

    var doc = $iframe.contentDocument;
    var $tags = doc.getElementById('tags');
    if (!$tag)
      setTimeout(stage0, RETRY_INTERVAL);

    if (oldTag) {
      var tags = $tags.value.trim().split(/\s+/);
      for (var i = 0; i < tags.length; i++)
      if (tags[i].toLowerCase() == oldTag.toLowerCase())
        tags[i] = newTag;
      $tags.value = tags.join(' ');
    } else {
      $tags.value += ' ' + newTag;
    }

    doc.forms[0].submit();
    $iframe.onload = stage2;
    watchdog = setTimeout(function () {
      if ($iframe.onload != stage2)
        return;
      doc.forms[0].submit();
    }, TIMEOUT);
  }
  function stage2() {
    if (watchdog) {
      clearTimeout(watchdog);
      watchdog = 0;
    }

    $iframe.onload = undefined;
    updateProcessBar(id);
    callback();
  }
}

// add a function for make subject privacy  2016/08/04
function make_privacy(id, flag_privacy,
                   $iframe, updateProcessBar, callback) {
  console.log('begin', id, flag_privacy);
  var url = '/update/' + id;
  var watchdog;
  stage0();

  function stage0() {
    $iframe.src = url;
    $iframe.onload = stage1;
    finished = false;
    watchdog = setTimeout(function () {
      if ($iframe.onload != stage1)
        return;
      url += '?';
      stage0();
    }, TIMEOUT);
  }
  function stage1() {
    if (watchdog) {
      clearTimeout(watchdog);
      watchdog = 0;
    }

    var doc = $iframe.contentDocument;
    var $privacy_checkbox = doc.getElementById('privacy');
    if (!$privacy_checkbox)
      window.setTimeout(stage0, RETRY_INTERVAL);
    if (flag_privacy)
      $privacy_checkbox.setAttribute('checked', 'checked');
    else {
      //$privacy_checkbox.setAttribute('checked', false);
      $privacy_checkbox.removeAttribute('checked');
      console.log('removed', id);
    }

    doc.forms[0].submit();
    $iframe.onload = stage2;
    watchdog = setTimeout(function () {
      if ($iframe.onload != stage2)
        return;
      doc.forms[0].submit();
    }, TIMEOUT);
  }
  function stage2() {
    if (watchdog) {
      clearTimeout(watchdog);
      watchdog = 0;
    }

    $iframe.onload = undefined;
    updateProcessBar(id);
    callback();
  }
  console.log('finished', id);
}

function batch_make_privacy(ids, flag_privacy, updateProcessBar) {
  var $iframe = $c('iframe');
  $iframe.style.display = 'none';
  document.body.appendChild($iframe);

  function nextItem() {
    var id = ids.shift();
    if (id) {
      make_privacy(id, flag_privacy,
                $iframe, updateProcessBar, nextItem);
    } else {
      workingJobs--;
      if (workingJobs === 0)
        location.reload();
    }
  }
  nextItem();
}