Фильтровать фанфики по разным параметрам.
// ==UserScript==
// @name Фильтр для Ficbook
// @description Фильтровать фанфики по разным параметрам.
// @license MIT
// @namespace https://github.com/MonkAlex/FicbookFilter
// @include htt*://ficbook.net/*
// @exclude htt*://ficbook.net/home/collections?type=update
// @exclude htt*://ficbook.net/home/change_*
// @grant none
// @require http://code.jquery.com/jquery-latest.min.js
// @version 2019.09.25a
// @author MonkAlex
// ==/UserScript==
/** Все фанфики на странице **/
let globalFanfics = new Set();
function setBannedAuthors(authorsId) {
localStorage.setItem(
'ficbookFilter.bannedAuthors',
JSON.stringify(authorsId)
)
}
function setBannedFanfics(fanficsId) {
localStorage.setItem(
'ficbookFilter.bannedFanfics',
JSON.stringify(fanficsId)
)
}
function setBannedDirections(directions) {
localStorage.setItem('ficbookFilter.bannedDirections', JSON.stringify(directions))
}
function setBannedFandoms(fandoms) {
localStorage.setItem('ficbookFilter.bannedFandoms', JSON.stringify(fandoms))
}
function setBannedPairings(pairings) {
localStorage.setItem('ficbookFilter.bannedPairings', JSON.stringify(pairings))
}
function getBannedAuthors() {
const str = localStorage.getItem('ficbookFilter.bannedAuthors');
return str ? JSON.parse(str) : []
}
function getBannedFanfics() {
const str = localStorage.getItem('ficbookFilter.bannedFanfics');
return str ? JSON.parse(str) : []
}
function getBannedDirections() {
const str = localStorage.getItem('ficbookFilter.bannedDirections');
return str ? JSON.parse(str) : []
}
function getBannedFandoms() {
const str = localStorage.getItem('ficbookFilter.bannedFandoms');
return str ? JSON.parse(str) : []
}
function getBannedPairings() {
const str = localStorage.getItem('ficbookFilter.bannedPairings');
return str ? JSON.parse(str) : []
}
/**
* Добавить кнопку "заблокировать".
* @param root элемент, к которому прицепится кнопка.
* @param title текст при наведении.
* @param inSup true, если это кнопки у загловока, там дополнительно используется sup элемент.
* @param fanfic контекст выполнения, по идее - фанфик.
* @param color цвет иконки.
* @param click обработчик нажатия на кнопку.
* @returns {HTMLElement} собственно кнопка, к которой потом можно повесить обработчик.
*/
function addButton(root, title, inSup, fanfic, color, click) {
let button = document.createElement("button");
button.innerHTML = '<svg viewBox="0 0 32 32" width="16" fill="' + color +'">\n' +
'<path d="M32 11.2c0 2.7-1.16 5.12-3.02 6.8H29L19 28c-1 1-2 2-3 2s-2-1-3-2L3.02 18A9.2 9.2 0 0 1 13.93 3.31L11 8l7 4-4 10 11-12-7-4 2.46-3.7A9.2 9.2 0 0 1 32 11.2z"></path>\n' +
'</svg>';
button.title = title;
let bs = button.style;
bs.padding = '0px';
bs.background = 'none';
bs.border = 'none';
button.fanfic = fanfic;
button.addEventListener("click", click);
if (inSup) {
let sup = document.createElement("sup");
sup.className = "count";
sup.appendChild(button);
button = sup;
}
root.appendChild(button);
return button;
}
class FanficFandom {
constructor(fanfic, fandom){
this.fanfic = fanfic;
this.fandom = fandom;
this.wrapper = $(fandom).wrap("<a/>")[0].parentElement;
this.fandomUri = this.fandom.href.match('\/fanfiction\/(.*)')[1];
this.fandomBtn = addButton(this.wrapper, 'Забанить фандом', false, this, 'rgb(180, 0, 0)', function () {
this.fanfic.banFandom();
});
this.restoreFandomBtn = addButton(this.wrapper, "Вернуть фандом", false, this, 'rgb(220, 220, 0)', function () {
this.fanfic.restoreFandom();
});
this.restoreFandomBtn.style.display = "none";
}
restoreFandom(){
let tempFandoms = getBannedFandoms();
if (tempFandoms.includes(this.fandomUri)) {
tempFandoms.splice(tempFandoms.indexOf(this.fandomUri), 1);
setBannedFandoms(tempFandoms);
console.warn('restore fandom ' + this.fandomUri);
}
globalFanfics.forEach(function (fanfic) {
fanfic.unHideFanfic();
})
}
banFandom() {
console.warn('hide fandom ' + this.fandomUri);
let bannedFandoms = getBannedFandoms();
bannedFandoms.push(this.fandomUri);
setBannedFandoms(bannedFandoms);
globalFanfics.forEach(function (fanfic) {
fanfic.hideFanfic();
});
}
fandomBanned() {
return getBannedFandoms().includes(this.fandomUri);
}
hide(){
let disliked_parameter_link = " disliked-parameter-link";
if (this.fandomBanned())
{
if (!this.fandom.className.includes(disliked_parameter_link))
{
this.fandom.className += disliked_parameter_link;
}
this.restoreFandomBtn.style.display = "";
this.fandomBtn.style.display = "none";
}
}
unHide(){
let disliked_parameter_link = " disliked-parameter-link";
if (!this.fandomBanned())
{
this.fandom.className = this.fandom.className.replace(disliked_parameter_link, "");
this.restoreFandomBtn.style.display = "none";
this.fandomBtn.style.display = "";
}
}
}
class FanficPairing {
constructor(fanfic, pairing){
this.fanfic = fanfic;
this.pairing = pairing;
this.wrapper = $(pairing).wrap("<a/>")[0].parentElement;
this.pairingUri = decodeURI(this.pairing.href.match('\/pairings\/(.*)')[1]);
this.pairingBtn = addButton(this.wrapper, 'Забанить пейринг', false, this, 'rgb(180, 0, 0)', function () {
this.fanfic.banPairing();
});
this.restorePairingBtn = addButton(this.wrapper, "Вернуть пейринг", false, this, 'rgb(220, 220, 0)', function () {
this.fanfic.restorePairing();
});
this.restorePairingBtn.style.display = "none";
}
restorePairing(){
let tempPairings = getBannedPairings();
if (tempPairings.includes(this.pairingUri)) {
tempPairings.splice(tempPairings.indexOf(this.pairingUri), 1);
setBannedPairings(tempPairings);
console.warn('restore pairing ' + this.pairingUri);
}
globalFanfics.forEach(function (fanfic) {
fanfic.unHideFanfic();
})
}
banPairing() {
console.warn('hide pairing ' + this.pairingUri);
let bannedPairings = getBannedPairings();
bannedPairings.push(this.pairingUri);
setBannedPairings(bannedPairings);
globalFanfics.forEach(function (fanfic) {
fanfic.hideFanfic();
});
}
pairingBanned() {
return getBannedPairings().includes(this.pairingUri);
}
hide(){
let disliked_parameter_link = " disliked-parameter-link";
let pairing_highlight = " pairing-highlight";
if (this.pairingBanned())
{
if (!this.pairing.className.includes(disliked_parameter_link))
{
this.pairing.className += disliked_parameter_link;
}
if (this.pairing.className.includes(pairing_highlight))
{
this.pairing.className = this.pairing.className.replace(pairing_highlight, "");
}
this.restorePairingBtn.style.display = "";
this.pairingBtn.style.display = "none";
}
}
unHide(){
let disliked_parameter_link = " disliked-parameter-link";
let pairing_highlight = " pairing-highlight";
if (!this.pairingBanned())
{
this.pairing.className = this.pairing.className.replace(disliked_parameter_link, "");
if (!this.pairing.className.includes(pairing_highlight))
{
this.pairing.className += pairing_highlight;
}
this.restorePairingBtn.style.display = "none";
this.pairingBtn.style.display = "";
}
}
}
class Fanfic {
constructor(article) {
this.title = article.querySelector("a.visit-link");
this.author = article.querySelector("div.description ul.listing.list-inline li");
this.authorLink = this.author.querySelector("a");
this.authorId = parseInt(this.authorLink.href.match(/\/(\d+)+/)[1], 10);
this.fanficId = parseInt(this.title.href.match(/\/(\d+)+/)[1], 10);
this.direction = article.querySelector("span.direction");
this.directionName = this.direction.className.replace("direction direction-before-", "");
this.article = article;
this.fandoms = Array.from(article.querySelector("dl.info dd").querySelectorAll("a")).map(function (fandom) {
return new FanficFandom(this, fandom);
}, this);
this.pairings = Array.from(article.querySelectorAll("dl.info a.pairing-link")).map(function (pairing) {
return new FanficPairing(this, pairing);
}, this);
this.fanficBtn = addButton(this.title.parentElement, 'Забанить фанфик', true, this, 'rgb(180, 0, 0)', function () {
this.fanfic.banFanfic();
});
this.authorBtn = addButton(this.author, 'Забанить автора', false, this, 'rgb(180, 0, 0)', function () {
this.fanfic.banAuthor();
});
this.directionBtn = addButton(this.direction, 'Забанить тип фанфиков', false, this, 'rgb(180, 0, 0)', function () {
this.fanfic.banDirection();
});
this.restoreFanficBtn = addButton(this.title.parentElement, "Вернуть фанфик", true, this, 'rgb(220, 220, 0)', function () {
this.fanfic.restoreFanfic();
});
this.restoreAuthorBtn = addButton(this.author, "Вернуть автора", false, this, 'rgb(220, 220, 0)', function () {
this.fanfic.restoreAuthor();
});
this.restoreDirectionBtn = addButton(this.direction, "Вернуть тип фанфиков", false, this, 'rgb(220, 220, 0)', function () {
this.fanfic.restoreDirection();
});
this.restoreFanficBtn.style.display = "none";
this.restoreAuthorBtn.style.display = "none";
this.restoreDirectionBtn.style.display = "none";
}
restoreFanfic() {
let tempFanfics = getBannedFanfics();
if (tempFanfics.includes(this.fanficId)) {
tempFanfics.splice(tempFanfics.indexOf(this.fanficId), 1);
setBannedFanfics(tempFanfics);
console.warn('restore fanfic ' + this.fanficId);
}
this.unHideFanfic();
}
restoreAuthor(){
let tempAuthors = getBannedAuthors();
if (tempAuthors.includes(this.authorId)) {
tempAuthors.splice(tempAuthors.indexOf(this.authorId), 1);
setBannedAuthors(tempAuthors);
console.warn('restore author ' + this.authorId);
}
globalFanfics.forEach(function (fanfic) {
if (!fanfic.getFanficBanned())
fanfic.unHideFanfic();
})
}
restoreDirection(){
let tempDirections = getBannedDirections();
if (tempDirections.includes(this.directionName)) {
tempDirections.splice(tempDirections.indexOf(this.directionName), 1);
setBannedDirections(tempDirections);
console.warn('restore direction ' + this.directionName);
}
globalFanfics.forEach(function (fanfic) {
if (!fanfic.getFanficBanned())
fanfic.unHideFanfic();
})
}
banAuthor() {
console.warn('hide author ' + this.authorId);
let bannedAuthors = getBannedAuthors();
bannedAuthors.push(this.authorId);
setBannedAuthors(bannedAuthors);
globalFanfics.forEach(function (fanfic) {
if (fanfic.getFanficBanned())
fanfic.hideFanfic();
});
}
banFanfic() {
console.warn('hide fanfic ' + this.fanficId);
let bannedFanfics = getBannedFanfics();
bannedFanfics.push(this.fanficId);
setBannedFanfics(bannedFanfics);
this.hideFanfic();
}
banDirection() {
console.warn('hide direction ' + this.directionName);
let bannedDirections = getBannedDirections();
bannedDirections.push(this.directionName);
setBannedDirections(bannedDirections);
globalFanfics.forEach(function (fanfic) {
if (fanfic.getFanficBanned())
fanfic.hideFanfic();
});
}
hideFanfic() {
let fanfic_block_disliked = " fanfic-block-disliked";
let disliked_parameter_link = " disliked-parameter-link";
if (this.getFanficBanned())
{
if (!this.article.className.includes(fanfic_block_disliked))
{
this.article.className += fanfic_block_disliked;
}
}
if (this.authorBanned())
{
if (!this.authorLink.className.includes(disliked_parameter_link))
{
this.authorLink.className += disliked_parameter_link;
}
this.restoreAuthorBtn.style.display = "";
this.authorBtn.style.display = "none";
}
if (this.fanficBanned())
{
if (!this.title.className.includes(disliked_parameter_link))
{
this.title.className += disliked_parameter_link;
}
this.restoreFanficBtn.style.display = "";
this.fanficBtn.style.display = "none";
}
if (this.directionBanned())
{
this.restoreDirectionBtn.style.display = "";
this.directionBtn.style.display = "none";
}
this.fandoms.forEach(function (fandom) {
fandom.hide();
});
this.pairings.forEach(function (pairing) {
pairing.hide();
});
// TODO: fics can be hiden
// $thumb.parent().parent().hide()
}
unHideFanfic() {
let fanfic_block_disliked = " fanfic-block-disliked";
let disliked_parameter_link = " disliked-parameter-link";
if (!this.getFanficBanned())
{
this.article.className = this.article.className.replace(fanfic_block_disliked, "");
}
if (!this.authorBanned())
{
this.authorLink.className = this.authorLink.className.replace(disliked_parameter_link, "");
this.restoreAuthorBtn.style.display = "none";
this.authorBtn.style.display = "";
}
if (!this.fanficBanned())
{
this.title.className = this.title.className.replace(disliked_parameter_link, "");
this.restoreFanficBtn.style.display = "none";
this.fanficBtn.style.display = "";
}
if (!this.directionBanned())
{
this.restoreDirectionBtn.style.display = "none";
this.directionBtn.style.display = "";
}
this.fandoms.forEach(function (fandom) {
fandom.unHide();
});
this.pairings.forEach(function (pairing) {
pairing.unHide();
});
// TODO: fics can be hiden
// $thumb.parent().parent().hide()
}
getFanficBanned() {
return this.fanficBanned()
|| this.authorBanned()
|| this.directionBanned()
|| this.anyFandomBanned()
|| this.anyPairingBanned();
}
directionBanned() {
return getBannedDirections().includes(this.directionName);
}
authorBanned() {
return getBannedAuthors().includes(this.authorId);
}
fanficBanned() {
return getBannedFanfics().includes(this.fanficId);
}
anyFandomBanned(){
return this.fandoms.some(function (fandom) {
return fandom.fandomBanned();
});
}
anyPairingBanned(){
return this.pairings.some(function (pairing) {
return pairing.pairingBanned();
});
}
}
(function () {
// Hide fanfics
$('article.block').each(function () {
let fanfic = new Fanfic(this);
globalFanfics.add(fanfic);
if (fanfic.getFanficBanned())
fanfic.hideFanfic();
});
})();
console.log("Ficbook filter " + GM_info.script.version + " loaded.");