Last active
April 18, 2025 20:50
-
-
Save 1oh1/a52f038ec169f44a5386c14078b0e17d to your computer and use it in GitHub Desktop.
Hotstar Subtitles on Rewind
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Hotstar Subtitles on Rewind (with Hotkey & Toast UI) | |
// @namespace http://tampermonkey.net/ | |
// @version 2.0 | |
// @description Auto-enable subtitles for 15s on rewind, with hotkeys and on-screen feedback | |
// @match https://www.hotstar.com/* | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
let timeoutId = null; | |
let subtitleMode = 'auto'; // 'auto', 'on', 'off' | |
function simulateClick(el) { | |
if (el) { | |
el.dispatchEvent(new MouseEvent('mouseover', { bubbles: true })); | |
el.click(); | |
} | |
} | |
function openAudioSubtitlesMenu() { | |
const icon = document.querySelector('i.icon-subtitle-line'); | |
const button = icon?.closest('button'); | |
if (button) { | |
simulateClick(button); | |
return true; | |
} | |
return false; | |
} | |
function waitForSubtitleButtons(timeout = 5000) { | |
return new Promise((resolve, reject) => { | |
const endTime = Date.now() + timeout; | |
function check() { | |
const allButtons = document.querySelectorAll('button, [role="button"]'); | |
if (allButtons.length >= 17) { | |
resolve(Array.from(allButtons)); | |
} else if (Date.now() > endTime) { | |
reject('Subtitle buttons did not appear'); | |
} else { | |
setTimeout(check, 100); | |
} | |
} | |
check(); | |
}); | |
} | |
async function setSubtitlesTo(label, clickCount = 1) { | |
try { | |
const opened = openAudioSubtitlesMenu(); | |
if (!opened) throw new Error('Could not open Audio & Subtitles menu'); | |
const buttons = await waitForSubtitleButtons(); | |
const matches = buttons.filter(btn => btn.textContent.trim().toLowerCase() === label.toLowerCase()); | |
if (matches.length === 0) throw new Error(`No button found for "${label}"`); | |
let clicked = 0; | |
for (let i = 0; i < matches.length && clicked < clickCount; i++) { | |
simulateClick(matches[i]); | |
clicked++; | |
} | |
console.log(`[Hotstar] Clicked "${label}" ${clicked} time(s).`); | |
} catch (err) { | |
console.warn('[Hotstar] Subtitle change failed:', err); | |
} | |
} | |
function triggerSubtitleWindow() { | |
if (subtitleMode !== 'auto') return; | |
if (timeoutId) clearTimeout(timeoutId); | |
setSubtitlesTo('English', 2); | |
timeoutId = setTimeout(() => { | |
setSubtitlesTo('Off', 1); | |
}, 15000); | |
} | |
function setupRewindListener() { | |
const observer = new MutationObserver(() => { | |
const rewindBtn = document.querySelector('[data-testid="seek-rewind"]'); | |
if (rewindBtn && !rewindBtn.dataset.listenerAdded) { | |
rewindBtn.dataset.listenerAdded = 'true'; | |
rewindBtn.addEventListener('click', triggerSubtitleWindow); | |
console.log('[Hotstar] Rewind listener (button) attached'); | |
} | |
}); | |
observer.observe(document.body, { childList: true, subtree: true }); | |
} | |
function getUiContainer() { | |
return document.fullscreenElement || document.body; | |
} | |
function showToast(message, duration = 3000) { | |
const container = getUiContainer(); | |
const toast = document.createElement('div'); | |
toast.textContent = message; | |
toast.style.cssText = ` | |
position: fixed; | |
bottom: 50px; | |
left: 50%; | |
transform: translateX(-50%); | |
background: rgba(0,0,0,0.85); | |
color: white; | |
padding: 10px 20px; | |
border-radius: 8px; | |
font-size: 14px; | |
z-index: 9999; | |
opacity: 0; | |
transition: opacity 0.3s ease; | |
pointer-events: none; | |
`; | |
container.appendChild(toast); | |
requestAnimationFrame(() => { | |
toast.style.opacity = '1'; | |
}); | |
setTimeout(() => { | |
toast.style.opacity = '0'; | |
setTimeout(() => toast.remove(), 300); | |
}, duration); | |
} | |
function showHelpBox() { | |
const container = getUiContainer(); | |
const existing = container.querySelector('#hotstar-help-box'); | |
if (existing) { | |
existing.remove(); | |
return; | |
} | |
const box = document.createElement('div'); | |
box.id = 'hotstar-help-box'; | |
box.innerHTML = ` | |
<div style="font-weight:bold; margin-bottom: 5px;">Hotstar Subtitle Hotkeys:</div> | |
<ul style="margin: 0; padding-left: 18px;"> | |
<li><strong>Shift + Alt + E</strong> — Enable English subtitles permanently</li> | |
<li><strong>Shift + Alt + D</strong> — Disable subtitles permanently</li> | |
<li><strong>Shift + Alt + A</strong> — Auto mode (15s subtitles on rewind)</li> | |
<li><strong>Shift + Alt + ?</strong> — Show/hide this help menu</li> | |
</ul> | |
<div style="margin-top: 10px; text-align: right;"> | |
<button id="close-help-btn" style="padding: 4px 8px; font-size: 12px;">Close</button> | |
</div> | |
`; | |
box.style.cssText = ` | |
position: fixed; | |
top: 60px; | |
right: 60px; | |
background: #111; | |
color: #fff; | |
border-radius: 10px; | |
padding: 15px 20px; | |
box-shadow: 0 0 10px rgba(0,0,0,0.3); | |
font-family: sans-serif; | |
font-size: 13px; | |
z-index: 10000; | |
max-width: 300px; | |
`; | |
container.appendChild(box); | |
box.querySelector('#close-help-btn').onclick = () => box.remove(); | |
} | |
function setupKeyboardListener() { | |
window.addEventListener('keydown', (e) => { | |
if (e.key === 'ArrowLeft') { | |
triggerSubtitleWindow(); | |
} | |
if (e.altKey && e.shiftKey) { | |
const key = e.key.toLowerCase(); | |
if (key === 'e') { | |
subtitleMode = 'on'; | |
clearTimeout(timeoutId); | |
setSubtitlesTo('English', 2); | |
showToast('Subtitles: ON (English)'); | |
} | |
if (key === 'd') { | |
subtitleMode = 'off'; | |
clearTimeout(timeoutId); | |
setSubtitlesTo('Off', 1); | |
showToast('Subtitles: OFF'); | |
} | |
if (key === 'a') { | |
subtitleMode = 'auto'; | |
showToast('Subtitles: AUTO (15s on rewind)'); | |
} | |
if (key === '?') { | |
showHelpBox(); | |
} | |
} | |
}); | |
} | |
setTimeout(() => { | |
setupRewindListener(); | |
setupKeyboardListener(); | |
}, 3000); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
🎬 Hotstar Subtitles Userscript
This userscript enhances your viewing experience on Hotstar.com by making subtitles smarter and more accessible with keyboard shortcuts:
✨ Features
Auto Subtitles on Rewind
Whenever you click the "Rewind 10s" button or press the ← Left Arrow key, English subtitles will be enabled automatically for 15 seconds, then disabled. Perfect for catching missed dialogue without turning subs on permanently.
Subtitle Control Hotkeys
Toggle subtitle behavior with simple keyboard combos:
Shift + Alt + E
→ Permanently enable English subtitlesShift + Alt + D
→ Permanently disable subtitlesShift + Alt + A
→ Return to Auto Mode (15s on rewind)Shift + Alt + ?
→ Show or hide the help popupFullscreen Compatible
Works seamlessly even in fullscreen mode — UI messages and help box show up correctly over the video.
Toast Notifications
Displays a short message on-screen whenever the mode is changed, so you always know what subtitle mode you're in.
🛠 How to Use
Inspired by ThioJoe: https://www.youtube.com/watch?v=YM0lVVFBZ5w
Fully generated by ChatGPT
Need more features or language support? Ask ChatGPT!