// ==UserScript==
// @name Twitch Clips - Show date & time
// @version 0.5.1
// @description Displays the actual date & time of when a clip was created, instead of the useless "xxx days/months/weeks ago"
// @author Decicus
// @updateURL https://gist.github.com/Decicus/ec4745e680e06cfff5b1fa0a53fcff72/raw/twitch-clips-datetime.user.js
// @downloadURL https://gist.github.com/Decicus/ec4745e680e06cfff5b1fa0a53fcff72/raw/twitch-clips-datetime.user.js
// @homepageURL https://gist.github.com/Decicus/ec4745e680e06cfff5b1fa0a53fcff72
// @icon https://i.alex.lol/2021-08-29_PmO4zo.png
// @match https://clips.twitch.tv/*
// @match https://www.twitch.tv/*
// @license MIT
// ==/UserScript==
/**
* Insert timestamp for the `clips.twitch.tv` website.
*/
function clipsSubdomain(createdAt, dateAndTime)
{
const box = document.querySelector('.clips-sidebar-info');
const layoutClass = box.classList[0];
const textElement = document.querySelector('span[class*="CoreText"]');
const textClass = textElement.classList[0];
const element = document.createElement('div');
element.className = layoutClass;
element.setAttribute('style', 'text-align: center; margin-top: 1em;');
element.innerHTML = `Clip created: ${dateAndTime}`;
box.insertAdjacentElement('afterbegin', element);
}
/**
* Insert timestamp for the `www.twitch.tv` (main) website.
* E.g. https://www.twitch.tv/$channelName/clip/$clipSlug
*/
function clipsMainWebsite(createdAt, dateAndTime)
{
const timestampBar = document.querySelector('.timestamp-metadata__bar');
const parent = timestampBar.parentElement;
// Use for text styling
const textElement = document.querySelector('p[class*="CoreText"]');
const textClass = textElement.classList[0];
const element = document.createElement('p');
element.className = textClass;
element.innerHTML = `- Clip created: ${dateAndTime}`;
element.setAttribute('title', createdAt);
element.setAttribute('style', 'margin-left: 0.25em;');
parent.insertAdjacentElement('beforeend', element);
}
async function fetchClip() {
const url = new URL(window.location.href);
/**
* TODO: Handle regular highlights/VODs
* For now we just make sure it's a clip page on the main website
* before we try to do anything else.
*/
if (url.hostname === 'www.twitch.tv' && !url.pathname.includes('/clip/')) {
console.log('Not a Twitch clip, probably VOD/highlight');
return;
}
const pathFragments = url.pathname.split('/');
const clipSlug = pathFragments[pathFragments.length - 1];
const slug = clipSlug.match(/([A-z0-9-_]+)/m)[1];
if (!slug) {
return;
}
const response = await fetch(`https://api.twitch.tv/kraken/clips/${slug}`, {
headers: {
Accept: 'application/vnd.twitchtv.v5+json',
'Client-ID': 'zs377ogpzz01ogfx26pvbddx9jodg1',
},
});
const data = await response.json();
if (!data.created_at) {
return;
}
const createdAt = data.created_at;
const created = new Date(createdAt);
const dateAndTime = created.toLocaleString();
if (url.hostname === 'clips.twitch.tv') {
clipsSubdomain(createdAt, dateAndTime);
return;
}
clipsMainWebsite(createdAt, dateAndTime);
}
/**
* Observe the DOM until we find the element we're interested in.
* Once complete, disconnect the observer and call the `fetchClip()` function which actually inserts the
* timestamp into the DOM.
*/
function observerHandler(mutations, observer)
{
// clips.twitch.tv
const clipsInfo = document.querySelector('.clips-chat-info span[class*="CoreText"]');
// www.twitch.tv
const timestampBar = document.querySelector('.timestamp-metadata__bar');
if (!clipsInfo && !timestampBar) {
return;
}
console.log('Clips page', clipsInfo !== null);
console.log('Main website', timestampBar !== null);
fetchClip();
observer.disconnect();
}
const observer = new MutationObserver(observerHandler);
observer.observe(document, {
attributes: false,
childList: true,
characterData: false,
subtree: true,
});