// ==UserScript== // @name ao3 savior // @description Tumblr savior clone for AO3 works pages. // @namespace ao3 // @include http*://archiveofourown.org/* // @grant none // @version 1.5 // @downloadURL none // ==/UserScript== /**** CONFIG ********************/ window.ao3SaviorConfig = { showReasons: true, // set to false if you don't want to see why works were hidden showPlaceholders: true, // set to false if you don't want to see the "This work is hidden!" boxes (could result in empty works lists. Check out the "saved filters" script) authorBlacklist: ['Hated Author 1', 'smeyer'], // excludes works with an author that exactly matches at least one term tagBlacklist: ['dobby', 'jar jar binks', '*mimes'], // excludes works with a tag that exactly matches at least one term. Use * for wildcard summaryBlacklist: ['horse-sized ducks', 'duck-sized horses', "bee's knees"] // excludes works with summaries that contain at least one term }; /********************************/ (function($) { var works = $('li.blurb'); if (!works[0]) return; var toggleClass = 'ao3-savior-hide-toggle', fold = $('

').addClass('fold').append( $('').addClass(toggleClass).text('This work is hidden! '), $('').addClass(toggleClass).html('This work was hidden. ').hide(), $('').addClass('reason'), $('').addClass('actions').append( $('').addClass('action').css({ 'position': 'absolute', 'right': 8, 'top': 10 }).text('Unhide') ) ), bl = window.ao3SaviorConfig, termsMatch = function(testTerm, listTerm) { testTerm = testTerm.toLowerCase(); listTerm = listTerm.toLowerCase(); if (testTerm == listTerm) { return true; } if (listTerm.indexOf('*') == -1) return false; var parts = listTerm.split('*'), prevPartIndex = 0, firstPart, lastPart; for (var i = 0, part, len = parts.length; i < len; i++) { part = parts[i]; partIndex = testTerm.indexOf(part); if (part && partIndex < prevPartIndex) { return false; } prevPartIndex = partIndex + part.length; } firstPart = parts[0]; lastPart = parts[parts.length-1]; return !( firstPart && testTerm.indexOf(firstPart) != 0 || lastPart && testTerm.indexOf(lastPart)+lastPart.length != testTerm.length ); }, shouldBlacklist = function(work) { var authors = work.find('a[rel=author]'), tags = work.find('a.tag'), summary = work.find('blockquote.summary').text(), reason = 'Reason: '; for (var i = 0, blAuthor; blAuthor = bl.authorBlacklist[i]; i++) { var done; if (blAuthor == 'Anonymous' && !authors[0]) { done = true; } else { for (var j = 0, author; author = $(authors[j]).text(); j++) { if (author == blAuthor) { done = true; break; } } } if (done) { return reason +'author is ' +blAuthor +''; } } for (var i = 0, tag; tag = $(tags[i]).text(); i++) { for (var j = 0, blTag; blTag = bl.tagBlacklist[j]; j++) { if (termsMatch(tag, blTag)) { return reason +'tags include ' +blTag +''; } } } for (var i = 0, blSummaryTerm; blSummaryTerm = bl.summaryBlacklist[i]; i++) { if (summary.indexOf(blSummaryTerm) != -1) { return reason +'summary includes ' +blSummaryTerm +''; } } return ''; }, blacklist = function(work, reason) { var cut = $('

').addClass('cut').html(work.html()), reason = '(' +reason +'.)', thisFold = fold.clone(), reasonContainer = thisFold.find('.reason'); if (!ao3SaviorConfig.showPlaceholders) { work.hide(); return; } if (ao3SaviorConfig.showReasons) { reasonContainer.html(reason); } else { reasonContainer.remove(); } work.empty().append(thisFold, cut.hide()); work.find('a.action').click(function() { var fold = $(this).closest('.fold'), cut = fold.next('.cut'); cut.add(fold.children('.'+toggleClass)).toggle(); $(this).text(cut.is(':visible') ? 'Hide' : 'Unhide'); }) }; works.each(function() { var reason = shouldBlacklist($(this)); if (reason) { blacklist($(this), reason) } }); })(window.jQuery);