FB: Post Tools & Statistics

Shows exact timestamps and post information on Facebook Posts.

当前为 2019-08-10 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name     FB: Post Tools & Statistics
// @match    https://www.facebook.com/*
// @match    https://*.facebook.com/*
// @match    http://www.facebook.com/*
// @match    http://*.facebook.com/*
// @run-at   document-start
// @grant    GM_addStyle
// @author   JZersche & wOxxOm
// @require  https://greasyfork.org/scripts/12228/code/setMutationHandler.js
// @  require  https://momentjs.com/downloads/moment.min.js
// @  require  https://momentjs.com/downloads/moment-with-locales.min.js
// @  require  https://html2canvas.hertzen.com/dist/html2canvas.js
// @version 1.08 BETA
// @namespace https://greasyfork.org/users/95175
// @description Shows exact timestamps and post information on Facebook Posts.
// ==/UserScript==

var options = {
	weekday: 'long',
	year: 'numeric',
	month: 'numeric',
	day: '2-digit'
};
GM_addStyle('.h_1zif-zjsf {color: red;}' + '.full-timestamp { opacity: 0.95; color: #f00!important; }' + '.full-timestamp:hover { opacity: 1.0; }' + '.full-timestamp:before { content: ""; }' + '.full-timestamp:after  { content: ""; }' + '.timestampContent { display: none; }' + '._5ptz.timestamp.livetimestamp .timestampContent { display: inline-block; }' + '._5pcp._5lel._2jyu._232_ {line-height: 16px;font-size:9px;}' /* Status Information Spacing */ + '.sponsored { color: #06b;}' + '.copybtnP { margin-bottom: 8px }' + '.copybtnP, .s2img {display: inline-block;}' + '._3ds9 {border: 1px dashed #385898 !important; border-radius: 1px; padding-bottom: 0px !important; margin-bottom: 8px !important; background: #38589811;}' + '.copybtn, .copybtnP, .s2img { border: 1px solid #e2e4e5; background: #fff; color: #365899; border-radius: 8px; letter-spacing: 0.05px;font-weight: 700;height: 23px;}' + '.canvasArea {height: 23px;overflow: hidden;color: #c1c1c1;word-break: break-all;display: block;font-size: 10px;letter-spacing: -0.70px;font-family: "Segoe UI" !important;line-height: 11px;text-align: justify;margin-top: 5px;margin-bottom: 1px;background: #00000010;border-radius: 10px;border: 1px dashed #c1c1c1;margin-top: 5px;padding-bottom: 0px;padding-left: 1px;padding-right: 1px;}' + 'span.SaveAsImageFile a { border:0px solid red; position:relative; font-weight:600; color:#aaa;font-family: \'Segoe UI\';font-variant-caps: all-small-caps;}' + 'div._3ekx._29_4 div._6m3._--6 div._59tj._2iau { top: 7px !important;position: relative;}' + 'span.externalURLs { position: absolute;color: #606770;padding-left: 2px;display: inline-block;top: 4px;width: 489px;font-size: 10px;border-radius: 3px;background: #f2f3f5;left: 3px;white-space: pre;text-overflow: ellipsis;overflow: hidden;border: 1px dashed #bec3c9;}' + 'span.ViewImage { color: #888 !important; font-family: \'Segoe UI\';font-variant-caps: all-small-caps;}' + 'span.ViewImage a { color: #888 !important; font-family: \'Segoe UI\';font-variant-caps: all-small-caps;}');
// process the already loaded portion of the page if any
expandDates(document.querySelectorAll('abbr[data-utime]'));
RecentTimestamps(document.querySelectorAll('.q_1zif-zjsq'));
RecentPostURLs(document.querySelectorAll('.q_1zif-zjsq, ._5r69, ._6ks'));
ExternalURLs(document.querySelectorAll('._52c6'));
expandPostIDs(document.querySelectorAll('._5pcq'));
document.querySelectorAll('.hasCaption');
// process the stuff added from now on
setMutationHandler(document, 'abbr[data-utime]', expandDates);
setMutationHandler(document, '.q_1zif-zjsq', RecentTimestamps);
setMutationHandler(document, '.q_1zif-zjsq, ._5r69, ._6ks', RecentPostURLs);
setMutationHandler(document, '._52c6', ExternalURLs);
setMutationHandler(document, '._5pcq', expandPostIDs);
/*
html2canvas(document.querySelector('._3576')).then(canvas => {
    document.getElementsByClassName('s2img')[0].addEventListener('click', function(event) {node.insertAdjacentHTML('afterend', canvas.toDataURL());})
});
*/
setMutationHandler({
	target: document.querySelector('._3576'),
	selector: '.s2img',
	handler: nodes => nodes.forEach(node => {
		node.setAttribute("style", "color: red; border: 1px solid red;");

		node.addEventListener('click', function (event) {
			//node.closest('._5pcp._5lel').setAttribute("style", "font-size: 7px;line-height: 16px;");
			node.setAttribute("style", "color: #5550; border: 1px solid #0000; display:none;");
			node.nextSibling.setAttribute("style", "color: #00ff; border: 1px solid #00ff; display:inline-block;");
			var PageTitleColorPROMPT = '#fff';
            //console.log(event.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.className);
            //event.target.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.setAttribute("style", "background:#222;");
			//var PageTitleColorPROMPT = prompt('Enter the HTML Hex Color # the Page Title should be:','#fff');
			/* Name of Page Color Change on Click */
			/* Likes Information (Hide/Show) */
			var classCheck0 = event.target.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.children;
            var classCheck1 = event.target.parentNode.children;
            var classCheck2 = event.target.parentNode;


			if (classCheck0.length >= 0 && window.location.href.match(/(facebook\.com\/(\D+|\D+\d+)\/posts\/\d+|(https:\/\/www\.facebook\.com\/(\w+)\/posts\/\d+\?))/)) {
				console.log('URL is supported 0 by script. 1.04 Version. OK :) :: ' + window.location.href);
            event.target.parentNode.setAttribute("style", "background:#222;");
			node.nextSibling.setAttribute("style", "color: #f55f; font-weight:600;float:right; border: 1px solid #00f0; background:#2220; display:inline-block;"); /* Change Copy Text button to Copy Base64 */
			node.nextSibling.value = 'Copy Base64';
            event.target.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.setAttribute("style", "color: #fff; background: #222; display:block; border:0px solid #222!important;");
			event.target.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.parentNode.setAttribute("style", "color: #fff; background: #222; display:block; border:0px solid #222!important;");
			event.target.closest('._1dwg._1w_m._q7o').nextSibling.childNodes[0].childNodes[4].childNodes[0].nextSibling.childNodes[0].setAttribute("style", "display:block; background:#0000;");
			event.target.closest('._1dwg._1w_m._q7o').nextSibling.childNodes[0].childNodes[4].childNodes[0].nextSibling.childNodes[0].childNodes[0].setAttribute("style", "border-bottom: 2px solid #0000;");
			event.target.closest('.u_1zif-yanm').children[0].children[0].children[1].children[0].children[0].children[0].children[0].style.color = PageTitleColorPROMPT;
            event.target.closest('.n_1zif-ycce.h_1zif-v9xd').setAttribute("style", "background:#222;");
	//if(!window.location.href.match(/\d/)) {};
	//node.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.parentNode.children[1].children[2].children[1].children[0].children[0].children[1].children[1].children[0].children[0].children[0].children[2].setAttribute("style", "display:none;");
	//node.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.parentNode.children[1].children[2].children[1].children[0].children[0].children[1].children[1].children[0].children[0].children[0].children[3].setAttribute("style", "display:none;");
 var iCapture = event.target.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.parentNode;
			html2canvas(iCapture, {
				useCORS: true,
                backgroundColor: '#222',
				logging: true,
				x: 285,
				y: 425,
				width: 489
			}).then(canvas => {
				var a = canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream");
				var iNameGen = Math.random().toString(36).substring(2, 15);
				node.insertAdjacentHTML('afterend', '<span class="SaveAsImageFile"><a href="' + a + '" download="' + iNameGen + '.jpg">Save As Image File</a></span>');
				node.insertAdjacentHTML('afterend', '<span class="ViewImage"><a href="' + a + '" target="_blank">View Image</a> / </span>');
				node.insertAdjacentHTML('afterend', '<div class="canvasArea">' + canvas.toDataURL("image/jpg") + '</div>');
				setTimeout(function () {
					node.setAttribute("style", "color: red; border: 1px solid red; display:none;");
					node.nextSibling.nextSibling.setAttribute("style", "color: red;");
					/* Likes Information (Show) */
					event.target.closest('._1dwg._1w_m._q7o').nextSibling.childNodes[0].childNodes[4].childNodes[0].nextSibling.childNodes[0].setAttribute("style", "display:none;background:#0f0;");
				}, 0);
			})



			} else { console.log('URL is ' + window.location.href); console.log('Capturing statuses on this page is NOT supported! ');
			          node.setAttribute("style", "color: #6666; border: 1px solid #8888; display:inline-block;");
                      node.value = 'Coming Soon';
			         }

        


		});
	})
});
/* — Insert Copy Text Button — */
setMutationHandler({
	target: document.querySelector('._3576'),
	selector: '.copybtnP',
	handler: nodes => nodes.forEach(node => {
		node.setAttribute("style", "color:blue; border: 1px solid blue;");
		node.addEventListener('click', function (event) {
			var classCheck = document.getElementsByClassName('canvasArea');
			var status_content = event.target.closest("._1dwg._1w_m._q7o").childNodes[0].nextSibling.childNodes[0].nextSibling;
			console.log(event.target.parentNode.parentNode.nextSibling.nextSibling.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.nextSibling.className);
			console.log(event.target.closest("._1dwg._1w_m._q7o").childNodes[0].nextSibling.childNodes[0].nextSibling.className);
			if (classCheck.length > 0) {
				status_content = event.target.previousSibling.previousSibling.previousSibling;
			}
			//alert(status_content + ' (Working)');
			//alert(event.target.previousSibling.innerText);
			getSelection().removeAllRanges();
			var range = document.createRange();
			range.selectNode(status_content);
			window.getSelection().addRange(range);
			try {
				var successful = document.execCommand('copy');
				var msg = successful ? 'successful' : 'unsuccessful';
				//console.log('Copying text command was ' + msg);
			} catch (err) {
				console.log('Oops, unable to copy');
			}
			return false;
		})
	})
});
/* — Gather Status Information — */
var nodeCount = 0;
var NumIncr = 0;
setMutationHandler({
	target: document.querySelector('._3576'),
	selector: '._5pcq',
	processExisting: false,
	handler: nodes => nodes.forEach(node => {
		nodeCount++;
		/*console.log(nodeCount);*/
		node.setAttribute("style", "font-size:10.5px;position:reltive;top:-4px;letter-spacing:1px;color:#0e2;");
		/* Set a delay so script shows last */
		setTimeout(function () {
			if (!node.parentNode.innerHTML.match(/copybtnP"|s2img"/)) {
				//console.log('(' + NumIncr++ + ') ' + node.innerText);
				console.log(node.innerText);
				node.insertAdjacentHTML('afterend', '<input type="button" class="copybtnP" name="copyp" value="Copy Text"/>');
				node.insertAdjacentHTML('afterend', '<br><input type="button" class="s2img" name="s2img" value="Export Status"/>');
			}
		}, 0);
	})
});
setMutationHandler({
	target: document.querySelector('.fbPhotosPhotoCaption'),
	selector: '.hasCaption',
	handler: nodes => nodes.forEach(node => {
		node.style.color = '#f00';
		var PhotoCaption = document.getElementsByClassName('hasCaption')[0];
		console.log('Current Image: ' + PhotoCaption.innerText);
		if (!document.getElementsByClassName('fbPhotosPhotoCaption')[0].innerHTML.includes('copybtn"')) {
			PhotoCaption.insertAdjacentHTML('afterend', '<input type="button" class="copybtn" name="copy" value="Copy"/>');
		}
		var copyTextareaBtn = document.querySelector('.copybtn');
		copyTextareaBtn.addEventListener('click', function (event) {
			var copy_text = document.getElementsByClassName("hasCaption")[0];
			var range = document.createRange();
			range.selectNode(copy_text);
			window.getSelection().addRange(range);
			try {
				var successful = document.execCommand('copy');
				var msg = successful ? 'successful' : 'unsuccessful';
				console.log('Copying text command was ' + msg);
			} catch (err) {
				console.log('Oops, unable to copy');
			}
		});
	})
});

function pad(n, width, z) {
	z = z || '0';
	n = n + '';
	return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

function expandDates(e) {
	for (var t, a = 0; t = e[a++];) t.querySelector(".full-timestamp") || t.insertAdjacentHTML("beforeend", '<span class="full-timestamp"> on ' + moment(new Date(1e3 * t.dataset.utime)).format("l \\at LTS"))
}

function RecentTimestamps(e) {
	for (var t, n = 0; t = e[n++];)
		if (!t.querySelector(".full-timestamp")) {
			if (1 == t.innerText.includes("min")) {
				var a = t.innerText.match(/[0-9]{1,2}/),
					s = parseInt(a, 10);
				t.insertAdjacentHTML("beforeend", '<span class="full-timestamp"> <span style="color:#365899">(' + moment(new Date).subtract(s, "minutes").format("h:mm:ss A") + ' ≃ <span style="color:#365899">ᴀᴘᴘʀᴏxɪᴍᴀᴛᴇ)</span><br>')
			}
			if (1 == t.innerText.includes("hr")) {
				var r = t.innerText.match(/[0-9]{1,2}/),
					m = parseInt(r, 10),
					o = 10 * parseInt(moment(new Date).format("mm") / 10, 10),
					l = 10 * parseInt(moment(new Date).format("ss") / 10, 10);
				t.insertAdjacentHTML("beforeend", '<span class="full-timestamp"> <span style="color:#365899">on ' + moment(new Date).subtract(m, "hours").format("l \\at h:") + pad(o, 2) + ":" + pad(l, 2) + '<span style="color:#365899"> ≃ (ᴀᴘᴘʀᴏxɪᴍᴀᴛᴇ)</span><br>')
			}
		}
}

function RecentPostURLs(e) {
	if (e.parentNode) {
		for (var a = 0; a < e.length; a++) {
			var r = e[a];
			!1 === r.innerHTML.includes("<br>") && "_5r69" != r.className && (r.getElement, r.insertAdjacentHTML("afterend", '<br><span style="color:#9c9dc3">' + r.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.previousSibling.href.replace(/\?fref=nf/, "").replace("&__tn__=", "").replace("&__tn__=m-R", "").replace("7%2Cdm-R-R", "").replace("%2Cdm-R-R", "").replace(/&eid=.+/, "").match(/facebook.com\/[a-z|A-Z|[0-9|\-|_|.]+.[a-zA-Z|[0-9|\-|_|.|]+[a-zA-Z|[0-9|\-|_|.|?=]+/) + "</span>"))
		}
	}
}

function ExternalURLs(e) {
	for (var n = 0; n < e.length; n++) {
		var r = e[n],
			a = r.href.replace(/https:\/\/l\.facebook.com\/l.php\?u=/, "");
		!1 === r.innerHTML.includes("<br>") && "_5r69" != r.className && r.insertAdjacentHTML("afterend", '<span class="externalURLs">' + decodeURIComponent(a.replace(/\+/g, " ")).replace(/.fbclid=[\D}\d]+/, "").slice(0, 256) + "</span>")
	}
}

function expandPostIDs(e) {
	for (var r = 0; r < e.length; r++) {
		var p = e[r];
		!1 === p.innerHTML.includes("<br>") && "_5pcq" === p.className && p.insertAdjacentHTML("beforeend", "<br>" + p.href.replace(/(\?__xts__%.+|\/\?type=\d&__xts__%.+)/gm, "").replace("permalink.php?", "&nbsp;permalink.php?").replace("/groups/", "Group: ").replace("/permalink/", "<br>Post ID: ").slice(24, 100).replace("/", ""))
	}
}