您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Replace hitcount with kudos/average hits per chapter percentage. Sort works on the page by this ratio.
// ==UserScript== // @name AO3: Kudos/average hits per chapter ratio // @description Replace hitcount with kudos/average hits per chapter percentage. Sort works on the page by this ratio. // @namespace https://greasyfork.org/en/scripts/39361-ao3-kudos-average-hits-per-chapter-ratio // @author Min, with updates by ObliqueRed // @version 1.0 // @history 1.0 - Customization of the script AO3: Kudos/hits ratio by Min, version 1.4. Changes percentages to use periods instead of commas (12.3% instead of 12,3%). Changes how percentages are calculated to better reflect multi-chapter stories. // @grant none // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js // @include http://archiveofourown.org/* // @include https://archiveofourown.org/* // ==/UserScript== // Notes: This is a customization of Min's AO3: Kudos/hits ratio. The original script expresses the ratio of kudos to total hits on a work. This version expresses the ratio of kudos to the average number of hits per chapter. // New or altered portions of Min's original code are commented. // Reasoning: Each reader of a multi-chaptered story will generate at least one hit per chapter of the story, but can only leave kudos once (or twice if they leave both a guest kudo and a logged in kudo.) // Because of this, the original version artificially deflated the ratio for multi-chaptered stories, making them seem to be less liked by their readers than they really are. This altered version divides the number of hits on the work // by the number of chapters to arrive at an average hits per chapter number, and displays the ratio of kudos to that. This gives a rough approximation of "kudos per reader." // Caveats: Every hit on a work is not a unique reader. Hits can be produced by bots, downloaders, and reloads as well as readers. Therefore, this is only a rough approximation. However, this variant will hopefully give a more apples-to-apples comparison // between one-shot and multi-chapter stories, since multi-chapter stories will have significantly more hits as readers click through. However, this script may still underestimate the popularity of stories that are re-read many times, because those // re-reads will gradually keep increasing the hit count without increasing the kudos (since readers can't leave a kudo every time they read a story.) // ~~ SETTINGS ~~ // // count kudos/hits automatically: true/false var always_count = true; // sort works on this page by kudos/hits ratio in descending order automatically: true/false var always_sort = false; // hide hitcount: true/false var hide_hitcount = false; // colour background depending on percentage: true/false var colourbg = true; // lvl1 & lvl2 - percentage levels separating red, yellow and green background; ratio_red, ratio_yellow, ratio_green - background colours var ratio_red = '#ffdede'; var lvl1 = 4; var ratio_yellow = '#fdf2a3'; var lvl2 = 7; var ratio_green = '#c4eac3'; // ~~ END OF SETTINGS ~~ // // STUFF HAPPENS BELOW // (function($) { // check user settings if (typeof(Storage) !== 'undefined') { var always_count_set = localStorage.getItem('alwayscountlocal'); var always_sort_set = localStorage.getItem('alwayssortlocal'); var hide_hitcount_set = localStorage.getItem('hidehitcountlocal'); if (always_count_set == 'no') { always_count = false; } if (always_sort_set == 'yes') { always_sort = true; } if (hide_hitcount_set == 'no') { hide_hitcount = false; } } // set defaults for countableness and sortableness var countable = false; var sortable = false; var stats_page = false; // check if it's a list of works or bookmarks, or header on work page, and attach the menu checkCountable(); // if set to automatic if (always_count) { countRatio(); if (always_sort) { sortByRatio(); } } // check if it's a list of works/bookmarks/statistics, or header on work page function checkCountable() { var found_stats = $('dl.stats'); if (found_stats.length) { if (found_stats.closest('li').is('.work') || found_stats.closest('li').is('.bookmark')) { countable = true; sortable = true; addRatioMenu(); } else if (found_stats.parents('.statistics').length) { countable = true; sortable = true; stats_page = true; addRatioMenu(); } else if (found_stats.parents('dl.work').length) { countable = true; addRatioMenu(); } } } function countRatio() { if (countable) { $('dl.stats').each(function() { var hits_value = $(this).find('dd.hits'); var kudos_value = $(this).find('dd.kudos'); // new: gets the chapter count in the format x/y, where x is a number and y is either a number or a ? var chapters_value = $(this).find('dd.chapters'); var chapters_value_string = chapters_value.text(); // new: extracts the current number of chapters in the work - x - from the chapter count // where in the string is the / character? var position_of_slash = chapters_value_string.indexOf('/'); // slice off the part of the string before the / - this is the current number of chapters var current_chapter_value = chapters_value_string.slice(0, position_of_slash); // if hits and kudos were found if (kudos_value.length && hits_value.length && hits_value.text() !== '0') { // get counts var hits_count = parseInt(hits_value.text()); var kudos_count = parseInt(kudos_value.text()); // new: turns the string into a number var chapters_count = parseInt(current_chapter_value); //altered: calculate hits per chapter var hits_per_chapter = hits_count/chapters_count; // count percentage of kudos to hits per chapter var percents = kudos_count/hits_per_chapter*100; // get percentage with one decimal point var percents_print = percents.toFixed(1); // If you want a comma instead of a period in your percents (12,4% instead of 12.4%) use this line instead of the previous one // var percents_print = percents.toFixed(1).replace('.',','); // add ratio stats var ratio_label = $('<dt class="kudoshits"></dt>').text('Kudos/Hits:'); var ratio_value = $('<dd class="kudoshits"></dd>').text(percents_print + '%'); hits_value.after('\n', ratio_label, '\n', ratio_value); if (colourbg) { // colour background depending on percentage if (percents >= lvl2) { ratio_value.css('background-color', ratio_green); } else if (percents >= lvl1) { ratio_value.css('background-color', ratio_yellow); } else { ratio_value.css('background-color', ratio_red); } } if (hide_hitcount && !stats_page) { // hide hitcount label and value $(this).find('.hits').css('display', 'none'); } // add attribute to the blurb for sorting $(this).closest('li').attr('kudospercent', percents); } else { // add attribute to the blurb for sorting $(this).closest('li').attr('kudospercent', 0); } }); } } function sortByRatio(ascending) { if (sortable) { var sortable_lists = $('dl.stats').closest('li').parent(); sortable_lists.each(function() { var list_elements = $(this).children('li'); // sort by kudos/hits ratio in descending order list_elements.sort(function(a, b) { return parseFloat(b.getAttribute('kudospercent')) - parseFloat(a.getAttribute('kudospercent')); }); if (ascending) { $(list_elements.get().reverse()).detach().appendTo($(this)); } else { list_elements.detach().appendTo($(this)); } }); } } // attach the menu function addRatioMenu() { // get the header menu var header_menu = $('ul.primary.navigation.actions'); // create and insert menu button var ratio_menu = $('<li class="dropdown"></li>').html('<a>Kudos/hits</a>'); header_menu.find('li.search').before(ratio_menu); // create and append dropdown menu var drop_menu = $('<ul class="menu dropdown-menu"></li>'); ratio_menu.append(drop_menu); // create button - count var button_count = $('<li></li>').html('<a>Count on this page</a>'); button_count.click(function() {countRatio();}); // create button - sort var button_sort = $('<li></li>').html('<a>Sort on this page</a>'); button_sort.click(function() {sortByRatio();}); // create button - settings var button_settings = $('<li></li>').html('<a style="padding: 0.5em 0.5em 0.25em; text-align: center; font-weight: bold;">— Settings (click to change): —</a>'); // create button - always count var button_count_yes = $('<li class="count-yes"></li>').html('<a>Count automatically: YES</a>'); drop_menu.on('click', 'li.count-yes', function() { localStorage.setItem('alwayscountlocal', 'no'); button_count_yes.replaceWith(button_count_no); }); // create button - not always count var button_count_no = $('<li class="count-no"></li>').html('<a>Count automatically: NO</a>'); drop_menu.on('click', 'li.count-no', function() { localStorage.setItem('alwayscountlocal', 'yes'); button_count_no.replaceWith(button_count_yes); }); // create button - always sort var button_sort_yes = $('<li class="sort-yes"></li>').html('<a>Sort automatically: YES</a>'); drop_menu.on('click', 'li.sort-yes', function() { localStorage.setItem('alwayssortlocal', 'no'); button_sort_yes.replaceWith(button_sort_no); }); // create button - not always sort var button_sort_no = $('<li class="sort-no"></li>').html('<a>Sort automatically: NO</a>'); drop_menu.on('click', 'li.sort-no', function() { localStorage.setItem('alwayssortlocal', 'yes'); button_sort_no.replaceWith(button_sort_yes); }); // create button - hide hitcount var button_hide_yes = $('<li class="hide-yes"></li>').html('<a>Hide hitcount: YES</a>'); drop_menu.on('click', 'li.hide-yes', function() { localStorage.setItem('hidehitcountlocal', 'no'); $('.stats .hits').css('display', ''); button_hide_yes.replaceWith(button_hide_no); }); // create button - don't hide hitcount var button_hide_no = $('<li class="hide-no"></li>').html('<a>Hide hitcount: NO</a>'); drop_menu.on('click', 'li.hide-no', function() { localStorage.setItem('hidehitcountlocal', 'yes'); $('.stats .hits').css('display', 'none'); button_hide_no.replaceWith(button_hide_yes); }); // append buttons to the dropdown menu drop_menu.append(button_count); if (sortable) { drop_menu.append(button_sort); } if (typeof(Storage) !== 'undefined') { drop_menu.append(button_settings); if (always_count) { drop_menu.append(button_count_yes); } else { drop_menu.append(button_count_no); } if (always_sort) { drop_menu.append(button_sort_yes); } else { drop_menu.append(button_sort_no); } if (hide_hitcount) { drop_menu.append(button_hide_yes); } else { drop_menu.append(button_hide_no); } } // add button for statistics if ($('#main').is('.stats-index')) { var button_sort_stats = $('<li></li>').html('<a>↓ Kudos/hits</a>'); button_sort_stats.click(function() { sortByRatio(); button_sort_stats.after(button_sort_stats_asc).detach(); }); var button_sort_stats_asc = $('<li></li>').html('<a>↑ Kudos/hits</a>'); button_sort_stats_asc.click(function() { sortByRatio(true); button_sort_stats_asc.after(button_sort_stats).detach(); }); $('ul.sorting.actions li:nth-child(3)').after('\n', button_sort_stats); } } })(jQuery);