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 62cd8752bd4026d5c84fc375d0864e7e4701699b

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.1 - 2021-12-30
    • Minor bug where it tried to fetch the date & time of a clip when watching highlights/VODs.
      • At some point I'll update the script to support VODs/highlights, but for now I'm sticking to clips.
  • 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.1
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
59 /**
60 * TODO: Handle regular highlights/VODs
61 * For now we just make sure it's a clip page on the main website
62 * before we try to do anything else.
63 */
64 if (url.hostname === 'www.twitch.tv' && !url.pathname.includes('/clip/')) {
65 console.log('Not a Twitch clip, probably VOD/highlight');
66 return;
67 }
68
69 const pathFragments = url.pathname.split('/');
70 const clipSlug = pathFragments[pathFragments.length - 1];
71
72 const slug = clipSlug.match(/([A-z0-9-_]+)/m)[1];
73
74 if (!slug) {
75 return;
76 }
77
78 const response = await fetch(`https://api.twitch.tv/kraken/clips/${slug}`, {
79 headers: {
80 Accept: 'application/vnd.twitchtv.v5+json',
81 'Client-ID': 'zs377ogpzz01ogfx26pvbddx9jodg1',
82 },
83 });
84
85 const data = await response.json();
86
87 if (!data.created_at) {
88 return;
89 }
90
91 const createdAt = data.created_at;
92 const created = new Date(createdAt);
93 const dateAndTime = created.toLocaleString();
94
95 if (url.hostname === 'clips.twitch.tv') {
96 clipsSubdomain(createdAt, dateAndTime);
97 return;
98 }
99
100 clipsMainWebsite(createdAt, dateAndTime);
101}
102
103/**
104 * Observe the DOM until we find the element we're interested in.
105 * Once complete, disconnect the observer and call the `fetchClip()` function which actually inserts the
106 * timestamp into the DOM.
107 */
108function observerHandler(mutations, observer)
109{
110 // clips.twitch.tv
111 const clipsInfo = document.querySelector('.clips-chat-info span[class*="CoreText"]');
112
113 // www.twitch.tv
114 const timestampBar = document.querySelector('.timestamp-metadata__bar');
115
116 if (!clipsInfo && !timestampBar) {
117 return;
118 }
119
120 console.log('Clips page', clipsInfo !== null);
121 console.log('Main website', timestampBar !== null);
122
123 fetchClip();
124 observer.disconnect();
125}
126
127const observer = new MutationObserver(observerHandler);
128observer.observe(document, {
129 attributes: false,
130 childList: true,
131 characterData: false,
132 subtree: true,
133});