(function () {
if (window.__YAKTUBE_ENGINE_LOADED__) return;
window.__YAKTUBE_ENGINE_LOADED__ = true;
console.log('[YakTube] YakNet SSO, Custom Branding, A11y & On-Demand Engine Active');
// Dynamic Instance Name Helper
function getInstanceName() {
if (
window.PeertubeServerConfig &&
window.PeertubeServerConfig.instance &&
window.PeertubeServerConfig.instance.name
) {
return window.PeertubeServerConfig.instance.name;
}
var metaSite = document.querySelector('meta[property="og:site_name"]');
if (metaSite && metaSite.content) return metaSite.content;
var brandEl = document.querySelector('.header-left .brand-name, .instance-name, a.brand');
if (brandEl && brandEl.textContent) return brandEl.textContent.trim();
return 'YakTube';
}
// 1. Screen Reader Live Announcer
var liveRegion = null;
function getLiveRegion() {
if (!liveRegion || !document.body.contains(liveRegion)) {
liveRegion = document.getElementById('yaktube-a11y-live-region');
if (!liveRegion) {
liveRegion = document.createElement('div');
liveRegion.id = 'yaktube-a11y-live-region';
liveRegion.setAttribute('aria-live', 'polite');
liveRegion.setAttribute('aria-atomic', 'true');
liveRegion.className = 'yaktube-sr-only';
document.body.appendChild(liveRegion);
}
}
return liveRegion;
}
function announce(text, assertive) {
var region = getLiveRegion();
if (assertive) {
region.setAttribute('aria-live', 'assertive');
} else {
region.setAttribute('aria-live', 'polite');
}
region.textContent = '';
setTimeout(function () {
region.textContent = text;
}, 50);
}
function triggerYakNetOAuth() {
sessionStorage.removeItem('yaknet_manual_logout');
var callbackUrl = 'https://yaktube.yakhub.com.tr/plugins/peertube-plugin-auth-yaknet/router/auth-callback';
window.location.href =
'https://auth.yakhub.com.tr/oauth/authorize?client_id=01a03c41-f758-721e-b927-619bffde5c23&redirect_uri=' +
encodeURIComponent(callbackUrl) +
'&response_type=code&scope=';
}
// Handle direct postMessage from YakNet SSO frame
window.addEventListener('message', function (ev) {
if (ev.data && ev.data.type === 'YAKNET_SSO_STATUS') {
if (ev.data.authenticated && ev.data.user) {
var token = localStorage.getItem('access_token');
if (
!token &&
!window.location.search.includes('local=true') &&
!window.location.search.includes('externalAuthError')
) {
sessionStorage.removeItem('yaknet_manual_logout');
console.log('[YakTube] Live YakNet session detected via SSO frame! Connecting...', ev.data.user);
triggerYakNetOAuth();
}
} else if (ev.data.authenticated === false) {
var hasToken = localStorage.getItem('access_token') || localStorage.getItem('username');
if (hasToken) {
console.log('[YakTube] YakNet session ended elsewhere. Clearing YakTube...');
try {
localStorage.clear();
sessionStorage.clear();
} catch (e) {}
window.location.reload();
}
}
}
});
// Global listener for YakNet SSO broadcast from auth.yakhub.com.tr
window.addEventListener('yaknet-auth', function (e) {
if (e.detail && e.detail.authenticated && e.detail.user) {
var token = localStorage.getItem('access_token');
if (
!token &&
!window.location.search.includes('local=true') &&
!window.location.search.includes('externalAuthError')
) {
sessionStorage.removeItem('yaknet_manual_logout');
console.log('[YakTube] Initiating automatic single-sign-on handshake for:', e.detail.user);
triggerYakNetOAuth();
}
} else if (e.detail && e.detail.authenticated === false) {
var hasToken = localStorage.getItem('access_token') || localStorage.getItem('username');
if (hasToken) {
try {
localStorage.clear();
sessionStorage.clear();
} catch (err) {}
window.location.reload();
}
}
});
// Unified single sign-out for YakTube and YakNet
function performUnifiedLogout() {
try {
localStorage.clear();
sessionStorage.clear();
sessionStorage.setItem('yaknet_manual_logout', 'true');
} catch (err) {}
window.location.replace(
'https://auth.yakhub.com.tr/sdk/logout?redirect_uri=' + encodeURIComponent('https://yaktube.yakhub.com.tr')
);
}
document.addEventListener(
'click',
function (e) {
var el = e.target;
if (el && el.closest) {
var isLogout = el.closest(
'a[href*="logout"], button[title*="Log out"], button[title*="Çıkış"], .logout-button, [class*="logout"], [aria-label*="Çıkış"], [aria-label*="Log out"]'
);
if (isLogout) {
e.preventDefault();
e.stopPropagation();
performUnifiedLogout();
return;
}
var isLogin = el.closest(
'my-login-link, .login-button, a[href*="/login"]:not(#yaktube-show-admin-login), a[aria-label*="Giriş"], a[title*="Giriş"], a[title*="login"], a[aria-label*="login"], .yaknet-sso-login-btn'
);
if (isLogin && !window.location.search.includes('local=true')) {
e.preventDefault();
e.stopPropagation();
sessionStorage.removeItem('yaknet_manual_logout');
triggerYakNetOAuth();
return;
}
}
},
true
);
// 2. YakNet SSO Header & Login Flow
function injectYakNetSSO() {
// 2.1 Header: Place YakNet Account widget in top-right .buttons-container
var headerRight =
document.querySelector('my-header .buttons-container') ||
document.querySelector('.buttons-container') ||
document.querySelector('my-header .header-right') ||
document.querySelector('my-header .user-menu') ||
document.querySelector('my-header .action-buttons') ||
document.querySelector('.header-right') ||
document.querySelector('header .right');
var token = localStorage.getItem('access_token');
var uName = localStorage.getItem('username');
var uEmail = localStorage.getItem('email');
var displayName = localStorage.getItem('displayName') || uName || '';
var emailStr = uEmail || '';
var isAuth = !!token && !!uName;
if (headerRight) {
var liveWidget = headerRight.querySelector('#yaknet-header-account-widget');
if (!liveWidget) {
var widgetWrap = document.createElement('div');
widgetWrap.id = 'yaknet-header-account-widget';
widgetWrap.className = 'yaknet-header-widget';
widgetWrap.style.display = 'inline-flex';
widgetWrap.style.alignItems = 'center';
widgetWrap.style.marginRight = '8px';
widgetWrap.innerHTML =
'' +
' ';
var targetSibling =
headerRight.querySelector('my-user-menu') ||
headerRight.querySelector('my-login-link') ||
headerRight.querySelector('.user-menu') ||
headerRight.querySelector('.settings-button') ||
headerRight.querySelector('my-user-notifications') ||
headerRight.querySelector('my-notification-bell');
if (targetSibling && targetSibling.parentElement === headerRight) {
headerRight.insertBefore(widgetWrap, targetSibling);
} else {
headerRight.prepend(widgetWrap);
}
var defaultLoginLink = headerRight.querySelector('my-login-link');
if (defaultLoginLink) {
defaultLoginLink.setAttribute('aria-hidden', 'true');
defaultLoginLink.setAttribute('tabindex', '-1');
defaultLoginLink.style.display = 'none';
}
} else {
// Sync widget attributes dynamically if auth state changed
var el = liveWidget.querySelector('yaknet-account');
if (el) {
if (el.shadowRoot) {
var shadowLogoutBtn =
el.shadowRoot.getElementById('logoutBtn') ||
el.shadowRoot.querySelector('.yn-logout-btn') ||
el.shadowRoot.querySelector('button[title*="Çıkış"], button[aria-label*="Çıkış"]');
if (shadowLogoutBtn && !shadowLogoutBtn.hasAttribute('data-yaktube-hooked')) {
shadowLogoutBtn.setAttribute('data-yaktube-hooked', 'true');
shadowLogoutBtn.addEventListener(
'click',
function (ev) {
ev.preventDefault();
ev.stopPropagation();
performUnifiedLogout();
},
true
);
}
}
var expectedAuth = isAuth ? 'true' : 'false';
var expectedName = isAuth ? displayName : '';
var expectedEmail = isAuth ? emailStr : '';
if (el.getAttribute('authenticated') !== expectedAuth || el.getAttribute('user-name') !== expectedName) {
el.setAttribute('authenticated', expectedAuth);
el.setAttribute('user-name', expectedName);
el.setAttribute('user-email', expectedEmail);
if (typeof el.syncStateFromAttributes === 'function') {
el.syncStateFromAttributes();
el.render();
}
}
}
}
}
// 2.2 Login Modal / Page
var loginCard =
document.querySelector('my-login') ||
document.querySelector('.login-page') ||
document.querySelector('.login-container') ||
document.querySelector('form.login') ||
document.querySelector('form[action*="login"]') ||
document.querySelector('my-login-modal');
if (loginCard && !document.getElementById('yaknet-login-section')) {
var isLocalLogin = window.location.search.includes('local=true') || window.location.pathname.includes('/admin');
var ssoBox = document.createElement('div');
ssoBox.id = 'yaknet-login-section';
ssoBox.className = 'yaknet-login-banner';
ssoBox.innerHTML =
'
YakNet ile YakTube\'a Katılın
' +
'' +
'YouTube gibi tek bir YakNet hesabıyla güvenle giriş yapabilir, kendi video ve müzik kanallarınızı oluşturabilirsiniz.' +
'
' +
'' +
' ' +
'YakNet ile Giriş Yap ' +
' ' +
'' +
'' +
'';
var formFirstChild = loginCard.firstElementChild;
if (formFirstChild) {
loginCard.insertBefore(ssoBox, formFirstChild);
} else {
loginCard.appendChild(ssoBox);
}
var registerLinks = document.querySelectorAll('a[href*="/signup"], a[href*="/register"]');
registerLinks.forEach(function (l) {
l.href = 'https://auth.yakhub.com.tr/register';
l.target = '_blank';
l.innerText = 'YakNet Hesabı Oluştur';
});
var formInputs = loginCard.querySelector('.form-group, .inputs, form') || loginCard.querySelector('input');
var containerToHide = formInputs ? formInputs.closest('form') || formInputs.parentElement : null;
if (containerToHide && !isLocalLogin) {
var subElements = Array.from(loginCard.children).filter(function (el) {
return (
el.id !== 'yaknet-login-section' && !el.classList.contains('title') && !el.classList.contains('page-title')
);
});
subElements.forEach(function (el) {
el.style.display = 'none';
});
var showAdminBtn = document.getElementById('yaktube-show-admin-login');
if (showAdminBtn) {
showAdminBtn.addEventListener('click', function (e) {
e.preventDefault();
subElements.forEach(function (el) {
el.style.display = '';
});
showAdminBtn.style.display = 'none';
announce('Yönetici kullanıcı adı ve şifre giriş formu açıldı.');
});
}
}
}
}
// 3. Intelligent Branding & A11y DOM Auto-Fixer
function autoFixDOM() {
injectYakNetSSO();
// Aggressively remove generic Framasoft Open-in-App / Play Store banners
var genericAppBanners = document.querySelectorAll(
'my-open-app, my-client-app-banner, .open-app-container, .app-banner, [class*="open-app"], [class*="open-in-app"], .mobile-app-banner, my-open-in-app, .app-promotion, a[href*="play.google.com/store/apps/details?id=app.joinpeertube"], a[href*="f-droid.org"]'
);
genericAppBanners.forEach(function (banner) {
banner.setAttribute('aria-hidden', 'true');
banner.setAttribute('tabindex', '-1');
if (banner.parentElement) {
try {
banner.remove();
} catch (e) {
banner.style.display = 'none';
}
}
});
// Replace leftover PeerTube branding in visible UI texts
var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
var node;
while ((node = walker.nextNode())) {
var val = node.nodeValue;
if (val && (val.includes('PeerTube') || val.includes('Peertube'))) {
var parentTag = node.parentElement ? node.parentElement.tagName : '';
var parentElem = node.parentElement;
if (
parentElem &&
(parentElem.closest('#yaktube-ondemand-container') ||
parentElem.closest('#yaktube-live-watch-container') ||
parentElem.tagName === 'SCRIPT' ||
parentElem.tagName === 'STYLE')
) {
continue;
}
if (true) {
node.nodeValue = val
.replace(/PeerTube hakkında/gi, 'YakTube Hakkında')
.replace(/PeerTube'a katılın/gi, "YakTube'a Katılın")
.replace(/PeerTube örneği/gi, 'YakTube Sunucusu')
.replace(/PeerTube/g, 'YakTube');
}
}
}
// Semantic Headings (H3 for video titles, H2 for sections)
document
.querySelectorAll('.video-miniature, my-video-miniature, .video-card, .yaktube-card, [class*="miniature"]')
.forEach(function (card) {
var titleElement = card.querySelector(
'.video-miniature-name, .video-name, .yaktube-video-name, a[title], .title'
);
if (titleElement) {
if (!['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(titleElement.tagName)) {
titleElement.setAttribute('role', 'heading');
titleElement.setAttribute('aria-level', '3');
}
}
});
document
.querySelectorAll('.section-title, .sub-header, .videos-header, .page-header, .yaktube-title-h3')
.forEach(function (sec) {
if (!['H1', 'H2'].includes(sec.tagName)) {
sec.setAttribute('role', 'heading');
sec.setAttribute('aria-level', '2');
}
});
// Make native PeerTube comment authors accessible as H3 headings for screen readers
document
.querySelectorAll('my-video-comment, .video-comment, my-video-comment-thread, .comment, .comment-thread')
.forEach(function (commentEl) {
var authorEl = commentEl.querySelector(
'.display-name, .actor-name, .comment-author, a.actor-link, .video-comment-header-left a, .video-comment-header-left span'
);
if (
authorEl &&
!['H1', 'H2', 'H3', 'H4', 'H5', 'H6'].includes(authorEl.tagName) &&
!authorEl.getAttribute('role')
) {
authorEl.setAttribute('role', 'heading');
authorEl.setAttribute('aria-level', '3');
}
});
// Auto-fix unlabeled buttons
document.querySelectorAll('button:not([data-a11y-fixed])').forEach(function (btn) {
btn.setAttribute('data-a11y-fixed', 'true');
var text = (btn.textContent || '').trim();
var hasAria = btn.getAttribute('aria-label') || btn.getAttribute('title');
if (!text && !hasAria) {
var html = btn.innerHTML.toLowerCase();
var className = (btn.className || '').toLowerCase();
var icon = btn.querySelector('my-global-icon, i, svg, [class*="icon-"]');
var iconName = icon ? icon.className || icon.getAttribute('name') || '' : '';
if (html.includes('search') || className.includes('search') || iconName.includes('search')) {
btn.setAttribute('aria-label', 'Ara');
} else if (html.includes('bell') || className.includes('notification') || iconName.includes('bell')) {
btn.setAttribute('aria-label', 'Bildirimler');
} else if (html.includes('cog') || html.includes('setting') || className.includes('setting')) {
btn.setAttribute('aria-label', 'Ayarlar');
} else if (
html.includes('menu') ||
html.includes('bars') ||
className.includes('burger') ||
className.includes('menu')
) {
btn.setAttribute('aria-label', 'Ana Gezinme Menüsü');
} else if (html.includes('play') || className.includes('play')) {
btn.setAttribute('aria-label', 'Oynat');
} else if (html.includes('pause') || className.includes('pause')) {
btn.setAttribute('aria-label', 'Duraklat');
} else if (html.includes('volume') || html.includes('mute') || className.includes('volume')) {
btn.setAttribute('aria-label', 'Ses Kontrolü');
} else if (html.includes('fullscreen') || className.includes('fullscreen')) {
btn.setAttribute('aria-label', 'Tam Ekran');
} else if (
html.includes('ellipsis') ||
html.includes('more') ||
className.includes('more') ||
className.includes('action')
) {
btn.setAttribute('aria-label', 'Diğer İşlemler ve Seçenekler');
} else if (html.includes('trash') || html.includes('delete') || className.includes('delete')) {
btn.setAttribute('aria-label', 'Sil');
} else if (html.includes('edit') || className.includes('edit')) {
btn.setAttribute('aria-label', 'Düzenle');
} else if (html.includes('share') || className.includes('share')) {
btn.setAttribute('aria-label', 'Paylaş');
} else if (html.includes('thumb-up') || html.includes('like') || className.includes('like')) {
btn.setAttribute('aria-label', 'Beğen');
} else if (html.includes('thumb-down') || html.includes('dislike') || className.includes('dislike')) {
btn.setAttribute('aria-label', 'Beğenme');
} else if (html.includes('filter') || className.includes('filter')) {
btn.setAttribute('aria-label', 'Filtreler');
} else if (html.includes('close') || html.includes('times') || className.includes('close')) {
btn.setAttribute('aria-label', 'Kapat');
} else if (btn.closest('.vjs-control-bar')) {
btn.setAttribute('aria-label', 'Oynatıcı Düğmesi');
} else {
var parent = btn.parentElement;
if (parent && parent.title) {
btn.setAttribute('aria-label', parent.title);
} else {
btn.setAttribute('aria-label', 'Düğme');
}
}
}
});
// Auto-fix unlabeled images
document.querySelectorAll('img:not([data-a11y-fixed])').forEach(function (img) {
img.setAttribute('data-a11y-fixed', 'true');
var alt = img.getAttribute('alt');
if (!alt || alt.trim() === '') {
var card = img.closest('.video-miniature, .video-card, .yaktube-card, [class*="miniature"]');
if (card) {
var titleEl = card.querySelector('.video-miniature-name, .video-name, .yaktube-video-name, h3, h4, a[title]');
var titleText = titleEl ? (titleEl.textContent || titleEl.getAttribute('title') || '').trim() : '';
if (titleText) {
img.setAttribute('alt', titleText + ' video kapağı');
return;
}
}
var avatarContainer = img.closest('.actor-avatar, .channel-avatar, .avatar, [class*="avatar"]');
if (avatarContainer) {
var nameEl = avatarContainer.parentElement
? avatarContainer.parentElement.querySelector('.name, .actor-name, .channel-name')
: null;
var nameText = nameEl ? (nameEl.textContent || '').trim() : '';
img.setAttribute('alt', (nameText ? nameText + ' ' : '') + 'Profil Resmi');
return;
}
if (img.src && (img.src.includes('logo') || img.className.includes('logo'))) {
img.setAttribute('alt', getInstanceName() + ' Logo');
return;
}
var parentLink = img.closest('a');
if (parentLink && parentLink.textContent && parentLink.textContent.trim().length > 0) {
img.setAttribute('alt', '');
} else if (parentLink && parentLink.getAttribute('title')) {
img.setAttribute('alt', parentLink.getAttribute('title'));
} else {
img.setAttribute('alt', 'Görsel');
}
}
});
// Auto-fix unlabeled links
document.querySelectorAll('a:not([data-a11y-fixed])').forEach(function (a) {
a.setAttribute('data-a11y-fixed', 'true');
var text = (a.textContent || '').trim();
var hasAria = a.getAttribute('aria-label') || a.getAttribute('title');
if (!text && !hasAria) {
var img = a.querySelector('img');
if (img && img.alt) {
a.setAttribute('aria-label', img.alt);
} else if (a.href) {
if (a.href.includes('/videos/watch/')) {
a.setAttribute('aria-label', 'Videoyu İzle');
} else if (a.href.includes('/video-channels/')) {
a.setAttribute('aria-label', 'Kanal Sayfasına Git');
} else if (a.href.includes('/accounts/')) {
a.setAttribute('aria-label', 'Hesap Profiline Git');
} else if (a.href.includes('/videos/search')) {
a.setAttribute('aria-label', 'Arama Sayfası');
} else {
a.setAttribute('aria-label', 'Bağlantı');
}
}
}
});
// Auto-fix search inputs
document.querySelectorAll('input:not([data-a11y-fixed])').forEach(function (inp) {
inp.setAttribute('data-a11y-fixed', 'true');
if (!inp.getAttribute('aria-label') && !inp.getAttribute('placeholder') && !(inp.labels && inp.labels.length)) {
var type = (inp.getAttribute('type') || 'text').toLowerCase();
if (type === 'search') {
inp.setAttribute('aria-label', getInstanceName() + ' Video Arama');
} else if (type === 'checkbox') {
inp.setAttribute('aria-label', 'Seçim Kutusu');
} else if (type === 'password') {
inp.setAttribute('aria-label', 'Åifre');
}
}
});
}
setInterval(autoFixDOM, 1000);
// 3. Keyboard Shortcuts Modal
function toggleShortcutsModal() {
var modal = document.getElementById('yaktube-shortcuts-dialog');
if (modal) {
if (modal.style.display === 'none' || !modal.style.display) {
modal.style.display = 'flex';
announce('Klavye kısayolları yardım penceresi açıldı. Kapatmak i�in Escape tuşuna basın.');
var closeBtn = document.getElementById('yaktube-shortcuts-close');
if (closeBtn) closeBtn.focus();
} else {
modal.style.display = 'none';
announce('Yardım penceresi kapatıldı.');
}
} else {
modal = document.createElement('div');
modal.id = 'yaktube-shortcuts-dialog';
modal.className = 'yaktube-modal-overlay';
modal.setAttribute('role', 'dialog');
modal.setAttribute('aria-modal', 'true');
modal.setAttribute('aria-labelledby', 'yaktube-shortcuts-title');
modal.innerHTML =
'' +
'
?? YakTube Klavye K�sayollar� ' +
'
' +
'Kısayol İşlev ' +
'' +
'Space veya K Oynat / Duraklat ' +
'Sol Ok veya J 5 saniye geri sar ' +
'Sağ Ok veya L 5 saniye ileri sar ' +
'Yukarı / Aşağı Ok Sesi %5 artır / azalt ' +
'M Sesi Kapat / A� (Mute) ' +
'F Tam Ekran ' +
'C Altyazıları A� / Kapat ' +
'/ (Bölü)Arama kutusuna hızlı git ' +
'0 - 9 Videonun %0 - %90 noktasına atla ' +
'? (Shift+/)Bu yardım kılavuzunu aç / kapat ' +
'Esc Pencereleri kapat ' +
' ' +
'
' +
'
Kılavuzu Kapat (Esc) ' +
'
';
document.body.appendChild(modal);
document.getElementById('yaktube-shortcuts-close').addEventListener('click', function () {
modal.style.display = 'none';
});
var closeBtn = document.getElementById('yaktube-shortcuts-close');
if (closeBtn) closeBtn.focus();
announce('Klavye kısayolları yardım penceresi açıldı. Kapatmak i�in Escape tuşuna basın.');
}
}
function isInputFocused() {
var el = document.activeElement;
if (!el) return false;
var tag = el.tagName ? el.tagName.toUpperCase() : '';
return tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT' || el.isContentEditable;
}
function getVideoElement() {
return document.querySelector('video');
}
function formatTime(seconds) {
if (isNaN(seconds) || seconds < 0) return '0 saniye';
var mins = Math.floor(seconds / 60);
var secs = Math.floor(seconds % 60);
if (mins === 0) return secs + ' saniye';
return mins + ' dakika ' + secs + ' saniye';
}
// 4. Global Keydown Listener
window.addEventListener('keydown', function (e) {
if (e.key === 'Escape') {
var shortcutsModal = document.getElementById('yaktube-shortcuts-dialog');
if (shortcutsModal && shortcutsModal.style.display !== 'none') {
shortcutsModal.style.display = 'none';
announce('Pencere kapatıldı.');
return;
}
var importModal = document.getElementById('yaktube-import-modal');
if (importModal && importModal.style.display !== 'none') {
importModal.style.display = 'none';
announce('İndirme penceresi kapatıldı.');
return;
}
if (isInputFocused()) {
document.activeElement.blur();
}
return;
}
if (e.key === '?' || (e.shiftKey && e.key === '/')) {
if (!isInputFocused()) {
e.preventDefault();
toggleShortcutsModal();
return;
}
}
if (e.key === '/' && !isInputFocused()) {
e.preventDefault();
var searchInput =
document.querySelector('input[type="search"]') ||
document.querySelector('input[name="search"]') ||
document.querySelector('.search-input') ||
document.querySelector('input');
if (searchInput) {
searchInput.focus();
if (searchInput.select) searchInput.select();
announce('Arama kutusuna odaklanıldı.');
}
return;
}
if (isInputFocused()) {
return;
}
var video = getVideoElement();
if (!video) return;
var key = e.key.toLowerCase();
if (key === ' ' || key === 'k') {
e.preventDefault();
if (video.paused) {
video.play();
announce('Video oynatılıyor.');
} else {
video.pause();
announce('Video duraklatıldı.');
}
} else if (key === 'j' || e.key === 'ArrowLeft') {
e.preventDefault();
video.currentTime = Math.max(0, video.currentTime - 5);
announce('5 saniye geri sarıldı. Åu an: ' + formatTime(video.currentTime));
} else if (key === 'l' || e.key === 'ArrowRight') {
e.preventDefault();
video.currentTime = Math.min(video.duration || 99999, video.currentTime + 5);
announce('5 saniye ileri sarıldı. Åu an: ' + formatTime(video.currentTime));
} else if (e.key === 'ArrowUp') {
e.preventDefault();
video.volume = Math.min(1, video.volume + 0.05);
announce('Ses seviyesi yüzde ' + Math.round(video.volume * 100));
} else if (e.key === 'ArrowDown') {
e.preventDefault();
video.volume = Math.max(0, video.volume - 0.05);
announce('Ses seviyesi yüzde ' + Math.round(video.volume * 100));
} else if (key === 'm') {
e.preventDefault();
video.muted = !video.muted;
announce(video.muted ? 'Ses kapatıldı (Sessiz).' : 'Ses açıldı.');
} else if (key === 'f') {
e.preventDefault();
if (!document.fullscreenElement) {
var container = video.closest('.video-js') || video.parentElement || video;
if (container.requestFullscreen) container.requestFullscreen();
announce('Tam ekran moduna geçildi.');
} else {
if (document.exitFullscreen) document.exitFullscreen();
announce('Tam ekrandan çıkıldı.');
}
} else if (key === 'c') {
e.preventDefault();
var tracks = video.textTracks;
if (tracks && tracks.length > 0) {
var isShowing = tracks[0].mode === 'showing';
tracks[0].mode = isShowing ? 'disabled' : 'showing';
announce(isShowing ? 'Altyazılar kapatıldı.' : 'Altyazılar açıldı.');
} else {
announce('Bu videoda altyazı bulunmuyor.');
}
} else if (key >= '0' && key <= '9' && !e.ctrlKey && !e.altKey && !e.metaKey) {
e.preventDefault();
var percent = parseInt(key, 10) * 10;
if (video.duration) {
video.currentTime = (video.duration * percent) / 100;
announce('Videonun yüzde ' + percent + ' noktasına atlandı. Åu an: ' + formatTime(video.currentTime));
}
}
});
// 5. On-Demand Search & Import with Duplicate Awareness
var lastQuery = null;
var isSearching = false;
function showModal(title, desc) {
var overlay = document.getElementById('yaktube-import-modal');
if (!overlay) {
overlay = document.createElement('div');
overlay.id = 'yaktube-import-modal';
overlay.className = 'yaktube-modal-overlay';
overlay.setAttribute('role', 'dialog');
overlay.setAttribute('aria-modal', 'true');
overlay.setAttribute('aria-labelledby', 'yaktube-modal-title');
overlay.innerHTML =
'' +
'
' +
'
' +
(title || "YakTube'a Aktarılıyor...") +
' ' +
'
' +
(desc || 'Seçtiğiniz video D: diskinize aktarılıyor...') +
'
' +
'
';
document.body.appendChild(overlay);
} else {
var titleElem = document.getElementById('yaktube-modal-title');
var descElem = document.getElementById('yaktube-modal-desc');
if (titleElem) titleElem.innerText = title;
if (descElem) descElem.innerText = desc;
overlay.style.display = 'flex';
}
announce((title || '') + '. ' + (desc || ''), true);
}
function hideModal() {
var overlay = document.getElementById('yaktube-import-modal');
if (overlay) overlay.style.display = 'none';
}
function handleLiveStream(url, videoTitle, isRestoring) {
var videoIdMatch = url.match(/[?&]v=([^&]+)/) || url.match(/youtu\.be\/([^?]+)/);
var videoId = videoIdMatch ? videoIdMatch[1] : '';
if (!videoId) {
alert('Canl\u0131 yay\u0131n ID bulunamad\u0131.');
return;
}
// Persist active live stream state in sessionStorage
try {
sessionStorage.setItem(
'yaktube_active_live',
JSON.stringify({
url: url,
title: videoTitle,
videoId: videoId
})
);
} catch (e) {}
var liveContainer = document.getElementById('yaktube-live-watch-container');
if (liveContainer) liveContainer.remove();
liveContainer = document.createElement('div');
liveContainer.id = 'yaktube-live-watch-container';
liveContainer.className = 'yaktube-live-watch-section';
liveContainer.setAttribute('role', 'region');
liveContainer.setAttribute('tabindex', '-1');
liveContainer.setAttribute('aria-label', videoTitle + ' Canl\u0131 Yay\u0131n\u0131');
liveContainer.innerHTML =
'' +
'
' +
'
' +
'\ud83d\udd34 CANLI YAYIN ' +
'
' +
videoTitle +
' ' +
'' +
'
' +
'\u2715 Yay\u0131n\u0131 Kapat (Esc)' +
' ' +
'
' +
'
' +
'' +
'
' +
'
' +
'
\ud83d\udce1 YakTube Canl\u0131 Yay\u0131n Ak\u0131\u015f\u0131 \u2022 Reklams\u0131z ve Kesintisiz
' +
'
ESC tu\u015funa basarak yay\u0131n\u0131 kapatabilirsiniz.
' +
'
' +
'' +
'
';
var mainMount =
document.querySelector('my-search, my-search-results, router-outlet, main, .main-col') || document.body;
if (mainMount && mainMount.firstChild) {
mainMount.insertBefore(liveContainer, mainMount.firstChild);
} else if (mainMount) {
mainMount.appendChild(liveContainer);
}
if (!isRestoring) {
liveContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
setTimeout(function () {
var liveTitle = document.getElementById('yaktube-live-title');
if (liveTitle) liveTitle.focus();
else liveContainer.focus();
}, 150);
announce(
videoTitle +
' canl\u0131 yay\u0131n\u0131 ba\u015flat\u0131ld\u0131. Canl\u0131 yay\u0131n alan\u0131na odaklan\u0131ld\u0131.',
true
);
}
var commentNextToken = null;
var commentsList = document.getElementById('yaktube-comments-list');
var toggleCommentsBtn = document.getElementById('yaktube-toggle-comments-btn');
var moreCommentsWrap = document.getElementById('yaktube-more-comments-wrap');
var moreCommentsBtn = document.getElementById('yaktube-load-more-comments-btn');
function renderCommentCard(c) {
var card = document.createElement('div');
card.className = 'yaktube-comment-item';
card.setAttribute('role', 'article');
card.setAttribute('tabindex', '0');
card.setAttribute('aria-label', c.author + ' isimli kullan\u0131c\u0131n\u0131n yorumu: ' + c.content);
card.style.cssText =
'background: #1e293b; padding: 12px 14px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.05); display: flex; gap: 12px; align-items: flex-start;';
var avatarLetter = (c.author || 'U').replace('@', '').charAt(0).toUpperCase();
var avatarHtml =
'' +
avatarLetter +
'
';
var safeContent = c.content
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/\n/g, ' ');
card.innerHTML =
avatarHtml +
'' +
'
' +
'' +
'' +
c.published +
' ' +
(c.likeCount && c.likeCount !== '0'
? '👍 ' +
c.likeCount +
' '
: '') +
'
' +
'
' +
safeContent +
'
' +
'
';
return card;
}
function fetchComments(token) {
if (!token) {
toggleCommentsBtn.disabled = true;
toggleCommentsBtn.textContent = '⏳ Yorumlar Y\u00fckleniyor...';
} else {
moreCommentsBtn.disabled = true;
moreCommentsBtn.textContent = '⏳ Y\u00fckleniyor...';
}
var fetchUrl =
'/api-custom/youtube-comments?id=' +
encodeURIComponent(videoId) +
(token ? '&token=' + encodeURIComponent(token) : '');
fetch(fetchUrl)
.then(function (r) {
return r.json();
})
.then(function (res) {
if (!token) {
commentsList.innerHTML = '';
commentsList.style.display = 'flex';
toggleCommentsBtn.textContent = '🔄 Yorumlar\u0131 Yenile';
toggleCommentsBtn.disabled = false;
} else {
moreCommentsBtn.textContent = '➕ Daha Fazla Yorum G\u00f6ster (+20 Yorum)';
moreCommentsBtn.disabled = false;
}
var list = res.comments || [];
if (list.length === 0 && !token) {
commentsList.innerHTML =
'Bu videoda/yay\u0131nda hen\u00fcz yorum bulunmuyor.
';
moreCommentsWrap.style.display = 'none';
announce('Bu videoda henüz yorum bulunmuyor.');
return;
}
list.forEach(function (c) {
commentsList.appendChild(renderCommentCard(c));
});
commentNextToken = res.nextToken;
if (commentNextToken) {
moreCommentsWrap.style.display = 'block';
} else {
moreCommentsWrap.style.display = 'none';
}
announce(list.length + ' adet YouTube yorumu yüklendi.');
})
.catch(function (err) {
if (!token) {
toggleCommentsBtn.disabled = false;
toggleCommentsBtn.textContent = '⚠️ Tekrar Dene';
} else {
moreCommentsBtn.disabled = false;
moreCommentsBtn.textContent = '⚠️ Tekrar Dene';
}
alert('Yorumlar yüklenirken hata oluştu: ' + err.message);
});
}
if (toggleCommentsBtn) {
toggleCommentsBtn.addEventListener('click', function () {
fetchComments(null);
});
}
if (moreCommentsBtn) {
moreCommentsBtn.addEventListener('click', function () {
if (commentNextToken) fetchComments(commentNextToken);
});
}
function closeLiveTheater() {
try {
sessionStorage.removeItem('yaktube_active_live');
} catch (e) {}
if (liveContainer && liveContainer.parentNode) {
var ifr = liveContainer.querySelector('iframe');
if (ifr) ifr.src = '';
liveContainer.remove();
}
document.removeEventListener('keydown', handleEsc);
announce('Canl\u0131 yay\u0131n izleme alan\u0131 kapat\u0131ld\u0131.');
}
function handleEsc(e) {
if (e.key === 'Escape' || e.keyCode === 27) {
closeLiveTheater();
}
}
var closeBtn = document.getElementById('yaktube-close-live-theater');
if (closeBtn) closeBtn.addEventListener('click', closeLiveTheater);
document.addEventListener('keydown', handleEsc);
}
function restoreActiveLiveStream() {
try {
var saved = sessionStorage.getItem('yaktube_active_live');
if (!saved) return;
var data = JSON.parse(saved);
if (data && data.url && data.title && !document.getElementById('yaktube-live-watch-container')) {
handleLiveStream(data.url, data.title, true);
}
} catch (e) {}
}
function handleImport(url, btn, videoTitle) {
btn.disabled = true;
btn.innerHTML = '⏳ Aktarılıyor...';
showModal(
'[1/2] 📥 Video İndiriliyor...',
(videoTitle ? '"' + videoTitle + '" ' : 'Video ') + "YouTube'dan sunucunuza aktarılıyor. Lütfen bekleyin..."
);
fetch('/api-custom/ondemand-import', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ targetUrl: url, title: videoTitle })
})
.then(function (res) {
return res.json();
})
.then(function (data) {
if (!data || !data.ok) {
throw new Error(data && data.error ? data.error : 'İçe aktarma başlatılamadı.');
}
var videoId = data.video.id;
var videoUuid = data.video.uuid;
var attempts = 0;
var pollInterval = setInterval(function () {
attempts++;
fetch('/api-custom/status/' + videoId)
.then(function (sRes) {
return sRes.json();
})
.then(function (sData) {
if (sData.isImporting) {
showModal('[1/2] 📥 Video İndiriliyor...', 'Video sunucuya indiriliyor (' + attempts * 2 + ' sn)...');
} else if (sData.isTranscoding) {
showModal('[2/2] ⚙️ Oynatıcı Hazırlanıyor...', 'Video işleniyor ve yüksek kalite akış hazırlanıyor...');
}
if (sData.isPublished || (sData.hasFiles && attempts >= 8)) {
clearInterval(pollInterval);
showModal('🎉 Video Hazır!', 'Video kütüphanenize eklendi. Oynatıcı açılıyor...');
setTimeout(function () {
window.location.href = '/videos/watch/' + (sData.uuid || videoUuid);
}, 600);
} else if (sData.isFailed) {
clearInterval(pollInterval);
hideModal();
btn.disabled = false;
btn.innerHTML = "📥 YakTube'a Aktar & İzle";
alert('Video indirme sırasında bir hata oluştu.');
announce('Video indirme sırasında bir hata oluştu.', true);
}
})
.catch(function (e) {
console.error('[YakTube] Status poll error:', e);
});
if (attempts > 35) {
clearInterval(pollInterval);
hideModal();
btn.disabled = false;
btn.innerHTML = "📥 YakTube'a Aktar & İzle";
alert(
'İndirme arka planda tamamlanıyor. Ana sayfada veya Videolarım sayfasında kısa süre içinde hazır olacaktır.'
);
announce('İndirme arka planda tamamlanıyor. Ana sayfada kısa süre içinde hazır olacaktır.');
}
}, 1500);
})
.catch(function (err) {
hideModal();
btn.disabled = false;
btn.innerHTML = "📥 YakTube'a Aktar & İzle";
alert('İndirme hatası: ' + err.message);
announce('İndirme hatası: ' + err.message, true);
});
}
function checkAndInjectSearchResults() {
var url = new URL(window.location.href);
var searchParam = url.searchParams.get('search');
if (!window.location.pathname.includes('/search') || !searchParam || searchParam.trim().length < 2) {
var existing = document.getElementById('yaktube-ondemand-container');
if (existing) existing.remove();
lastQuery = null;
return;
}
var query = searchParam.trim();
if (query === lastQuery) return;
lastQuery = query;
var container = document.getElementById('yaktube-ondemand-container');
if (!container) {
container = document.createElement('div');
container.id = 'yaktube-ondemand-container';
container.className = 'yaktube-ondemand-section';
container.setAttribute('role', 'region');
container.setAttribute('aria-label', 'Canl\u0131 YouTube Arama Sonu\u00e7lar\u0131');
var mainContent =
document.querySelector('my-search, my-search-results, router-outlet, main, .main-col') || document.body;
if (mainContent && mainContent.firstChild) {
mainContent.insertBefore(container, mainContent.firstChild);
} else if (mainContent) {
mainContent.appendChild(container);
}
}
container.innerHTML =
'' +
'' +
'
' +
'
YouTube\'daki en pop\u00fcler e\u015fle\u015fmeler taran\u0131yor...
' +
'
';
var shortcutsBtn = document.getElementById('yaktube-open-shortcuts');
if (shortcutsBtn) {
shortcutsBtn.addEventListener('click', toggleShortcutsModal);
}
announce(query + ' i\u00e7in canl\u0131 YouTube aramas\u0131 ba\u015flat\u0131ld\u0131.');
isSearching = true;
fetch('/api-custom/youtube-search?q=' + encodeURIComponent(query))
.then(function (res) {
return res.json();
})
.then(function (data) {
var rawResults = data.results || [];
var uniqueResults = [];
var seenIds = {};
rawResults.forEach(function (item) {
if (item && item.id && !seenIds[item.id] && item.title) {
seenIds[item.id] = true;
uniqueResults.push(item);
}
});
var count = uniqueResults.length;
if (count === 0) {
container.innerHTML =
'';
announce(query + " için YouTube\'da eşleşen video bulunamadı.");
} else {
var countText = count === 1 ? '1 Video Bulundu' : count + ' Video Bulundu';
announce(query + ' araması için ' + count + ' video listelendi.');
var visibleCount = Math.min(12, count);
function render() {
var visibleResults = uniqueResults.slice(0, visibleCount);
var cardsHtml = '';
visibleResults.forEach(function (item) {
var isLocal = !!item.isDownloaded;
var isLive = !!item.isLive;
var statusBadge = '';
if (isLive) {
statusBadge =
'🔴 CANLI YAYIN ';
} else if (isLocal) {
statusBadge =
'✅ ' +
getInstanceName() +
"'da Mevcut ";
}
var actionButton = '';
if (isLive) {
actionButton =
'🔴 Canlı Yayını İzle ';
} else if (isLocal) {
actionButton =
'▶️ ' +
getInstanceName() +
"'dan İzle ";
} else {
actionButton =
'📥 ' +
getInstanceName() +
"'a Aktar & İzle ";
}
var durationText = isLive ? 'CANLI' : item.durationFormatted;
var cardLabel =
item.title +
(isLive ? ' (Canlı Yayın)' : isLocal ? ' (' + getInstanceName() + ' kütüphanenizde mevcut)' : '') +
', ' +
item.channel +
' kanalı, Süre: ' +
durationText;
cardsHtml +=
'' +
'
' +
'
' +
'
' +
durationText +
' ' +
'
' +
'
' +
'
' +
statusBadge +
'
' +
item.title +
' ' +
'
' +
item.channel +
'
' +
'
' +
actionButton +
'
' +
'
';
});
var loadMoreHtml = '';
if (visibleCount < count) {
loadMoreHtml =
'' +
'' +
'➕ Daha Fazla Video Göster (' +
visibleCount +
' / ' +
count +
')' +
' ' +
'
';
}
container.innerHTML =
'' +
'' +
cardsHtml +
'
' +
loadMoreHtml;
var sBtn = document.getElementById('yaktube-open-shortcuts');
if (sBtn) {
sBtn.addEventListener('click', toggleShortcutsModal);
}
var loadMoreBtn = document.getElementById('yaktube-load-more-btn');
if (loadMoreBtn) {
loadMoreBtn.addEventListener('click', function () {
visibleCount = Math.min(visibleCount + 6, count);
render();
announce(visibleCount + ' adet video gösteriliyor.');
});
}
container.querySelectorAll('.yaktube-live-btn').forEach(function (btn) {
btn.addEventListener('click', function (e) {
var liveUrl = e.currentTarget.getAttribute('data-url');
var liveTitle = e.currentTarget.getAttribute('data-title');
handleLiveStream(liveUrl, liveTitle);
});
});
container.querySelectorAll('.yaktube-import-btn').forEach(function (btn) {
btn.addEventListener('click', function (e) {
var videoUrl = e.currentTarget.getAttribute('data-url');
var videoTitle = e.currentTarget.getAttribute('data-title');
handleImport(videoUrl, e.currentTarget, videoTitle);
});
});
}
render();
}
})
.catch(function (err) {
console.error('[YakTube] Search fetch error:', err);
container.innerHTML =
'';
announce('Arama s\u0131ras\u0131nda bir ba\u011flant\u0131 sorunu olu\u015ftu.');
})
.finally(function () {
isSearching = false;
});
}
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// 8. FULL YOUTUBE SEARCH & VOICE MODAL ENGINE (v1.3.2 - Clean Generic Labels)
// --------------------------------------------------------------------------
var activeVoiceRec = null;
var isVoiceListening = false;
function createFullSearchModal() {
var existingModal = document.getElementById('yaktube-full-search-modal');
if (existingModal) return existingModal;
var modal = document.createElement('div');
modal.id = 'yaktube-full-search-modal';
modal.className = 'yaktube-full-search-modal';
modal.setAttribute('role', 'dialog');
modal.setAttribute('aria-modal', 'true');
modal.setAttribute('aria-labelledby', 'yaktube-modal-search-title');
modal.style.display = 'none';
modal.innerHTML =
'' +
'
' +
'
← ' +
'
' +
' ' +
'✕ ' +
'
' +
'
🔍 Ara ' +
'
🎙️ ' +
'
' +
'
' +
'
' +
'
🎙️ Dinleniyor...
' +
'
Lütfen aramak istediğiniz videoyu söyleyin...
' +
'
🎙️ ' +
'
' +
'
🔥 Hızlı ve Popüler Aramalar
' +
'
' +
'🎵 Tarkan ' +
'🎸 Barış Manço ' +
'💻 Python Dersleri ' +
'🤖 Yapay Zeka ' +
'🎧 Sesli Kitap ' +
'📺 Canlı Haber ' +
'🎼 Gitar Dersi ' +
'🌍 Bilim Belgeseli ' +
'
' +
'' +
'
' +
'
';
document.body.appendChild(modal);
var inp = modal.querySelector('#yaktube-modal-input');
var clearBtn = modal.querySelector('#yaktube-modal-clear-btn');
var backBtn = modal.querySelector('#yaktube-modal-back-btn');
var submitBtn = modal.querySelector('#yaktube-modal-submit-btn');
var voiceBtn = modal.querySelector('#yaktube-modal-voice-btn');
var micPulseBtn = modal.querySelector('#yaktube-modal-mic-pulse');
// Input typing & clear
inp.addEventListener('input', function () {
if (inp.value && inp.value.trim().length > 0) {
clearBtn.style.display = 'inline-flex';
} else {
clearBtn.style.display = 'none';
}
});
clearBtn.addEventListener('click', function () {
inp.value = '';
clearBtn.style.display = 'none';
inp.focus();
announce('Arama metni temizlendi.');
});
// Close on Back button or Escape
backBtn.addEventListener('click', function () {
closeFullSearchModal();
});
modal.addEventListener('click', function (e) {
if (e.target === modal) {
closeFullSearchModal();
}
});
// Search execute
function executeSearch(query) {
var q = (query || inp.value || '').trim();
if (q) {
announce('"' + q + '" için arama yapılıyor...', true);
closeFullSearchModal();
window.location.href = '/search/videos?search=' + encodeURIComponent(q);
}
}
submitBtn.addEventListener('click', function () {
executeSearch();
});
inp.addEventListener('keydown', function (e) {
if (e.key === 'Enter') {
e.preventDefault();
executeSearch();
} else if (e.key === 'Escape') {
e.preventDefault();
closeFullSearchModal();
}
});
// Chips click
modal.querySelectorAll('.yaktube-modal-chip').forEach(function (chip) {
chip.addEventListener('click', function () {
var query = chip.getAttribute('data-query');
executeSearch(query);
});
});
// Voice button click
voiceBtn.addEventListener('click', function () {
toggleVoiceInsideModal();
});
micPulseBtn.addEventListener('click', function () {
toggleVoiceInsideModal();
});
return modal;
}
function openFullSearchModal(initialQuery, autoStartVoice) {
var modal = createFullSearchModal();
modal.style.display = 'flex';
var inp = modal.querySelector('#yaktube-modal-input');
var clearBtn = modal.querySelector('#yaktube-modal-clear-btn');
if (inp) {
inp.value = initialQuery || '';
if (inp.value) clearBtn.style.display = 'inline-flex';
setTimeout(function () {
inp.focus();
inp.select();
}, 50);
}
announce('Arama penceresi açıldı. Arayacağınız konuyu yazın veya sesle arayın.', true);
if (autoStartVoice) {
startVoiceInsideModal();
}
}
function closeFullSearchModal() {
var modal = document.getElementById('yaktube-full-search-modal');
if (modal) modal.style.display = 'none';
stopVoiceInsideModal();
announce('Arama penceresi kapatıldı.');
}
function toggleVoiceInsideModal() {
if (isVoiceListening) {
stopVoiceInsideModal();
} else {
startVoiceInsideModal();
}
}
function startVoiceInsideModal() {
var SpeechRec = window.SpeechRecognition || window.webkitSpeechRecognition;
var modal = document.getElementById('yaktube-full-search-modal');
if (!modal) return;
var voiceSec = modal.querySelector('#yaktube-modal-voice-section');
var statusText = modal.querySelector('#yaktube-modal-voice-status');
var transcriptEl = modal.querySelector('#yaktube-modal-voice-transcript');
var inp = modal.querySelector('#yaktube-modal-input');
if (voiceSec) voiceSec.style.display = 'block';
if (statusText) statusText.textContent = '🎙️ Dinleniyor...';
if (transcriptEl) transcriptEl.textContent = 'Lütfen aramak istediğiniz videoyu söyleyin...';
if (!SpeechRec) {
if (statusText) statusText.textContent = 'Tarayıcıda Ses Tanıma Desteklenmiyor';
if (transcriptEl) transcriptEl.textContent = 'Lütfen Google Chrome veya Microsoft Edge kullanın.';
announce('Tarayıcınız ses tanımayı desteklemiyor. Lütfen Chrome veya Edge kullanın.');
return;
}
announce('Sesli arama dinleniyor, lütfen aramak istediğiniz videoyu söyleyin.', true);
try {
activeVoiceRec = new SpeechRec();
activeVoiceRec.lang = navigator.language || 'tr-TR';
activeVoiceRec.continuous = false;
activeVoiceRec.interimResults = true;
activeVoiceRec.maxAlternatives = 1;
isVoiceListening = true;
activeVoiceRec.onresult = function (ev) {
if (ev.results && ev.results[0]) {
var transcript = ev.results[0][0].transcript.trim();
if (transcriptEl) transcriptEl.textContent = '"' + transcript + '"';
if (inp) inp.value = transcript;
if (ev.results[0].isFinal) {
announce('"' + transcript + '" için arama başlatılıyor...', true);
setTimeout(function () {
closeFullSearchModal();
window.location.href = '/search/videos?search=' + encodeURIComponent(transcript);
}, 500);
}
}
};
activeVoiceRec.onerror = function (ev) {
if (statusText) statusText.textContent = 'Ses Algılanamadı';
if (transcriptEl) transcriptEl.textContent = 'Tekrar denemek için mikrofona dokunun.';
stopVoiceInsideModal();
};
activeVoiceRec.onend = function () {
stopVoiceInsideModal();
};
activeVoiceRec.start();
} catch (err) {
stopVoiceInsideModal();
}
}
function stopVoiceInsideModal() {
isVoiceListening = false;
if (activeVoiceRec) {
try {
activeVoiceRec.stop();
} catch (e) {}
activeVoiceRec = null;
}
var modal = document.getElementById('yaktube-full-search-modal');
if (modal) {
var voiceSec = modal.querySelector('#yaktube-modal-voice-section');
if (voiceSec) voiceSec.style.display = 'none';
}
}
function transformToYouTubeSearchBar(searchInp, searchContainer) {
if (searchContainer.hasAttribute('data-yaktube-trigger-styled')) return;
searchContainer.setAttribute('data-yaktube-trigger-styled', 'true');
// Hide original native inputs
searchInp.style.display = 'none';
searchInp.setAttribute('tabindex', '-1');
searchInp.setAttribute('aria-hidden', 'true');
var nativeInputs = searchContainer.querySelectorAll('input, button');
nativeInputs.forEach(function (el) {
if (!el.classList.contains('yaktube-search-trigger-pill') && !el.classList.contains('yaktube-voice-search-btn')) {
el.style.display = 'none';
el.setAttribute('tabindex', '-1');
el.setAttribute('aria-hidden', 'true');
}
});
// 1. Create Outer Wrapper
var outerWrap = searchContainer.querySelector('.yaktube-search-outer-wrap');
if (!outerWrap) {
outerWrap = document.createElement('div');
outerWrap.className = 'yaktube-search-outer-wrap';
searchContainer.appendChild(outerWrap);
}
// 2. Create Single Sleek Pill Trigger
var triggerPill = outerWrap.querySelector('.yaktube-search-trigger-pill');
if (!triggerPill) {
triggerPill = document.createElement('button');
triggerPill.type = 'button';
triggerPill.className = 'yaktube-search-trigger-pill';
triggerPill.setAttribute('aria-label', 'Ara');
triggerPill.setAttribute('title', 'Arama Yap (/)');
triggerPill.innerHTML =
'🔍 ' +
'Ara... ' +
'/ ';
outerWrap.appendChild(triggerPill);
triggerPill.addEventListener('click', function (e) {
e.preventDefault();
openFullSearchModal('', false);
});
}
// 3. YouTube Circular Voice Button (🎙️) Beside the Pill Box
var voiceBtn = outerWrap.querySelector('.yaktube-voice-search-btn');
if (!voiceBtn) {
voiceBtn = document.createElement('button');
voiceBtn.type = 'button';
voiceBtn.className = 'yaktube-voice-search-btn';
voiceBtn.setAttribute('aria-label', 'Sesle Ara (Shift+V)');
voiceBtn.setAttribute('title', 'Sesle Ara (Shift+V)');
voiceBtn.innerHTML = '🎙️';
outerWrap.appendChild(voiceBtn);
voiceBtn.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
openFullSearchModal('', true);
});
}
}
function injectSearchEnhancements() {
var searchContainers = document.querySelectorAll(
'my-search-typeahead, .search-container, .header-search, my-header .search'
);
searchContainers.forEach(function (container) {
var searchInp = container.querySelector('input[type="search"], input[type="text"], input');
if (searchInp) {
transformToYouTubeSearchBar(searchInp, container);
}
});
// Clean up repetitive card titles and strange relative date buttons
document.querySelectorAll('my-video-miniature, .video-miniature').forEach(function (card) {
var thumbLink = card.querySelector('a.thumbnail-link, .video-thumbnail a, a.thumbnail');
if (thumbLink && !thumbLink.hasAttribute('aria-hidden')) {
thumbLink.setAttribute('aria-hidden', 'true');
thumbLink.setAttribute('tabindex', '-1');
}
var dateBtn = card.querySelector('.video-date-line button, .video-date button, button[title*="tarih"]');
if (dateBtn && !dateBtn.hasAttribute('data-cleaned')) {
dateBtn.setAttribute('data-cleaned', 'true');
var dateText = dateBtn.textContent.trim();
dateBtn.setAttribute('aria-label', dateText);
}
});
}
// Global Keyboard Shortcuts
document.addEventListener('keydown', function (e) {
var activeTag = document.activeElement ? document.activeElement.tagName.toLowerCase() : '';
var isInputActive = activeTag === 'input' || activeTag === 'textarea';
// Shift + V: Open YouTube Voice Search Modal
if (e.shiftKey && (e.key === 'V' || e.key === 'v') && !isInputActive) {
e.preventDefault();
openFullSearchModal('', true);
}
// Escape: Close Full Search Modal
else if (e.key === 'Escape' || e.keyCode === 27) {
var modal = document.getElementById('yaktube-full-search-modal');
if (modal && modal.style.display === 'flex') {
e.preventDefault();
closeFullSearchModal();
}
}
// / or S: Open Search Modal
else if ((e.key === '/' || e.key === 's' || e.key === 'S') && !isInputActive && !e.ctrlKey && !e.metaKey) {
e.preventDefault();
openFullSearchModal('', false);
}
});
// 7.5. Reactive Hybrid Related Videos Engine (Watch Page)
var currentActiveVideoKey = null;
var isFetchingRelated = false;
var relatedShowAll = false;
var cachedRelatedResults = [];
var cachedRelatedQuery = '';
function renderRelatedCards(container, results, query) {
var count = results ? results.length : 0;
if (count === 0) {
container.style.display = 'none';
return;
}
container.style.display = 'block';
var limit = relatedShowAll ? count : Math.min(count, 12);
var displayed = results.slice(0, limit);
var cardsHtml = '';
displayed.forEach(function (item) {
var isLocal = !!item.isDownloaded;
var statusBadge = isLocal
? '✅ ' +
getInstanceName() +
"'da İzle "
: '⚡ Canlı Keşif ';
var actionButton = isLocal
? '▶️ Hemen İzle '
: '📥 İndir ve İzle ';
var cardLabel =
item.title +
(isLocal ? ' (' + getInstanceName() + ' kütüphanenizde mevcut)' : ' (Canlı YouTube keşfi)') +
', ' +
item.channel +
' kanalı, Süre: ' +
item.durationFormatted;
cardsHtml +=
'' +
'
' +
'
' +
'
' +
item.durationFormatted +
' ' +
'
' +
'
' +
'
' +
statusBadge +
'
' +
item.title +
' ' +
'
' +
item.channel +
'
' +
'
' +
actionButton +
'
' +
'
';
});
var loadMoreBtn = '';
if (count > 12) {
if (!relatedShowAll) {
loadMoreBtn =
'' +
'➕ Daha Fazla Öneri Göster (' +
(count - 12) +
' video daha)' +
' ';
} else {
loadMoreBtn =
'' +
'🔼 Daha Az Göster' +
' ';
}
}
var headerCountText = count > 12 && !relatedShowAll ? displayed.length + ' / ' + count : count;
container.innerHTML =
'' +
'' +
cardsHtml +
'
' +
loadMoreBtn;
var toggleBtn = document.getElementById('yaktube-related-toggle-more');
if (toggleBtn) {
toggleBtn.addEventListener('click', function () {
relatedShowAll = !relatedShowAll;
renderRelatedCards(container, cachedRelatedResults, cachedRelatedQuery);
announce(
relatedShowAll ? 'Tüm ' + cachedRelatedResults.length + ' önerilen video açıldı.' : 'Öneriler daraltıldı.'
);
});
}
var refreshBtn = document.getElementById('yaktube-related-refresh-btn');
if (refreshBtn) {
refreshBtn.addEventListener('click', function () {
currentActiveVideoKey = null;
checkAndInjectRelatedVideos(true);
});
}
container.querySelectorAll('.yaktube-related-import').forEach(function (btn) {
btn.addEventListener('click', function (e) {
var videoUrl = e.currentTarget.getAttribute('data-url');
var videoTitle = e.currentTarget.getAttribute('data-title');
handleImport(videoUrl, e.currentTarget, videoTitle);
});
});
container.querySelectorAll('.yaktube-related-play-link').forEach(function (link) {
link.addEventListener('click', function () {
currentActiveVideoKey = null;
});
});
}
function checkAndInjectRelatedVideos(forceReload) {
var isWatchPage = window.location.pathname.includes('/videos/watch/') || window.location.pathname.startsWith('/w/');
if (!isWatchPage) {
var existing = document.getElementById('yaktube-hybrid-related-container');
if (existing) existing.remove();
currentActiveVideoKey = null;
return;
}
var titleElem =
document.querySelector('h1.video-name') ||
document.querySelector('.video-info h1') ||
document.querySelector('.video-watch-heading h1') ||
document.querySelector('h1') ||
document.querySelector('.title');
var rawTitle = titleElem ? (titleElem.textContent || titleElem.innerText || '').trim() : '';
if (!rawTitle || rawTitle.length < 3) {
return;
}
var currentPath = window.location.pathname;
var thisVideoKey = currentPath + '::' + rawTitle.toLowerCase();
if (
!forceReload &&
thisVideoKey === currentActiveVideoKey &&
document.getElementById('yaktube-hybrid-related-container')
) {
return;
}
if (isFetchingRelated) return;
isFetchingRelated = true;
var cleanTopic = rawTitle
.replace(/YakTube/gi, '')
.replace(/[\(\[].*?[\)\]]/g, '')
.replace(/official video|video klip|klip|hd|4k|lyric video|audio|remix|feat\.?|ft\.?/gi, '')
.trim();
var words = cleanTopic.split(/\s+/).filter(function (w) {
return w.length > 2;
});
var searchQuery = words.slice(0, 3).join(' ') || cleanTopic;
var container = document.getElementById('yaktube-hybrid-related-container');
if (!container) {
container = document.createElement('div');
container.id = 'yaktube-hybrid-related-container';
container.className = 'yaktube-ondemand-section';
container.setAttribute('role', 'region');
container.setAttribute('aria-label', 'YakTube Akıllı Önerilen Videolar');
}
var recVideosMount = document.querySelector('my-recommended-videos, .other-videos');
var commentsMount = document.querySelector('#yaktube-watch-comments-panel, my-video-comments, .video-comments');
var videoBottomMount = document.querySelector('.video-bottom, .video-info');
var watchMount = document.querySelector('my-video-watch') || document.querySelector('main');
if (recVideosMount) {
if (container.parentElement !== recVideosMount) {
recVideosMount.prepend(container);
}
} else if (commentsMount) {
if (container.previousElementSibling !== commentsMount) {
commentsMount.insertAdjacentElement('afterend', container);
}
} else if (videoBottomMount) {
if (container.previousElementSibling !== videoBottomMount) {
videoBottomMount.insertAdjacentElement('afterend', container);
}
} else if (watchMount) {
if (container.parentElement !== watchMount) {
watchMount.appendChild(container);
}
} else {
isFetchingRelated = false;
return;
}
container.innerHTML =
'' +
'' +
'
' +
'
YouTube ve Fediverse\'deki en alakalı videolar getiriliyor...
' +
'
';
announce(searchQuery + ' için ilgili video önerileri yükleniyor.');
fetch('/api-custom/youtube-search?q=' + encodeURIComponent(searchQuery))
.then(function (res) {
return res.json();
})
.then(function (data) {
var rawResults = data.results || [];
var normalizedCurrentTitle = rawTitle.toLowerCase().trim();
var uniqueResults = [];
var seenIds = {};
rawResults.forEach(function (item) {
if (item && item.id && !seenIds[item.id] && item.title) {
var itemTitle = item.title.toLowerCase().trim();
if (itemTitle !== normalizedCurrentTitle && !itemTitle.includes(normalizedCurrentTitle)) {
seenIds[item.id] = true;
uniqueResults.push(item);
}
}
});
cachedRelatedResults = uniqueResults;
cachedRelatedQuery = searchQuery;
currentActiveVideoKey = thisVideoKey;
relatedShowAll = false;
renderRelatedCards(container, uniqueResults, searchQuery);
var initialCount = Math.min(uniqueResults.length, 12);
if (uniqueResults.length === 0) {
announce(searchQuery + ' için ilgili öneri bulunamadı.');
} else {
announce(
searchQuery +
' için ' +
initialCount +
' öneri gösteriliyor' +
(uniqueResults.length > 12 ? ', toplam ' + uniqueResults.length + ' video bulundu' : '') +
'.'
);
}
})
.catch(function (err) {
console.error('[YakTube] Related fetch error:', err);
container.style.display = 'none';
})
.finally(function () {
isFetchingRelated = false;
});
}
var lastWatchUuid = null;
function checkAndInjectWatchPageComments() {
var pathname = window.location.pathname;
var match = pathname.match(/\/videos\/watch\/([a-zA-Z0-9_-]+)/) || pathname.match(/\/w\/([a-zA-Z0-9_-]+)/);
if (!match) {
lastWatchUuid = null;
var existingWatchComments = document.getElementById('yaktube-watch-comments-panel');
if (existingWatchComments) existingWatchComments.remove();
return;
}
var uuid = match[1];
var existingPanel = document.getElementById('yaktube-watch-comments-panel');
if (uuid === lastWatchUuid && existingPanel) {
var nativeComments = document.querySelector('my-video-comments, .video-comments, .comments-block, #comments');
if (nativeComments && existingPanel.previousElementSibling !== nativeComments) {
nativeComments.insertAdjacentElement('afterend', existingPanel);
}
return;
}
lastWatchUuid = uuid;
var mountTarget =
document.querySelector('my-video-comments, .video-comments, my-video-watch, .video-bottom') || document.body;
if (!mountTarget) return;
fetch('/api-custom/video-origin/' + encodeURIComponent(uuid))
.then(function (r) {
return r.json();
})
.then(function (originData) {
if (!originData || !originData.ok || !originData.hasYouTubeOrigin || !originData.youtubeId) {
var old = document.getElementById('yaktube-watch-comments-panel');
if (old) old.remove();
return;
}
var youtubeId = originData.youtubeId;
var existing = document.getElementById('yaktube-watch-comments-panel');
if (existing) existing.remove();
var panel = document.createElement('div');
panel.id = 'yaktube-watch-comments-panel';
panel.className = 'yaktube-comments-panel';
panel.setAttribute('role', 'region');
panel.setAttribute('aria-label', 'YouTube Orijinal Yorumlar\u0131');
panel.style.cssText =
'margin-top: 24px; margin-bottom: 24px; background: #0f172a; border-radius: 12px; padding: 20px; border: 1px solid rgba(255,255,255,0.08); box-shadow: 0 8px 24px rgba(0,0,0,0.4);';
panel.innerHTML =
'' +
'
' +
'
' +
"\ud83d\udcac YouTube'daki Orijinal Yorumlar" +
' ' +
'
Bu video YouTube\'dan aktar\u0131lm\u0131\u015ft\u0131r. Orijinal topluluk yorumlar\u0131n\u0131 a\u015fa\u011f\u0131dan anl\u0131k olarak y\u00fckleyebilirsiniz.
' +
'
' +
'' +
'
' +
'' +
'';
var nativeComments = document.querySelector('my-video-comments, .video-comments, .comments-block, #comments');
if (nativeComments && nativeComments.parentElement) {
nativeComments.insertAdjacentElement('afterend', panel);
} else {
var watchCol = document.querySelector('.video-info, .video-bottom, my-video-watch, .main-col');
if (watchCol) {
watchCol.appendChild(panel);
} else {
mountTarget.appendChild(panel);
}
}
var watchCommentToken = null;
var listContainer = document.getElementById('yaktube-watch-comments-list');
var toggleBtn = document.getElementById('yaktube-watch-toggle-comments-btn');
var moreWrap = document.getElementById('yaktube-watch-more-comments-wrap');
var moreBtn = document.getElementById('yaktube-watch-more-comments-btn');
function fetchWatchComments(token) {
if (!token) {
toggleBtn.disabled = true;
toggleBtn.textContent = '⏳ Yorumlar Y\u00fckleniyor...';
} else {
moreBtn.disabled = true;
moreBtn.textContent = '⏳ Y\u00fckleniyor...';
}
var fUrl =
'/api-custom/youtube-comments?id=' +
encodeURIComponent(youtubeId) +
(token ? '&token=' + encodeURIComponent(token) : '');
fetch(fUrl)
.then(function (r) {
return r.json();
})
.then(function (res) {
if (!token) {
listContainer.innerHTML = '';
listContainer.style.display = 'flex';
toggleBtn.textContent = '🔄 Yorumlar\u0131 Yenile';
toggleBtn.disabled = false;
} else {
moreBtn.textContent = '➕ Daha Fazla Yorum G\u00f6ster (+20 Yorum)';
moreBtn.disabled = false;
}
var cList = res.comments || [];
if (cList.length === 0 && !token) {
listContainer.innerHTML =
'Bu videoda hen\u00fcz YouTube yorumu bulunmuyor.
';
moreWrap.style.display = 'none';
announce('Bu videoda henüz YouTube yorumu bulunmuyor.');
return;
}
cList.forEach(function (c) {
var card = document.createElement('div');
card.className = 'yaktube-comment-item';
card.setAttribute('role', 'article');
card.setAttribute('tabindex', '0');
card.setAttribute('aria-label', c.author + ' isimli kullan\u0131c\u0131n\u0131n yorumu: ' + c.content);
card.style.cssText =
'background: #1e293b; padding: 14px 16px; border-radius: 8px; border: 1px solid rgba(255,255,255,0.05); display: flex; gap: 12px; align-items: flex-start;';
var avatarLetter = (c.author || 'U').replace('@', '').charAt(0).toUpperCase();
var avatarHtml =
'' +
avatarLetter +
'
';
var safeContent = c.content
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/\n/g, ' ');
card.innerHTML =
avatarHtml +
'' +
'
' +
'' +
'' +
c.published +
' ' +
(c.likeCount && c.likeCount !== '0'
? '👍 ' +
c.likeCount +
' '
: '') +
'
' +
'
' +
safeContent +
'
' +
'
';
listContainer.appendChild(card);
});
watchCommentToken = res.nextToken;
if (watchCommentToken) {
moreWrap.style.display = 'block';
} else {
moreWrap.style.display = 'none';
}
announce(cList.length + ' adet YouTube yorumu y\u00fcklendi.');
})
.catch(function (err) {
if (!token) {
toggleBtn.disabled = false;
toggleBtn.textContent = '⚠️ Tekrar Dene';
} else {
moreBtn.disabled = false;
moreBtn.textContent = '⚠️ Tekrar Dene';
}
alert('Yorumlar y\u00fcklenirken hata olu\u015ftu: ' + err.message);
});
}
if (toggleBtn) {
toggleBtn.addEventListener('click', function () {
fetchWatchComments(null);
});
}
if (moreBtn) {
moreBtn.addEventListener('click', function () {
if (watchCommentToken) fetchWatchComments(watchCommentToken);
});
}
})
.catch(function () {});
}
// 6. PWA Mobile App Install Engine & Standalone Detection
var isInsideYakTubeApp =
navigator.userAgent.indexOf('YakTubeMobileApp') !== -1 ||
window.matchMedia('(display-mode: standalone)').matches ||
window.navigator.standalone === true;
var isMobileDevice = /Android|iPhone|iPad|iPod|Mobile|Tablet/i.test(navigator.userAgent);
var deferredInstallPrompt = null;
window.addEventListener('beforeinstallprompt', function (e) {
if (isInsideYakTubeApp) return;
e.preventDefault();
deferredInstallPrompt = e;
injectPWAInstallButton();
});
function injectPWAInstallButton() {
if (isInsideYakTubeApp) {
var existBtn = document.getElementById('yaktube-pwa-install-btn');
if (existBtn) {
existBtn.setAttribute('aria-hidden', 'true');
existBtn.remove();
}
return;
}
if (!deferredInstallPrompt || document.getElementById('yaktube-pwa-install-btn')) return;
var headerButtons =
document.querySelector('my-header .buttons-container') ||
document.querySelector('.buttons-container') ||
document.querySelector('my-header');
if (!headerButtons) return;
var installBtn = document.createElement('button');
installBtn.id = 'yaktube-pwa-install-btn';
installBtn.className = 'yaktube-pwa-btn';
installBtn.setAttribute('type', 'button');
installBtn.setAttribute('aria-label', 'YakTube Mobil Uygulamasını Yükle');
installBtn.style.cssText =
'background: linear-gradient(135deg, #ff8f37, #f97316); color: #000; border: none; padding: 6px 14px; border-radius: 20px; font-weight: 700; font-size: 12px; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; margin-right: 8px; box-shadow: 0 4px 12px rgba(255,143,55,0.4);';
installBtn.innerHTML = '📲 Uygulamayı Yükle';
installBtn.addEventListener('click', function () {
if (deferredInstallPrompt) {
deferredInstallPrompt.prompt();
deferredInstallPrompt.userChoice.then(function (choiceResult) {
if (choiceResult.outcome === 'accepted') {
installBtn.remove();
announce('YakTube uygulaması cihazınıza yükleniyor.');
}
deferredInstallPrompt = null;
});
}
});
headerButtons.prepend(installBtn);
}
function injectApkDownloadButton() {
// 1. If inside APK: NEVER show APK button
if (isInsideYakTubeApp) {
var existBtnApp = document.getElementById('yaktube-apk-download-btn');
if (existBtnApp) {
existBtnApp.setAttribute('aria-hidden', 'true');
existBtnApp.remove();
}
return;
}
// 2. If on Desktop: NEVER show in top header (keep header clean)
if (!isMobileDevice) {
var existBtnDesktop = document.getElementById('yaktube-apk-download-btn');
if (existBtnDesktop) {
existBtnDesktop.setAttribute('aria-hidden', 'true');
existBtnDesktop.remove();
}
return;
}
// 3. If on Mobile Web: Show in header
if (document.getElementById('yaktube-apk-download-btn')) return;
var headerButtons =
document.querySelector('my-header .buttons-container') ||
document.querySelector('my-header .header-right') ||
document.querySelector('.buttons-container') ||
document.querySelector('my-header');
if (!headerButtons) return;
var apkBtn = document.createElement('a');
apkBtn.id = 'yaktube-apk-download-btn';
apkBtn.href = '/yaktube.apk';
apkBtn.className = 'yaktube-apk-btn';
apkBtn.setAttribute('download', 'YakTube_Mobile_v1.0.apk');
apkBtn.setAttribute('aria-label', 'YakTube Android APK İndir (4.5 MB)');
apkBtn.style.cssText =
'background: #1e293b; color: #ff8f37; border: 1px solid #ff8f37; padding: 6px 12px; border-radius: 20px; font-weight: 700; font-size: 11px; text-decoration: none; display: inline-flex; align-items: center; gap: 4px; margin-right: 6px; transition: all 0.2s; box-shadow: 0 4px 12px rgba(0,0,0,0.3);';
apkBtn.innerHTML = '🤖 APK İndir (4.5 MB)';
headerButtons.prepend(apkBtn);
}
function injectSidebarApkLink() {
// If inside APK: NEVER show in sidebar
if (isInsideYakTubeApp) {
var existLink = document.getElementById('yaktube-sidebar-apk-link');
if (existLink) {
existLink.setAttribute('aria-hidden', 'true');
existLink.remove();
}
return;
}
if (document.getElementById('yaktube-sidebar-apk-link')) return;
var menuContainer = document.querySelector('my-menu, .menu, .main-menu, .nav-list');
if (!menuContainer) return;
var sidebarLink = document.createElement('a');
sidebarLink.id = 'yaktube-sidebar-apk-link';
sidebarLink.href = '/yaktube.apk';
sidebarLink.className = 'menu-link item-link';
sidebarLink.setAttribute('download', 'YakTube_Mobile_v1.0.apk');
sidebarLink.setAttribute('aria-label', 'YakTube Android Uygulamasını İndir (4.5 MB)');
sidebarLink.style.cssText =
'display: flex; align-items: center; gap: 10px; padding: 10px 16px; margin: 8px 12px; background: rgba(255, 143, 55, 0.1); color: #ff8f37; border: 1px solid rgba(255, 143, 55, 0.3); border-radius: 8px; font-weight: 700; font-size: 13px; text-decoration: none;';
sidebarLink.innerHTML = '🤖 YakTube Android APK (4.5 MB) ';
menuContainer.appendChild(sidebarLink);
}
setInterval(function () {
checkAndInjectSearchResults();
injectSearchEnhancements();
checkAndInjectRelatedVideos(false);
restoreActiveLiveStream();
checkAndInjectWatchPageComments();
injectPWAInstallButton();
injectApkDownloadButton();
injectSidebarApkLink();
}, 800);
restoreActiveLiveStream();
window.addEventListener('popstate', function () {
currentActiveVideoKey = null;
checkAndInjectSearchResults();
checkAndInjectRelatedVideos(true);
checkAndInjectWatchPageComments();
});
checkAndInjectWatchPageComments();
})();