Skip to content

Instantly share code, notes, and snippets.

@ArturT
Last active January 30, 2026 20:48
Show Gist options
  • Select an option

  • Save ArturT/cd1f63cbc7028577dc9366ddbe14cb37 to your computer and use it in GitHub Desktop.

Select an option

Save ArturT/cd1f63cbc7028577dc9366ddbe14cb37 to your computer and use it in GitHub Desktop.
HBO MAX Precision Rewind - rewind by a specified number of seconds.

About

A JavaScript script designed for language learners using the English Shadowing technique on HBO Max and watching TV shows like Friends.

This script transforms your streaming experience into an interactive language lab by allowing you to "frame" dialogue and repeat it with zero friction.

🌟 Why this is perfect for Shadowing

The English Shadowing technique requires listening to a speaker and repeating what they say in real-time or immediately after. This script solves the biggest frustrations of shadowing while streaming:

  • The -1s Buffer: Pressing S automatically captures the second before you hit the key, ensuring you don't cut off the start of the sentence.

  • Automatic Looping: Frame a difficult phrase and let it loop while you practice the mouth movements and intonation.

  • Micro-Rewinds: Use 1-9 keys to jump back just a few seconds if you missed a specific word's pronunciation.

✨ Key Features

  • Precision Rewind: Keys 1 through 9 rewind by exactly that many seconds.

  • Smart Start Marker (S - start): Sets a start point with an automatic -1s buffer so you never miss the beginning of a line.

  • Stop & Pause (D - done): Sets an end point and instantly pauses the video.

  • Master Loop Toggle (L - loop): Toggles an automatic loop between your Start and End points.

  • Home-Run Jump (J - jump): Instantly jump back to your start point and resume playback.

  • Clear End (W - wipe): Remove the end moment marker.

  • Visual HUD: Sleek on-screen notifications for every action.

How to use it

Open HBO MAX in your browser, then open the browser console. Paste the script there.

πŸ›  How to Open the Browser Console

If the script isn't working or you want to verify it has loaded, you may need to open the Developer Console.

🌐 Google Chrome

  • Right-click anywhere on the page and select Inspect.

  • Click on the Console tab at the top of the window that appears.

  • Shortcut: Cmd + Option + J (Mac) or Ctrl + Shift + J (Windows).

🧭 Safari

Safari requires you to enable the developer menu first:

  • Go to Safari > Settings (or Preferences) in the top menu bar.

  • Click the Advanced tab.

  • Check the box at the bottom: "Show features for web developers" (or "Show Develop menu").

  • Now, right-click the page and select Inspect Element, then click the Console tab.

  • Shortcut: Cmd + Option + C.

(function() {
'use strict';
let startTimestamp = null;
let stopTimestamp = null;
let isLoopingActive = false;
const toast = document.createElement('div');
Object.assign(toast.style, {
position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
backgroundColor: 'rgba(0, 0, 0, 0.85)', color: 'white', padding: '15px 30px',
borderRadius: '50px', fontSize: '22px', fontWeight: 'bold', zIndex: '9999',
display: 'none', pointerEvents: 'none', fontFamily: 'sans-serif', transition: 'opacity 0.2s ease'
});
document.body.appendChild(toast);
let timeout;
function showToast(text, color = 'white') {
toast.innerText = text;
toast.style.color = color;
toast.style.display = 'block';
toast.style.opacity = '1';
clearTimeout(timeout);
timeout = setTimeout(() => {
toast.style.opacity = '0';
setTimeout(() => { toast.style.display = 'none'; }, 200);
}, 850);
}
setInterval(() => {
const video = document.querySelector('video');
if (video && isLoopingActive && startTimestamp !== null && stopTimestamp !== null) {
if (video.currentTime >= stopTimestamp) {
video.currentTime = startTimestamp;
video.play();
showToast("Looping...", "#00FF7F");
}
}
}, 100);
window.addEventListener('keydown', function(e) {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
const video = document.querySelector('video');
if (!video) return;
const key = e.key.toLowerCase();
// S - MARK START (1 second before current time)
if (key === 's') {
startTimestamp = Math.max(0, video.currentTime - 1);
showToast("Start marked (-1s)", "#FFD700");
}
// D - MARK END AND STOP
else if (key === 'd') {
if (startTimestamp !== null && video.currentTime <= startTimestamp) {
showToast("Error: End must be after Start", "#FF5252");
} else {
stopTimestamp = video.currentTime;
isLoopingActive = false;
video.pause();
showToast("End marked & Paused", "#FF5252");
}
}
// L - TOGGLE LOOP
else if (key === 'l') {
if (isLoopingActive) {
isLoopingActive = false;
showToast("Loop: OFF", "white");
} else {
if (startTimestamp !== null && stopTimestamp !== null) {
isLoopingActive = true;
video.currentTime = startTimestamp;
video.play();
showToast("Loop: ON", "#00FF7F");
} else {
showToast("Mark Start(S) and End(D) first", "#FF5252");
}
}
}
// J - JUMP TO START
else if (key === 'j') {
if (startTimestamp !== null) {
video.currentTime = startTimestamp;
video.play();
showToast("Jump to start", "#00E5FF");
}
}
// W - CLEAR END
else if (key === 'w') {
stopTimestamp = null;
isLoopingActive = false;
showToast("End Point Cleared", "white");
}
// 1-9 REWIND
else if (/^[1-9]$/.test(key)) {
const rewindAmount = parseInt(key);
e.stopImmediatePropagation();
e.preventDefault();
video.currentTime = Math.max(0, video.currentTime - rewindAmount);
showToast(`Β« ${rewindAmount}s`);
}
}, true);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment