E-H Visited

Marks visited galleries.

目前為 2019-04-04 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name           E-H Visited
// @description    Marks visited galleries.
// @author         Hen Tie
// @homepage       https://hen-tie.tumblr.com/
// @namespace      https://greasyfork.org/en/users/8336
// @include        /https?:\/\/(e-|ex)hentai\.org\/.*/
// @require        https://code.jquery.com/jquery-3.3.1.min.js
// @grant          GM_setValue
// @grant          GM_getValue
// @icon           https://i.imgur.com/pMMVGRx.png
// @version        3.2
// ==/UserScript==
// 2019 fork of exvisited (sleazyfork.org/en/scripts/22270)
// bug reports: greasyfork.org/en/forum/post/discussion?script=377945

/*═════════════════════════╦═════════════════════════════╦════════════════════════╗
║          IMPORT          ║           EXPORT            ║          CSS           ║
╠══════════════════════════╬═════════════════════════════╬════════════════════════╣
║ data format is unchanged ║ localstorage is impermanent ║ you can set custom css ║
║ should import from any   ║ but exporting is simple     ║ for marking viewed     ║
║ old exvisited scripts    ║ one click gives plain text  ║ galleries              ║
╚══════════════════════════╩═════════════════════════════╩═══════════════════════*/

var storageName = "ehVisited"; //name of object, to avoid clash with old installs
var url = document.URL;
var sto = localStorage.getItem(storageName) ? localStorage.getItem(storageName) : '{"data":{}}';
var vis = JSON.parse(sto);
var spl = url.split("/");
var d1 = spl[3]
var d2 = spl[4];
var d3 = spl[5];
var css = GM_getValue("css") ? GM_getValue("css") : "background:rgba(2, 129, 255, .2) !important"; //default highlight colour

if (css === "initial") {
	css = "background:rgba(2, 129, 255, .2) !important";
} else if (css === "none") {
	css = "";
}

vis.data = !vis.data ? Array() : vis.data;

if (typeof (Storage) == "undefined") {
	alert("E-H Visited:\nYour browser does not support localStorage :(");
}

// date.now shim (probably unnecessary)
if (!Date.now) {
	Date.now = function () {
		return new Date().getTime();
	};
}

Number.prototype.pad0 = function (length) {
	var result = this.toString();
	while (result.length < length) result = "0" + result;
	return result;
}

Object.size = function (obj) {
	var size = 0,
		key;
	for (key in obj) {
		if (obj.hasOwnProperty(key)) size++;
	}
	return size;
};

function timeDifference(current, previous, abbreviate) {
	var msPerMinute = 60 * 1000;
	var msPerHour = msPerMinute * 60;
	var msPerDay = msPerHour * 24;
	var msPerMonth = msPerDay * 30;
	var msPerYear = msPerDay * 365;
	var elapsed = current - previous;

	if (elapsed < msPerMinute) {
		return Math.round(elapsed / 1000) + ((typeof abbreviate !== 'undefined') ? '&nbsp;sec' : ' seconds ago');
	} else if (elapsed < msPerHour) {
		return Math.round(elapsed / msPerMinute) + ((typeof abbreviate !== 'undefined') ? '&nbsp;min' : ' minutes ago');
	} else if (elapsed < msPerDay) {
		return Math.round(elapsed / msPerHour) + ((typeof abbreviate !== 'undefined') ? '&nbsp;hrs' : ' hours ago');
	} else if (elapsed < msPerMonth) {
		return Math.round(elapsed / msPerDay) + ((typeof abbreviate !== 'undefined') ? '&nbsp;days' : ' days ago');
	} else if (elapsed < msPerYear) {
		return Math.round(elapsed / msPerMonth) + ((typeof abbreviate !== 'undefined') ? '&nbsp;mos' : ' months ago');
	} else {
		return Math.round(elapsed / msPerYear) + ((typeof abbreviate !== 'undefined') ? '&nbsp;yrs' : ' years ago');
	}
}

function ehvTimestamp() {
	var list = $("table.itg>tbody>tr"); //present only in list views
	var thumb = $(".itg .gl1t"); //present only in thumbnail view
	var gid;
	var d;
	var galleryId;

	// check current view
	if (list.length > 0) {
		if ($('.gl1e').length) { //extended
			for (i = 0; i < list.length; i++) {
				gid = $(list[i]).find(".gl1e a").attr("href").split("/");
				galleryId = gid[4] + "." + gid[5];
				if (vis.data[galleryId] != undefined) {
					d = new Date(vis.data[galleryId]);
					$(list[i]).addClass("ehv-visited");
					//check for fav pages
					if ($(list[i]).find('.gl3e').children('div').length >= 7) { //date favourited div is present
						$(list[i]).find('.gl3e > div:last-child').append("<br><ehv class='ehv-extended-favs'>&#128065;" + timeDifference(Date.now(), vis.data[galleryId]) + "<br>" + d.getFullYear().toString() + "&#8209;" + (d.getMonth() + 1) + "&#8209;" + d.getDate() + " (" + d.getHours().pad0(2) + ":" + d.getMinutes().pad0(2) + ")</ehv>");
					} else {
						//empty div avoids nth-child styles meant for date favourited
						$(list[i]).find('.gl3e').append("<div></div><ehv class='ehv-extended'>&#128065;" + timeDifference(Date.now(), vis.data[galleryId]) + "<br>" + d.getFullYear().toString() + "&#8209;" + (d.getMonth() + 1) + "&#8209;" + d.getDate() + " (" + d.getHours().pad0(2) + ":" + d.getMinutes().pad0(2) + ")</ehv>");
					}
				}
			}
		} else if ($('.gl1c').length) { //compact
			var borderColour = $('.gl1c').first().css('border-top-color'); //border colour different between domains
			$('table.itg tbody>tr:first-child th:nth-child(2)').after('<th>Visited</th>');
			for (i = 1; i < list.length; i++) {
				gid = $(list[i]).find(".glname a").attr("href").split("/");
				galleryId = gid[4] + "." + gid[5];
				if (vis.data[galleryId] != undefined) {
					d = new Date(vis.data[galleryId]);
					$(list[i]).addClass("ehv-visited");
					$(list[i]).children('.gl2c').after('<td class="ehv-compact" style="border-color:' + borderColour + ';"><ehv>' + timeDifference(Date.now(), vis.data[galleryId], true) + "<br>(" + d.getHours().pad0(2) + ":" + d.getMinutes().pad0(2) + ')<br>' + d.getFullYear().toString().substr(2) + "&#8209;" + (d.getMonth() + 1) + "&#8209;" + d.getDate() + '</ehv></td>');
				} else {
					$(list[i]).children('.gl2c').after('<td class="ehv-compact" style="border-color:' + borderColour + ';"></td>');
				}
			}
		} else { //minimal
			$('table.itg tbody>tr:first-child th:nth-child(2)').after('<th title="E-H Visited: Hover for timestamps">&#128065;</th>');
			for (i = 1; i < list.length; i++) {
				gid = $(list[i]).find(".glname a").attr("href").split("/");
				galleryId = gid[4] + "." + gid[5];
				if (vis.data[galleryId] != undefined) {
					d = new Date(vis.data[galleryId]);
					$(list[i]).addClass("ehv-visited");
					$(list[i]).children('.gl2m').after('<td class="ehv-minimal" title="E-H Visited: ' + timeDifference(Date.now(), vis.data[galleryId]) + " (" + d.getHours().pad0(2) + ":" + d.getMinutes().pad0(2) + ") " + d.getFullYear().toString() + "&#8209;" + (d.getMonth() + 1) + "&#8209;" + d.getDate() + '">&#128065;</td>');
				} else {
					$(list[i]).children('.gl2m').after('<td class="ehv-minimal"></td>');
				}
			}
		}
	} else if (thumb.length > 0) { //thumbnail
		for (var i = 0; i < thumb.length; i++) {
			gid = $(thumb[i]).find(".gl3t a").attr("href").split("/");
			galleryId = gid[4] + "." + gid[5];
			if (vis.data[galleryId] != undefined) {
				d = new Date(vis.data[galleryId]);
				$(thumb[i]).addClass("ehv-visited");
				$(thumb[i]).children('.gl5t').after("<ehv class='ehv-thumbnail'>&#128065;" + timeDifference(Date.now(), vis.data[galleryId]) + " (" + d.getHours().pad0(2) + ":" + d.getMinutes().pad0(2) + ") " + d.getFullYear().toString() + "&#8209;" + (d.getMonth() + 1) + "&#8209;" + d.getDate() + "</ehv>");
			}
		}
	} else {
		console.log("E-H Visited:\n	Something is wrong, I don't know what view mode this is!\n	Bug reports: greasyfork.org/en/forum/post/discussion?script=377945");
	}
}

//script body
$(function () {

	$('a').bind('mouseup', function () {
		var spl = this.href.split("/");
		var d1 = spl[3]
		var d2 = spl[4];
		var d3 = spl[5];

		if (d1 == "g") {
			var c = d2 + "." + d3;
			vis.data[c] = Date.now();
			localStorage.setItem(storageName, JSON.stringify(vis));
		}
	});

	if (d1.substr(0, 1) == "?" || d1.substr(0, 1) == "#" || d1.substr(0, 1) == "f" || d1.substr(0, 1) == "t" || !d1) {
		var len = Object.size(vis.data);
		$("#toppane").append("<ehv class='ehv-controls'>Galleries visited: " + len + " (<a href='javascript:;' class='ehv-import'>Import</a> / <a href='javascript:;' class='ehv-export'>Export</a> / <a href='javascript:;' class='ehv-css'>CSS</a>)</ehv>");

		$(".ehv-export").click(function () {
			var e = "";
			for (var d in vis.data) {
				e += d + ":" + vis.data[d] + ";";
			}
			prompt("E-H Visited:\nYour data has been exported.", e);
		});

		$(".ehv-import").click(function () {
			var c = prompt("E-H Visited:\nPaste here to import, and overwrite current data.");
			if (c) {
				var d = JSON.parse('{"data":{}}');
				var sp = c.split(";");
				for (var k in sp) {
					var s = sp[k].split(":");
					d.data[s[0]] = parseInt(s[1]);
				}

				alert("Imported " + Object.size(d.data) + " entries.");
				localStorage.setItem(storageName, JSON.stringify(d))
				location.reload();

			}
		});

		$(".ehv-css").click(function () {
			var c = prompt("E-H Visited:\nThis CSS is applied to visited galleries.\n('initial' to reset, or 'none' for no styling)", css);
			if (c) {
				GM_setValue("css", c);
				location.reload();
			}
		});

		ehvTimestamp();

		$("<style data-jqstyle='ehVisited'>.gl2c{width:115px;}.gl3e>div:nth-child(6){left:unset;width:100%;text-align:center;}" + //overrides
			".ehv-compact{border-style:solid;border-width:1px 0;text-align:center;}" +
			".ehv-extended{width:120px;position:absolute;left:3px;top:180px;text-align:center;font-size:8pt;line-height:1.5;}" +
			".ehv-extended-favs{padding:3px 1px;display:block;line-height:1.5;}" +
			".ehv-thumbnail{display:block;text-align:center;margin:3px 0 5px;line-height:12px;}" +
			".ehv-controls{text-align:center;display:block;}" +
			"table.itg>tbody>tr.ehv-visited, .gl1t.ehv-visited{" + css + "}" +
			"</style>").appendTo("head");
	}
});