- // ==UserScript==
- // @name Swatch Internet Time
- // @author Nik Rolls
- // @description Convert times to Swatch Internet Time .beats
- // @match *://*/*
- // @require https://greasyfork.org/scripts/395037-monkeyconfig-modern/code/MonkeyConfig%20Modern.js?version=764968
- // @grant GM_getMetadata
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @grant GM_addStyle
- // @version 0.0.1.20200412020302
- // @namespace https://greasyfork.org/users/503103
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- const cfg = new MonkeyConfig({
- menuCommand: true,
- params: {
- global_timezone: {
- label: 'Use global BMT timezone',
- type: 'checkbox',
- default: true
- }
- }
- });
-
- let interval = null;
-
- document.addEventListener('visibilitychange', detectVisibility);
- detectVisibility();
-
- function detectVisibility() {
- if (document.visibilityState === 'visible') {
- startWatching();
- } else {
- stopWatching();
- }
- }
-
- function startWatching() {
- augmentAllTimes();
- interval = window.setInterval(augmentAllTimes, 1000);
- }
-
- function stopWatching() {
- if (interval) {
- window.clearInterval(interval);
- }
- }
-
- function augmentAllTimes() {
- do {} while (augmentTimes())
- }
-
- function augmentTimes() {
- const items = document.evaluate('/html/body//*[not(self::style or self::script or self::time or self::input or self::textarea or boolean(@contenteditable)) and text()[contains(.,":0") or contains(.,":1") or contains(.,":2") or contains(.,":3") or contains(.,":4") or contains(.,":5") or contains(.,":6") or contains(.,":7") or contains(.,":8") or contains(.,":9") or contains(.,"0pm") or contains(.,"1pm") or contains(.,"2pm") or contains(.,"3pm") or contains(.,"4pm") or contains(.,"5pm") or contains(.,"6pm") or contains(.,"7pm") or contains(.,"8pm") or contains(.,"9pm") or contains(.,"0 pm") or contains(.,"1 pm") or contains(.,"2 pm") or contains(.,"3 pm") or contains(.,"4 pm") or contains(.,"5 pm") or contains(.,"6 pm") or contains(.,"7 pm") or contains(.,"8 pm") or contains(.,"9 pm") or contains(.,"0am") or contains(.,"1am") or contains(.,"2am") or contains(.,"3am") or contains(.,"4am") or contains(.,"5am") or contains(.,"6am") or contains(.,"7am") or contains(.,"8am") or contains(.,"9am") or contains(.,"0 am") or contains(.,"1 am") or contains(.,"2 am") or contains(.,"3 am") or contains(.,"4 am") or contains(.,"5 am") or contains(.,"6 am") or contains(.,"7 am") or contains(.,"8 am") or contains(.,"9 am")]]', document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
- for (var i = 0; i < items.snapshotLength; i++) {
- const item = items.snapshotItem(i);
- if (item.isContentEditable) {
- return;
- }
-
- const pattern = /(?:(?:([1-9][0-9]?(?::\d{2})*)\s*(a\.?m\.?|p\.?m\.?))|(\d{1,2}?:\d{2}(?::\d{2}(?:\.\d+)?)?))/i;
- const match = item.innerText.match(pattern);
- if (match) {
- let dateTime;
-
- if (match[1]) {
- const time = match[1];
- const meridiem = match[2].replace(/\./g, '');
- dateTime = createDateTime(time, meridiem);
- } else if (match[3]) {
- dateTime = createDateTime(match[3]);
- }
-
- if (dateTime) {
- const internetTime = convertToInternetTime(dateTime);
- const textNodes = Array.from(item.childNodes).filter(node => node.nodeType === Node.TEXT_NODE);
- textNodes.forEach((textNode) => {
- const textParts = textNode.textContent.match(new RegExp(`(.*)(${match[0]})(.*)`));
- if (textParts) {
- const newParts = [];
-
- if (textParts[1]) {
- newParts.push(document.createTextNode(textParts[1]));
- }
-
- if (textParts[2]) {
- const timeNode = document.createElement('time');
- timeNode.dateTime = dateTime.toISOString().replace(/^.*T|\+.*$|Z.*$/g, '');
- timeNode.title = match[0];
- timeNode.textContent = '@' + internetTime;
- newParts.push(timeNode);
- }
-
- if (textParts[3]) {
- newParts.push(document.createTextNode(textParts[3]));
- }
- newParts.forEach(part => item.insertBefore(part, textNode));
- textNode.remove();
- }
- });
- }
- }
- }
-
- return items.snapshotLength;
- }
-
- function createDateTime(time, meridiem) {
- const timeParts = time.match(/\d+/g);
- const dateTime = new Date();
- dateTime.setHours(meridiem && timeParts[0] == 12 ? 0 : timeParts[0], timeParts[1] || 0, timeParts[2] || 0, timeParts[3] || 0);
- if (meridiem && meridiem.startsWith('p')) {
- dateTime.setHours(dateTime.getHours() + 12);
- }
- return dateTime;
- }
-
- function convertToInternetTime(dateTime) {
- dateTime = new Date(dateTime.getTime());
-
- if (cfg.get('global_timezone')) {
- dateTime.setMinutes(dateTime.getMinutes() + dateTime.getTimezoneOffset() + 60);
- }
-
- const midnight = new Date(dateTime.getTime());
- midnight.setHours(0, 0, 0, 0);
-
- const msPastMidnight = dateTime - midnight;
- const decimal = (msPastMidnight / 86400000) * 1000;
- return Math.floor((decimal + Number.EPSILON) * 100) / 100
- }
- })();