Advertisement
Kaanbaltlak

FanFictionNavigator - español

Jun 19th, 2024
677
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        FanFictionNavigator
  3. // @name:ru     FanFictionNavigator
  4. // @license MIT
  5. // @version     80
  6. // @namespace   window
  7. // @description  Mark and hide fanfics or authors
  8. // @description:ru  Выделяет цветом/скрывает фанфики или авторов
  9. // @include https://ficbook.net/*
  10. // @include     https://www.fanfiction.net/*
  11. // @include     https://archiveofourown.org/*
  12. // @include     http://archiveofourown.org/*
  13. // @include     http://www.archiveofourown.org/*
  14. // @include     https://www.archiveofourown.org/*
  15. // @run-at      document-end
  16.  
  17. // @require     https://code.jquery.com/jquery-1.7.2.min.js
  18. // @require     https://greasyfork.org/scripts/17419-underscore-js-1-8-3/code/Underscorejs%20183.js?version=109803
  19. // @grant       GM_addStyle
  20. // @description Mark and hide fanfics or authors
  21. // @downloadURL https://update.greasyfork.org/scripts/25670/FanFictionNavigator.user.js
  22. // @updateURL https://update.greasyfork.org/scripts/25670/FanFictionNavigator.meta.js
  23. // ==/UserScript==
  24.  
  25. // Based on https://chrome.google.com/webstore/detail/fanfiction-organizer/adlnghnicfngjnofbljedmclmdoepcbe
  26. // by Stefan Hayden
  27.  
  28. // Fics:
  29. const FIC_LIKED = 0;
  30. const FIC_DISLIKED = 1;
  31. const FIC_MARKED = 2;
  32. const FIC_INLIBRARY = 3;
  33.  
  34. // Authors:
  35. const AUTHOR_LIKED = 0;
  36. const AUTHOR_DISLIKED = 1;
  37.  
  38. // Communities:
  39. const COMMUNITY_LIKED = 0;
  40. const COMMUNITY_DISLIKED = 1;
  41.  
  42. // colors. now used for like/dislike/etc links
  43. const COLOR_LIKED = '#C4FFCA';
  44. const COLOR_DISLIKED = '#FCB0B0';
  45. const COLOR_MARKED = '#CCCCCC';
  46. const COLOR_INLIBRARY = '#F1D173';
  47. const COLOR_CLEARED = '#FFF';
  48. const COLOR_FB_CLEAR = '#FFF';
  49.  
  50.  
  51. // styles for author/story links; <a> links should have only one of these so order doesn't matter
  52. GM_addStyle("a.ffn_dislike_fic {text-decoration: line-through; font-weight: bold;}");
  53. GM_addStyle("a.ffn_like_fic {font-weight: bold;} ");
  54. GM_addStyle("a.ffn_dislike_author {text-decoration: line-through; font-weight: bold;}");
  55. GM_addStyle("a.ffn_like_author {font-weight: bold;} ");
  56. GM_addStyle("a.ffn_mark {font-weight: bold;}");
  57. GM_addStyle("a.ffn_inlibrary {font-weight: bold;}");
  58. GM_addStyle("a.ffn_dislike_community {text-decoration: line-through; font-weight: bold;}");
  59. GM_addStyle("a.ffn_like_community {font-weight: bold;} ");
  60.  
  61. // styles for box background; fic style should overwrite author style
  62. GM_addStyle(".ffn_like_author:not(a) {background-color:#C4FFCA !important;}");
  63. GM_addStyle(".ffn_dislike_author:not(a) {background-color:#FCB0B0 !important;}");
  64. GM_addStyle(".ffn_like_fic:not(a) {background-color:#C4FFCA !important;}");
  65. GM_addStyle(".ffn_dislike_fic:not(a) {background-color:#FCB0B0 !important;}");
  66. GM_addStyle(".ffn_mark:not(a) {background-color:#CCCCCC !important;}");
  67. GM_addStyle(".ffn_inlibrary:not(a) {background-color:#F1D173 !important;}");
  68. GM_addStyle(".ffn_like_community:not(a) {background-color:#C4FFCA !important;}");
  69. GM_addStyle(".ffn_dislike_community:not(a) {background-color:#FCB0B0 !important;}");
  70.  
  71.  
  72.  
  73. // styles for boxes, they differ between sites
  74.  
  75. /*
  76. switch(window.location.hostname){
  77. case "www.fanfiction.net":
  78.     GM_addStyle("div.ffn_dislike {background-color:#FCB0B0 !important;}");
  79.     GM_addStyle("div.ffn_like {background-color:#C4FFCA !important;}");
  80.     GM_addStyle("div.ffn_mark {background-color:#CCCCCC !important;}");
  81.     GM_addStyle("div.ffn_inlibrary {background-color:#F1D173 !important;}");
  82. break
  83. case "archiveofourown.org":
  84.     GM_addStyle(".ffn_dislike {background-color:#FCB0B0 !important;}");
  85.     GM_addStyle(".ffn_like {background-color:#C4FFCA !important;}");
  86.     GM_addStyle(".ffn_mark {background-color:#CCCCCC !important;}");
  87.     GM_addStyle(".ffn_inlibrary {background-color:#F1D173 !important;}");
  88. break
  89. case "ficbook.net":
  90.     GM_addStyle("div.ffn_dislike {background-color:#FCB0B0 !important;}");
  91.     GM_addStyle("div.ffn_like {background-color:#C4FFCA !important;}");
  92.     GM_addStyle("div.ffn_mark {background-color:#CCCCCC !important;}");
  93.     GM_addStyle("div.ffn_inlibrary {background-color:#F1D173 !important;}");
  94.     GM_addStyle("ul.ffn_dislike {background-color:#FCB0B0 !important;}");
  95.     GM_addStyle("ul.ffn_like {background-color:#C4FFCA !important;}");
  96.     GM_addStyle("ul.ffn_mark {background-color:#CCCCCC !important;}");
  97.     GM_addStyle("ul.ffn_inlibrary {background-color:#F1D173 !important;}");
  98. break
  99. }
  100. */
  101.  
  102. // prevent conflicts with websites' jQuery version
  103. this.ffn$ = this.jQuery = jQuery.noConflict(true);
  104.  
  105.  
  106. var db = JSON.parse(localStorage.getItem("FFLikerAA") || '{}');
  107. db.options = db.options || {};
  108. db.version = db.version || '0.2';
  109.  
  110.  
  111. //
  112. // APP
  113. //
  114.  
  115. // Main
  116. var patharr = window.location.pathname.split("/");     // moved to main block to save on split functions elsewhere
  117.  
  118. var Application = function Application(optionsin) {
  119.     var a = {};
  120.     var options = optionsin || {};
  121.  
  122.     if(!options.namespace) { throw new Error("namespace is required"); }
  123.     if(!options.db) { throw new Error("database object is required"); }
  124.  
  125.     a.namespace = options.namespace;
  126.     var db = options.db;
  127.     db[a.namespace] = db[a.namespace] || { fic: {}, author:{}, community:{} };
  128.  
  129.     a.collection = [];
  130.  
  131.     a.color = {
  132.         link_default: ffn$("ol.work.index.group > li:first a:first").css("color"),
  133.         like_link:'',
  134.         like_background:'',
  135.         dislike_link:'',
  136.         dislike_background:'',
  137.     };
  138.  
  139.     a.save = function(type,id,value){
  140.         if(type == "fic" || type == "author" || type == "community") {
  141.             a.saveNameSpaced(type,id,value);
  142.         } else {
  143.             if(value === "clear") {
  144.                 delete db[type][id];
  145.             } else {
  146.                 db[type][id] = value;
  147.             }
  148.             localStorage.setItem("FFLikerAA", JSON.stringify(db));
  149.         }
  150.     };
  151.  
  152.     a.saveNameSpaced = function(type,id,value){
  153.         if(value === "clear") {
  154.             delete db[a.namespace][type][id];
  155.         } else {
  156.             if (typeof(db[a.namespace][type]) == 'undefined') {
  157.                 db[a.namespace][type] = {};
  158.             }
  159.             db[a.namespace][type][id] = value;
  160.         }
  161.         localStorage.setItem("FFLikerAA", JSON.stringify(db));
  162.     };
  163.  
  164.  
  165.     a.author = {};
  166.  
  167.         a.author.get = function(id){
  168.             return db[a.namespace].author[id];
  169.         };
  170.  
  171.         a.author.like = function(id) {
  172.             a.save("author",id,AUTHOR_LIKED);
  173.  
  174.             _.each(a.author.getFics(id), function(story){
  175.                 story.author = AUTHOR_LIKED;
  176.                 story.like_author();
  177.             });
  178.         };
  179.  
  180.         a.author.dislike = function(id) {
  181.             a.save("author",id,AUTHOR_DISLIKED);
  182.             //ga('set', 'metric3', 1);
  183.  
  184.             _.each(a.author.getFics(id), function(story){
  185.                 story.author = AUTHOR_DISLIKED;
  186.                 story.dislike_author();
  187.             });
  188.         };
  189.  
  190.         a.author.clear = function(id) {
  191.             a.save("author",id,"clear");
  192.  
  193.             _.each(a.author.getFics(id), function(story){
  194.                 story.author = '';
  195.                 story.clear_author();
  196.             });
  197.         };
  198.  
  199.         a.author.getFics = function(id) {
  200.             return _.filter(a.collection,function(story){
  201.                 return story.authorId() == id;
  202.             });
  203.         };
  204.  
  205.     a.fic = {};
  206.  
  207.         a.fic.get = function(id) {
  208.             return db[a.namespace].fic[id];
  209.         };
  210.  
  211.         a.fic.like = function(id) {
  212.             a.save("fic",id,FIC_LIKED);
  213.  
  214.             var story = _.find(a.collection,function(story){
  215.                 return story.ficId() == id;
  216.             });
  217.  
  218.             story.fic = FIC_LIKED;
  219.             story.like_story();
  220.         };
  221.  
  222.         a.fic.dislike = function(id) {
  223.             a.save("fic",id,FIC_DISLIKED);
  224.             var story = _.find(a.collection,function(story){
  225.                 return story.ficId() == id;
  226.             });
  227.             story.fic = FIC_DISLIKED;
  228.             story.dislike_story();
  229.         };
  230.  
  231.         a.fic.mark = function(id) {
  232.             a.save("fic",id,FIC_MARKED);
  233.             var story = _.find(a.collection,function(story){
  234.                 return story.ficId() == id;
  235.             });
  236.             story.fic = FIC_MARKED;
  237.             story.mark_story();
  238.         };
  239.  
  240.         a.fic.inlibrary = function(id) {
  241.             a.save("fic",id,FIC_INLIBRARY);
  242.             var story = _.find(a.collection,function(story){
  243.                 return story.ficId() == id;
  244.             });
  245.             story.fic = FIC_INLIBRARY;
  246.             story.inlibrary_story();
  247.         };
  248.  
  249.  
  250.         a.fic.clear = function(id) {
  251.             a.save("fic",id,"clear");
  252.             var story = _.find(a.collection,function(story){
  253.                 return story.ficId() == id;
  254.             });
  255.             story.fic = '';
  256.             story.clear_story();
  257.         };
  258.  
  259.     a.community = {};
  260.         a.community.get = function(id) {
  261.             if (typeof(db[a.namespace].community) == "undefined") {
  262.                 db[a.namespace].community = {}
  263.             }
  264.             return db[a.namespace].community[id];
  265.         };
  266.  
  267.         a.community.like = function(id) {
  268.             a.save("community",id,COMMUNITY_LIKED);
  269.  
  270.             var community = _.find(a.collection,function(community){
  271.                 return community.communityId() == id;
  272.             });
  273.  
  274.             community.community = COMMUNITY_LIKED;
  275.             community.like_community();
  276.         };
  277.  
  278.         a.community.dislike = function(id) {
  279.             a.save("community",id,COMMUNITY_DISLIKED);
  280.             var community = _.find(a.collection,function(community){
  281.                 return community.communityId() == id;
  282.             });
  283.             community.community = COMMUNITY_DISLIKED;
  284.             community.dislike_community();
  285.         };
  286.  
  287.  
  288.         a.community.clear = function(id) {
  289.             a.save("community",id,"clear");
  290.             var community = _.find(a.collection,function(community){
  291.                 return community.communityId() == id;
  292.             });
  293.             community.community = '';
  294.             community.clear_community();
  295.         };
  296.  
  297.     a.options = function(name, value) {
  298.  
  299.         if(!name) { throw new Error("name is required. what option are you looking for?"); }
  300.  
  301.         if(typeof value !== "undefined") {
  302.             a.save("options",name,value);
  303.             return false;
  304.         } else {
  305.             return db.options[name];
  306.         }
  307.     };
  308.  
  309.     return a;
  310. };
  311.  
  312. var Story = function(optionsin) {
  313.  
  314.     var a = {};
  315.     var options  = optionsin || {};
  316.  
  317.     if(!options.instance) { throw new Error("instance of this is required"); }
  318.     if(!options.namespace) { throw new Error("namespace is required"); }
  319.  
  320.     var _this = ffn$(options.instance);
  321.  
  322.     a["default"] = {
  323.         template: function() {
  324.             var template =  '<div class="new_like_actions" style="margin:0px 0px 0px 20px; font-size:11px;">'+
  325.  
  326.                                 'Fanfic: <a href="" class="like_story"><font color="'+COLOR_LIKED+'">Favorito</font></a> | '+
  327.                                 '<a href="" class="dislike_story"><font color="'+COLOR_DISLIKED+'">Rechazado</font></a> | '+
  328.                                 '<a href="" class="mark_story"><font color="'+COLOR_MARKED+'">Marcado</font></a> | '+
  329.                                 '<a href="" class="inlibrary_story"><font color="'+COLOR_INLIBRARY+'">Descargado</font></a> | '+
  330.                                 '<a href="" class="clear_story" style="color:blue;">Eliminar</a>'+
  331.  
  332.                                 '   Ficker: <a href="" class="like_author" style="color:blue;">Favorito</a> | '+
  333.                                 '<a href="" class="dislike_author" style="color:blue;">Rechazado</a> | '+
  334.                                 '<a href="" class="clear_author" style="color:blue;">Eliminar</a>'+
  335.  
  336.                             '</div>';
  337.             return template;
  338.         },
  339.         addActions: function() {
  340.             var instance = this;
  341.             _this.append(this.template());
  342.  
  343.             _this.find('.new_like_actions .like_author').click(function(){ app.author.like(instance.authorId()); return false; });
  344.             _this.find('.new_like_actions .dislike_author').click(function(){ app.author.dislike(instance.authorId()); return false; });
  345.             _this.find('.new_like_actions .clear_author').click(function(){ app.author.clear(instance.authorId()); return false; });
  346.  
  347.             _this.find('.new_like_actions .like_story').click(function(){ app.fic.like(instance.ficId()); return false; });
  348.             _this.find('.new_like_actions .dislike_story').click(function(){ app.fic.dislike(instance.ficId()); return false; });
  349.             _this.find('.new_like_actions .mark_story').click(function(){ app.fic.mark(instance.ficId()); return false; });
  350.             _this.find('.new_like_actions .inlibrary_story').click(function(){ app.fic.inlibrary(instance.ficId()); return false; });
  351.             _this.find('.new_like_actions .clear_story').click(function(){ app.fic.clear(instance.ficId()); return false; });
  352.         },
  353.         hide: function() {
  354.             _this.hide();
  355.         },
  356.         set_story: function(){
  357.             switch(this.fic){
  358.             case FIC_LIKED:
  359. //              _this.css('background-color',COLOR_LIKED);
  360. //              this.$fic.css('font-weight','900')
  361.                 _this.addClass("ffn_like_fic");
  362.                 this.$fic.addClass("ffn_like_fic");
  363.                 break;
  364.             case FIC_DISLIKED:
  365.                 _this.addClass("ffn_dislike_fic");
  366.                 this.$fic.addClass("ffn_dislike_fic");
  367.                 break;
  368.             case FIC_MARKED:
  369.                 _this.addClass("ffn_mark");
  370.                 this.$fic.addClass("ffn_mark");
  371.                 break;
  372.             case FIC_INLIBRARY:
  373.                 _this.addClass("ffn_inlibrary");
  374.                 this.$fic.addClass("ffn_inlibrary");
  375.                 break;
  376.             }
  377.         },
  378.         set_author: function() {
  379.             if(this.author === AUTHOR_LIKED) {
  380.                 this.$author.addClass("ffn_like_author");
  381.                 _this.addClass("ffn_like_author");
  382.             }
  383.             if(this.author === AUTHOR_DISLIKED) {
  384.                 this.$author.addClass("ffn_dislike_author");
  385.                 _this.addClass("ffn_dislike_author");
  386.             }
  387.         },
  388.         like_story: function(){
  389.             this.clear_story();
  390.             _this.addClass("ffn_like_fic");
  391.             this.$fic.addClass("ffn_like_fic");
  392.         },
  393.         dislike_story: function(){
  394.             this.clear_story();
  395.             _this.addClass("ffn_dislike_fic");
  396.             this.$fic.addClass("ffn_dislike_fic");
  397.         },
  398.         mark_story: function(){
  399.             this.clear_story();
  400.             _this.addClass("ffn_mark");
  401.             this.$fic.addClass("ffn_mark");
  402.         },
  403.         inlibrary_story: function(){
  404.             this.clear_story();
  405.             _this.addClass("ffn_inlibrary");
  406.             this.$fic.addClass("ffn_inlibrary");
  407.         },
  408.         clear_story: function(){
  409.             _this.removeClass("ffn_like_fic ffn_dislike_fic ffn_mark ffn_inlibrary");
  410.             this.$fic.removeClass("ffn_like_fic ffn_dislike_fic ffn_mark ffn_inlibrary");
  411.  
  412.         },
  413.         like_author: function(){
  414.             this.clear_author();
  415.             this.$author.addClass("ffn_like_author");
  416.             _this.addClass("ffn_like_author");
  417.         },
  418.         dislike_author: function(){
  419.             this.clear_author();
  420.             this.$author.addClass("ffn_dislike_author");
  421.             _this.addClass("ffn_dislike_author");
  422.         },
  423.         clear_author: function(){
  424.             _this.removeClass("ffn_like_author ffn_dislike_author");
  425.             this.$author.removeClass("ffn_like_author ffn_dislike_author");
  426.         }
  427.     };
  428.  
  429. // Specific sites overrides
  430.  
  431.     a["www.fanfiction.net"] = {
  432.         $author: _this.find('a[href^="/u"]:first'),
  433.         $fic: _this.find('a[href^="/s"]:first'),
  434.         authorId: function() {
  435.             if (typeof this.$author.attr('href') === "undefined") {
  436.                 return patharr[2];
  437.             } else {
  438.                 return this.$author.attr('href').split('/')[2];
  439.             }
  440.         },
  441.         ficId: function() {
  442.             if (this.$fic.length === 0) {
  443.                 return patharr[2];
  444.             } else {
  445.                 return this.$fic.attr('href').split('/')[2];
  446.             }
  447.         },
  448.         hide: function() {
  449.             // do not hide story header on reading page and story block on author page
  450.             if (!patharr[1].match("^s$|^u$")) _this.hide(); // do not hide fic on author pages (to clearly see how many fics you like and dislike) and on reading pages
  451.         }
  452.     };
  453.  
  454. //
  455.  
  456.     a["archiveofourown.org"] = {
  457.         $author: _this.find('a[href^="/users/"]:first'),
  458.         $fic: _this.find('a[href^="/works/"]:first'),
  459.         authorId: function() {
  460.             // old: return this.$author.attr('href').split('/')[2];
  461.             // Contributed by Vannis:
  462.             if (this.$author.length === 0) {
  463.                 return 0;
  464.             } else {
  465.                 return this.$author.attr('href').split('/')[2];
  466.             }
  467.         },
  468.         ficId: function() {
  469.             if (this.$fic.length === 0) {
  470.                 return patharr[2];
  471.             } else {
  472.                 return this.$fic.attr('href').split('/')[2];
  473.             }
  474.         },
  475.         hide:function(){
  476.             if (patharr[1] !== "users" &&    // do not hide fic on author pages (to clearly see how many fics you like and dislike)
  477.                 !/(collections\/[^\/]+\/)?works\/\d+/.test(window.location.pathname)) { // do not hide fic header on reading pages)
  478.                 _this.hide();
  479.             }
  480.         }
  481.     };
  482.  
  483. //
  484.  
  485.     a["ficbook.net"] = {
  486.         $author: _this.find('a[href^="/authors"]:first'),
  487.         $fic: _this.find('a[href^="/readfic"]:first'),
  488.         authorId: function() {
  489.             return this.$author.attr('href').split('/')[2];
  490.         },
  491.         ficId: function() {
  492.             if (this.$fic.length === 0) {
  493.                 return patharr[2].replace(/([0123456789abcdef-]+).*?$/,"$1");
  494.             } else {
  495.                 return this.$fic.attr('href').split('/')[2].replace(/([0123456789abcdef-]+).*?$/,"$1");
  496.             }
  497.         },
  498.         hide:function(){
  499.             if (patharr[1]==="popular-fanfics"){
  500.                 _this.parent().hide();
  501.                 return;
  502.             }
  503.             if (patharr[1]!=="readfic" && patharr[2]!=="favourites") {
  504.                 _this.hide();
  505.                 return;
  506.             }
  507.         }
  508.     };
  509.  
  510. //
  511.     a["author.today"] = {
  512.         $author: _this.find('a[href^="/u"]:first'),
  513.         $fic: _this.find('a[href^="/work/"]:first'),
  514.         authorId: function() {
  515.             if (typeof this.$author.attr('href') === "undefined") {
  516.                 return patharr[2];
  517.             } else {
  518.                 return this.$author.attr('href').split('/')[2];
  519.             }
  520.         },
  521.         ficId: function() {
  522.             //console.log(this.$fic);
  523.             if (typeof this.$fic.attr('href') === "undefined" ||
  524.                patharr[2].match(/^\d+$/)) {
  525.                 return patharr[2];
  526.             } else {
  527.                 return this.$fic.attr('href').split('/')[2];
  528.             }
  529.         },
  530.         hide: function() {
  531.             // do not hide story header on reading page and story block on author page
  532.             if (!patharr[1].match("^work$|^u$")) {
  533.                 _this.parent().hide();
  534.             }
  535.         }
  536.     };
  537.  
  538.     var b = ffn$.extend({}, a["default"], a[options.namespace]);
  539.     b.fic = app.fic.get(b.ficId());
  540.  
  541.     b.author = app.author.get(b.authorId());
  542.     // do not show liker links if ficid or authorid are undefined (tweak for tbooklist.org)
  543.     if (b.ficId() !== 0 && b.authorId() !== 0) {
  544.         b.addActions();
  545.     }
  546.     b.set_story();
  547.     b.set_author();
  548.  
  549.     //hide
  550.     if((app.options("hide_dislikes") === true && (b.fic === FIC_DISLIKED || b.author === AUTHOR_DISLIKED)) ||
  551.        (app.options("hide_likes") === true && (b.fic === FIC_LIKED)) ||  // || b.author === AUTHOR_LIKED  (removed to show new fics of liked authors)
  552.        (app.options("hide_marked") === true && b.fic === FIC_MARKED) ||
  553.        (app.options("hide_inlibrary") === true && b.fic === FIC_INLIBRARY)){
  554. //      if(b.fic !== true && b.author) { // for liked fics of disliked authors
  555.             b.hide();
  556. //      }
  557.     }
  558.     return b;
  559. };
  560.  
  561. // Community
  562.  
  563. var Community = function(optionsin) {
  564.  
  565.     var c = {};
  566.     var options  = optionsin || {};
  567.  
  568.     if(!options.instance) { throw new Error("instance of this is required"); }
  569.     if(!options.namespace) { throw new Error("namespace is required"); }
  570.  
  571.     var _this = ffn$(options.instance);
  572.  
  573.     c["default"] = {
  574.         template: function() {
  575.             var template =  '<div class="new_like_actions" style="margin:0px 0px 0px 20px; font-size:11px;">'+
  576.                                 'Community: <a href="" class="like_community"><font color="'+COLOR_LIKED+'">Favorito</font></a> | '+
  577.                                 '<a href="" class="dislike_community"><font color="'+COLOR_DISLIKED+'">Rechazado</font></a> | '+
  578.                                 '<a href="" class="clear_community" style="color:blue;">Eliminar</a>'+
  579.                             '</div>';
  580.             return template;
  581.         },
  582.         addActions: function() {
  583.             var instance = this;
  584.             _this.append(this.template());
  585.  
  586.             _this.find('.new_like_actions .like_community').click(function(){ app.community.like(instance.communityId()); return false; });
  587.             _this.find('.new_like_actions .dislike_community').click(function(){ app.community.dislike(instance.communityId()); return false; });
  588.             _this.find('.new_like_actions .clear_community').click(function(){ app.community.clear(instance.communityId()); return false; });
  589.         },
  590.         hide: function() {
  591.             _this.hide();
  592.         },
  593.         set_community: function(){
  594.             switch(this.community){
  595.             case COMMUNITY_LIKED:
  596.                 _this.addClass("ffn_like_community");
  597.                 this.$community.addClass("ffn_like_community");
  598.                 break;
  599.             case COMMUNITY_DISLIKED:
  600.                 _this.addClass("ffn_dislike_community");
  601.                 this.$community.addClass("ffn_dislike_community");
  602.                 break;
  603.             }
  604.         },
  605.         like_community: function(){
  606.             this.clear_community();
  607.             _this.addClass("ffn_like_community");
  608.             this.$community.addClass("ffn_like_community");
  609.         },
  610.         dislike_community: function(){
  611.             this.clear_community();
  612.             _this.addClass("ffn_dislike_community");
  613.             this.$community.addClass("ffn_dislike_community");
  614.         },
  615.         clear_community: function(){
  616.             _this.removeClass("ffn_like_community ffn_dislike_community");
  617.             this.$community.removeClass("ffn_like_community ffn_dislike_community");
  618.  
  619.         }
  620.     };
  621.  
  622. // Specific sites overrides
  623.  
  624.     c["www.fanfiction.net"] = {
  625.         $community: _this.find('a[href^="/community"]:first'),
  626.         communityId: function() {
  627.             if (typeof this.$community.attr('href') === "undefined") {
  628.                 return patharr[3];
  629.             } else {
  630.                 return this.$community.attr('href').split('/')[3];
  631.             }
  632.         },
  633.         hide: function() {
  634.             // needrework for community
  635.             // do not hide story header on reading page and story block on author page
  636.             if (!patharr[1].match("^s$|^u$")) _this.hide(); // do not hide fic on author pages (to clearly see how many fics you like and dislike) and on reading pages
  637.         }
  638.     };
  639.  
  640.     var d = ffn$.extend({}, c["default"], c[options.namespace]);
  641.     d.community = app.community.get(d.communityId());
  642.  
  643.     // do not show liker links if communityId is undefined
  644.     if (d.communityId() !== 0) {
  645.         d.addActions();
  646.     }
  647.     d.set_community();
  648.  
  649.     //hide
  650.     if((app.options("hide_dislikes") === true && d.community === COMMUNITY_DISLIKED) ||
  651.        (app.options("hide_likes") === true && d.community === COMMUNITY_LIKED)){
  652.             d.hide();
  653. //      }
  654.     }
  655.     return d;
  656. };
  657.  
  658.  
  659. var app  = new Application({namespace:document.location.host, db: db});
  660.  
  661. // Adding action links and navigation shortcuts to pages
  662. switch(window.location.hostname){
  663.     case "www.fanfiction.net":
  664.         // small tweak to allow text selection
  665.         GM_addStyle("* {user-select:text !important;}");
  666.         // adding hotkeys
  667.         // added toggle option, suggested by Vannius
  668.         if (app.options("enable_list_hotkeys")) {
  669.             document.addEventListener('keydown', function(e){
  670.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  671.                     switch (e.keyCode){
  672.                         case 37:
  673.                             var Prev = ffn$("a:contains('« Prev')");
  674.                             if (typeof(Prev[0])!=='undefined') {Prev[0].click();}
  675.                             break;
  676.                         case 39:
  677.                             var Next = ffn$("a:contains('Next »')");
  678.                             if (typeof(Next[0])!=='undefined') {Next[0].click();}
  679.                             break;
  680.                     }
  681.                 }
  682.             }, false);
  683.         }
  684.         if (app.options("enable_read_hotkeys")) {
  685.             document.addEventListener('keydown', function(e){
  686.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  687.                     switch (e.keyCode){
  688.                         case 37:
  689.                             var Prev = ffn$("button:contains('< Prev')");
  690.                             if (typeof(Prev[0])!=='undefined') {Prev.click();}
  691.                             break;
  692.                         case 39:
  693.                             var Next = ffn$("button:contains('Next >')");
  694.                             if (typeof(Next[0])!=='undefined') {Next.click();}
  695.                             break;
  696.                     }
  697.                 }
  698.             }, false);
  699.         }
  700.         // links in list
  701.         if (patharr[1] == "communities") {
  702.             ffn$(".z-list").each(function(){
  703.                 var community = new Community({ namespace: app.namespace, instance: this });
  704.                 app.collection.push(community);
  705.             });
  706.  
  707.         } else {
  708.             ffn$(".z-list").each(function(){
  709.                 var story = new Story({ namespace: app.namespace, instance: this });
  710.                 app.collection.push(story);
  711.             });
  712.         }
  713.  
  714.         // links on reading page
  715.         ffn$("div#profile_top").each(function(){
  716.             var story = new Story({ namespace: app.namespace, instance: this });
  717.             app.collection.push(story);
  718.         });
  719.  
  720.         // hide/show options
  721.         ffn$('div#content_wrapper_inner').after(
  722.             '<div class="liker_script_options" style="padding:5px; border:1px solid #333399; margin-bottom:5px; background:#D8D8FF;">'+
  723.             '<b>Liker Options:</b> '+
  724.             '</div>'
  725.         );
  726.         break;
  727.     case "archiveofourown.org":
  728.         // adding hotkeys
  729.         if (app.options("enable_list_hotkeys")) {
  730.             document.addEventListener('keydown', function(e){
  731.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  732.                     switch (e.keyCode){
  733.                         case 37:
  734.                             var Prev = ffn$("a:contains('← Previous')");
  735.                             if (typeof(Prev[0])!=='undefined') {Prev[0].click();}
  736.                             break;
  737.                         case 39:
  738.                             var Next = ffn$("a:contains('Next →')");
  739.                             if (typeof(Next[0])!=='undefined') {Next[0].click();}
  740.                             break;
  741.                     }
  742.                 }
  743.             }, false);
  744.         }
  745.         if (app.options("enable_read_hotkeys")) {
  746.             document.addEventListener('keydown', function(e){
  747.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  748.                     switch (e.keyCode){
  749.                         case 37:
  750.                             var Prev = ffn$("a:contains('←Previous Chapter')");
  751.                             if (typeof(Prev[0])!=='undefined') {Prev[0].click();}
  752.                             break;
  753.                         case 39:
  754.                             var Next = ffn$("a:contains('Next Chapter →')");
  755.                             if (typeof(Next[0])!=='undefined') {Next[0].click();}
  756.                             break;
  757.                     }
  758.                 }
  759.             }, false);
  760.         }
  761.         // in lists
  762.         // old: ffn$("ol.work.index.group > li").each(function(){
  763.         // contribution by Vannius from greasyfork site
  764.         ffn$(".blurb").each(function(){
  765.             var story = new Story({ namespace: app.namespace, instance: this });
  766.             app.collection.push(story);
  767.         });
  768.         // on reading page
  769.         ffn$("div.preface.group").each(function(){
  770.             var story = new Story({ namespace: app.namespace, instance: this });
  771.             app.collection.push(story);
  772.         });
  773.         // hide/show options
  774.         ffn$('div.navigation.actions.module, div.primary.header.module').after(
  775.             '<div class="liker_script_options" style="padding:5px; border:1px solid #333399; margin-bottom:5px; background:#D8D8FF;">'+
  776.             '<b>Liker Options:</b> '+
  777.             '</div>'
  778.         );
  779.         break;
  780.     case "ficbook.net":
  781.         // on reading page
  782.         if (patharr[1]==="readfic"){
  783.             //ffn$("div.row.hat-row > ul.list-unstyled").each(function() {
  784.              //ffn$("section.fanfiction-hat.container-fluid").each(function() {
  785.             ffn$("div.fanfic-hat-body").each(function() {
  786. //                console.log(this);
  787.                 var story = new Story({
  788.                     namespace: app.namespace,
  789.                     instance: this
  790.                 });
  791.                 app.collection.push(story);
  792.             });
  793.             if (app.options("enable_read_hotkeys")) {
  794.                 document.addEventListener('keydown', function(e){
  795.                     var textcontent;
  796.                     if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  797.                         switch (e.keyCode){
  798.                             case 37:
  799.                                 var Prev = ffn$("a.btn-back");
  800.                                 if (Prev.length>0) window.location.href = Prev[0];
  801.                                 break;
  802.                             case 39:
  803.                                 var Next = ffn$("a.btn-next");
  804.                                 if (Next.length>0) window.location.href = Next[0];
  805.                                 break;
  806.                         }
  807.                     }
  808.                     //   Ctrl+ up/dn hotkeys
  809.                     if (e.ctrlKey && !e.altKey && !e.shiftKey) {
  810.                         switch (e.keyCode){
  811.                             case 38:
  812.                                 console.log("Ctrl+up")
  813.                                 textcontent = document.getElementById("content");
  814.                                 var txt = textcontent.outerHTML;
  815.                                 txt = txt.replace(/&nbsp;/g," ");
  816.                                 txt = txt.replace(/(<div[^>]*id=\"content\"[^>]*>)[ ]*/m,"$1    ");
  817.                                 txt = txt.replace(/[\r\n][\ \r\n\t]+/gm,"\r\n");
  818.                                 txt = txt.replace(/^((<[^>]+>)*)[ \t]+/gm,"$1");
  819.                                 txt = txt.replace(/\n[ \t]*/gm,"\n    ");
  820.                                 txt = txt.replace("- ","— ");
  821.                                 textcontent.outerHTML = txt;
  822.                                 break;
  823.                             /* removed since we don't have a way to completely restore formatting after deleting so much junk
  824.                             case 40:
  825.                                 textcontent = document.getElementById("content");
  826.                                 textcontent.outerHTML = textcontent.outerHTML.replace(/<br n=\"2\">/gi,"<br>\n<br>");
  827.                                 ffn$("#undo_typograf").click();
  828.                                 break;
  829.                             */
  830.                         }
  831.                     }
  832.                     if (!e.ctrlKey && !e.altKey && e.shiftKey) {
  833.                         switch (e.keyCode){
  834.                             case 38:
  835.                                 ffn$("#do_typograf").click();
  836.                                 break;
  837.                             case 40:
  838.                                 ffn$("#undo_typograf").click();
  839.                                 break;
  840.                         }
  841.                     }
  842.                 }, false);
  843.             }
  844.         }
  845.         // in lists
  846.         if (/^find-fanfics[\-0-9]*/.test(patharr[1]) ||
  847.             (/^popular-fanfics[\-0-9]*/.test(patharr[1])) ||
  848.             (patharr[1]==="collections") ||
  849.             (patharr[1]==="fanfiction") ||
  850.             (patharr[3]==="profile" && patharr[4]==="works") ||            // in author profile / works
  851.             (patharr[1] === "home" && ["favourites","collections"].indexOf(patharr[2])!=-1) ){ // indexOf => checks if patharr[2] is in [] array
  852.             ffn$("article.fanfic-inline").each(function() {
  853.             //ffn$("div.js-toggle-description").each(function() {
  854.                 var story = new Story({
  855.                     namespace: app.namespace,
  856.                     instance: this
  857.                 });
  858.                 app.collection.push(story);
  859.             });
  860.         }
  861.         // button for quickly reading/unreading story
  862.         if (/^find-fanfics[\-0-9]*/.test(patharr[1]) ||
  863.             (/^popular-fanfics[\-0-9]*/.test(patharr[1])) ||
  864.             (patharr[2]==="favourites") ||
  865.             (patharr[1]==="authors" && patharr[3]==="profile" && patharr[4]==="works")) {
  866.             ffn$("article.fanfic-inline").each(function() { // need more wide block to detect if the fic is read/unread to construct correct button
  867.                 var _this = ffn$(this);
  868.                 //console.log(_this);
  869.                 var ficId = _this.find('a[href^="/readfic"]:first').attr('href').split('/')[2].replace(/([0123456789abcdef-]+).*?$/,"$1");
  870.                 var readButton;
  871.                 console.log(_this.find(".read-notification").length);
  872.                 if (_this.find(".read-notification").length!==0 && _this.find(".new-content").length===0) {   // button should be 'read' if there's a notification and there's no indication of new chapters (for consistency with readfic pages)
  873.                     _this.find(".new_like_actions").append('<button type="button" class="btn btn-success jsVueComponent read"><svg class="ic_checkbox-checked2"><use href="/assets/icons/icons-sprite20.svg#ic_checkbox-checked2"></use></svg> Прочитано </button>');
  874.                     readButton = _this.find("button.btn-success");
  875.                 } else {
  876.                     _this.find(".new_like_actions").append('<button type="button" class="btn btn-default jsVueComponent notread"><svg class="ic_checkbox-unchecked2"><use href="/assets/icons/icons-sprite20.svg#ic_checkbox-unchecked2"></use></svg> Прочитано </button>');
  877.                     readButton = _this.find("button.btn-default");
  878.                 };
  879.                 readButton.click(function(e){
  880.                     e.preventDefault();
  881.                     if (readButton.hasClass("notread")){
  882.                         fanfiction_net_read(ficId);
  883.                         readButton.removeClass("notread btn-default ");
  884.                         readButton.addClass("read btn-success");
  885.                         readButton.html('<svg class="ic_checkbox-checked2"><use href="/assets/icons/icons-sprite20.svg#ic_checkbox-checked2"></use></svg> Прочитано ');
  886.                     } else {
  887.                         fanfiction_net_unread(ficId);
  888.                         readButton.removeClass("read btn-success");
  889.                         readButton.addClass("notread btn-default ");
  890.                         readButton.html('<svg class="ic_checkbox-unchecked2"><use href="/assets/icons/icons-sprite20.svg#ic_checkbox-unchecked2"></use></svg> Прочитано ');
  891.                     }
  892.                 });
  893.             });
  894.         }
  895. //        */
  896.         // add hotkeys
  897.         if (app.options("enable_list_hotkeys")) {
  898.             document.addEventListener('keydown', function(e){
  899.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  900.                     switch (e.keyCode){
  901.                         case 37:
  902.                             var Prev = ffn$("a[aria-label='Предыдущая']");
  903.                             if (Prev.length>0) Prev[0].click();
  904.                             break;
  905.                         case 39:
  906.                             var Next = ffn$("a[aria-label='Следующая']");
  907.                             if (Next.length>0) Next[0].click();
  908.                             break;
  909.                     }
  910.                 }
  911.             }, false);
  912.         }
  913.  
  914.         // hide/show options
  915.         ffn$('section.content-section').after(
  916.             '<div class="liker_script_options" style="padding:5px; border:1px solid #333399; margin-bottom:5px; background:#D8D8FF;">'+
  917.             '<b>Liker Options:</b> '+
  918.             '</div>'
  919.         );
  920.         break;
  921.     case "author.today":
  922.         //if (window.location.pathname.match("^/work/[0123456789]+$")){
  923.         //    console.log("TRUE");
  924.         //};
  925.         GM_addStyle("* {user-select:text !important;}");
  926.         // adding hotkeys
  927.         // added toggle option, suggested by Vannius
  928.         if (app.options("enable_list_hotkeys")) {
  929.             document.addEventListener('keydown', function(e){
  930.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  931.                     switch (e.keyCode){
  932.                         case 37:
  933.                             var Prev = ffn$("a:contains('« Prev')");
  934.                             if (typeof(Prev[0])!=='undefined') {Prev[0].click();}
  935.                             break;
  936.                         case 39:
  937.                             var Next = ffn$("a:contains('Next »')");
  938.                             if (typeof(Next[0])!=='undefined') {Next[0].click();}
  939.                             break;
  940.                     }
  941.                 }
  942.             }, false);
  943.         }
  944.         if (app.options("enable_read_hotkeys")) {
  945.             document.addEventListener('keydown', function(e){
  946.                 if (!e.ctrlKey && !e.altKey && !e.shiftKey) {
  947.                     switch (e.keyCode){
  948.                         case 37:
  949.                             var Prev = ffn$("button:contains('< Prev')");
  950.                             if (typeof(Prev[0])!=='undefined') {Prev.click();}
  951.                             break;
  952.                         case 39:
  953.                             var Next = ffn$("button:contains('Next >')");
  954.                             if (typeof(Next[0])!=='undefined') {Next.click();}
  955.                             break;
  956.                     }
  957.                 }
  958.             }, false);
  959.         }
  960.         // links on fic page
  961.         if (patharr[1] === "work") {
  962.             ffn$("div.book-row-content").each(function(){
  963.                 var story = new Story({ namespace: app.namespace, instance: this });
  964.                 app.collection.push(story);
  965.             });
  966.             ffn$("div.book-meta-panel").each(function(){
  967.                 var story = new Story({ namespace: app.namespace, instance: this });
  968.                 app.collection.push(story);
  969.             });
  970.         }
  971.         // links on author page
  972.         if (patharr[1] === "u" && patharr[3] === "works") {
  973.             ffn$("div.book-row-content").each(function(){
  974.                 var story = new Story({ namespace: app.namespace, instance: this });
  975.                 app.collection.push(story);
  976.             });
  977.         }
  978.         // Options panel
  979.         ffn$('div#search-results').after(
  980.             '<div class="liker_script_options" style="padding:5px; border:1px solid #333399; margin-bottom:5px; background:#D8D8FF;">'+
  981.             '<b>Liker Options:</b> '+
  982.             '</div>'
  983.         );
  984.         ffn$('div#profile-work-search-results').after(
  985.             '<div class="liker_script_options" style="padding:5px; border:1px solid #333399; margin-bottom:5px; background:#D8D8FF;">'+
  986.             '<b>Liker Options:</b> '+
  987.             '</div>'
  988.         );
  989.         break;
  990.  
  991. }
  992.  
  993. //  OPTIONS
  994. //  -  show/hide global options
  995. //
  996.  
  997. if(app.options("hide_likes")){
  998.     ffn$('.liker_script_options').append('<a href="" class="show_likes" style="color:blue">Mostrar favoritos (fics)</a>');
  999.     ffn$('.liker_script_options .show_likes').click(function(){ show_likes();  });
  1000. } else {
  1001.     ffn$('.liker_script_options').append('<a href="" class="hide_likes" style="color:blue">Ocultar favoritos (fics)</a>');
  1002.     ffn$('.liker_script_options .hide_likes').click(function(){ hide_likes(); });
  1003. }
  1004. ffn$('.liker_script_options').append('| ');
  1005.  
  1006. if(app.options("hide_dislikes")){
  1007.     ffn$('.liker_script_options').append('<a href="" class="show_dislikes" style="color:blue">Mostrar rechazados (todos)</a>');
  1008.     ffn$('.liker_script_options .show_dislikes').click(function(){ show_dislikes();  });
  1009. } else {
  1010.     ffn$('.liker_script_options').append('<a href="" class="hide_dislikes" style="color:blue">Ocultar rechazados (todos)</a>');
  1011.     ffn$('.liker_script_options .hide_dislikes').click(function(){ hide_dislikes(); });
  1012. }
  1013. ffn$('.liker_script_options').append('| ');
  1014.  
  1015. if(app.options("hide_marked")){
  1016.     ffn$('.liker_script_options').append('<a href="" class="show_marked" style="color:blue">Mostrar marcados</a>');
  1017.     ffn$('.liker_script_options .show_marked').click(function(){ show_marked();  });
  1018. } else {
  1019.     ffn$('.liker_script_options').append('<a href="" class="hide_marked" style="color:blue">Ocultar marcados</a>');
  1020.     ffn$('.liker_script_options .hide_marked').click(function(){ hide_marked(); });
  1021. }
  1022. ffn$('.liker_script_options').append('| ');
  1023.  
  1024. if(app.options("hide_inlibrary")){
  1025.     ffn$('.liker_script_options').append('<a href="" class="show_inlibrary" style="color:blue">Mostrar descargados</a>');
  1026.     ffn$('.liker_script_options .show_inlibrary').click(function(){ show_inlibrary(); });
  1027. } else {
  1028.     ffn$('.liker_script_options').append('<a href="" class="hide_inlibrary" style="color:blue">Ocultar descargados</a>');
  1029.     ffn$('.liker_script_options .hide_inlibrary').click(function(){ hide_inlibrary(); });
  1030. }
  1031.  
  1032. // specific links for sites
  1033.  
  1034. // dislike all authors, currently on ffnet only (enter some slash community and blacklist everyone there, saves time when browsing HP fanfics later)
  1035. if (window.location.hostname === "www.fanfiction.net") {
  1036.     ffn$('.liker_script_options').append('| ');
  1037.     ffn$('.liker_script_options').append('<a href="" class="dislike_all" style="color:blue">Rechazar todos lxs autores</a>');
  1038.     ffn$('.liker_script_options .dislike_all').click(function(e){ e.preventDefault(); dislike_all();});
  1039.     if (patharr[1] === "s") {
  1040.         ffn$('.new_like_actions').append('| Actions: <a href="" id="ffn_open_all_chapters" style="color:blue">Abrir todos los capítulos</a>');
  1041.         ffn$('#ffn_open_all_chapters').click(function(e){ e.preventDefault(); fanfiction_net_open_all();});
  1042.     }
  1043. }
  1044.  
  1045. if (window.location.hostname === "ficbook.net") {
  1046. switch(patharr[1]){
  1047.         case "find-fanfics":
  1048.             // revert read status for all visible fics (circumvent ficbook bug where alreadн read fics still appear in search)
  1049.             ffn$('.liker_script_options').append('| Actions: ');
  1050.             ffn$('.liker_script_options').append('<a href="" class="ffn_ficbook_invert_read" style="color:blue">Invertir estatus de leído</a>');
  1051.             ffn$('.liker_script_options .ffn_ficbook_invert_read').click(function(e){ e.preventDefault(); ficbook_invertread(); return false; });
  1052.             break
  1053.         case "readfic":
  1054.             // specific request - download fb2 and like fic in one click
  1055.             ffn$('.new_like_actions').append('| Actions: <a href="" class="ffn_ficbook_fb2_and_like" style="color:blue">FB2+Fav+Leído</a>');
  1056.             ffn$('.new_like_actions .ffn_ficbook_fb2_and_like').click(function(e){ e.preventDefault(); ficbook_fb2andlike(); return false; });
  1057.             ffn$('.new_like_actions').append(' <a href="" id="ficbook_open_all_chapters" style="color:blue">Abrir todo los capítulos</a>');
  1058.             ffn$('#ficbook_open_all_chapters').click(function(e){ e.preventDefault(); ficbooknet_open_all();});
  1059.             break
  1060.     }
  1061.     //
  1062. }
  1063.  
  1064. function ficbook_fb2andlike(){
  1065.     var a= ffn$('a[href^="/fanfic_download/fb2/"]');
  1066.     ffn$('.like_story').click();
  1067.     document.location = a.attr("href");
  1068.     ffn$('.js-mark-readed').not('.btn-success').click();
  1069.     return false;
  1070. }
  1071.  
  1072.  
  1073. ffn$('.liker_script_options').append('| <a href="" id="ffn_OptionsToggle" style="color:blue">Opciones de FFN</a>');
  1074. ffn$('.liker_script_options').after(
  1075.     "<div id='ffn_options_block' style='display:none;'>" +
  1076.     "<input type='checkbox' id='ffn_checkbox_hide_likes'> Ocultar Favs (solo fics, no autores)</br>" +
  1077.     "<input type='checkbox' id='ffn_checkbox_hide_dislikes'> Ocultar Rechazados (fics y autores)</br>" +
  1078.     "<input type='checkbox' id='ffn_checkbox_hide_marked'> Ocultar marcados</br>" +
  1079.     "<input type='checkbox' id='ffn_checkbox_hide_inlibrary'> Ocultar descargados</br>" +
  1080.     "</br>" +
  1081.     "<input type='checkbox' id='ffn_checkbox_enable_list_hotkeys'> Atajos en páginas de navegación: ON (Izquierda/Derecha para siguiente/previo)</br>" +
  1082.     "<input type='checkbox' id='ffn_checkbox_enable_read_hotkeys'> Atajos en páginas de lectura: ON (Izquierda/Derecha para siguiente/previo)</br>" +
  1083.     "</br>" +
  1084.     "<button id='ffn_options_button_save'>Guardar opciones y recargar página</button></br>" +
  1085.     "</br>" +
  1086.     "</br>" +
  1087.     "Exportar datos: <button id='ffn_export_to_file'>Descargar archivo de texto</button></br>" +
  1088.     "Importar datos: <input id='ffn_import_file_box' type='file' accept='text/plain'>" + "<button id='ffn_import_file_button'>Importar</button>" +
  1089.  
  1090. // Old import/export (slow when db is big)
  1091. /*    "<a href='' class='backupToggle' style='color:blue'>Manage Site Data</a>'" +
  1092.     "    <div class='backup_text' style='display:none'>" +
  1093.     "    <table><tr>" +
  1094.     "    <td class='backup_data' valign='top'>" +
  1095.     "       <b>Backup data</b><br />" +
  1096.     "       Copy this text some where safe<br />" +
  1097.     "       <textarea class=''></textarea>" +
  1098.     "    </td>" +
  1099.     "    <td>&nbsp;&nbsp;</td>" +
  1100.     "    <td class='save_new_data' valign='top'>" +
  1101.     "       <b>Upload new Data</b><br>" +
  1102.     "       Upload data you had previously saved<br />" +
  1103.     "       <textarea></textarea><br >" +
  1104.     "       <button class='new_data_save'>save</button>" +
  1105.     "    </td></tr></table>" +
  1106.     "    </div>" +*/
  1107.  
  1108.  
  1109.  
  1110.     "</div>"
  1111.  
  1112. );
  1113.  
  1114. ffn$('#ffn_import_file_button').click(function(){
  1115.     var selectedFile = document.getElementById('ffn_import_file_box').files.item(0);
  1116.     if (selectedFile === null) return;
  1117.     fileToText(selectedFile, (text) => {
  1118.         var new_db;
  1119.         try {
  1120.             new_db = JSON.parse(text);
  1121.         } catch(err) {
  1122.             alert("JSON data in file is invalid");
  1123.             return;
  1124.         }
  1125.         localStorage.setItem("FFLikerAA", JSON.stringify(new_db));
  1126.         document.location = document.location;
  1127.     });
  1128. });
  1129.  
  1130. function fileToText(file, callback) {
  1131.   const reader = new FileReader();
  1132.   reader.readAsText(file);
  1133.   reader.onload = () => {
  1134.     callback(reader.result);
  1135.   };
  1136. }
  1137.  
  1138. ffn$('#ffn_OptionsToggle').click(function(){
  1139.     ffn$("#ffn_options_block").toggle();
  1140.     ffn$("#ffn_checkbox_hide_likes").prop("checked",app.options("hide_likes"));
  1141.     ffn$("#ffn_checkbox_hide_dislikes").prop("checked",app.options("hide_dislikes"));
  1142.     ffn$("#ffn_checkbox_hide_marked").prop("checked",app.options("hide_marked"));
  1143.     ffn$("#ffn_checkbox_hide_inlibrary").prop("checked",app.options("hide_inlibrary"));
  1144.     ffn$("#ffn_checkbox_enable_list_hotkeys").prop("checked",app.options("enable_list_hotkeys"));
  1145.     ffn$("#ffn_checkbox_enable_read_hotkeys").prop("checked",app.options("enable_read_hotkeys"));
  1146.     return false;
  1147. });
  1148. ffn$('#ffn_options_button_save').click(function(){
  1149.     app.options("hide_likes", ffn$("#ffn_checkbox_hide_likes").prop("checked"));
  1150.     app.options("hide_dislikes", ffn$("#ffn_checkbox_hide_dislikes").prop("checked"));
  1151.     app.options("hide_marked", ffn$("#ffn_checkbox_hide_marked").prop("checked"));
  1152.     app.options("hide_inlibrary", ffn$("#ffn_checkbox_hide_inlibrary").prop("checked"));
  1153.     app.options("enable_list_hotkeys", ffn$("#ffn_checkbox_enable_list_hotkeys").prop("checked"));
  1154.     app.options("enable_read_hotkeys", ffn$("#ffn_checkbox_enable_read_hotkeys").prop("checked"));
  1155.     location.reload();
  1156.     return false;
  1157. });
  1158.  
  1159. // import/export db data
  1160.  
  1161. /* old import/export, with textboxes
  1162. ffn$('.backup_text .backup_data textarea').on("click",function(){
  1163.     ffn$(this).select();
  1164. });
  1165.  
  1166. ffn$('.backup_text .save_new_data button').on("click",function(){
  1167.     var v = ffn$('.backup_text .save_new_data textarea').val();
  1168.     var new_db;
  1169.     try {
  1170.         new_db = JSON.parse(v);
  1171.     } catch(err) {
  1172.         alert("that data is not valid");
  1173.         return;
  1174.     }
  1175.     localStorage.setItem("FFLikerAA", JSON.stringify(new_db));
  1176.     document.location = document.location;
  1177. });
  1178.  
  1179. ffn$('.backupToggle').click(function(){
  1180.     ffn$(".backup_text").toggle();
  1181.     ffn$(".backup_text .backup_data textarea").html(JSON.stringify(db));
  1182.     return false;
  1183. });
  1184. */
  1185.  
  1186. //ffn$('.liker_script_options').append('| <a href="" id="testlink" style="color:blue">test' + '</a>');
  1187.  
  1188. ffn$('#ffn_export_to_file').click(function(){
  1189.     var curdate = new Date();
  1190.     var year = curdate.getFullYear();
  1191.     var month = curdate.getMonth() + 1;
  1192.     month = month<10? "0"+month : month;
  1193.     var day = curdate.getDate();
  1194.     day = day<10? "0"+day : day;
  1195.     export_file(JSON.stringify(db,null," "),"FFN_" + window.location.host + "_" + year + "-" + month + "-" + day + ".txt", "text/plain");
  1196.     return false;
  1197. });
  1198.  
  1199. function export_file(content, fileName, mime) {
  1200.     const blob = new Blob([content], {
  1201.       type: mime
  1202.     });
  1203.     const url = URL.createObjectURL(blob);
  1204.     const a = document.createElement("a");
  1205.     a.style = "display: none";
  1206.     a.href = url;
  1207.     a.download = fileName;
  1208.     document.body.appendChild(a);
  1209.     a.click();
  1210.     setTimeout(function(){
  1211.         document.body.removeChild(a);
  1212.         window.URL.revokeObjectURL(url);
  1213.     }, 100);
  1214. }
  1215.  
  1216. function show_dislikes(){
  1217.     app.options("hide_dislikes",false);
  1218.     return false;
  1219. }
  1220.  
  1221. function hide_dislikes(){
  1222.     app.options("hide_dislikes",true);
  1223.     return false;
  1224. }
  1225.  
  1226. function show_likes(){
  1227.     app.options("hide_likes",false);
  1228.     return false;
  1229. }
  1230.  
  1231. function hide_likes(){
  1232.     app.options("hide_likes",true);
  1233.     return false;
  1234. }
  1235.  
  1236. function show_marked(){
  1237.     app.options("hide_marked",false);
  1238.     return false;
  1239. }
  1240.  
  1241. function hide_marked(){
  1242.     app.options("hide_marked",true);
  1243.     return false;
  1244. }
  1245.  
  1246. function show_inlibrary(){
  1247.     app.options("hide_inlibrary",false);
  1248.     return false;
  1249. }
  1250.  
  1251. function hide_inlibrary(){
  1252.     app.options("hide_inlibrary",true);
  1253.     return false;
  1254. }
  1255.  
  1256. function dislike_all(){
  1257.     ffn$("div.z-list:visible").each(function() {
  1258.         var story = new Story({
  1259.             namespace: app.namespace,
  1260.             instance: this
  1261.         });
  1262.         app.collection.push(story);
  1263.         app.author.dislike(story.authorId());
  1264.     });
  1265. }
  1266.  
  1267. function ficbook_invertread(){
  1268.     ffn$("button.btn.btn-primary.btn-success.js-mark-readed:visible").each(function() {
  1269.         this.click();
  1270.     })
  1271.     ffn$("button.btn.btn-primary.btn-default.js-mark-readed:visible").each(function() {
  1272.         this.click();
  1273.     })
  1274. }
  1275.  
  1276. function ficbooknet_open_all(){
  1277.     // get fic id
  1278.     var ficid = patharr[2];
  1279.     // get links to chapters
  1280.     var chapters = ffn$.find("ul.list-of-fanfic-parts > li > a");
  1281.     var chapnum = chapters.length - 1;
  1282.     if (confirm("Are you sure? This will open " + chapnum + " tabs\n(Delay of 2 seconds for each tab)") === true) {
  1283.         for (let i=0; i<chapnum;i++) {
  1284.             setTimeout(function(){
  1285.                 window.open(chapters[i].href,"_blank");
  1286.             },i*2000);
  1287.         }
  1288.     }
  1289.  
  1290. }
  1291.  
  1292.  
  1293.  
  1294. function fanfictionnet_dislike_all(){
  1295.     ffn$("div.z-list:visible").each(function() {
  1296.         var story = new Story({
  1297.             namespace: app.namespace,
  1298.             instance: this
  1299.         });
  1300.         app.collection.push(story);
  1301.         app.author.dislike(story.authorId());
  1302.     });
  1303. }
  1304.  
  1305.  
  1306. function fanfiction_net_open_all(){
  1307.     // get fic id
  1308.     var ficid = patharr[2];
  1309.     // get number of chapters from header
  1310.     var chapnum = ffn$.find("div#profile_top")[0].textContent.match(/.*Chapters: (\d+) - .*/)[1];
  1311.     if (chapnum === null) {
  1312.         console.log("FFN: Could not find chapters count")
  1313.         return false;
  1314.     }
  1315.     chapnum = parseInt(chapnum);
  1316.     if (confirm("Are you sure? This will open " + chapnum + " tabs") === true) {
  1317.         var url;
  1318.         for (let i=1; i < (chapnum+1); i++) {
  1319.             setTimeout(function(){
  1320.                 url = "https://www.fanfiction.net/s/" + ficid + "/" + i + "/";
  1321.                 window.open(url,"_blank");
  1322.             }, i * 500);
  1323.         }
  1324.     }
  1325. }
  1326.  
  1327. function fanfiction_net_read(ff_id){
  1328.     console.log(ff_id);
  1329.     var xhr = new XMLHttpRequest();
  1330.     xhr.open("POST", "https://ficbook.net/fanfic_read/read", true);
  1331.     xhr.setRequestHeader("Content-Type"," application/x-www-form-urlencoded; charset=UTF-8");
  1332.     xhr.send("fanfic_id=" + ff_id);
  1333. }
  1334. function fanfiction_net_unread(ff_id){
  1335.     var xhr = new XMLHttpRequest();
  1336.     xhr.open("POST", "https://ficbook.net/fanfic_read/unread", true);
  1337.     xhr.setRequestHeader("Content-Type"," application/x-www-form-urlencoded; charset=UTF-8");
  1338.     xhr.send("fanfic_id=" + ff_id);
  1339. }
  1340.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement