1. DLP Flash Christmas Competition + Writing Marathon 2024!

    Competition topic: Magical New Year!

    Marathon goal? Crank out words!

    Check the marathon thread or competition thread for details.

    Dismiss Notice
  2. Hi there, Guest

    Only registered users can really experience what DLP has to offer. Many forums are only accessible if you have an account. Why don't you register?
    Dismiss Notice
  3. Introducing for your Perusing Pleasure

    New Thread Thursday
    +
    Shit Post Sunday

    READ ME
    Dismiss Notice

Repairing this filter script?

Discussion in 'Fanfic Discussion' started by Jormungandr, Jul 5, 2012.

  1. Jormungandr

    Jormungandr Prisoner

    Joined:
    Jul 26, 2010
    Messages:
    2,961
    Gender:
    Male
    Location:
    Merry ol' England
    Ever since FanFiction.net decided to bumble-fuck update their crap with even shittier features (see story covers/avatars, for one), the Grease Monkey script I used to filter out slash broke down. Completely.

    I've tried looking through it for anything obvious (such as an URL change, or something), but I couldn'd find out why the script's gone dud.

    Does anyone else have any ideas on how to fix this?

    Here's the script:

    Code:
    // ==UserScript==
    // @name           FanFiction.Net - Extended Functionality.
    // @author         Sean Davies
    // @version        3.3
    // @description    Remove Menu rollover effect, filter stories by various criteria such as characters, word count, category or keywords. Highlight various character's, both good and bad.
    // @include        http://*.fanfiction.net/*
    // @include        https://*.fanfiction.net/*
    // ==/UserScript==
    
    ///////////////////////////////////////---SETTINGS---///////////////////////////////////////////////////////
    
    // Settings:
    // Enabled - 1
    // Disabled - 0
    
    // Remove menu rollover effect.
    var removeMenu = "1";
    
    // Remove story containing specified characters and/or character pairing.
    var storyRemove = "1";
    
    // Highlight storys containing specified characters.
    var charHighlight = "1";
    
    // Remove stories with specified catergory.
    var catRemove = "0";
    
    // Only display stories above a specified word count.
    var wordCount = "0";
    
    // Only display stories that don't contain certain words.
    var wordRemove = "0";
    
    // Remove Share options.
    var shareRemove = "1";
    
    // Characters and/or character pair stories to remove.
    var removeChars = ['Draco M.','Ginny W.', 'Severus S.', 'Voldemort', 'Tom R. Jr.', 'Bella', 'Lucius M.', 'Shego', 'Hermione G.'];
    
    // Characters to highlight in green.
    var goodChars = ['Harry P.','Fawkes', 'Edward', 'Jasper', 'Hermione G.', 'Sirius B.', 'Dean T.', 'Seamus F.', 'Blaise Z.','Luna L.', 'Jacob', 'Ron W.', 'Cedric D.']
    
    // Characters to highlight in red.
    var badChars = ['Draco M.','Ginny W.', 'Bellatrix L.', 'Bella', 'Severus S.', 'Voldemort', 'Tom R. Jr.'];
    
    // Remove stories whose summary contains any of the following words (words must be lowercase).
    var remWords = ['slash', 'mpreg', 'hpdm', 'femslash', 'dmhp', 'severitus', 'hpss', 'harmony', 'yaoi', 'slashyaoi', 'harem', 'spanish', 'french', 'russian', 'books', 'reading', 'vulcan', 'smut', 'bashing', 'songfic', 'dumbles', 'voldy', 'moldyshorts', 'mprg'];
    
    // Keep stories whose summary contains any of the following words (words must be lowercase).
    var keepWords = ['no slash'];
    
    ///////////////////////////////////////---END SETTINGS---///////////////////////////////////////////////////////
    
    var data = document.getElementsByTagName('div');
    
    if(removeMenu == "1")
    {
        var menuItems = ['menu-home-c','menu-justin-c', 'menu-community-c', 'menu-forum-c', 'menu-beta-c', 'menu-search-c', 'menu-extra-c'];
        
        for (i=0; i < menuItems.length; i++)
        {
            var menuItem = document.getElementById(menuItems[i]);
            menuItem.parentNode.removeChild(menuItem);
        }
    }
    
    if(storyRemove == "1")
    {
        for (i = 0; i < removeChars.length; i++)
        {
            for(j = 0; j < data.length; j++)
            {
                if (data[j].className == "gray z-padtop2")
                {
                    var remChar = removeChars[i].replace("&", "&amp;");
                    
                    if(data[j].innerHTML.match(remChar))
                    {     
                        var div = data[j].parentNode;
                        div = div.parentNode;
                        div.style.display = 'none';
                    }
                }
            }
        }
    }
    
    if(charHighlight == "1")
    {   
        for (i = 0; i < goodChars.length; i++) {
            for(j = 0; j < data.length; j++) {
                if (data[j].className == "gray z-padtop2"){
                    if(data[j].innerHTML.match(goodChars[i])) {
                        var html = data[j].innerHTML;
                    
                        html = html.replace(goodChars[i], "<span style=\"color:green; font-weight: bold;\">" + goodChars[i] + "</span>");
                    
                        data[j].innerHTML = html;
                    }
                }
            }
        }   
        
        for (i = 0; i < badChars.length; i++) {
            for(j = 0; j < data.length; j++) {
                if (data[j].className == "gray z-padtop2"){
                    if(data[j].innerHTML.match(badChars[i])) {
                        var html = data[j].innerHTML;
                    
                        html = html.replace(badChars[i], "<span style=\"color:red; font-weight: bold;\">" + badChars[i] + "</span>");
                        
                        data[j].innerHTML = html;
                    }
                }
            }
        }
    }
    
    if(catRemove == "1")
    {
        for (i = 0; i < removeCat.length; i++)
        {
            for(j = 0; j < data.length; j++)
            {
                if (data[j].className == "gray z-padtop2")
                {   
                    if(data[j].innerHTML.match(removeCat[i]))
                    {     
                        var div = data[j].parentNode;
                        div = div.parentNode;
                        div.style.display = 'none';
                    }
                }
            }
        }
    }
    
    if(wordCount == "1")
    {
        for(i = 0; i < data.length; i++)
        {
            if (data[i].className == "gray z-padtop2")
            {
                var html = data[i].innerHTML;
                var text = html.split("Words: ");
                var txt = text[1].split("-");
                var count = txt[0].replace(",", "");
                
                if(count < lowWordCount)
                {
                    var div = data[i].parentNode;
                    div = div.parentNode;
                    div.style.display = 'none';
                }
            }
        }
    }
    
    if(wordRemove == "1")
    {
        for (i = 0; i < remWords.length; i++)
        {
            for(j = 0; j < data.length; j++)
            {
                if (data[j].className == "z-indent z-padtop")
                {
                    var dat = data[j].innerHTML.toLowerCase();
    
                    if(dat.match(keepWords[i]))
                    {
                        next;
                    }
                    else if(dat.match(remWords[i]))
                    {
                        var div = data[j].parentNode;
                        div.style.display = 'none';
                    }
                }
            }
        }
    }
    
    if(shareRemove == "1")
    {
    
        for(i = 0; i < data.length; i++)
        {
            if (data[i].className == "a2a_kit a2a_default_style")
            {
                    var div = data[i];
                    div.style.display = 'none';
            }
        }
    }
    
    //Script update checker from http://userscripts.org/scripts/review/20145
    var SUC_script_num = 73219;
    try{function updateCheck(forced){if ((forced) || (parseInt(GM_getValue('SUC_last_update', '0')) + 86400000 <= (new Date().getTime()))){try{GM_xmlhttpRequest({method: 'GET',url: 'http://userscripts.org/scripts/source/'+SUC_script_num+'.meta.js?'+new Date().getTime(),headers: {'Cache-Control': 'no-cache'},onload: function(resp){var local_version, remote_version, rt, script_name;rt=resp.responseText;GM_setValue('SUC_last_update', new Date().getTime()+'');remote_version=parseInt(/@uso:version\s*(.*?)\s*$/m.exec(rt)[1]);local_version=parseInt(GM_getValue('SUC_current_version', '-1'));if(local_version!=-1){script_name = (/@name\s*(.*?)\s*$/m.exec(rt))[1];GM_setValue('SUC_target_script_name', script_name);if (remote_version > local_version){if(confirm('There is an update available for the Greasemonkey script "'+script_name+'."\nWould you like to go to the install page now?')){GM_openInTab('http://userscripts.org/scripts/show/'+SUC_script_num);GM_setValue('SUC_current_version', remote_version);}}else if (forced)alert('No update is available for "'+script_name+'."');}else GM_setValue('SUC_current_version', remote_version+'');}});}catch (err){if (forced)alert('An error occurred while checking for updates:\n'+err);}}}GM_registerMenuCommand(GM_getValue('SUC_target_script_name', '???') + ' - Manual Update Check', function(){updateCheck(true);});updateCheck(false);}catch(err){}
    
     
  2. Saot

    Saot Groundskeeper

    Joined:
    May 9, 2011
    Messages:
    321
    The code was awful so I ended up rewriting most of it. It's sort of amusing how short some of the pages are with it enabled.

    Code:
    // ==UserScript==
    // @name           FanFiction.Net - Extended Functionality.
    // @author         Sean Davies
    // @version        3.3
    // @description    Remove Menu rollover effect, filter stories by various criteria such as characters, word count, category or keywords. Highlight various character's, both good and bad.
    // @include        http://*.fanfiction.net/*
    // @include        https://*.fanfiction.net/*
    // ==/UserScript==
    
    ///////////////////////////////////////---SETTINGS---///////////////////////////////////////////////////////
    
    // Settings:
    // Enabled - 1
    // Disabled - 0
    
    // Remove menu rollover effect.
    var removeMenu = "1";
    
    // Remove story containing specified characters and/or character pairing.
    var storyRemove = "1";
    
    // Highlight storys containing specified characters.
    var charHighlight = "1";
    
    // Remove stories with specified catergory.
    var catRemove = "0";
    
    // Only display stories above a specified word count.
    var wordCount = "1";
    var lowWordCount = 2000;
    
    // Only display stories that don't contain certain words.
    var wordRemove = "0";
    
    // Characters and/or character pair stories to remove.
    var removeChars = ['Draco M.','Ginny W.', 'Severus S.', 'Voldemort', 'Tom R. Jr.', 'Bella', 'Lucius M.', 'Shego', 'Hermione G.'];
    
    // Characters to highlight in green.
    var goodChars = ['Harry P.','Fawkes', 'Edward', 'Jasper', 'Hermione G.', 'Sirius B.', 'Dean T.', 'Seamus F.', 'Blaise Z.','Luna L.', 'Jacob', 'Ron W.', 'Cedric D.']
    
    // Characters to highlight in red.
    var badChars = ['Draco M.','Ginny W.', 'Bellatrix L.', 'Bella', 'Severus S.', 'Voldemort', 'Tom R. Jr.'];
    
    // Remove stories whose summary contains any of the following words (words must be lowercase).
    var remWords = ['slash', 'mpreg', 'hpdm', 'femslash', 'dmhp', 'severitus', 'hpss', 'harmony', 'yaoi', 'slashyaoi', 'harem', 'spanish', 'french', 'russian', 'books', 'reading', 'vulcan', 'smut', 'bashing', 'songfic', 'dumbles', 'voldy', 'moldyshorts', 'mprg'];
    
    // Keep stories whose summary contains any of the following words (words must be lowercase).
    var keepWords = ['no slash'];
    
    ///////////////////////////////////////---END SETTINGS---///////////////////////////////////////////////////////
    
    function searchList(option, elements, list, matchingOnly, func) {
        if (option != "1") return;
        for (var i = 0; i < elements.length; ++i) {
            for (var j = 0; j < list.length; ++j) {
                if (!matchingOnly || elements[i].innerHTML.match(list[j]))
                    func(elements[i], list[j]);
            }
        }
    }
    
    var characters = document.getElementsByClassName('z-padtop2');
    var data = document.getElementsByClassName('z-list');
    
    if(removeMenu == "1")
    {
        var menuItems = ['menu-home-c','menu-justin-c', 'menu-community-c', 'menu-forum-c', 'menu-beta-c', 'menu-search-c'];
    
        for (i=0; i < menuItems.length; i++)
        {
            var menuItem = document.getElementById(menuItems[i]);
            menuItem.parentNode.removeChild(menuItem);
        }
    }
    
    for (var i = 0; i < removeChars.length; ++i)
        removeChars[i] = removeChars[i].replace("&", "&amp;");
    
    searchList(storyRemove, characters, removeChars, true, function (node, character) {
        node.parentNode.parentNode.style.display = 'none';
    });
    
    searchList(charHighlight, characters, goodChars, true, function (node, character) {
        node.innerHTML = node.innerHTML.replace(character, "<span style=\"color:green; font-weight: bold;\">" + character + "</span>");
    });
    
    searchList(charHighlight, characters, badChars, true, function (node, character) {
        node.innerHTML = node.innerHTML.replace(character, "<span style=\"color:red; font-weight: bold;\">" + character + "</span>");
    });
    
    searchList(wordRemove, data, remWords, false, function (node, word) {
        var lower = node.innerHTML.toLowerCase();
        if (lower.match(word)) {
            for (var i = 0; i < keepWords.length; ++i) {
                if (lower.match(keepWords[i]))
                    return;
            }
    
            node.style.display = 'none';
        }
    });
    
    if(wordCount == "1")
    {
        for(i = 0; i < characters.length; i++)
        {
            var html = characters[i].innerHTML;
            var text = html.split("Words: ");
            var txt = text[1].split("-");
            var count = txt[0].replace(",", "");
    
            if(count < lowWordCount)
                characters[i].parentNode.parentNode.style.display = 'none';
        }
    }
    
     
  3. Jormungandr

    Jormungandr Prisoner

    Joined:
    Jul 26, 2010
    Messages:
    2,961
    Gender:
    Male
    Location:
    Merry ol' England
    Bloody brilliant - thank you! :D
     
  4. SilverOtter

    SilverOtter Seventh Year

    Joined:
    Feb 20, 2011
    Messages:
    263
    Location:
    USA
    How hard would it be to highlight words in a story description with this?

    Edit :: Here's a list of characters that are commonly in slash fanfics.

    var removeChars = ['Draco M.', 'Scorpius M.', 'Lucius M.', // Malfoys
    'Gregory G.', 'Vincent C.', 'Marcus F.', 'Marcus B.', 'Theodore N.', // Other Slytherins
    'Charlie W', 'Fred W.', 'George W.', 'Ron W.', 'Percy W.', 'Bill W.', // Weasleys
    'Teddy L.', 'Albus S. P.', 'James S. P.', 'Dominique W.', // Epilogue.
    'Remus L.', 'Sirius B.', 'Tom R. Jr.', 'Severus S.', 'James P.', 'Voldemort', 'Oliver W.', 'Albus D.', // Older people
    'Regulus B.', 'Gideon P.', 'Audrey W.', 'Rabastan L.', // More older people
    'Cedric D.', 'Viktor K.', 'Neville L.', 'Scabior', 'Seamus F.', 'Colin C.', 'Barty C. Jr.', // Others known for slash.
    ];
     
    Last edited: Jul 14, 2012
  5. Nuit

    Nuit Dark Lord

    Joined:
    Feb 14, 2010
    Messages:
    1,934
    Location:
    The Peach State
    Is there a way to add 'Shirō E.' to the character settings. I've tried myself but the ō causes an error and a regular o won't catch the character.

    Edit: Nevermind, I just had to change the encoding to UTF-8.
     
    Last edited: Jul 19, 2012
  6. xaowx

    xaowx Muggle

    Joined:
    Nov 26, 2011
    Messages:
    4
    Related to an extent, does anyone know why this script doesn't work either? I'm not the greatest with code and I didn't feel it worthy to make a new thread over it. Sorry if I inappropriately bumped this thread.

    Code:
    
    // ==UserScript==
    // @version       1.4.0
    // @include       http://www.fanfiction.net/s/*
    // @namespace     ffnet
    // @name          Fanfiction.net story export script.
    // @author        Alssn
    // @description   Writes all chapters of the story on one page.
    // @changes       Now changes title after export.
    // ==/UserScript==
    
    function find(expr)
    {
        var posts = document.evaluate(expr, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return posts.singleNodeValue;
    }
    
    function addButtons(){
    // Adding buttons
        res = document.getElementById('f_size');
        //creating links
        var addHeadersButton=document.createElement('a');
        addHeadersButton.href='javascript:';
        addHeadersButton.innerHTML='Headers';
        addHeadersButton.setAttribute('title','Add header to each chapter');
        var addIndexButton=document.createElement('a');
        addIndexButton.href='javascript:';
        addIndexButton.innerHTML='Index';
        addIndexButton.setAttribute('title','Create table of contents');
        var expAllButton=document.createElement('a');
        expAllButton.id='exportAllButton';
        expAllButton.href='javascript:';
        expAllButton.setAttribute('title','Show the whole story on one page');
        expAllButton.innerHTML='Story';
        var expButton=document.createElement('a');
        expButton.setAttribute('title','Show only text');
        expButton.href='javascript:';
        expButton.innerHTML='Text';
        // Adding listeners - that's the only way to do something after main code finsihed working;
        expAllButton.addEventListener('click',exportAll,false);
        expButton.addEventListener('click',exportCh,false);
        addHeadersButton.addEventListener('click',addHeaders,false);
        addIndexButton.addEventListener('click',addIndex,false);
        //fE and fA
        var e = document.createElement('span');
        e.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4');
        e.setAttribute('title','Export');
        e.innerHTML = "fE: ";
        var a = document.createElement('span');
        a.setAttribute('title','Add');
        a.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4');
        a.innerHTML = "fA: ";
        insertNode = res.parentNode;
        insertNode.appendChild(e);
        insertNode.appendChild(expAllButton);
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(expButton);
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(a);    
        insertNode.appendChild(addHeadersButton);    
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(addIndexButton,insertNode);
        insertNode.appendChild(document.createTextNode(' '));
    
        }
    
    //Adding buttons to page;
    addButtons();
    
    //Adding table of contents
    function addIndex(){
        var storytext = document.getElementById('storytext'); //Point of insert
        var chapters = document.getElementsByName('ffnee_chapter');
        //Creating base structure
        var index = document.createElement('div');
        index.innerHTML = '<h2>Table of contents</h2>';
        index.setAttribute('id','ffnee_index');
        var toC = document.createElement('ol');
        index.appendChild(toC);
        //Processing chapters
        for (var i=0;i<chapters.length;i++){
            var item = chapters.item(i); //chapter we are currently processing
            var id = item.getAttribute('id');
            var entry = document.createElement('li'); //Entry corresponding to the chapter in ToC
            entry.innerHTML = '<a href="#'+id+'">'+item.getAttribute('title')+'</a>';
            toC.appendChild(entry);
        }    
        storytext.insertBefore(index,storytext.firstChild);
    }
    //adding headers, as entered by author
    function addHeaders(){
        var chapters = document.getElementsByName('ffnee_chapter');
        for (var i=0;i<chapters.length;i++){
        var item = chapters.item(i); //chapter to which we are adding a header
        var header = document.createElement('p');
        header.innerHTML = '<h2>Chapter '+(i+1)+': '+item.getAttribute('title')+'</h2>';
        item.insertBefore(header,item.firstChild);
        }
    }
    
    function exportCh(){
    document.body.innerHTML='<div style=\'padding-left:2em;padding-right:2em;padding-top:1em;\'>'+document.getElementById('storytextp').innerHTML+'</div>';
    //Sadly, it is not possible to automatically copy text to clipboard in firefox without changing browser settings;
    }
    function exportAll(){
    // Main actions   
        //Set title
        var storyAuthor = find("//a[contains(@href, '\/u\/')]");
        var storyTitle = find("//img[@class='cimage']");
        document.title = storyTitle.nextSibling.textContent+" by "+storyAuthor.textContent;
        // Progress indicator
        var expDiv = document.getElementById('exportAllButton');
        var expText = expDiv.childNodes[0];
        var chapters = new Array();
        var hr=location.href;
        var chapterNumIndex=hr.search(/\/\d{1,3}\//);
        //Getting number of chapters
        var storyLength=getLength(); 
        if (storyLength == 1){
            expText.nodeValue = 'Oneshot';
            return;
        }
        var totalStoryLength = storyLength;//reference
        //launching retrieving of all chapters simultaneously
        for (var i=1;i<=storyLength;i++){
        loadChapter(i);
        }
    //Functions
        // Converting chapters' array into a whole;
        function parseStory(){
            var numCh= chapters.length;
            //document.body.innerHTML=chapters[0];
            var appendNode=document.getElementById('storytext');
            appendNode.innerHTML= '';
            for (var i=0;i<numCh;i++){
                //findHeader(chapters[i]);  //smart header search
                var st=chapters[i];
                st.setAttribute('name','ffnee_chapter');
                st.setAttribute('id','ffnee_ch'+i);
                if (i!=0){
                    st.style.marginTop='10em';
                }
                appendNode.appendChild(st);
            }
            expText.nodeValue='story(re)';
        }
        //  Getting number of chapters;
        function getLength(){
            //var chNum=document.evaluate('//SELECT[@title=\'chapter navigation\']',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var chNum = document.getElementById('chap_select');
            if (chNum==null){
                numChapters = 1;
            }else {
                var numChapters = chNum.getElementsByTagName('option').length;
            }
            return (numChapters);
        }
        // This function loads chapters and extracts chapter's number and title 
        function loadChapter(num){
            var replStr='\/'+String(num)+'\/';
            var currentURL=hr.replace(/\/\d{1,3}\//,replStr);
            GM_xmlhttpRequest({ //Internal Greesemonkey function - main reason this couldn't work as a bookmarklet.
                method: 'GET',
                url: currentURL,
                onload: function(responseDetails) {
                    parseChapter(responseDetails.responseText, num);
                    storyLength--;
                    if (storyLength==0){
                        parseStory();
                    }
                  }
            });
        }
        function parseChapter(chapterHtml, chapterNumber){
            var t=document.createElement('div');
            t.innerHTML=chapterHtml;
            //extracting text only
              var ev='.//div[@id=\'storytext\']';
            var xpathResult = document.evaluate(ev,t,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var chapterContent=document.createElement('div');
            chapterContent.setAttribute('title',getChapterName(t));
            chapterContent.innerHTML = xpathResult.snapshotItem(0).innerHTML;
            chapters[chapterNumber-1]=chapterContent;
            expText.nodeValue = 'Export: Chapter '+String(totalStoryLength-storyLength+1)+' out of '+totalStoryLength;
            function getChapterName(obj){
                var select = obj.getElementsByTagName('select')[1].getElementsByTagName('option');
                 for (var i=0;i<select.length;i++){
                     if (select[i].getAttribute('selected')!=null){
                         return(select[i].innerHTML.split(/[. ]{2}/)[1]);
                     }
                }
            }
        }
    
    }
    
    // ==UserScript==
    // @version       1.4.0
    // @include       http://www.fanfiction.net/s/*
    // @namespace     ffnet
    // @name          Fanfiction.net story export script.
    // @author        Alssn
    // @description   Writes all chapters of the story on one page.
    // @changes       Now changes title after export.
    // ==/UserScript==
    
    function find(expr)
    {
        var posts = document.evaluate(expr, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return posts.singleNodeValue;
    }
    
    function addButtons(){
    // Adding buttons
        res = document.getElementById('f_size');
        //creating links
        var addHeadersButton=document.createElement('a');
        addHeadersButton.href='javascript:';
        addHeadersButton.innerHTML='Headers';
        addHeadersButton.setAttribute('title','Add header to each chapter');
        var addIndexButton=document.createElement('a');
        addIndexButton.href='javascript:';
        addIndexButton.innerHTML='Index';
        addIndexButton.setAttribute('title','Create table of contents');
        var expAllButton=document.createElement('a');
        expAllButton.id='exportAllButton';
        expAllButton.href='javascript:';
        expAllButton.setAttribute('title','Show the whole story on one page');
        expAllButton.innerHTML='Story';
        var expButton=document.createElement('a');
        expButton.setAttribute('title','Show only text');
        expButton.href='javascript:';
        expButton.innerHTML='Text';
        // Adding listeners - that's the only way to do something after main code finsihed working;
        expAllButton.addEventListener('click',exportAll,false);
        expButton.addEventListener('click',exportCh,false);
        addHeadersButton.addEventListener('click',addHeaders,false);
        addIndexButton.addEventListener('click',addIndex,false);
        //fE and fA
        var e = document.createElement('span');
        e.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4');
        e.setAttribute('title','Export');
        e.innerHTML = "fE: ";
        var a = document.createElement('span');
        a.setAttribute('title','Add');
        a.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4');
        a.innerHTML = "fA: ";
        insertNode = res.parentNode;
        insertNode.appendChild(e);
        insertNode.appendChild(expAllButton);
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(expButton);
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(a);    
        insertNode.appendChild(addHeadersButton);    
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(addIndexButton,insertNode);
        insertNode.appendChild(document.createTextNode(' '));
    
        }
    
    //Adding buttons to page;
    addButtons();
    
    //Adding table of contents
    function addIndex(){
        var storytext = document.getElementById('storytext'); //Point of insert
        var chapters = document.getElementsByName('ffnee_chapter');
        //Creating base structure
        var index = document.createElement('div');
        index.innerHTML = '<h2>Table of contents</h2>';
        index.setAttribute('id','ffnee_index');
        var toC = document.createElement('ol');
        index.appendChild(toC);
        //Processing chapters
        for (var i=0;i<chapters.length;i++){
            var item = chapters.item(i); //chapter we are currently processing
            var id = item.getAttribute('id');
            var entry = document.createElement('li'); //Entry corresponding to the chapter in ToC
            entry.innerHTML = '<a href="#'+id+'">'+item.getAttribute('title')+'</a>';
            toC.appendChild(entry);
        }    
        storytext.insertBefore(index,storytext.firstChild);
    }
    //adding headers, as entered by author
    function addHeaders(){
        var chapters = document.getElementsByName('ffnee_chapter');
        for (var i=0;i<chapters.length;i++){
        var item = chapters.item(i); //chapter to which we are adding a header
        var header = document.createElement('p');
        header.innerHTML = '<h2>Chapter '+(i+1)+': '+item.getAttribute('title')+'</h2>';
        item.insertBefore(header,item.firstChild);
        }
    }
    
    function exportCh(){
    document.body.innerHTML='<div style=\'padding-left:2em;padding-right:2em;padding-top:1em;\'>'+document.getElementById('storytextp').innerHTML+'</div>';
    //Sadly, it is not possible to automatically copy text to clipboard in firefox without changing browser settings;
    }
    function exportAll(){
    // Main actions   
        //Set title
        var storyAuthor = find("//a[contains(@href, '\/u\/')]");
        var storyTitle = find("//img[@class='cimage']");
        document.title = storyTitle.nextSibling.textContent+" by "+storyAuthor.textContent;
        // Progress indicator
        var expDiv = document.getElementById('exportAllButton');
        var expText = expDiv.childNodes[0];
        var chapters = new Array();
        var hr=location.href;
        var chapterNumIndex=hr.search(/\/\d{1,3}\//);
        //Getting number of chapters
        var storyLength=getLength(); 
        if (storyLength == 1){
            expText.nodeValue = 'Oneshot';
            return;
        }
        var totalStoryLength = storyLength;//reference
        //launching retrieving of all chapters simultaneously
        for (var i=1;i<=storyLength;i++){
        loadChapter(i);
        }
    //Functions
        // Converting chapters' array into a whole;
        function parseStory(){
            var numCh= chapters.length;
            //document.body.innerHTML=chapters[0];
            var appendNode=document.getElementById('storytext');
            appendNode.innerHTML= '';
            for (var i=0;i<numCh;i++){
                //findHeader(chapters[i]);  //smart header search
                var st=chapters[i];
                st.setAttribute('name','ffnee_chapter');
                st.setAttribute('id','ffnee_ch'+i);
                if (i!=0){
                    st.style.marginTop='10em';
                }
                appendNode.appendChild(st);
            }
            expText.nodeValue='story(re)';
        }
        //  Getting number of chapters;
        function getLength(){
            //var chNum=document.evaluate('//SELECT[@title=\'chapter navigation\']',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var chNum = document.getElementById('chap_select');
            if (chNum==null){
                numChapters = 1;
            }else {
                var numChapters = chNum.getElementsByTagName('option').length;
            }
            return (numChapters);
        }
        // This function loads chapters and extracts chapter's number and title 
        function loadChapter(num){
            var replStr='\/'+String(num)+'\/';
            var currentURL=hr.replace(/\/\d{1,3}\//,replStr);
            GM_xmlhttpRequest({ //Internal Greesemonkey function - main reason this couldn't work as a bookmarklet.
                method: 'GET',
                url: currentURL,
                onload: function(responseDetails) {
                    parseChapter(responseDetails.responseText, num);
                    storyLength--;
                    if (storyLength==0){
                        parseStory();
                    }
                  }
            });
        }
        function parseChapter(chapterHtml, chapterNumber){
            var t=document.createElement('div');
            t.innerHTML=chapterHtml;
            //extracting text only
              var ev='.//div[@id=\'storytext\']';
            var xpathResult = document.evaluate(ev,t,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var chapterContent=document.createElement('div');
            chapterContent.setAttribute('title',getChapterName(t));
            chapterContent.innerHTML = xpathResult.snapshotItem(0).innerHTML;
            chapters[chapterNumber-1]=chapterContent;
            expText.nodeValue = 'Export: Chapter '+String(totalStoryLength-storyLength+1)+' out of '+totalStoryLength;
            function getChapterName(obj){
                var select = obj.getElementsByTagName('select')[1].getElementsByTagName('option');
                 for (var i=0;i<select.length;i++){
                     if (select[i].getAttribute('selected')!=null){
                         return(select[i].innerHTML.split(/[. ]{2}/)[1]);
                     }
                }
            }
        }
    
    }// ==UserScript==
    // @version       1.4.0
    // @include       http://www.fanfiction.net/s/*
    // @namespace     ffnet
    // @name          Fanfiction.net story export script.
    // @author        Alssn
    // @description   Writes all chapters of the story on one page.
    // @changes       Now changes title after export.
    // ==/UserScript==
    
    function find(expr)
    {
        var posts = document.evaluate(expr, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
        return posts.singleNodeValue;
    }
    
    function addButtons(){
    // Adding buttons
        res = document.getElementById('f_size');
        //creating links
        var addHeadersButton=document.createElement('a');
        addHeadersButton.href='javascript:';
        addHeadersButton.innerHTML='Headers';
        addHeadersButton.setAttribute('title','Add header to each chapter');
        var addIndexButton=document.createElement('a');
        addIndexButton.href='javascript:';
        addIndexButton.innerHTML='Index';
        addIndexButton.setAttribute('title','Create table of contents');
        var expAllButton=document.createElement('a');
        expAllButton.id='exportAllButton';
        expAllButton.href='javascript:';
        expAllButton.setAttribute('title','Show the whole story on one page');
        expAllButton.innerHTML='Story';
        var expButton=document.createElement('a');
        expButton.setAttribute('title','Show only text');
        expButton.href='javascript:';
        expButton.innerHTML='Text';
        // Adding listeners - that's the only way to do something after main code finsihed working;
        expAllButton.addEventListener('click',exportAll,false);
        expButton.addEventListener('click',exportCh,false);
        addHeadersButton.addEventListener('click',addHeaders,false);
        addIndexButton.addEventListener('click',addIndex,false);
        //fE and fA
        var e = document.createElement('span');
        e.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4');
        e.setAttribute('title','Export');
        e.innerHTML = "fE: ";
        var a = document.createElement('span');
        a.setAttribute('title','Add');
        a.setAttribute('style','font-family: serif;font-weight:bolder;color:#61a4e4');
        a.innerHTML = "fA: ";
        insertNode = res.parentNode;
        insertNode.appendChild(e);
        insertNode.appendChild(expAllButton);
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(expButton);
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(a);    
        insertNode.appendChild(addHeadersButton);    
        insertNode.appendChild(document.createTextNode(' '));    
        insertNode.appendChild(addIndexButton,insertNode);
        insertNode.appendChild(document.createTextNode(' '));
    
        }
    
    //Adding buttons to page;
    addButtons();
    
    //Adding table of contents
    function addIndex(){
        var storytext = document.getElementById('storytext'); //Point of insert
        var chapters = document.getElementsByName('ffnee_chapter');
        //Creating base structure
        var index = document.createElement('div');
        index.innerHTML = '<h2>Table of contents</h2>';
        index.setAttribute('id','ffnee_index');
        var toC = document.createElement('ol');
        index.appendChild(toC);
        //Processing chapters
        for (var i=0;i<chapters.length;i++){
            var item = chapters.item(i); //chapter we are currently processing
            var id = item.getAttribute('id');
            var entry = document.createElement('li'); //Entry corresponding to the chapter in ToC
            entry.innerHTML = '<a href="#'+id+'">'+item.getAttribute('title')+'</a>';
            toC.appendChild(entry);
        }    
        storytext.insertBefore(index,storytext.firstChild);
    }
    //adding headers, as entered by author
    function addHeaders(){
        var chapters = document.getElementsByName('ffnee_chapter');
        for (var i=0;i<chapters.length;i++){
        var item = chapters.item(i); //chapter to which we are adding a header
        var header = document.createElement('p');
        header.innerHTML = '<h2>Chapter '+(i+1)+': '+item.getAttribute('title')+'</h2>';
        item.insertBefore(header,item.firstChild);
        }
    }
    
    function exportCh(){
    document.body.innerHTML='<div style=\'padding-left:2em;padding-right:2em;padding-top:1em;\'>'+document.getElementById('storytextp').innerHTML+'</div>';
    //Sadly, it is not possible to automatically copy text to clipboard in firefox without changing browser settings;
    }
    function exportAll(){
    // Main actions   
        //Set title
        var storyAuthor = find("//a[contains(@href, '\/u\/')]");
        var storyTitle = find("//img[@class='cimage']");
        document.title = storyTitle.nextSibling.textContent+" by "+storyAuthor.textContent;
        // Progress indicator
        var expDiv = document.getElementById('exportAllButton');
        var expText = expDiv.childNodes[0];
        var chapters = new Array();
        var hr=location.href;
        var chapterNumIndex=hr.search(/\/\d{1,3}\//);
        //Getting number of chapters
        var storyLength=getLength(); 
        if (storyLength == 1){
            expText.nodeValue = 'Oneshot';
            return;
        }
        var totalStoryLength = storyLength;//reference
        //launching retrieving of all chapters simultaneously
        for (var i=1;i<=storyLength;i++){
        loadChapter(i);
        }
    //Functions
        // Converting chapters' array into a whole;
        function parseStory(){
            var numCh= chapters.length;
            //document.body.innerHTML=chapters[0];
            var appendNode=document.getElementById('storytext');
            appendNode.innerHTML= '';
            for (var i=0;i<numCh;i++){
                //findHeader(chapters[i]);  //smart header search
                var st=chapters[i];
                st.setAttribute('name','ffnee_chapter');
                st.setAttribute('id','ffnee_ch'+i);
                if (i!=0){
                    st.style.marginTop='10em';
                }
                appendNode.appendChild(st);
            }
            expText.nodeValue='story(re)';
        }
        //  Getting number of chapters;
        function getLength(){
            //var chNum=document.evaluate('//SELECT[@title=\'chapter navigation\']',document,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var chNum = document.getElementById('chap_select');
            if (chNum==null){
                numChapters = 1;
            }else {
                var numChapters = chNum.getElementsByTagName('option').length;
            }
            return (numChapters);
        }
        // This function loads chapters and extracts chapter's number and title 
        function loadChapter(num){
            var replStr='\/'+String(num)+'\/';
            var currentURL=hr.replace(/\/\d{1,3}\//,replStr);
            GM_xmlhttpRequest({ //Internal Greesemonkey function - main reason this couldn't work as a bookmarklet.
                method: 'GET',
                url: currentURL,
                onload: function(responseDetails) {
                    parseChapter(responseDetails.responseText, num);
                    storyLength--;
                    if (storyLength==0){
                        parseStory();
                    }
                  }
            });
        }
        function parseChapter(chapterHtml, chapterNumber){
            var t=document.createElement('div');
            t.innerHTML=chapterHtml;
            //extracting text only
              var ev='.//div[@id=\'storytext\']';
            var xpathResult = document.evaluate(ev,t,null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
            var chapterContent=document.createElement('div');
            chapterContent.setAttribute('title',getChapterName(t));
            chapterContent.innerHTML = xpathResult.snapshotItem(0).innerHTML;
            chapters[chapterNumber-1]=chapterContent;
            expText.nodeValue = 'Export: Chapter '+String(totalStoryLength-storyLength+1)+' out of '+totalStoryLength;
            function getChapterName(obj){
                var select = obj.getElementsByTagName('select')[1].getElementsByTagName('option');
                 for (var i=0;i<select.length;i++){
                     if (select[i].getAttribute('selected')!=null){
                         return(select[i].innerHTML.split(/[. ]{2}/)[1]);
                     }
                }
            }
        }
    
    }
     
  7. Nuit

    Nuit Dark Lord

    Joined:
    Feb 14, 2010
    Messages:
    1,934
    Location:
    The Peach State
    When adding another term to filter out a message about Grant Metadata popped up. http://wiki.greasespot.net/@grant

    Will this prevent the script from doing what it usually does?
     
  8. Saot

    Saot Groundskeeper

    Joined:
    May 9, 2011
    Messages:
    321
    It doesn't use the greasemonkey API at all so that shouldn't break anything. Adding [fixed]// @grant none[/fixed] to the comment block at the top will stop the message from reappearing in the future.
     
  9. Nuit

    Nuit Dark Lord

    Joined:
    Feb 14, 2010
    Messages:
    1,934
    Location:
    The Peach State
    Ah, alright, thanks.
     
  10. SilverOtter

    SilverOtter Seventh Year

    Joined:
    Feb 20, 2011
    Messages:
    263
    Location:
    USA
    Last edited: Mar 24, 2013
Loading...