Ever put on a YouTube video and wondered if you'll finish it before you have to leave, go to sleep, or get back to work? I had that thought one too many times, so I built a small Safari extension to solve it.
It adds the end time directly inside YouTube's native time bubble:
0:20 / 7:23 Β· ends 11:44pm
That's it. Simple, but surprisingly useful.
How it works
The core logic is about three lines:
const remainingSec = (video.duration - video.currentTime) / video.playbackRate;
const endDate = new Date(Date.now() + remainingSec * 1000);
Grab the remaining seconds, divide by the playback rate (so it works correctly at 0.5Γ, 1.5Γ, 2Γ etc.), add it to the current time. Done.
The trickier part was getting it to feel native.
Injecting into YouTube's player
YouTube's player controls are built with a bunch of class-named spans. The time bubble you see is a .ytp-time-display element containing:
-
.ytp-time-currentβ the current position -
.ytp-time-separatorβ the/ -
.ytp-time-durationβ the total length
I inject a new <span> directly after .ytp-time-duration, so the end time sits inside the same pill β inheriting YouTube's exact font, colour and sizing automatically without needing to hardcode any styles.
const duration = document.querySelector('.ytp-time-duration');
duration.insertAdjacentElement('afterend', mySpan);
The YouTube SPA problem
YouTube is a single-page app, so navigating between videos doesn't trigger a full page reload. The player DOM gets rebuilt, which means my injected element disappears.
The fix is two-pronged:
1. Listen for YouTube's own navigation events:
['yt-navigate-finish', 'yt-page-data-updated', 'yt-player-updated'].forEach(evt => {
document.addEventListener(evt, reinject);
});
2. A MutationObserver as a fallback:
const obs = new MutationObserver(() => {
if (!document.getElementById('yt-end-time-ext')
&& document.querySelector('.ytp-time-duration')) {
reinject();
}
});
obs.observe(document.body, { childList: true, subtree: true });
Between these two, re-injection is reliable across every navigation scenario I've tested.
Packaging for Safari
This is where it gets slightly annoying. Safari doesn't load unpacked extensions the way Chrome does β you need to wrap it in a macOS app using Xcode.
Apple provides a converter tool that does the heavy lifting:
xcrun safari-web-extension-converter ./youtube-end-time-extension
This generates a full Xcode project with your extension embedded. You hit βR, it builds a small launcher app, and then you enable the extension in Safari's settings. For open source projects this works fine β anyone can clone the repo and build it themselves in a couple of minutes.
The one gotcha: Safari requires you to re-enable Develop β Allow Unsigned Extensions every time you restart the browser. A minor annoyance, but not a dealbreaker for a personal tool.
What I'd add next
- A subtle tooltip on hover showing the exact end time with seconds
- Auto-hiding when a video is paused for a long time (since the end time becomes meaningless)
- Firefox/Chrome support via the same manifest v3 codebase β it's already compatible, just needs packaging
Try it
The full source is on GitHub β it's about 100 lines of vanilla JS and works on any Mac with Xcode installed.
github.com/yourusername/youtube-end-time
If you build something on top of it or spot a bug, PRs are open. Would love to know if anyone finds this actually useful day-to-day.
United States
NORTH AMERICA
Related News
Trump Calls Off AI Executive Order Over Concern It Could Weaken US Tech Edge
4h ago

Microservices Didn't Fail. People Did
4h ago

Meta Settles Lawsuit That Claimed Social Media Addiction Screwed Up Schools
4h ago

Centralized Authentication for a Multi-Brand Laravel Ecosystem
12h ago
Gizmo Guard - Safeguard Bot (Powered by Gemma4)
4h ago