// ==UserScript== // @name AO3: Kudosed and seen history // @description Highlight or hide works you kudosed/marked as seen. // @namespace https://greasyfork.org/scripts/5835-ao3-kudosed-and-seen-history // @author Min // @version 2.3 // @history 2.3 - checking for kudos in the bg disabled by default, export options // @history 2.2.1 - fix for bookmarked blurbs // @history 2.2 - separate kudosed and seen settings, smaller icons // @history 2.1 - fix for reversi // @history 2.0 - rewrite, click actions for blurbs, new highlighting // @history 1.5 - import/export seen list // @history 1.4 - thinner stripes, remembers bookmarks you left // @history 1.3 - option to collapse blurbs of seen works // @history 1.2.1 - double click on date marks work as seen // @history 1.2 - check for bookmarks you left, changes to the menu // @grant none // @require https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js // @include http://*archiveofourown.org/* // @include https://*archiveofourown.org/* // @downloadURL none // ==/UserScript== (function ($) { var DEBUG = false; // newest more-or-less major version, for the update notice var current_version = '2.03'; var kudos_history = {}, seen_buttons = {}, saved_settings = {}; var main = $('#main'); // check if reversi var body_bg_color = window.getComputedStyle(document.body).backgroundColor; if (body_bg_color == 'rgb(51, 51, 51)') { main.addClass('kh-reversi'); } // uncomment the next five lines if you need to clear your local lists (then comment them again after refreshing the page once) // localStorage.removeItem('kudoshistory_kudosed'); // localStorage.removeItem('kudoshistory_checked'); // localStorage.removeItem('kudoshistory_seen'); // localStorage.removeItem('kudoshistory_bookmarked'); // localStorage.removeItem('kudoshistory_skipped'); var KHList = { init: function init(name, max_length) { this.name = name; this.max_length = max_length || 200000; this.list = localStorage.getItem('kudoshistory_' + this.name) || ','; return this; }, reload: function reload() { this.list = localStorage.getItem('kudoshistory_' + this.name) || this.list; return this; }, save: function save() { try { localStorage.setItem('kudoshistory_' + this.name, this.list.slice(0, this.max_length)); } catch (e) { localStorage.setItem('kudoshistory_' + this.name, this.list.slice(0, this.list.length * 0.9)); } return this; }, hasId: function hasId(work_id) { if (this.list.indexOf(',' + work_id + ',') > -1) { this.list = ',' + work_id + this.list.replace(',' + work_id + ',', ','); return true; } else { return false; } }, add: function add(work_id) { this.list = ',' + work_id + this.list.replace(',' + work_id + ',', ','); return this; }, remove: function remove(work_id) { this.list = this.list.replace(',' + work_id + ',', ','); return this; }, }; var KHSetting = { init: function init(setting) { this.name = setting.name; this.label = setting.label; this.description = setting.description; this.options = setting.options; this.current = saved_settings[this.name] || setting.default_value; return this; }, next: function next() { this.current = this.options[this.options.indexOf(this.current) + 1] || this.options[0]; this.updateButton(); this.save(); addMainClass(true); }, getButton: function getButton() { this.button_link = $('').text(this.label + ': ' + this.current.toUpperCase()).prop('title', this.options.join(' / ').toUpperCase()); this.button = $('
').append(this.button_link); var this_setting = this; this.button.click(function () { this_setting.next(); }); return this.button; }, updateButton: function updateButton() { this.button_link.text(this.label + ': ' + this.current.toUpperCase()); }, changeValue: function changeValue(value) { this.current = value; this.updateButton(); this.updateSettingRow(); this.save(); addMainClass(true); }, getSettingRow: function getSettingRow() { var setting_row_info = $(' '); var setting_row_info_button = $('?'); var setting_row_label = $('' + this.label + ': ').append(setting_row_info_button); this.setting_row_options = $(''); this.setting_row = $('').append(setting_row_label, this.setting_row_options, setting_row_info); this.updateSettingRow(); setting_row_info_button.click(function () { setting_row_info.toggleClass('kh-hide-element'); }); return this.setting_row; }, updateSettingRow: function updateSettingRow() { var this_setting = this; this_setting.setting_row_options.empty(); this.options.forEach(function (option) { var option_link = $(''); option_link.click(function () { this_setting.changeValue(option); }); if (this_setting.current == option) { option_link.html('' + option.toUpperCase() + '').addClass('kh-setting-option-selected'); } else { option_link.text(option.toUpperCase()); } this_setting.setting_row_options.append(' ', option_link, ' •'); }); }, save: function save() { saved_settings[this.name] = this.current; localStorage.setItem('kudoshistory_settings', JSON.stringify(saved_settings)); }, check: function check(compare) { return (this.current === (compare || 'yes')); }, }; var settings_list = [ { name: 'kudosed_display', label: 'Kudosed works', description: 'Hide the works on lists, show the whole blurb, or show just the blurb header.', options: ['hide', 'show', 'collapse'], default_value: 'collapse', }, { name: 'seen_display', label: 'Seen works', description: 'Hide the works on lists, show the whole blurb, or show just the blurb header.', options: ['hide', 'show', 'collapse'], default_value: 'collapse', }, { name: 'skipped_display', label: 'Skipped works', description: 'Hide the works on lists, replace the blurb content with "Skipped", or show just the blurb header.', options: ['hide', 'placeholder', 'collapse'], default_value: 'placeholder', }, { name: 'toggles_display', label: 'Blurb options', description: 'The controls on top right of the blurb that let you mark/unmark the work as seen or skipped from the list.', options: ['hide', 'show', 'on hover'], default_value: 'on hover', }, { name: 'highlight_bookmarked', label: 'Highlight bookmarked', description: 'Show a striped stripe (yeah) on the right for works you\'ve bookmarked.', options: ['yes', 'no'], default_value: 'yes', }, { name: 'highlight_new', label: 'Highlight new', description: 'Show a thin coloured stripe on the left of the blurb for works you\'re seeing for the first time. Only shows on the lists.', options: ['yes', 'no'], default_value: 'yes', }, { name: 'autoseen', label: 'Mark as seen on open', description: 'Automatically mark as seen when you open the work page.', options: ['yes', 'no'], default_value: 'no', }, { name: 'background_check', label: 'Check for kudos while browsing works lists', description: 'The script checks kudos on the works in the background. Warning: This may cause too many requests to AO3 if you browse too quickly, and it\'s not very reliable since AO3 started paginating kudos (so the script may not find yours if it\'s further down the list).', options: ['yes', 'no'], default_value: 'no', }, ]; if (typeof (Storage) !== 'undefined') { saved_settings = JSON.parse(localStorage.getItem('kudoshistory_settings')) || {}; kudos_history = { kudosed: Object.create(KHList).init('kudosed'), checked: Object.create(KHList).init('checked'), seen: Object.create(KHList).init('seen', 2000000), bookmarked: Object.create(KHList).init('bookmarked'), skipped: Object.create(KHList).init('skipped'), username: localStorage.getItem('kudoshistory_username'), saveLists: function () { DEBUG && console.log('saving lists'); this.kudosed.save(); this.checked.save(); this.seen.save(); this.bookmarked.save(); this.skipped.save(); }, }; settings_list.forEach(function (setting) { kudos_history[setting.name] = Object.create(KHSetting).init(setting); }); var userlink = $('#greeting li.dropdown > a[href^="/users/"]'); if (!kudos_history.username) { localStorage.setItem('kudoshistory_lastver', current_version); } // if logged in if (userlink.length) { var found_username = userlink.attr('href').split('/')[2]; DEBUG && console.log('found username: ' + found_username); if (kudos_history.username !== found_username) { kudos_history.username = found_username; localStorage.setItem('kudoshistory_username', kudos_history.username); } } // if not logged in, but remembers username else if (!!kudos_history.username) { DEBUG && console.log("didn't find username on page, saved username: " + kudos_history.username); } else { kudos_history.username = prompt('AO3: Kudosed and seen history\n\nYour AO3 username:'); localStorage.setItem('kudoshistory_username', kudos_history.username); } $(document).ajaxStop(function () { kudos_history.saveLists(); }); // add css rules for kudosed works addCss(); var works_and_bookmarks = $('li.work.blurb, li.bookmark.blurb'); // if there's a list of works or bookmarks if (works_and_bookmarks.length) { addSeenMenu(); var blurb_index = $('.index'); // click on header to collapse/expand blurb_index.on('click', '.header', function (e) { if (!$(e.target).is('a') && !$(e.target).is('span')) { $(this).closest('.blurb').toggleClass('collapsed-blurb'); e.stopPropagation(); } }); // toggle seen/skipped blurb_index.on('click', '.kh-toggle', function (e) { changeBlurbStatus($(this).closest('.blurb'), $(this).data('list'), true); e.stopPropagation(); }); // click on delete bookmark blurb_index.on('click', '.own.user a[data-method="delete"]', function () { var work_id = $(this).closest('.blurb').data('work_id'); if (work_id) { kudos_history.bookmarked.reload().remove(work_id).save(); } }); // for each work and bookmark blurb works_and_bookmarks.not('.deleted').each(function () { blurbCheck($(this)); }); } // if it's the first time after an update addNotice(); // if it's a work page if ($('#workskin').length) { var work_meta = $('dl.work.meta.group'); // get work id var work_id = $('#kudo_commentable_id').val(); DEBUG && console.log('work_id ' + work_id); if (kudos_history.autoseen.check()) { kudos_history.seen.add(work_id); } // check if work id is on the seen list var is_seen = kudos_history.seen.hasId(work_id); if (is_seen) { work_meta.addClass('marked-seen'); } addSeenButtons(); // if work id is on the kudosed list if (kudos_history.kudosed.hasId(work_id)) { work_meta.addClass('has-kudos'); DEBUG && console.log('- on kudosed list'); } else { // check if there are kudos from the user var user_kudos = $('#kudos').find('[href="/users/' + kudos_history.username + '"]'); if (user_kudos.length) { // highlight blurb and add work id to kudosed list kudos_history.kudosed.add(work_id); kudos_history.checked.remove(work_id); work_meta.addClass('has-kudos'); } else { // add work id to checked list kudos_history.checked.add(work_id); $('#new_kudo').one('click', function () { kudos_history.kudosed.reload().add(work_id).save(); kudos_history.checked.reload().remove(work_id).save(); work_meta.addClass('has-kudos'); }); } } // check if it's bookmarked var bookmark_button_text = $('a.bookmark_form_placement_open').filter(':first').text(); if (bookmark_button_text.indexOf('Edit') > -1) { // highlight blurb kudos_history.bookmarked.add(work_id); work_meta.addClass('is-bookmarked'); } else { kudos_history.bookmarked.remove(work_id); } } // save all lists kudos_history.saveLists(); } // check if work is on lists function blurbCheck(blurb) { var work_id; var blurb_id = blurb.attr('id'); if (blurb.hasClass('work')) { work_id = blurb_id.replace('work_', ''); } else if (blurb.hasClass('bookmark')) { var work_link = blurb.find('h4 a:first').attr('href'); // if it's not a deleted work and not a series or external bookmark if (!!work_link && work_link.indexOf('series') === -1 && work_link.indexOf('external_work') === -1) { work_id = work_link.split('/').pop(); // if it's your own bookmark var own_bookmark = blurb.find('div.own.user.module.group'); if (own_bookmark.length) { kudos_history.bookmarked.add(work_id); } } } blurb.data('work_id', work_id); DEBUG && console.log('blurb check ' + blurb_id + ', work_id: ' + work_id); if (!work_id) { return false; } var found_on_list = false; var blurb_classes = 'blurb-with-toggles'; blurb.prepend('