AO3: Kudosed and seen history

Highlight or hide works you kudosed/marked as seen.

当前为 2015-03-20 提交的版本,查看 最新版本

// ==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	1.3
// @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
// @include     http://archiveofourown.org/*
// @include     https://archiveofourown.org/*
// ==/UserScript==


(function($) {
	
	if (typeof(Storage) !== 'undefined') {
		
		var username = localStorage.getItem('kudoshistory_username');
		
		// if there's no saved username, look for it on the page or ask
		if (!username) {
			var userlink = $('#greeting').find('[href^="/users/"]');
			
			if (userlink.length) {
				var userlink_parts = userlink.attr('href').split('/');
				var username = userlink_parts[2];
				localStorage.setItem('kudoshistory_username', username);
			}
			else {
				var username = prompt('AO3: Kudosed and seen history\n\nYour AO3 username:');
				localStorage.setItem('kudoshistory_username', username);
			}
		}
		
		// check the 'hide seen works' setting
		var hide_seen = 0;
		var hide_seen_set = localStorage.getItem('kudoshistory_hide');
		switch (hide_seen_set) {
			case 'yes':
				hide_seen = 1;
				break;
			case 'collapse':
				hide_seen = 2;
		}
		
		// check the 'mark as seen on open' setting
		var auto_seen = false;
		var auto_seen_set = localStorage.getItem('kudoshistory_autoseen');
		if (auto_seen_set == 'yes') {
			auto_seen = true;
		}
		
		// uncomment the next three 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');

		var list_kudosed = localStorage.getItem('kudoshistory_kudosed');
		var list_checked = localStorage.getItem('kudoshistory_checked');
		var list_seen = localStorage.getItem('kudoshistory_seen');
		
		if (!list_kudosed) { var list_kudosed = ','; }
		if (!list_checked) { var list_checked = ','; }
		if (!list_seen) { var list_seen = ','; }
		
		$(document).ajaxStop(function() {
			localStorage.setItem('kudoshistory_kudosed', list_kudosed);
			localStorage.setItem('kudoshistory_checked', list_checked);
			localStorage.setItem('kudoshistory_seen', list_seen);
		});
		
		// add css rules for kudosed works
		addCss(false);
		
		// if there's a list of works or bookmarks, add menu
		var found_blurbs = $('li.work.blurb').add('li.bookmark.blurb');
		
		if (found_blurbs.length) {
			addSeenMenu();
		}
		
		// for each work blurb
		$('li.work.blurb').not('.deleted').each(function() {
			
			// get work id
			var work_id = $(this).attr('id').replace('work_', '');
			
			blurbCheck(work_id, 'work_' + work_id, $(this));
			
			// double click on date marks work as seen
			var work_date = $(this).not('.marked-seen').not('.has-kudos').find('p.datetime');
			if (work_date.length) {
				work_date.one('dblclick', function() {
					list_seen = localStorage.getItem('kudoshistory_seen');
					list_seen = ',' + work_id + list_seen;
					localStorage.setItem('kudoshistory_seen', list_seen);
					$('#work_' + work_id).addClass('marked-seen');
				});
			}
		});
		
		// for each bookmark blurb
		$('li.bookmark.blurb').not('.deleted').each(function() {
			
			// get bookmark and work ids
			var bookmark_id = $(this).attr('id');
			var work_link = $(this).find('h4 a:first').attr('href');
			
			// if it's not a series bookmark
			if (work_link.indexOf('series') == -1) {
				var work_id = work_link.split('/').pop();
				blurbCheck(work_id, bookmark_id, $(this));
			}
		});
		
		// if it's a work page
		if ($('#workskin').length) {
			
			// get work id
			var url_parts = location.pathname.split('/');
			var work_id = url_parts[url_parts.indexOf('works')+1];
			
			// check if work id is on the seen list
			var is_seen = list_seen.indexOf(',' + work_id + ',');
			
			if (auto_seen) {
				if (is_seen == -1) {
					list_seen = ',' + work_id + list_seen;
					is_seen = 1;
				}
				$('dl.work.meta.group').addClass('marked-seen');
			}
			else if (is_seen > -1) {
				$('dl.work.meta.group').addClass('marked-seen');
			}
			
			addSeenButtons();
			
			// if work id is on the kudosed list
			if (list_kudosed.indexOf(',' + work_id + ',') > -1) {
				$('dl.work.meta.group').addClass('has-kudos');
			}
			else {
				var found_kudos = false;
				
				// check if there are kudos from the user
				var user_kudos = $('#kudos').find('[href="/users/' + username + '"]');
				
				if (user_kudos.length) {
					// highlight blurb and add work id to kudosed list
					list_kudosed = ',' + work_id + list_kudosed;
					list_checked = list_checked.replace(',' + work_id + ',', ',');
					$('dl.work.meta.group').addClass('has-kudos');
					found_kudos = true;
				}
				else if (list_checked.indexOf(',' + work_id + ',') == -1) {
					// add work id to checked list
					list_checked = ',' + work_id + list_checked;
				}
				
				if (!found_kudos) {
					$('#new_kudo').click(function() {
						list_kudosed = localStorage.getItem('kudoshistory_kudosed');
						list_checked = localStorage.getItem('kudoshistory_checked');
						list_kudosed = ',' + work_id + list_kudosed;
						list_checked = list_checked.replace(',' + work_id + ',', ',');
						$('dl.work.meta.group').addClass('has-kudos');
						localStorage.setItem('kudoshistory_kudosed', list_kudosed);
						localStorage.setItem('kudoshistory_checked', list_checked);
					}); 
				}
			}
			
			// check if it's bookmarked
			var bookmark_button_text = $('a.bookmark_form_placement_open:first').text();
			
			if (bookmark_button_text.indexOf('Edit') > -1) {
				// highlight blurb
				$('dl.work.meta.group').addClass('is-bookmarked');
			}
		}
		
		// keep the kudos and checked lists under 200k characters (~25k works)
		if (list_kudosed.length > 200000) {
			list_kudosed = list_kudosed.slice(0,180000);
		}
		if (list_checked.length > 200000) {
			list_checked = list_checked.slice(0,180000);
		}
		
		// keep the seen list under 2mil characters (~250k works)
		if (list_seen.length > 2000000) {
			list_seen = list_seen.slice(0,1900000);
		}
		
		// save all lists
		try {
			localStorage.setItem('kudoshistory_kudosed', list_kudosed);
			localStorage.setItem('kudoshistory_checked', list_checked);
			localStorage.setItem('kudoshistory_seen', list_seen);
		}
		catch(e) {
			list_seen = list_seen.slice(0,list_seen.length*0.9);
			localStorage.setItem('kudoshistory_kudosed', list_kudosed);
			localStorage.setItem('kudoshistory_checked', list_checked);
			localStorage.setItem('kudoshistory_seen', list_seen);
		}
	}
	
	// check if work is on lists
	function blurbCheck(work_id, blurb_id, blurb) {
		
		// if work id is on the kudosed list
		if (list_kudosed.indexOf(',' + work_id + ',') > -1) {
			blurb.addClass('has-kudos');
			list_kudosed = ',' + work_id + list_kudosed.replace(',' + work_id + ',', ',');
		}
		// if work id is on the seen list
		else if (list_seen.indexOf(',' + work_id + ',') > -1) {
			blurb.addClass('marked-seen');
			list_seen = ',' + work_id + list_seen.replace(',' + work_id + ',', ',');
		}
		// if work id is on the checked list
		else if (list_checked.indexOf(',' + work_id + ',') > -1) {
			list_checked = ',' + work_id + list_checked.replace(',' + work_id + ',', ',');
		}
		else {
			// add a div to the blurb that will house the kudos
			blurb.append('<div id="kudos_' + blurb_id + '" style="display: none;"></div>');
			
			// retrieve a list of kudos from the work
			var work_url = 'http://archiveofourown.org/works/' + work_id + '/kudos #kudos';
			$('#kudos_' + blurb_id).load(work_url, function() {
				// check if there are kudos from the user
				var user_kudos = $('#kudos_' + blurb_id).find('[href="/users/' + username + '"]');
				
				if (user_kudos.length) {
					// highlight blurb and add work id to kudosed list
					$('#' + blurb_id).addClass('has-kudos');
					list_kudosed = ',' + work_id + list_kudosed;
				}
				else {
					// add work id to checked list
					list_checked = ',' + work_id + list_checked;
				}
			});
		}
	}
	
	// mark all works on the page as seen
	function markPageSeen() {
		
		list_seen = localStorage.getItem('kudoshistory_seen');
		
		// for each work blurb
		$('li.work.blurb').not('.marked-seen').not('.has-kudos').not('.deleted').each(function() {
			
			var work_id = $(this).attr('id').replace('work_', '');
			
			$(this).addClass('marked-seen');
			list_seen = ',' + work_id + list_seen;
		});
		
		// for each bookmark blurb
		$('li.bookmark.blurb').not('.marked-seen').not('.has-kudos').not('.deleted').each(function() {
			
			var work_link = $(this).find('h4 a:first').attr('href');
			
			// if it's not a series bookmark
			if (work_link.indexOf('series') == -1) {
				var work_id = work_link.split('/').pop();
				$(this).addClass('marked-seen');
				list_seen = ',' + work_id + list_seen;
			}
		});
		
		localStorage.setItem('kudoshistory_seen', list_seen);
	}
	
	// mark all works on the page as unseen
	function markPageUnseen() {
		
		list_seen = localStorage.getItem('kudoshistory_seen');
		
		// for each work blurb
		$('li.work.blurb').not('.deleted').each(function() {
			
			var work_id = $(this).attr('id').replace('work_', '');
			
			$(this).removeClass('marked-seen');
			list_seen = list_seen.replace(',' + work_id + ',', ',');
		});
		
		// for each bookmark blurb
		$('li.bookmark.blurb').not('.deleted').each(function() {
			
			var work_link = $(this).find('h4 a:first').attr('href');
			
			// if it's not a series bookmark
			if (work_link.indexOf('series') == -1) {
				var work_id = work_link.split('/').pop();
				$(this).removeClass('marked-seen');
				list_seen = list_seen.replace(',' + work_id + ',', ',');
			}
		});
		
		localStorage.setItem('kudoshistory_seen', list_seen);
	}
	
	// re-check the page for kudos
	function recheckKudos() {
		
		list_kudosed = localStorage.getItem('kudoshistory_kudosed');
		list_checked = localStorage.getItem('kudoshistory_checked');
		
		// for each non-kudosed work blurb
		$('li.work.blurb').not('.has-kudos').not('.deleted').each(function() {
			
			// get work id
			var work_id = $(this).attr('id').replace('work_', '');
			
			loadKudos(work_id, 'work_' + work_id, $(this));
		});
		
		// for each non-kudosed bookmark blurb
		$('li.bookmark.blurb').not('.has-kudos').not('.deleted').each(function() {
			
			// get bookmark and work ids
			var bookmark_id = $(this).attr('id');
			var work_link = $(this).find('h4 a:first').attr('href');
			
			// if it's not a series bookmark
			if (work_link.indexOf('series') == -1) {
				var work_id = work_link.split('/').pop();
				loadKudos(work_id, bookmark_id, $(this));
			}
		});
		
		function loadKudos(work_id, blurb_id, blurb) {
			// add a div to the blurb that will house the kudos
			blurb.append('<div id="kudos_' + blurb_id + '" style="display: none;"></div>');
			
			// retrieve a list of kudos from the work
			var work_url = 'http://archiveofourown.org/works/' + work_id + '/kudos #kudos';
			$('#kudos_' + blurb_id).load(work_url, function() {
				// check if there are kudos from the user
				var user_kudos = $('#kudos_' + blurb_id).find('[href="/users/' + username + '"]');
				
				if (user_kudos.length) {
					// highlight blurb and add work id to kudosed list
					$('#' + blurb_id).addClass('has-kudos');
					list_kudosed = ',' + work_id + list_kudosed;
					list_checked = list_checked.replace(',' + work_id + ',', ',');
				}
			});
		}
		
		localStorage.setItem('kudoshistory_kudosed', list_kudosed);
		localStorage.setItem('kudoshistory_checked', list_checked);
	}
	
	// check the page for bookmarks
	function checkForBookmarks() {
		
		// for each work and bookmark blurb
		$('li.work.blurb').add('li.bookmark.blurb').not('.deleted').each(function() {
			
			// get work link
			var blurb_id = $(this).attr('id');
			var work_link = $(this).find('h4 a:first').attr('href');
			
			// add a div to the blurb that will house the bookmark button
			$(this).append('<div id="bookmarked_' + blurb_id + '" style="display: none;"></div>');
			
			// retrieve the bookmark button from the work
			var work_url = 'http://archiveofourown.org' + work_link + ' a.bookmark_form_placement_open:first';
			$('#bookmarked_' + blurb_id).load(work_url, function() {
				// check if there is a bookmark from the user
				var bookmark_button_text = $('#bookmarked_' + blurb_id).find('a').text();
				
				if (bookmark_button_text.indexOf('Edit') > -1) {
					// highlight blurb
					$('#' + blurb_id).addClass('is-bookmarked');
				}
			});
		});
	}
	
	// add the seen/unseen buttons
	function addSeenButtons() {
		
		var seen_button1 = $('<li class="mark-seen"></li>').html('<a>Seen &check;</a>');
		var seen_button2 = seen_button1.clone();
		$('ul.actions').on('click', 'li.mark-seen', function() {
			list_seen = localStorage.getItem('kudoshistory_seen');
			list_seen = ',' + work_id + list_seen;
			localStorage.setItem('kudoshistory_seen', list_seen);
			$('dl.work.meta.group').addClass('marked-seen');
			seen_button1.replaceWith(unseen_button1);
			seen_button2.replaceWith(unseen_button2);
		});
		
		var unseen_button1 = $('<li class="mark-unseen"></li>').html('<a>Unseen &cross;</a>');
		var unseen_button2 = unseen_button1.clone();
		$('ul.actions').on('click', 'li.mark-unseen', function() {
			list_seen = localStorage.getItem('kudoshistory_seen');
			list_seen = list_seen.replace(',' + work_id + ',', ',');
			localStorage.setItem('kudoshistory_seen', list_seen);
			$('dl.work.meta.group').removeClass('marked-seen');
			unseen_button1.replaceWith(seen_button1);
			unseen_button2.replaceWith(seen_button2);
		});
		
		if (is_seen == -1) {
			$('li.bookmark').after(seen_button1);
			$('#new_kudo').parent().after(seen_button2);
		}
		else {
			$('li.bookmark').after(unseen_button1);
			$('#new_kudo').parent().after(unseen_button2);
		}
	}
		
	// attach the menu
	function addSeenMenu() {
		
		// get the header menu
		var header_menu = $('ul.primary.navigation.actions');
		
		// create and insert menu button
		var seen_menu = $('<li class="dropdown"></li>').html('<a>Seen works</a>');
		header_menu.find('li.search').before(seen_menu);
		
		// create and append dropdown menu
		var drop_menu = $('<ul class="menu dropdown-menu"></li>');
		seen_menu.append(drop_menu);
		
		// create button - all works
		var button_all_works = $('<li></li>').html('<a style="padding: 0.5em 0.5em 0.25em; text-align: center; font-weight: bold;">&mdash; For all works on this page: &mdash;</a>');
		
		// create button - mark page as seen
		var button_page_seen = $('<li></li>').html('<a>Mark as seen</a>');
		button_page_seen.click(function() {markPageSeen();});
		
		// create button - mark page as unseen
		var button_page_unseen = $('<li></li>').html('<a>Unmark as seen</a>');
		button_page_unseen.click(function() {markPageUnseen();});
		
		// create button - re-check page for kudos
		var button_recheck_kudos = $('<li></li>').html('<a>Re-check for kudos</a>');
		button_recheck_kudos.click(function() {recheckKudos();});
		
		// create button - check page for bookmarks
		var button_check_bookmarks = $('<li></li>').html('<a>Check for bookmarks</a>');
		button_check_bookmarks.click(function() {checkForBookmarks();});
		
		// create button - settings
		var button_settings = $('<li></li>').html('<a style="padding: 0.5em 0.5em 0.25em; text-align: center; font-weight: bold;">&mdash; Settings (click to change): &mdash;</a>');
		
		// create button - don't hide seen works
		var button_hide_no = $('<li class="hide-no"></li>').html('<a>Hide seen works: NO</a>');
		drop_menu.on('click', 'li.hide-no', function() {
			localStorage.setItem('kudoshistory_hide', 'yes');
			hide_seen = 1;
			addCss(true);
			button_hide_no.replaceWith(button_hide_yes);
		});
		
		// create button - hide seen works
		var button_hide_yes = $('<li class="hide-yes"></li>').html('<a>Hide seen works: YES</a>');
		drop_menu.on('click', 'li.hide-yes', function() {
			localStorage.setItem('kudoshistory_hide', 'collapse');
			hide_seen = 2;
			addCss(true);
			button_hide_yes.replaceWith(button_hide_collapse);
		});
		
		// create button - collapse seen works
		var button_hide_collapse = $('<li class="hide-collapse"></li>').html('<a>Hide seen works: COLLAPSE</a>');
		drop_menu.on('click', 'li.hide-collapse', function() {
			localStorage.setItem('kudoshistory_hide', 'no');
			hide_seen = 0;
			addCss(true);
			button_hide_collapse.replaceWith(button_hide_no);
		});
		
		// create button - mark as seen on open
		var button_auto_yes = $('<li class="auto-yes"></li>').html('<a>Mark as seen on open: YES</a>');
		drop_menu.on('click', 'li.auto-yes', function() {
			localStorage.setItem('kudoshistory_autoseen', 'no');
			auto_seen = false;
			button_auto_yes.replaceWith(button_auto_no);
		});
		
		// create button - don't mark as seen on open
		var button_auto_no = $('<li class="auto-no"></li>').html('<a>Mark as seen on open: NO</a>');
		drop_menu.on('click', 'li.auto-no', function() {
			localStorage.setItem('kudoshistory_autoseen', 'yes');
			auto_seen = true;
			button_auto_no.replaceWith(button_auto_yes);
		});
		
		// append buttons to the dropdown menu
		drop_menu.append(button_all_works, button_page_seen, button_page_unseen, button_recheck_kudos, button_check_bookmarks, button_settings);
		
		switch (hide_seen) {
			case 1:
				drop_menu.append(button_hide_yes);
				break;
			case 2:
				drop_menu.append(button_hide_collapse);
				break;
			default:
				drop_menu.append(button_hide_no);
		}
		
		if (auto_seen) {
			drop_menu.append(button_auto_yes);
		}
		else {
			drop_menu.append(button_auto_no);
		}
	}
	
	// add css rules to page head
	function addCss(change) {
		var style = $('style');
		var css_highlight = '.has-kudos,\
			.has-kudos.marked-seen {background: url("http://i.imgur.com/qLvF6Md.png") left no-repeat, url("http://i.imgur.com/qdA6ylN.png") left repeat-y; padding-left: 70px !important;}\
			.marked-seen {background: url("http://i.imgur.com/qdA6ylN.png") left repeat-y; padding-left: 70px !important;}\
			.is-bookmarked {background: url("http://i.imgur.com/PwBH9aC.png") right repeat-y; padding-right: 70px !important;}\
			.has-kudos.is-bookmarked,\
			.has-kudos.marked-seen.is-bookmarked {background: url("http://i.imgur.com/qLvF6Md.png") left no-repeat, url("http://i.imgur.com/qdA6ylN.png") left repeat-y, url("http://i.imgur.com/PwBH9aC.png") right repeat-y;}\
			.marked-seen.is-bookmarked {background: url("http://i.imgur.com/qdA6ylN.png") left repeat-y, url("http://i.imgur.com/PwBH9aC.png") right repeat-y;}';
		var css_hide = 'li.has-kudos,\
			li.marked-seen {display: none !important;}';
		var css_collapse = 'li.has-kudos h6.landmark.heading,\
			li.has-kudos > ul,\
			li.has-kudos blockquote.userstuff.summary,\
			li.has-kudos dl.stats,\
			li.has-kudos .header .fandoms.heading,\
			li.marked-seen h6.landmark.heading,\
			li.marked-seen > ul,\
			li.marked-seen blockquote.userstuff.summary,\
			li.marked-seen dl.stats,\
			li.marked-seen .header .fandoms.heading {display: none !important;}\
			li.has-kudos ul.required-tags,\
			li.marked-seen ul.required-tags {opacity: 0.6;}\
			li.has-kudos ul.required-tags li + li,\
			li.marked-seen ul.required-tags li + li {position: absolute; left: 56px; top: 0px;}\
			li.has-kudos ul.required-tags li + li + li,\
			li.marked-seen ul.required-tags li + li + li {left: 28px;}\
			li.has-kudos ul.required-tags li + li + li + li,\
			li.marked-seen ul.required-tags li + li + li + li {left: 84px; top: 0px;}\
			li.has-kudos .header,\
			li.marked-seen .header {min-height: 27px;}\
			li.has-kudos .header .heading,\
			li.marked-seen .header .heading {margin: 0.375em 5.25em 0px 121px;}';

		if (!style.length) {
			style = $('<style type="text/css"></style>').appendTo($('head'));
		}
		
		if (change) {
			switch (hide_seen) {
				case 1:
					style.append(css_hide);
					break;
				case 2:
					style.html(style.html().replace(css_hide, ''));
					style.append(css_collapse);
					break;
				default:
					style.html(style.html().replace(css_collapse, ''));
			}
		}
		else {
			switch (hide_seen) {
				case 1:
					style.append(css_highlight, css_hide);
					break;
				case 2:
					style.append(css_highlight, css_collapse);
					break;
				default:
					style.append(css_highlight);
			}
		}
	}
})(jQuery);