Forked from Alex/Twitch clip datetime userscript

Last active 1707301996

A userscript for displaying the actual date & time (relative to local time) of when a Twitch clip was created.

Revision 65715d81a202c5a9adaa3a79fcf688f7f233d9c9

README.md Raw

Twitch clip datetime userscript

A userscript for displaying the actual date & time (relative to local time) of when a Twitch clip was created.

FYI: It only works on URLs that start with https://clips.twitch.tv/.
This script does not work with URLs that are on the Twitch "channel pages" (https://www.twitch.tv/CHANNEL_NAME_HERE/clip/...).
This has been added as of v0.5.0.

"Under the hood" the script uses Date.toLocaleString() to format the date. The format of the date & time may differ from the screenshots below.

Requirements:

  • Something like the Violentmonkey extension installed for your browser.

Installation:

  1. Install a userscript extension (such as Violentmonkey).
  2. Click on this link when Violentmonkey is installed, and it will prompt you to install the userscript.

Changelog

  • v0.5.0 - 2021-12-30
    • Script now supports clips on Twitch channel pages (e.g. https://www.twitch.tv/$channelName/clip/$clipSlug)
      • The @match rule will say https://www.twitch.tv/* to support navigating from the channel page to the clip page, otherwise script wouldn't load on regular Twitch browsing.
  • v0.4.1 - 2021-08-29
    • Make script compatible with Tampermonkey again.
  • v0.4.0 - 2021-08-29
    • Date/time placement was adjusted due to changes in the page on Twitch's end. See screenshots.
    • Previously I used Tampermonkey, but later switched to Violentmonkey. During my testing, I tested with Violentmonkey and it worked fine. However, if you're currently using Tampermonkey, v0.4.0 does not work. I'm unsure as to why, but I'll try to look into it.
    • Fixed in v0.4.1

Screenshots:

As of v0.4.0, the timestamp shows up a bit different compared to earlier versions.

Without chat (beginning of clip)

Screenshot of userscript in action, before chat history loads

With chat

Screenshot of userscript in action, with chat history loaded

Main Twitch website

When browsing Twitch channel clips on the main Twitch website.
Only v0.5.0 (December 30th, 2021) and newer

Screenshot of userscript on main Twitch website

twitch-clips-datetime.user.js Raw
1// ==UserScript==
2// @name Twitch Clips - Show date & time
3// @version 0.5.0
4// @description Displays the actual date & time of when a clip was created, instead of the useless "xxx days/months/weeks ago"
5// @author Decicus
6// @updateURL https://gist.github.com/Decicus/ec4745e680e06cfff5b1fa0a53fcff72/raw/twitch-clips-datetime.user.js
7// @downloadURL https://gist.github.com/Decicus/ec4745e680e06cfff5b1fa0a53fcff72/raw/twitch-clips-datetime.user.js
8// @homepageURL https://gist.github.com/Decicus/ec4745e680e06cfff5b1fa0a53fcff72
9// @icon https://i.alex.lol/2021-08-29_PmO4zo.png
10// @match https://clips.twitch.tv/*
11// @match https://www.twitch.tv/*
12// @license MIT
13// ==/UserScript==
14
15/**
16 * Insert timestamp for the `clips.twitch.tv` website.
17 */
18function clipsSubdomain(createdAt, dateAndTime)
19{
20 const box = document.querySelector('.clips-sidebar-info');
21 const layoutClass = box.classList[0];
22
23 const textElement = document.querySelector('span[class*="CoreText"]');
24 const textClass = textElement.classList[0];
25
26 const element = document.createElement('div');
27 element.className = layoutClass;
28 element.setAttribute('style', 'text-align: center; margin-top: 1em;');
29 element.innerHTML = `<span class="${textClass}" title="${createdAt}"><strong>Clip created:</strong> ${dateAndTime}</span>`;
30
31 box.insertAdjacentElement('afterbegin', element);
32}
33
34/**
35 * Insert timestamp for the `www.twitch.tv` (main) website.
36 * E.g. https://www.twitch.tv/$channelName/clip/$clipSlug
37 */
38function clipsMainWebsite(createdAt, dateAndTime)
39{
40 const timestampBar = document.querySelector('.timestamp-metadata__bar');
41 const parent = timestampBar.parentElement;
42
43 // Use for text styling
44 const textElement = document.querySelector('p[class*="CoreText"]');
45 const textClass = textElement.classList[0];
46
47 const element = document.createElement('p');
48 element.className = textClass;
49 element.innerHTML = `- Clip created: <strong>${dateAndTime}</strong>`;
50 element.setAttribute('title', createdAt);
51 element.setAttribute('style', 'margin-left: 0.25em;');
52
53 parent.insertAdjacentElement('beforeend', element);
54}
55
56async function fetchClip() {
57 const url = new URL(window.location.href);
58 const pathFragments = url.pathname.split('/');
59 const clipSlug = pathFragments[pathFragments.length - 1];
60
61 const slug = clipSlug.match(/([A-z0-9-_]+)/m)[1];
62
63 if (!slug) {
64 return;
65 }
66
67 const response = await fetch(`https://api.twitch.tv/kraken/clips/${slug}`, {
68 headers: {
69 Accept: 'application/vnd.twitchtv.v5+json',
70 'Client-ID': 'zs377ogpzz01ogfx26pvbddx9jodg1',
71 },
72 });
73
74 const data = await response.json();
75
76 if (!data.created_at) {
77 return;
78 }
79
80 const createdAt = data.created_at;
81 const created = new Date(createdAt);
82 const dateAndTime = created.toLocaleString();
83
84 if (url.hostname === 'clips.twitch.tv') {
85 clipsSubdomain(createdAt, dateAndTime);
86 return;
87 }
88
89 clipsMainWebsite(createdAt, dateAndTime);
90}
91
92/**
93 * Observe the DOM until we find the element we're interested in.
94 * Once complete, disconnect the observer and call the `fetchClip()` function which actually inserts the
95 * timestamp into the DOM.
96 */
97function observerHandler(mutations, observer)
98{
99 // clips.twitch.tv
100 const clipsInfo = document.querySelector('.clips-chat-info span[class*="CoreText"]');
101
102 // www.twitch.tv
103 const timestampBar = document.querySelector('.timestamp-metadata__bar');
104
105 if (!clipsInfo && !timestampBar) {
106 return;
107 }
108
109 console.log('Clips page', clipsInfo !== null);
110 console.log('Main website', timestampBar !== null);
111
112 fetchClip();
113 observer.disconnect();
114}
115
116const observer = new MutationObserver(observerHandler);
117observer.observe(document, {
118 attributes: false,
119 childList: true,
120 characterData: false,
121 subtree: true,
122});