NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name Ficscript(Ficbook.net)
// @author Dimava
// @include https://ficbook.net/*
// @include http://ficbook.net/*
// @version 1
// @grant none
// ==/UserScript==// ==UserScript==
// @name Ficscript(Ficbook.net)
// @author Dimava
// @include https://ficbook.net/*
// @include http://ficbook.net/*
// @version 1.4
// @grant none
// ==/UserScript==
function setHiddenAuthors(authorsId) {
localStorage.setItem('ficbookFilter.hiddenAuthors', JSON.stringify(authorsId)
)
}
function setHiddenWritings(writingsId) {
localStorage.setItem('ficbookFilter.hiddenWritings', JSON.stringify(writingsId)
)
}
function getHiddenAuthors() {
var str = localStorage.getItem('ficbookFilter.hiddenAuthors')
return str ? JSON.parse(str) : [
]
}
function getHiddenWritings() {
var str = localStorage.getItem('ficbookFilter.hiddenWritings')
return str ? JSON.parse(str) : [
]
}
function createEIbuttons() {
// Create export button
var $exportBtn = $('<div class="exportBtn"></div>').attr('title', 'Экспортировать бан-список').html('E').appendTo(document.body)
$exportBtn.click(function () {
var data = JSON.stringify({
authors: getHiddenAuthors(),
writings: getHiddenWritings()
})
var $a = $('<a/>').attr('href', 'data:text/plain,' + data).attr('download', 'ficbook-filters.json').appendTo(document.body)
$a[0].click()
$a.remove()
})
// Create import button
var $fileInput = $('<input type="file"/>').css({
position: 'absolute',
top: '-10000px',
left: '-10000px'
}).appendTo(document.body)
var $importBtn = $exportBtn.clone().css({
right: '110px'
}).attr('title', 'Импортировать бан-список').html('I').appendTo(document.body)
$importBtn.click(function () {
$fileInput.click()
})
$fileInput.change(function () {
try {
var fileReader = new FileReader()
fileReader.readAsText(this.files[0])
fileReader.onloadend = function () {
try {
var json = JSON.parse(this.result)
}
catch (e) {
alert('Ошибка. Файл бан-списка поврежден.\n' +
'По умолчанию это обычно "ficbook-filters.json".\n' +
'Может быть, вы выбрали какой-то другой файл?')
return
}
setHiddenWritings(json.writings)
setHiddenAuthors(json.authors)
alert('Импортировано ' + json.writings.length +
' произведений и ' + json.authors.length + ' авторов.\n' +
'Обновите страницу чтобы применить фильтры немедленно.')
}
}
catch (e) {
alert('Ошибка. Файл бан-списка поврежден.')
console.error(e.toString())
}
})
console.log('createEIbuttons applied');
}
// Hide writings
function hideFics() {
// Load hidden authors and writings
var hiddenAuthors = getHiddenAuthors()
var hiddenWritings = getHiddenWritings()
// Hide writings
$('.fanfic_thumb').each(function () {
var $title = $('a.title', this),
title = $title.text(),
writingId = parseInt($title.attr('href').match(/\/(\d+)$/) [1], 10),
text = $('b:eq(1)', this).closest('small').text(),
pageCount = parseInt(text.match(/(\d+)\s+страниц/) [1]),
slash = text.indexOf('(яой)') >= 0,
writingHidden = hiddenWritings.indexOf(writingId) >= 0,
$author = $('>tbody>tr:eq(1)>td:eq(0) a:eq(0)', this),
authorId = parseInt($author.attr('href').match(/\/(\d+)$/) [1], 10),
authorHidden = hiddenAuthors.indexOf(authorId) >= 0,
$thumb = $(this),
$ficbox = $thumb.closest('.ficbox')
function hideThisFic($hideReason) {
$resurrectBtn =
$ficbox.addClass('hiddenfic').prepend('<tr class="rsrbox"><td colspan=9></td></tr>').find('td:first').html('<span class="rsrBtn">' + $hideReason + '</span> <a href="' + $title.attr('href') + '">"'
+ title + '"</a> от <a href="' + $author.attr('href') + '">' + $author.text() + '</a>.').find('span').attr('title', 'Да ВОССТАНЬ!');
$ficbox.children().css('background-color', 'rgba(255,255,255,0.5)').css('transition', 'background-color 1s').find('>tr:not(.rsrbox)').hide();
$resurrectBtn.hover(function () {
$(this).parents('.ficbox').find('>*>tr:not(.rsrbox)').show();
}, function () {
$(this).parents('.ficbox').find('>*>tr:not(.rsrbox)').hide()
}).click(function () {
if (authorHidden) {
hiddenAuthors = getHiddenAuthors() // could be updated on the other tab
hiddenAuthors.splice(hiddenAuthors.indexOf(authorId), 1)
setHiddenAuthors(hiddenAuthors)
}
if (writingHidden) {
hiddenWritings = getHiddenWritings() // could be updated on the other tab
hiddenWritings.splice(hiddenWritings.indexOf(writingId), 1)
setHiddenWritings(hiddenWritings)
}
$(this).parents('.ficbox').removeClass('hiddenfic').children().css('background-color', 'transparent').find('tr').show().end().find('.rsrbox').remove();
return false
})
}
if (writingHidden)
hideThisFic('Отфильтрован фанф')
else if (authorHidden)
hideThisFic('Отфильтрован по автору')
else if (slash)
hideThisFic('Отфильтрован <i>слеш</i>')
else if (pageCount < 30)
hideThisFic('Отфильтрован по длине (' + pageCount + ')')
// Add removing writing button
var $rmWritingBtn = $('<span class="removeFic"></span>').attr('title', 'Забанить это произведение').html('✖')
$title.parent().append($rmWritingBtn)
$rmWritingBtn.click(function () {
alert()
hiddenWritings = getHiddenWritings() // could be updated on the other tab
hiddenWritings.push(writingId)
setHiddenWritings(hiddenWritings)
hideThisFic('Отфильтрован фанф')
return false
})
// Add removing author button
var $rmAuthorBtn = $('<span class="removeFic removeAuthor"></span>').attr('title', 'Забанить ВСЕ произведения этого автора').html('✖')
$title.closest('.ficbox').find('small:first a:first').after($rmAuthorBtn);
$rmAuthorBtn.click(function () {
hiddenAuthors = getHiddenAuthors() // could be updated on the other tab
hiddenAuthors.push(authorId)
setHiddenAuthors(hiddenAuthors)
hideThisFic('Отфильтрован по автору')
return false
})
})
console.log('hideFics applied');
}
//
//
//
// location detector v1
function getLoc() {
var a = window.location.pathname.split('/');
var b = window.location.href.split('=');
var c = '';
for (i = 1; i < a.length; i++) {
c += (a[i].charAt(0) <= '9' && a[i].charAt(0) >= '0') ? '0' : a[i].charAt(0);
}
for (i = 1; i < b.length; i++) {
c += (b[i].charAt(0) <= '9' && b[i].charAt(0) >= '0') ? '0' : b[i].charAt(0);
}
return c;
}
function testLoc(a) {
var c = getLoc()
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] == c) return true;
}
return false;
}
//
// ficboxes classifier v1 : adds .ficbox class
function classFics() {
if ($('table.fanfic_thumb').length > 0) {
if (testLoc('hcu')) { // create ficboxes
$('table:has(.fanfic_thumb):not(:has(h1))').addClass('ficbox');
} else {
$('table.fanfic_thumb').addClass('ficbox');
}
$('.ficbox:has(.new_parts_in_title)').addClass('newfic'); // select updated
$('table[style="background-color: #ffff99"]').addClass('newfic').attr('style', '');
return true;
} else {
return false;
}
console.log('classFics applied');
}
//
// everything compressor
function compressFics() {
// chapter TRASHHIDER v1
if (testLoc('r00')) {
if ($('.fanfic_reward_list').length > 15) { // hide 16+ rewards
$('.fanfic_reward_list:eq(0)').html('x' + $('.fanfic_reward_list:gt(0)').length);
$('.fanfic_reward_list:gt(0)').hide();
$('.fanfic_reward_list').parent().find('br:gt(1)').remove();
}
$('.give_reward_fic').hide(); // hide reward giver
$('.public_beta_info').hide(); // hide beta info
$('hr:first').nextUntil('table').css('display', 'inline').css('padding-right', '0'); // collapce font setter
$($('.choose_font').contents().filter(function () {
return this.nodeType == 3;
})).remove();
$('hr:first').nextUntil('table').addClass('hoverVisible').find('br').hide();
}
// contents compressor
if (testLoc('r0')) {
$('<div class="partListContainer"><div></div></div>').insertAfter($('.part_list').prev().prev()).children().append($('.part_list').prev().text($('.main_cell h1:first').text()).css('margin', '5px')).append('<h6>' + $('.main_cell td:last span.urlize:first').html() + '</h6>').parent().append($('.part_list').prepend('<div class="partListTop">^ ^ ^</div>').append('<div class="partListBottom">^ ^ ^</div>'));
}
console.log('compressFics applied');
}
//
// checker : adds checkboxes to open multiple fics at once
function checkFics() {
$('.ficbox>*>tr:has(.title)').append('<td align="right" style="width: 30px;"><input type="checkbox" class="openAll"></td>');
$('.ficbox td[style]:not([width])').attr('colspan', '2')
$('.openAll').click(function () {
$('#openAll').show();
$('.openAll').css('opacity', '1')
});
$('<button id="openAll">Открыть<br>выбранные</button>').appendTo($('body')).click(function () {
$('input.openAll:checked').each(function () {
window.open($(this).parent().parent().find('.title') [0].href, '_blank'
);
});
$('.ficbox').has('input.openAll:checked').children().css('background-color', 'rgba(127,255,0,0.3)');
});
console.log('checkFics applied');
}
//
// load new collections v1 : shows new fics in updated collection (/home/collections?type=other)
function loadCols(callback) {
collectionsNotLoaded = $('tr[style] .collection_thumb').length;
if (collectionsNotLoaded == 0) {
callback()
}
$('tr[style] .collection_thumb').each(function () {
$(this).after('<div style="display:none">!div!</div>').next().load($(this).find('.title a') [0].href, function () {
$(this).after($(this).find('.fic_and_collection[style]').each(function () {
$(this).append($(this).children().eq(0))
})
);
$(this).html('!!!div!!!');
collectionsNotLoaded--;
if (collectionsNotLoaded == 0) {
callback()
}
}
)
})
console.log('loadCols applied');
}
//
// keypress handler v2
function handleKeys() {
$(document).keydown(function (e) {
var tag = e.target.tagName.toLowerCase();
var keyStr = (e.ctrlKey ? '[Ctrl] + ' : '') + (e.shiftKey ? '[Shift] + ' : '') + '[' + (typeof e.key == 'undefined' ? ('#' + e.which) : e.key) + ']' + ' pressed' + ((tag != 'input' && tag != 'textarea') ? '' : ' inside input') + ((getSelectedText() == '') ? '' : ' with "' + getSelectedText() + '" selected');
var keyCode = (e.ctrlKey ? 'c' : '') + (e.shiftKey ? 's' : '') + ('#' + e.which) + ((tag != 'input' && tag != 'textarea') ? '' : 'i') + ((getSelectedText() == '' || getSelectedText == '\n') ? '' : '{}');
console.log(keyCode + ' : ' + keyStr);
switch (keyCode) {
case 's#37': // s#37 : [Shift] + [ArrowLeft] pressed {open prev or first chap}
if (testLoc('r0') && $('.part_list a:first') [0]) window.location.href = $('.part_list a:first') [0].href;
else if (testLoc('r00') && $('td[width="45%"]:first a') [0]) document.location.href = $('td[width="45%"]:first a') [0].href;
break
case 's#39': // s#39 : [Shift] + [ArrowRight] pressed {open next ol last chap}
if (testLoc('r0') && $('.part_list a:last') [0]) window.location.href = $('.part_list a:last') [0].href;
else if (testLoc('r00') && $('td[width="45%"]:last a') [0]) document.location.href = $('td[width="45%"]:last a') [0].href;
break
case 's#38': // s#38 : [Shift] + [ArrowUp] pressed {open contents}
if (testLoc('r00') && $('td[align="center"] a') [0]) document.location.href = $('td[align="center"] a') [0].href;
break
case '#39': // #39 : [ArrowRight] pressed {open next chap if read}
if (testLoc('r00') && $('td[width="45%"]:last a') [0] && ($('td[width="45%"]:last a') [0].getBoundingClientRect().top - window.innerHeight < 163)) document.location.href = $('td[width="45%"]:last a') [0].href;
break
}
});
console.log('handleKeys applied');
}
//
// scroll : scrolls page down to somewhere
function scrollFic() {
if (testLoc('r0')) {
$('.part_list').scrollTop(9999);
$('.partListContainer') [0].scrollIntoView();
}
}
//
// style
function styleFics() {
var styleStr = '<style>'
+ '.ficbox{margin:15px 0}'
+ '.newfic{background-color:#ff9;}'
+ '.rsrbox {color:#888; transition: background-color 0.3s; background-color: rgba(255,255,255,0.3);}'
+ '.rsrBtn:hover {color:red;cursor:pointer}'
+ '.rsrbox:hover {background-color: white}'
+ '.hiddenfic{border-collapse:collapse;margin:0}'
+ '.hiddenfic>*>tr:not(.rsrbox) {opacity: 0.5; background-color: white}'
+ '.openAll{opacity:0.1; transition: opacity 0.3s;}'
+ '.openAll:hover {opacity: 1 !important}'
+ '#openAll{display: none; position: fixed; right: 270px; bottom: 0px}'
+ '.exportBtn{position: fixed; bottom: 20px; right: 80px; color: white; background-color: rgba(0, 0, 0, 0.52); border-radius: 3px; width: 25px; text-align: center; height: 24px; line-height: 24px; cursor: pointer; font-size: 18px;opacity:0.1;transition: opacity 0.3s;}'
+ '.exportBtn:hover{opacity:1}'
+ '.removeFic{cursor: pointer; color: white; font-weight: bold; display: inline-block; background: rgb(136, 1, 1); border-radius: 10px; height: 20px; line-height: 19px; width: 20px;text-align: center;opacity:0.1;transition: opacity 0.3s;}'
+ '.removeAuthor{height: 14px; width: 14px; line-height: 14px; font-size: 12px; margin-left: 3px}'
+ '.removeFic:hover{opacity:1}'
+ '.hiddenfic .removeFic{display: none;}'
+ '.partListContainer{max-height:98vh;display:flex;flex-direction:column;box-shadow:0px 0px 2px inset,0px 0px 2px;margin-right:10px;padding:0px 5px 5px 0}'
+ '.partListBottom{font-size: 15px; height: 10px; overflow: hidden; text-align: center;}'
+ '.partListTop{font-size: 15px; height: 11px; overflow: hidden; text-align: center;transform: rotate(180deg);}'
+ '.part_list{overflow-y: auto}'
+ 'h6{margin:0;padding: 0 15px 10px 15px}'
/*!!!*/
+ 'table{border-collapse:collapse}'
/*!!!*/
+ 'td{padding-top: 0 !important;padding-bottom: 0 !important;}'
+ '.hoverVisible{opacity:0.1;transition: opacity 0.3s;}'
+ '.hoverVisible:hover{opacity:1}'
+ '</style>'
$('<style></style>').appendTo($('head')).html(styleStr);
console.log('styleFics applied');
}
//
// calls
function callFicscript() {
console.log('ficscript start');
styleFics();
loadCols(function () {
classFics();
if (testLoc('p', 'hc', 'hco', 'hcu', 'c0', 'c0a', 'c0a0', 'c0u')) {
createEIbuttons();
hideFics();
}
//removethis
/*
if (testLoc('hf')) {
$('.new_top').each(function () {
window.open(this.href, '_blank');
})
}*/
checkFics();
compressFics();
handleKeys();
scrollFic();
})
// unsafeWindow.callFicscript = callFicscript;
console.log('ficscript end')
}
//
callFicscript();