Greasy Fork

Greasy Fork is available in English.

FB: Full Timestamps 2019

Shows full timestamps on Facebook posts

当前为 2019-02-25 提交的版本,查看 最新版本

// ==UserScript==
// @name     FB: Full Timestamps 2019
// @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   wOxxOm & JZersche
// @require  http://greasyfork.icu/scripts/12228/code/setMutationHandler.js
// @  require  https://momentjs.com/downloads/moment.min.js
// @  require  https://momentjs.com/downloads/moment-with-locales.min.js
// @version 3.06
// @namespace http://greasyfork.icu/users/95175
// @description Shows full timestamps 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: inline-block; }' +
    '.sponsored {color: #06b;}'
);

// 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'));
// 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);

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(nodes) {
    for (var i = 0, abbr;
        (abbr = nodes[i++]);) {
        if (abbr.querySelector('.full-timestamp')) {
            // already processed
            continue;
        }
        abbr.insertAdjacentHTML(
            'beforeend', '<span class="full-timestamp">' +
            ' on ' + moment(new Date(abbr.dataset.utime * 1000)).format('l \\at LTS')
        );
    }
}

function RecentTimestamps(nodes) {
    for (var i = 0, abbr;
        (abbr = nodes[i++]);) {
        if (abbr.querySelector('.full-timestamp')) {
            // already processed
            continue;
        }
        if (abbr.innerText.includes('min') == true) {
            var minAdjust = abbr.innerText.match(/[0-9]{1,2}/);
            var minAdjustI = parseInt(minAdjust, 10);
            abbr.insertAdjacentHTML(
                'beforeend', '<span class="full-timestamp">' +
                ' <span style="color:#365899">(' + moment(new Date())
                .subtract(minAdjustI, 'minutes').format('h:mm:ss A') +
                ' ≃ <span style="color:#365899">ᴀᴘᴘʀᴏxɪᴍᴀᴛᴇ)</span><br>'
            );
        }
        if (abbr.innerText.includes('hr') == true) { // If innerText includes 'hr' in it (x hrs ago)
            var hrAdjust = abbr.innerText.match(/[0-9]{1,2}/); // Restrict the innerText to show only 1 or 2 numbers. |xx|
            var hrAdjustI = parseInt(hrAdjust, 10); // Convert |xx| to Integer from original String Format.
            var minRoundedDown = parseInt(moment(new Date()).format('mm') / 10, 10) * 10;
                                 // Return the current minute of the time, and round it down to the nearest 10.
            var secRoundedDown = parseInt(moment(new Date()).format('ss') / 10, 10) * 10;
                                 // Return the current minute of the time, and round it down to the nearest 10.

            abbr.insertAdjacentHTML(
                'beforeend', '<span class="full-timestamp">' +
                ' <span style="color:#365899">on ' + moment(new Date())
                .subtract(hrAdjustI, 'hours').format('l \\at h:') + pad(minRoundedDown, 2) + ':' + pad(secRoundedDown, 2) +
                '<span style="color:#365899"> ≃ (ᴀᴘᴘʀᴏxɪᴍᴀᴛᴇ)</span><br>'
            );
        }
    }
}

function RecentPostURLs(nodes) {
    for (var i = 0; i < nodes.length; i++) {
        var element = nodes[i];
        if (element.innerHTML.includes('<br>') === false && element.className != '_5r69') {
element.getElement
            element.insertAdjacentHTML(
                'afterend', '<br><span style="color:#9c9dc3">' +
                element.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(nodes) {
    for (var i = 0; i < nodes.length; i++) {
        var element = nodes[i];
var urlString = element.href.replace(/https:\/\/l\.facebook.com\/l.php\?u=/,'');

        if (element.innerHTML.includes('<br>') === false && element.className != '_5r69') {
            element.insertAdjacentHTML(

                'afterend', '<span style="color:#2233ff">' + decodeURIComponent(urlString.replace(/\+/g, ' ')).replace(/.fbclid=[\D}\d]+/,'') + '</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("/", ""));
    }
}