Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions js&css/web-accessible/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,41 @@ document.addEventListener('it-message-from-extension', function () {
ImprovedTube.disableAutoDubbing();
}
break
case 'livechat':
if (this.storage.livechat === 'hidden') {
document.documentElement.setAttribute('it-livechat', 'hidden');
} else if (this.storage.livechat === 'collapsed') {
document.documentElement.setAttribute('it-livechat', 'collapsed');
} else {
document.documentElement.removeAttribute('it-livechat');
}
break
case 'livechat_below_theater':
if (this.storage.livechat_below_theater === true) {
ImprovedTube.livechatBelowTheater();
ImprovedTube.livechatTheaterModeObserver();
} else {
// Clean up observer and restore chat position
if (ImprovedTube.livechatTheaterObserver) {
ImprovedTube.livechatTheaterObserver.disconnect();
ImprovedTube.livechatTheaterObserver = null;
}
// Restore live chat to original position
const liveChatFrame = document.querySelector("ytd-live-chat-frame#chat");
const secondaryInner = document.getElementById("secondary-inner");
if (liveChatFrame && secondaryInner && liveChatFrame.parentNode !== secondaryInner) {
if (liveChatFrame.parentNode) {
liveChatFrame.parentNode.removeChild(liveChatFrame);
}
secondaryInner.appendChild(liveChatFrame);
// Reset styling
liveChatFrame.style.width = "";
liveChatFrame.style.maxWidth = "";
liveChatFrame.style.marginTop = "";
liveChatFrame.style.marginBottom = "";
}
}
break
case 'returnYoutubeDislike':
if (ImprovedTube.storage.return_youtube_dislike === true) {
ImprovedTube.returnYoutubeDislike();
Expand Down
6 changes: 6 additions & 0 deletions js&css/web-accessible/functions.js
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@ ImprovedTube.videoPageUpdate = function () {
ImprovedTube.playerCinemaModeButton();
ImprovedTube.playerHamburgerButton();
ImprovedTube.playerControls();

// Initialize live chat below theater functionality
if (this.storage.livechat_below_theater === true) {
ImprovedTube.livechatBelowTheater();
ImprovedTube.livechatTheaterModeObserver();
}
}
};

Expand Down
93 changes: 93 additions & 0 deletions js&css/web-accessible/www.youtube.com/appearance.js
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,99 @@ ImprovedTube.livechat = function () {
}
} */
};

/*------------------------------------------------------------------------------
LIVECHAT BELOW THEATER
------------------------------------------------------------------------------*/
ImprovedTube.livechatBelowTheater = function () {
if (this.storage.livechat_below_theater === true) {
const watchFlexy = document.querySelector("ytd-watch-flexy");
const liveChatFrame = document.querySelector("ytd-live-chat-frame#chat");
const chatTemplate = document.getElementById("chat-template");

if (!watchFlexy || !liveChatFrame) return;

// Check if we're in theater mode
const isTheaterMode = watchFlexy.hasAttribute("theater");

if (isTheaterMode) {
// Move live chat below the player in theater mode
const primary = document.getElementById("primary");
const below = document.getElementById("below");

if (primary && below) {
// Remove live chat from its current position
if (liveChatFrame.parentNode) {
liveChatFrame.parentNode.removeChild(liveChatFrame);
}

// Insert live chat below the player (before comments)
const comments = document.querySelector("#comments");
if (comments && comments.parentNode === below) {
below.insertBefore(liveChatFrame, comments);
} else {
below.appendChild(liveChatFrame);
}

// Set proper styling for the repositioned chat
liveChatFrame.style.width = "100%";
liveChatFrame.style.maxWidth = "100%";
liveChatFrame.style.marginTop = "16px";
liveChatFrame.style.marginBottom = "16px";
}
} else {
// Restore live chat to original position when not in theater mode
const secondary = document.getElementById("secondary");
const secondaryInner = document.getElementById("secondary-inner");

if (secondary && secondaryInner && liveChatFrame.parentNode !== secondaryInner) {
// Remove from below position
if (liveChatFrame.parentNode) {
liveChatFrame.parentNode.removeChild(liveChatFrame);
}

// Restore to secondary column
secondaryInner.appendChild(liveChatFrame);

// Reset styling
liveChatFrame.style.width = "";
liveChatFrame.style.maxWidth = "";
liveChatFrame.style.marginTop = "";
liveChatFrame.style.marginBottom = "";
}
}
}
};

// Theater mode observer for live chat repositioning
ImprovedTube.livechatTheaterModeObserver = function () {
if (this.storage.livechat_below_theater === true) {
const watchFlexy = document.querySelector("ytd-watch-flexy");

if (watchFlexy && !this.livechatTheaterObserver) {
this.livechatTheaterObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'theater') {
// Reposition live chat when theater mode changes
ImprovedTube.livechatBelowTheater();
}
});
});

// Observe theater mode changes
this.livechatTheaterObserver.observe(watchFlexy, {
attributes: true,
attributeFilter: ['theater']
});
}
} else {
// Clean up observer when feature is disabled
if (this.livechatTheaterObserver) {
this.livechatTheaterObserver.disconnect();
this.livechatTheaterObserver = null;
}
}
};
/*------------------------------------------------------------------------------
DETAILS
------------------------------------------------------------------------------*/
Expand Down
117 changes: 117 additions & 0 deletions test-live-chat-below-theater.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Test script to verify the live chat below theater feature
// This script can be run in the browser console on a YouTube live stream page

function testLiveChatBelowTheater() {
console.log('πŸ§ͺ Testing Live Chat Below Theater Feature');

// Check if we're on a video page
if (document.documentElement.dataset.pageType !== 'video') {
console.error('❌ Not on a video page. Please navigate to a YouTube live stream first.');
return false;
}

// Check if live chat is present
const liveChatFrame = document.querySelector("ytd-live-chat-frame#chat");
if (!liveChatFrame) {
console.error('❌ Live chat not found. Please navigate to a YouTube live stream first.');
return false;
}

console.log('βœ… Found live chat frame');

// Check if ImprovedTube is loaded
if (typeof ImprovedTube === 'undefined') {
console.error('❌ ImprovedTube not loaded. Please ensure the extension is active.');
return false;
}

console.log('βœ… ImprovedTube loaded');

// Check if our new functions exist
if (typeof ImprovedTube.livechatBelowTheater !== 'function') {
console.error('❌ livechatBelowTheater function not found');
return false;
}

if (typeof ImprovedTube.livechatTheaterModeObserver !== 'function') {
console.error('❌ livechatTheaterModeObserver function not found');
return false;
}

console.log('βœ… New live chat functions are available');

// Test theater mode detection
const watchFlexy = document.querySelector("ytd-watch-flexy");
if (!watchFlexy) {
console.error('❌ Watch flexy element not found');
return false;
}

const isTheaterMode = watchFlexy.hasAttribute("theater");
console.log('βœ… Current theater mode status:', isTheaterMode);

// Test the repositioning function
try {
// Enable the feature temporarily for testing
const originalSetting = ImprovedTube.storage.livechat_below_theater;
ImprovedTube.storage.livechat_below_theater = true;

console.log('πŸ”„ Testing live chat repositioning...');
ImprovedTube.livechatBelowTheater();

// Check if chat moved position
const below = document.getElementById("below");
const chatInBelow = below && below.contains(liveChatFrame);

if (isTheaterMode && chatInBelow) {
console.log('βœ… Live chat successfully moved below player in theater mode');
} else if (!isTheaterMode && !chatInBelow) {
console.log('βœ… Live chat correctly stayed in sidebar when not in theater mode');
} else {
console.log('ℹ️ Chat position:', {
theaterMode: isTheaterMode,
inBelow: chatInBelow,
currentParent: liveChatFrame.parentNode?.id || liveChatFrame.parentNode?.tagName
});
}

// Test theater mode toggle
console.log('πŸ”„ Testing theater mode observer...');
ImprovedTube.livechatTheaterModeObserver();

if (ImprovedTube.livechatTheaterObserver) {
console.log('βœ… Theater mode observer created successfully');
} else {
console.log('ℹ️ Theater mode observer not created (feature may be disabled)');
}

// Restore original setting
ImprovedTube.storage.livechat_below_theater = originalSetting;

} catch (error) {
console.error('❌ Error during testing:', error);
return false;
}

console.log('πŸŽ‰ Live chat below theater feature test completed successfully!');
console.log('πŸ“ Manual testing instructions:');
console.log(' 1. Go to a YouTube live stream');
console.log(' 2. Enable "Live Chat Below Theater" in ImprovedTube settings');
console.log(' 3. Toggle theater mode (theater button on player)');
console.log(' 4. Verify live chat moves below player in theater mode');
console.log(' 5. Verify live chat returns to sidebar when exiting theater mode');

return true;
}

// Auto-run test if on a video page
if (document.documentElement.dataset.pageType === 'video') {
setTimeout(testLiveChatBelowTheater, 2000);
} else {
console.log('ℹ️ Navigate to a YouTube live stream to test the live chat below theater feature');
}

// Export for manual testing
if (typeof window !== 'undefined') {
window.testLiveChatBelowTheater = testLiveChatBelowTheater;
}
Loading