FB: Post Tools & Statistics

Shows exact timestamps and post information on Facebook Posts.

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

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

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

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

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

你需要先安裝一款使用者腳本管理器擴展,比如 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.06 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('.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;

			if (classCheck0.length >= 0 && window.location.href.match(/facebook\.com\/\D+\/\d+/)) {
				console.log('URL is supported 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;
			}


           if(classCheck1.length >= 0 && window.location.href.match(/facebook\.com\/\D+\/\d+/)) {
               console.log('Second '+event.target.parentNode.className);
				console.log('URL is supported by script. 1.04 Version. OK :) :: ' + window.location.href);

			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').parentNode.parentNode.setAttribute("style", "color: #fff; background: #333; display:block; border:0px solid #222!important;");
            event.target.closest('.n_1zif-ycce.h_1zif-v9xd').setAttribute("style", "background:#333;");
            event.target.parentNode.setAttribute("style", "background:#0000;");
			event.target.closest('.n_1zif-ycce.h_1zif-v9xd').parentNode.setAttribute("style", "color: #fff; background: #333; display:block; border:0px solid #222!important;");


				//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("/", ""))
	}
}