Display two subtitle languages simultaneously on any Jem.tv video.
Works in seconds • No installation neededFollow these simple steps to get started
Go to videos.jem.tv, play any video, and enable your desired subtitle language using the CC button.
Press these keys on your keyboard to open the browser console:
Windows / Linux:
Mac:
A panel will appear at the bottom or side of your screen. Make sure the Console tab is selected. You'll see a text area where you can type.
Copy the script below (click the button), paste it into the console, and press Enter. A popup will ask you to choose your second language!
Pasting code that you don't understand into a browser (especially if you are logged in, but also in general) can be devastating!
Make sure that you do NOT paste any code (including this code) into your browser before verifying with a professional computer programmer that it is safe to do so.
That being said, feel free to ask someone about this script's safety if you don't understand code.
!הצלחה
// Dual Subtitles Script for Jem.tv
(function() {
const video = document.querySelector('video');
if (!video) return alert('No video found!');
const allTracks = Array.from(video.textTracks);
const tracks = allTracks.filter(t =>
t.kind === 'subtitles' && t.label && t.label.length > 0 && !t.label.toLowerCase().includes('shaka')
);
if (tracks.length < 2) return alert('Need at least 2 subtitle tracks!');
// Choose layout mode
const layoutChoice = prompt('Choose layout mode:\n\n1 = Stacked (one above the other)\n2 = Side-by-Side (left and right)\n\nEnter 1 or 2:', '1');
if (layoutChoice === null) return;
const sideBySide = layoutChoice.trim() === '2';
// Show available languages
const langs = tracks.map((t, i) => `${i}: ${t.label} (${t.language})`).join('\n');
let leftTrack, rightTrack, secondTrack;
if (sideBySide) {
const leftIdx = prompt(`Choose LEFT subtitle language:\n${langs}\n\nEnter number:`, "0");
if (leftIdx === null) return;
leftTrack = tracks[parseInt(leftIdx)];
if (!leftTrack) return alert('Invalid selection!');
const rightIdx = prompt(`Choose RIGHT subtitle language:\n${langs}\n\nEnter number:`, "1");
if (rightIdx === null) return;
rightTrack = tracks[parseInt(rightIdx)];
if (!rightTrack) return alert('Invalid selection!');
// For side-by-side, we control both - hide all native tracks and native display
tracks.forEach(t => t.mode = 'hidden');
leftTrack.mode = 'hidden';
rightTrack.mode = 'hidden';
} else {
const idx = prompt(`Choose SECOND subtitle language:\n${langs}\n\nEnter number:`, "0");
if (idx === null) return;
secondTrack = tracks[parseInt(idx)];
if (!secondTrack) return alert('Invalid selection!');
secondTrack.mode = 'hidden';
}
// Remove existing containers and styles
document.getElementById('dual-sub-container')?.remove();
document.getElementById('dual-sub-left')?.remove();
document.getElementById('dual-sub-right')?.remove();
document.getElementById('dual-sub-style')?.remove();
// Hide native Jem.tv subtitle display
const hideNativeStyle = document.createElement('style');
hideNativeStyle.id = 'dual-sub-style';
if (sideBySide) {
// Hide all native subtitles for side-by-side
hideNativeStyle.textContent = `
app-player-subtitle .text-container.subtitles,
app-player-subtitle app-text,
.over-bottom-center app-player-subtitle {
display: none !important;
}
`;
}
// For stacked mode, keep native subtitles visible (user's primary language)
document.head.appendChild(hideNativeStyle);
// Find the right player container
const playerContainer = document.querySelector('jem-video-player') ||
document.querySelector('.vid-box') ||
video.closest('.vid-wrapper')?.parentElement ||
video.parentElement;
playerContainer.style.position = 'relative';
// Helper to sanitize subtitle text (allow only safe tags)
function sanitizeSubtitle(text) {
if (!text) return '';
const temp = document.createElement('div');
temp.innerHTML = text;
temp.querySelectorAll('script').forEach(s => s.remove());
return temp.innerHTML;
}
if (sideBySide) {
// Create side-by-side container
const wrapper = document.createElement('div');
wrapper.id = 'dual-sub-container';
const leftDiv = document.createElement('div');
leftDiv.id = 'dual-sub-left';
const rightDiv = document.createElement('div');
rightDiv.id = 'dual-sub-right';
wrapper.appendChild(leftDiv);
wrapper.appendChild(rightDiv);
playerContainer.appendChild(wrapper);
function updateStyles() {
const isFs = !!(document.fullscreenElement || document.webkitFullscreenElement);
const fontSize = isFs ? 'clamp(22px, 2.8vw, 40px)' : '17px';
const padding = isFs ? '12px 20px' : '6px 14px';
const bottom = isFs ? '6%' : 'calc(18% - 15px)';
const boxWidth = isFs ? '42vw' : '38vw';
const gap = isFs ? '50px' : '30px';
wrapper.style.cssText = `
position: absolute;
bottom: ${bottom};
left: 50%;
transform: translateX(-50%);
display: flex;
gap: ${gap};
justify-content: center;
align-items: flex-start;
z-index: 2147483647;
width: 95%;
pointer-events: none;
`;
const baseStyle = `
text-align: center;
font-size: ${fontSize};
color: white;
text-shadow: 2px 2px 3px black, -1px -1px 2px black, 1px -1px 2px black, -1px 1px 2px black;
padding: ${padding};
background: rgba(0,0,0,0.7);
border-radius: 6px;
line-height: 1.4;
width: ${boxWidth};
min-height: 1.5em;
`;
leftDiv.style.cssText = baseStyle + 'direction: auto; unicode-bidi: plaintext;';
rightDiv.style.cssText = baseStyle + 'direction: auto; unicode-bidi: plaintext;';
}
updateStyles();
document.addEventListener('fullscreenchange', updateStyles);
document.addEventListener('webkitfullscreenchange', updateStyles);
// Delay timers to prevent flashing between sentences
let leftTimer = null;
let rightTimer = null;
const CLEAR_DELAY = 1500; // 1.5 seconds
leftTrack.oncuechange = function() {
const cue = this.activeCues[0];
if (cue) {
clearTimeout(leftTimer);
leftDiv.innerHTML = sanitizeSubtitle(cue.text);
} else {
leftTimer = setTimeout(() => { leftDiv.innerHTML = ''; }, CLEAR_DELAY);
}
};
rightTrack.oncuechange = function() {
const cue = this.activeCues[0];
if (cue) {
clearTimeout(rightTimer);
rightDiv.innerHTML = sanitizeSubtitle(cue.text);
} else {
rightTimer = setTimeout(() => { rightDiv.innerHTML = ''; }, CLEAR_DELAY);
}
};
console.log(`✅ Side-by-side subtitles enabled! Left: ${leftTrack.label}, Right: ${rightTrack.label}`);
alert(`Side-by-side subtitles enabled!\nLeft: ${leftTrack.label}\nRight: ${rightTrack.label}`);
} else {
// Stacked mode (original behavior)
const dualSubContainer = document.createElement('div');
dualSubContainer.id = 'dual-sub-container';
playerContainer.appendChild(dualSubContainer);
function updateStyles() {
const isFullscreen = !!(document.fullscreenElement || document.webkitFullscreenElement);
if (isFullscreen) {
dualSubContainer.style.cssText = `
position: absolute;
bottom: 10%;
left: 50%;
transform: translateX(-50%);
text-align: center;
z-index: 2147483647;
font-size: clamp(28px, 3vw, 44px);
color: white;
text-shadow: 2px 2px 3px black, -1px -1px 2px black, 1px -1px 2px black, -1px 1px 2px black, 0 0 10px black;
max-width: 85%;
pointer-events: none;
padding: 8px 18px;
background: rgba(0,0,0,0.7);
border-radius: 6px;
line-height: 1.3;
direction: auto;
unicode-bidi: plaintext;
`;
} else {
dualSubContainer.style.cssText = `
position: absolute;
bottom: calc(22% - 20px);
left: 50%;
transform: translateX(-50%);
text-align: center;
z-index: 2147483647;
font-size: 18px;
color: white;
text-shadow: 1px 1px 2px black, -1px -1px 2px black, 1px -1px 2px black, -1px 1px 2px black;
max-width: 85%;
pointer-events: none;
padding: 4px 12px;
background: rgba(0,0,0,0.65);
border-radius: 4px;
line-height: 1.3;
direction: auto;
unicode-bidi: plaintext;
`;
}
}
updateStyles();
document.addEventListener('fullscreenchange', updateStyles);
document.addEventListener('webkitfullscreenchange', updateStyles);
// Delay timer to prevent flashing between sentences
let clearTimer = null;
const CLEAR_DELAY = 1500; // 1.5 seconds
secondTrack.oncuechange = function() {
const cue = this.activeCues[0];
if (cue) {
clearTimeout(clearTimer);
dualSubContainer.innerHTML = sanitizeSubtitle(cue.text);
} else {
clearTimer = setTimeout(() => { dualSubContainer.innerHTML = ''; }, CLEAR_DELAY);
}
};
console.log(`✅ Dual subtitles enabled! Second language: ${secondTrack.label}`);
alert(`Dual subtitles enabled!\nSecond language: ${secondTrack.label}`);
}
})();
You'll need to run this script again if you refresh the page or switch to a different video. The dual subtitles only work on videos that have multiple subtitle tracks available.
Don't want to open the console every time? Try the Bookmarklet Version — drag a button to your bookmarks bar and click it whenever you need dual subtitles. No typing required!
document.getElementById('dual-sub-container')?.remove();
dualSubContainer.style.cssText section. Change bottom: 85px to adjust position, or color: white to change the text color.