' +
- '
⌨️ Klavye Kısayolları (Ekran Okuyucu Uyumlu) ' +
- '
✕ ' +
+ '
' +
+ '
' +
+ '
⚙️ Sunucu Yöneticisi Girişi ' +
+ '✕ ' +
'' +
- '
💡 Ekran Okuyucu Notu: Sanal imleç (Browse mode) açıkken kısayolları Alt tuşuyla birlikte kullanabilir veya video oynatıcı butonlarından faydalanabilirsiniz.
' +
- '
' +
- 'Kısayol (Evrensel / Tek Tuş) İşlev ' +
- '' +
- 'Alt + K veya Space Oynat / Duraklat ' +
- 'Alt + J veya J 10 saniye geri sar ' +
- 'Alt + L veya L 10 saniye ileri sar ' +
- 'Alt + Yukarı / Aşağı Sesi %5 artır / azalt ' +
- 'Alt + M veya M Sesi Kapat / Aç (Mute) ' +
- 'Alt + T veya T Sinema / Tiyatro Modu ' +
- 'Alt + I veya I Hızlı Video Bilgisi & İstatistikler ' +
- 'Alt + C veya C Altyazıları Aç / Kapat ' +
- 'Alt + . / Alt + , Oynatma hızını artır / azalt ' +
- 'Alt + S veya / (Shift+7)Arama penceresini aç ' +
- 'Alt + V veya Shift + V Sesli aramayı başlat ' +
- 'Alt + H veya F1 veya ? Bu kılavuzu aç / kapat ' +
- ' ' +
- '
' +
+ '
Yerel yönetici (admin) kullanıcı adı ve şifrenizle giriş yaparak PeerTube yönetim paneline erişebilirsiniz.
' +
+ '
' +
'
';
+
document.body.appendChild(modal);
- var closeBtn = modal.querySelector('#yaktube-shortcuts-close');
- if (closeBtn) {
- closeBtn.addEventListener('click', function () {
- modal.style.display = 'none';
- });
- }
+ modal.querySelector('#yaktube-admin-modal-close').addEventListener('click', function () {
+ modal.style.display = 'none';
+ });
modal.addEventListener('click', function (e) {
if (e.target === modal) modal.style.display = 'none';
});
- announce('Klavye kısayolları yardım penceresi açıldı. Kapatmak için Escape tuşuna basın.');
- }
- }
+ var form = modal.querySelector('#yaktube-admin-direct-form');
+ var errEl = modal.querySelector('#yaktube-admin-login-error');
+ var uInput = modal.querySelector('#yaktube-admin-username');
+ var pInput = modal.querySelector('#yaktube-admin-password');
+ var sBtn = modal.querySelector('#yaktube-admin-login-submit');
- 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;
- }
+ uInput.focus();
- function getVideoElement() {
- return document.querySelector('video');
- }
+ form.addEventListener('submit', async function (ev) {
+ ev.preventDefault();
+ errEl.style.display = 'none';
+ sBtn.disabled = true;
+ sBtn.innerText = 'Giriş Yapılıyor...';
- 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';
- }
+ try {
+ var clientRes = await fetch('/api/v1/oauth-clients/local');
+ var clientData = await clientRes.json();
- function showQuickVideoInfo() {
- var video = getVideoElement();
- if (!video) {
- announce('Şu anda aktif oynatılan bir video bulunmuyor.');
- return;
- }
+ var bodyParams = new URLSearchParams({
+ client_id: clientData.client_id,
+ client_secret: clientData.client_secret,
+ grant_type: 'password',
+ username: uInput.value.trim(),
+ password: pInput.value
+ });
- var titleEl = document.querySelector('h1.video-title, .video-name, my-video-watch h1, .title');
- var title = titleEl ? titleEl.textContent.trim() : 'Video';
- var curTime = formatTime(video.currentTime);
- var totalTime = formatTime(video.duration || 0);
- var remaining = formatTime((video.duration || 0) - video.currentTime);
- var speed = (video.playbackRate || 1) + 'x';
- var volume = Math.round((video.volume || 1) * 100) + '%';
- var quality = video.videoHeight ? video.videoHeight + 'p' : 'Otomatik';
+ var tokenRes = await fetch('/api/v1/users/token', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: bodyParams.toString()
+ });
- // Visual Toast
- var existingToast = document.querySelector('.yaktube-video-info-toast');
- if (existingToast) existingToast.remove();
+ var tokenData = await tokenRes.json();
+ if (!tokenRes.ok || !tokenData.access_token) {
+ throw new Error(tokenData.error_description || tokenData.error || 'Kullanıcı adı veya şifre hatalı.');
+ }
- var toast = document.createElement('div');
- toast.className = 'yaktube-video-info-toast';
- toast.innerHTML =
- '
📊 Video Bilgisi & Durum
' +
- '
Başlık: ' +
- (title.length > 28 ? title.substring(0, 28) + '...' : title) +
- '
' +
- '
Konum / Süre: ' +
- curTime +
- ' / ' +
- totalTime +
- '
' +
- '
Kalan Süre: ' +
- remaining +
- '
' +
- '
Çözünürlük: ' +
- quality +
- '
' +
- '
Hız & Ses: ' +
- speed +
- ' | ' +
- volume +
- '
';
+ // Store tokens
+ localStorage.setItem('access_token', tokenData.access_token);
+ localStorage.setItem('refresh_token', tokenData.refresh_token);
+ localStorage.setItem('token_type', tokenData.token_type || 'Bearer');
+ localStorage.setItem('username', uInput.value.trim());
- document.body.appendChild(toast);
- setTimeout(function () {
- if (toast.parentElement) toast.remove();
- }, 4000);
+ // Get user details
+ var meRes = await fetch('/api/v1/users/me', {
+ headers: { Authorization: 'Bearer ' + tokenData.access_token }
+ });
+ if (meRes.ok) {
+ var meData = await meRes.json();
+ localStorage.setItem('email', meData.email || '');
+ localStorage.setItem('displayName', meData.displayName || meData.username || '');
+ }
- announce(
- 'Video Bilgisi: ' +
- title +
- '. Konum: ' +
- curTime +
- ', Toplam Süre: ' +
- totalTime +
- ', Kalan: ' +
- remaining +
- ', Oynatma Hızı: ' +
- speed +
- ', Ses: yüzde ' +
- Math.round(video.volume * 100) +
- ', Çözünürlük: ' +
- quality,
- true
- );
- }
-
- var speedSteps = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
-
- function adjustPlaybackSpeed(increase) {
- var video = getVideoElement();
- if (!video) return;
- var curSpeed = video.playbackRate || 1;
- if (increase) {
- var nextIdx = speedSteps.findIndex(function (s) {
- return s > curSpeed;
+ announce('Yönetici girişi başarılı! Yönetim paneline yönlendiriliyorsunuz.', true);
+ window.location.href = '/admin';
+ } catch (err) {
+ errEl.innerText = err.message;
+ errEl.style.display = 'block';
+ sBtn.disabled = false;
+ sBtn.innerText = 'Yönetici Olarak Giriş Yap';
+ }
});
- video.playbackRate = nextIdx !== -1 ? speedSteps[nextIdx] : 2;
- announce('Oynatma hızı ' + video.playbackRate + ' katına çıkarıldı.');
- } else {
- var prevSteps = speedSteps.filter(function (s) {
- return s < curSpeed;
- });
- video.playbackRate = prevSteps.length > 0 ? prevSteps[prevSteps.length - 1] : 0.25;
- announce('Oynatma hızı ' + video.playbackRate + ' katına düşürüldü.');
- }
- }
-
- // 3.1. Injects Accessible Player Action Bar under the Watch Video
- function injectAccessiblePlayerBar() {
- if (!window.location.pathname.includes('/videos/watch/')) return;
- var video = getVideoElement();
- if (!video) return;
-
- var targetContainer = document.querySelector(
- 'my-video-watch, .video-watch, .watch-container, #yaktube-ondemand-container'
- );
- if (!targetContainer) return;
-
- var existingBar = document.getElementById('yaktube-player-action-bar');
- if (existingBar) return;
-
- var bar = document.createElement('div');
- bar.id = 'yaktube-player-action-bar';
- bar.className = 'yaktube-player-action-bar';
- bar.setAttribute('role', 'toolbar');
- bar.setAttribute('aria-label', 'Erişilebilir Video Kontrolleri');
-
- bar.innerHTML =
- '
⚡ Oynatıcı Kontrolleri: ' +
- '
⏪ 10sn Geri ' +
- '
⏯️ Oynat/Duraklat ' +
- '
⏩ 10sn İleri ' +
- '
⚡ Hız ' +
- '
🎭 Sinema ' +
- '
📊 Bilgi ' +
- '
⌨️ Kısayollar ';
-
- var playerWrap =
- document.querySelector('.player-container, .video-player-container, .player-wrapper, my-video-watch .player') ||
- targetContainer;
- if (playerWrap && playerWrap.nextSibling) {
- playerWrap.parentNode.insertBefore(bar, playerWrap.nextSibling);
- } else {
- targetContainer.prepend(bar);
}
- // Attach button actions
- bar.querySelector('#yaktube-bar-rewind-btn').addEventListener('click', function () {
- if (video) {
- video.currentTime = Math.max(0, video.currentTime - 10);
- announce('10 saniye geri sarıldı. Konum: ' + formatTime(video.currentTime));
+ // 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 defaultLoginLink = headerRight.querySelector('my-login-link, a[href*="/login"], .login-button');
+ var liveWidget = headerRight.querySelector('#yaknet-header-account-widget');
+
+ if (isAuth) {
+ // Logged In: Show YakNet Profile Menu, Hide default login link
+ if (defaultLoginLink) {
+ defaultLoginLink.style.display = 'none';
+ defaultLoginLink.setAttribute('aria-hidden', 'true');
+ }
+
+ 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('.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);
+ }
+ } else {
+ 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
+ );
+ }
+ }
+
+ if (el.getAttribute('authenticated') !== 'true' || el.getAttribute('user-name') !== displayName) {
+ el.setAttribute('authenticated', 'true');
+ el.setAttribute('user-name', displayName);
+ el.setAttribute('user-email', emailStr);
+ if (typeof el.syncStateFromAttributes === 'function') {
+ el.syncStateFromAttributes();
+ el.render();
+ }
+ }
+ }
+ }
+ } else {
+ // Not Logged In: Remove YakNet widget to eliminate duplicate button, keep PeerTube native login button clean
+ if (liveWidget) {
+ liveWidget.remove();
+ }
+ if (defaultLoginLink) {
+ defaultLoginLink.style.display = '';
+ defaultLoginLink.removeAttribute('aria-hidden');
+
+ var loginAnchor =
+ defaultLoginLink.tagName.toLowerCase() === 'a' ? defaultLoginLink : defaultLoginLink.querySelector('a');
+ if (loginAnchor) {
+ loginAnchor.setAttribute('aria-label', 'YakNet ile Giriş Yap');
+ loginAnchor.setAttribute('title', 'YakNet Hesabınız ile Giriş Yapın');
+ var spanText = loginAnchor.querySelector('span');
+ if (spanText) {
+ spanText.textContent = 'YakNet ile Giriş Yap';
+ } else {
+ loginAnchor.textContent = 'YakNet ile Giriş Yap';
+ }
+ }
+ }
+ }
}
- });
- bar.querySelector('#yaktube-bar-play-btn').addEventListener('click', function () {
- if (video) {
+ // 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();
+ openLocalAdminLoginModal();
+ });
+ }
+ }
+ }
+ }
+
+ // 3. Intelligent Branding & A11y DOM Auto-Fixer
+ function autoFixDOM() {
+ injectAccessiblePlayerBar();
+
+ // Check if on 403 / unauthorized page and provide admin login button
+ var notAuthorizedEl = document.querySelector('my-not-found, .not-found, .forbidden, my-forbidden, .error-page');
+ if (notAuthorizedEl && !document.getElementById('yaktube-403-admin-btn')) {
+ var btn403 = document.createElement('div');
+ btn403.id = 'yaktube-403-admin-btn';
+ btn403.style.margin = '20px auto';
+ btn403.style.textAlign = 'center';
+ btn403.innerHTML =
+ '
🔑 Sunucu Yöneticisi Olarak Giriş Yap (Alt+A) ';
+ btn403.querySelector('button').addEventListener('click', openLocalAdminLoginModal);
+ notAuthorizedEl.appendChild(btn403);
+ }
+
+ injectYakNetSSO();
+
+ // Replace all login buttons labels and titles
+ document
+ .querySelectorAll(
+ 'my-login-link, a[href*="/login"], a[title*="Giriş sayfasına git"], [aria-label*="Giriş sayfasına git"]'
+ )
+ .forEach(function (el) {
+ if (el.getAttribute('title') && el.getAttribute('title').includes('Giriş sayfasına git')) {
+ el.setAttribute('title', 'YakNet ile Giriş Yap');
+ }
+ if (el.getAttribute('aria-label') && el.getAttribute('aria-label').includes('Giriş sayfasına git')) {
+ el.setAttribute('aria-label', 'YakNet ile Giriş Yap');
+ }
+ var anchor = el.tagName.toLowerCase() === 'a' ? el : el.querySelector('a');
+ if (anchor) {
+ anchor.setAttribute('title', 'YakNet ile Giriş Yap');
+ anchor.setAttribute('aria-label', 'YakNet ile Giriş Yap');
+ var spans = anchor.querySelectorAll('span');
+ spans.forEach(function (s) {
+ if (
+ s.textContent.includes('Giriş sayfasına git') ||
+ s.textContent.trim() === 'Giriş' ||
+ s.textContent.trim() === 'Giriş yap'
+ ) {
+ s.textContent = 'YakNet ile Giriş Yap';
+ }
+ });
+ }
+ });
+
+ // 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')
+ .replace(/Giriş sayfasına git/gi, 'YakNet ile Giriş Yap');
+ }
+ }
+ }
+
+ // 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. Screen-Reader & Turkish Q Optimized Shortcuts & Player Bar (v1.4.1)
+ 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 =
+ '
' +
+ '
' +
+ '
⌨️ Klavye Kısayolları (Ekran Okuyucu Uyumlu) ' +
+ '✕ ' +
+ '' +
+ '
💡 Ekran Okuyucu Notu: Sanal imleç (Browse mode) açıkken kısayolları Alt tuşuyla birlikte kullanabilir veya video oynatıcı butonlarından faydalanabilirsiniz.
' +
+ '
' +
+ 'Kısayol (Evrensel / Tek Tuş) İşlev ' +
+ '' +
+ 'Alt + K veya Space Oynat / Duraklat ' +
+ 'Alt + J veya J 10 saniye geri sar ' +
+ 'Alt + L veya L 10 saniye ileri sar ' +
+ 'Alt + Yukarı / Aşağı Sesi %5 artır / azalt ' +
+ 'Alt + M veya M Sesi Kapat / Aç (Mute) ' +
+ 'Alt + T veya T Sinema / Tiyatro Modu ' +
+ 'Alt + I veya I Hızlı Video Bilgisi & İstatistikler ' +
+ 'Alt + C veya C Altyazıları Aç / Kapat ' +
+ 'Alt + . / Alt + , Oynatma hızını artır / azalt ' +
+ 'Alt + S veya / (Shift+7)Arama penceresini aç ' +
+ 'Alt + V veya Shift + V Sesli aramayı başlat ' +
+ 'Alt + H veya F1 veya ? Bu kılavuzu aç / kapat ' +
+ ' ' +
+ '
' +
+ '
';
+ document.body.appendChild(modal);
+
+ var closeBtn = modal.querySelector('#yaktube-shortcuts-close');
+ if (closeBtn) {
+ closeBtn.addEventListener('click', function () {
+ modal.style.display = 'none';
+ });
+ }
+ modal.addEventListener('click', function (e) {
+ if (e.target === modal) modal.style.display = 'none';
+ });
+
+ 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';
+ }
+
+ function showQuickVideoInfo() {
+ var video = getVideoElement();
+ if (!video) {
+ announce('Şu anda aktif oynatılan bir video bulunmuyor.');
+ return;
+ }
+
+ var titleEl = document.querySelector('h1.video-title, .video-name, my-video-watch h1, .title');
+ var title = titleEl ? titleEl.textContent.trim() : 'Video';
+ var curTime = formatTime(video.currentTime);
+ var totalTime = formatTime(video.duration || 0);
+ var remaining = formatTime((video.duration || 0) - video.currentTime);
+ var speed = (video.playbackRate || 1) + 'x';
+ var volume = Math.round((video.volume || 1) * 100) + '%';
+ var quality = video.videoHeight ? video.videoHeight + 'p' : 'Otomatik';
+
+ // Visual Toast
+ var existingToast = document.querySelector('.yaktube-video-info-toast');
+ if (existingToast) existingToast.remove();
+
+ var toast = document.createElement('div');
+ toast.className = 'yaktube-video-info-toast';
+ toast.innerHTML =
+ '
📊 Video Bilgisi & Durum
' +
+ '
Başlık: ' +
+ (title.length > 28 ? title.substring(0, 28) + '...' : title) +
+ '
' +
+ '
Konum / Süre: ' +
+ curTime +
+ ' / ' +
+ totalTime +
+ '
' +
+ '
Kalan Süre: ' +
+ remaining +
+ '
' +
+ '
Çözünürlük: ' +
+ quality +
+ '
' +
+ '
Hız & Ses: ' +
+ speed +
+ ' | ' +
+ volume +
+ '
';
+
+ document.body.appendChild(toast);
+ setTimeout(function () {
+ if (toast.parentElement) toast.remove();
+ }, 4000);
+
+ announce(
+ 'Video Bilgisi: ' +
+ title +
+ '. Konum: ' +
+ curTime +
+ ', Toplam Süre: ' +
+ totalTime +
+ ', Kalan: ' +
+ remaining +
+ ', Oynatma Hızı: ' +
+ speed +
+ ', Ses: yüzde ' +
+ Math.round(video.volume * 100) +
+ ', Çözünürlük: ' +
+ quality,
+ true
+ );
+ }
+
+ var speedSteps = [0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2];
+
+ function adjustPlaybackSpeed(increase) {
+ var video = getVideoElement();
+ if (!video) return;
+ var curSpeed = video.playbackRate || 1;
+ if (increase) {
+ var nextIdx = speedSteps.findIndex(function (s) {
+ return s > curSpeed;
+ });
+ video.playbackRate = nextIdx !== -1 ? speedSteps[nextIdx] : 2;
+ announce('Oynatma hızı ' + video.playbackRate + ' katına çıkarıldı.');
+ } else {
+ var prevSteps = speedSteps.filter(function (s) {
+ return s < curSpeed;
+ });
+ video.playbackRate = prevSteps.length > 0 ? prevSteps[prevSteps.length - 1] : 0.25;
+ announce('Oynatma hızı ' + video.playbackRate + ' katına düşürüldü.');
+ }
+ }
+
+ // 3.1. Injects Accessible Player Action Bar under the Watch Video
+ function injectAccessiblePlayerBar() {
+ if (!window.location.pathname.includes('/videos/watch/')) return;
+ var video = getVideoElement();
+ if (!video) return;
+
+ var targetContainer = document.querySelector(
+ 'my-video-watch, .video-watch, .watch-container, #yaktube-ondemand-container'
+ );
+ if (!targetContainer) return;
+
+ var existingBar = document.getElementById('yaktube-player-action-bar');
+ if (existingBar) return;
+
+ var bar = document.createElement('div');
+ bar.id = 'yaktube-player-action-bar';
+ bar.className = 'yaktube-player-action-bar';
+ bar.setAttribute('role', 'toolbar');
+ bar.setAttribute('aria-label', 'Erişilebilir Video Kontrolleri');
+
+ bar.innerHTML =
+ '
⚡ Oynatıcı Kontrolleri: ' +
+ '
⏪ 10sn Geri ' +
+ '
⏯️ Oynat/Duraklat ' +
+ '
⏩ 10sn İleri ' +
+ '
⚡ Hız ' +
+ '
🎭 Sinema ' +
+ '
📊 Bilgi ' +
+ '
⌨️ Kısayollar ';
+
+ var playerWrap =
+ document.querySelector('.player-container, .video-player-container, .player-wrapper, my-video-watch .player') ||
+ targetContainer;
+ if (playerWrap && playerWrap.nextSibling) {
+ playerWrap.parentNode.insertBefore(bar, playerWrap.nextSibling);
+ } else {
+ targetContainer.prepend(bar);
+ }
+
+ // Attach button actions
+ bar.querySelector('#yaktube-bar-rewind-btn').addEventListener('click', function () {
+ if (video) {
+ video.currentTime = Math.max(0, video.currentTime - 10);
+ announce('10 saniye geri sarıldı. Konum: ' + formatTime(video.currentTime));
+ }
+ });
+
+ bar.querySelector('#yaktube-bar-play-btn').addEventListener('click', function () {
+ if (video) {
+ if (video.paused) {
+ video.play();
+ announce('Video oynatılıyor.');
+ } else {
+ video.pause();
+ announce('Video duraklatıldı.');
+ }
+ }
+ });
+
+ bar.querySelector('#yaktube-bar-forward-btn').addEventListener('click', function () {
+ if (video) {
+ video.currentTime = Math.min(video.duration || 99999, video.currentTime + 10);
+ announce('10 saniye ileri sarıldı. Konum: ' + formatTime(video.currentTime));
+ }
+ });
+
+ bar.querySelector('#yaktube-bar-speed-btn').addEventListener('click', function () {
+ adjustPlaybackSpeed(true);
+ });
+
+ bar.querySelector('#yaktube-bar-theater-btn').addEventListener('click', function () {
+ document.body.classList.toggle('yaktube-theater-mode');
+ var isT = document.body.classList.contains('yaktube-theater-mode');
+ announce(isT ? 'Sinema modu açıldı.' : 'Sinema modundan çıkıldı.');
+ });
+
+ bar.querySelector('#yaktube-bar-info-btn').addEventListener('click', function () {
+ showQuickVideoInfo();
+ });
+
+ bar.querySelector('#yaktube-bar-help-btn').addEventListener('click', function () {
+ toggleShortcutsModal();
+ });
+ }
+
+ // 4. Global Keydown Listener (Screen-Reader & Turkish Q Optimized)
+ 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;
+ }
+
+ // Admin Login: Alt+A
+ if (e.altKey && (e.key === 'a' || e.key === 'A') && !isInputFocused()) {
+ e.preventDefault();
+ openLocalAdminLoginModal();
+ return;
+ }
+
+ // Help Dialog: Alt+H, F1 or '?' key
+ if ((e.altKey && (e.key === 'h' || e.key === 'H')) || e.key === 'F1' || e.key === '?') {
+ if (!isInputFocused()) {
+ e.preventDefault();
+ toggleShortcutsModal();
+ return;
+ }
+ }
+
+ // Search Open: Alt+S, Ctrl+K or '/' key (Turkish Q Shift+7)
+ if (
+ ((e.altKey && (e.key === 's' || e.key === 'S')) ||
+ (e.ctrlKey && (e.key === 'k' || e.key === 'K')) ||
+ e.key === '/') &&
+ !isInputFocused()
+ ) {
+ e.preventDefault();
+ openFullSearchModal('', false);
+ return;
+ }
+
+ // Voice Search Open: Alt+V or Shift+V
+ if (
+ ((e.altKey && (e.key === 'v' || e.key === 'V')) || (e.shiftKey && (e.key === 'v' || e.key === 'V'))) &&
+ !isInputFocused()
+ ) {
+ e.preventDefault();
+ openFullSearchModal('', true);
+ return;
+ }
+
+ if (isInputFocused()) {
+ return;
+ }
+
+ var video = getVideoElement();
+ if (!video) return;
+
+ var key = e.key.toLowerCase();
+ var alt = e.altKey;
+
+ // Play / Pause (Alt+K, Space or K)
+ if (key === ' ' || key === 'k' || (alt && key === 'k')) {
+ e.preventDefault();
if (video.paused) {
video.play();
announce('Video oynatılıyor.');
@@ -972,2157 +1085,2064 @@
announce('Video duraklatıldı.');
}
}
- });
-
- bar.querySelector('#yaktube-bar-forward-btn').addEventListener('click', function () {
- if (video) {
+ // Seek 10s Back / Forward (Alt+J / Alt+L or J / L)
+ else if (key === 'j' || (alt && key === 'j')) {
+ e.preventDefault();
+ video.currentTime = Math.max(0, video.currentTime - 10);
+ announce('10 saniye geri sarıldı. Konum: ' + formatTime(video.currentTime));
+ } else if (key === 'l' || (alt && key === 'l')) {
+ e.preventDefault();
video.currentTime = Math.min(video.duration || 99999, video.currentTime + 10);
announce('10 saniye ileri sarıldı. Konum: ' + formatTime(video.currentTime));
}
- });
-
- bar.querySelector('#yaktube-bar-speed-btn').addEventListener('click', function () {
- adjustPlaybackSpeed(true);
- });
-
- bar.querySelector('#yaktube-bar-theater-btn').addEventListener('click', function () {
- document.body.classList.toggle('yaktube-theater-mode');
- var isT = document.body.classList.contains('yaktube-theater-mode');
- announce(isT ? 'Sinema modu açıldı.' : 'Sinema modundan çıkıldı.');
- });
-
- bar.querySelector('#yaktube-bar-info-btn').addEventListener('click', function () {
- showQuickVideoInfo();
- });
-
- bar.querySelector('#yaktube-bar-help-btn').addEventListener('click', function () {
- toggleShortcutsModal();
- });
- }
-
- // 4. Global Keydown Listener (Screen-Reader & Turkish Q Optimized)
- 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;
- }
-
- // Admin Login: Alt+A
- if (e.altKey && (e.key === 'a' || e.key === 'A') && !isInputFocused()) {
- e.preventDefault();
- openLocalAdminLoginModal();
- return;
- }
-
- // Help Dialog: Alt+H, F1 or '?' key
- if ((e.altKey && (e.key === 'h' || e.key === 'H')) || e.key === 'F1' || e.key === '?') {
- if (!isInputFocused()) {
+ // Seek 5s Back / Forward (ArrowLeft / ArrowRight or Alt+Left/Right)
+ else if (e.key === 'ArrowLeft' || (alt && e.key === 'ArrowLeft')) {
e.preventDefault();
- toggleShortcutsModal();
+ video.currentTime = Math.max(0, video.currentTime - 5);
+ announce('5 saniye geri sarıldı. Konum: ' + formatTime(video.currentTime));
+ } else if (e.key === 'ArrowRight' || (alt && e.key === 'ArrowRight')) {
+ e.preventDefault();
+ video.currentTime = Math.min(video.duration || 99999, video.currentTime + 5);
+ announce('5 saniye ileri sarıldı. Konum: ' + formatTime(video.currentTime));
+ }
+ // Volume Up / Down (ArrowUp / ArrowDown or Alt+Up/Down)
+ else if (e.key === 'ArrowUp' || (alt && e.key === 'ArrowUp')) {
+ e.preventDefault();
+ video.volume = Math.min(1, (video.volume || 1) + 0.05);
+ announce('Ses seviyesi yüzde ' + Math.round(video.volume * 100));
+ } else if (e.key === 'ArrowDown' || (alt && e.key === 'ArrowDown')) {
+ e.preventDefault();
+ video.volume = Math.max(0, (video.volume || 1) - 0.05);
+ announce('Ses seviyesi yüzde ' + Math.round(video.volume * 100));
+ }
+ // Mute (Alt+M or M)
+ else if (key === 'm' || (alt && key === 'm')) {
+ e.preventDefault();
+ video.muted = !video.muted;
+ announce(video.muted ? 'Ses kapatıldı (Sessiz).' : 'Ses açıldı.');
+ }
+ // Fullscreen (Alt+F or F)
+ else if (key === 'f' || (alt && 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ı.');
+ }
+ }
+ // Theater Mode (Alt+T or T)
+ else if (key === 't' || (alt && key === 't')) {
+ e.preventDefault();
+ document.body.classList.toggle('yaktube-theater-mode');
+ var isTheater = document.body.classList.contains('yaktube-theater-mode');
+ announce(isTheater ? 'Sinema modu açıldı.' : 'Sinema modundan çıkıldı.');
+ }
+ // Quick Video Info (Alt+I or I)
+ else if (key === 'i' || (alt && key === 'i')) {
+ e.preventDefault();
+ showQuickVideoInfo();
+ }
+ // Subtitles (Alt+C or C)
+ else if (key === 'c' || (alt && 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.');
+ }
+ }
+ // Speed Controls (Alt+. / Alt+, or > / <)
+ else if ((alt && (e.key === '.' || e.key === '>')) || e.key === '>') {
+ e.preventDefault();
+ adjustPlaybackSpeed(true);
+ } else if ((alt && (e.key === ',' || e.key === '<')) || e.key === '<') {
+ e.preventDefault();
+ adjustPlaybackSpeed(false);
+ }
+ // Percentage Jumps (0 - 9)
+ 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ı. Konum: ' + 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;
}
- }
- // Search Open: Alt+S, Ctrl+K or '/' key (Turkish Q Shift+7)
- if (
- ((e.altKey && (e.key === 's' || e.key === 'S')) ||
- (e.ctrlKey && (e.key === 'k' || e.key === 'K')) ||
- e.key === '/') &&
- !isInputFocused()
- ) {
- e.preventDefault();
- openFullSearchModal('', false);
- return;
- }
-
- // Voice Search Open: Alt+V or Shift+V
- if (
- ((e.altKey && (e.key === 'v' || e.key === 'V')) || (e.shiftKey && (e.key === 'v' || e.key === 'V'))) &&
- !isInputFocused()
- ) {
- e.preventDefault();
- openFullSearchModal('', true);
- return;
- }
-
- if (isInputFocused()) {
- return;
- }
-
- var video = getVideoElement();
- if (!video) return;
-
- var key = e.key.toLowerCase();
- var alt = e.altKey;
-
- // Play / Pause (Alt+K, Space or K)
- if (key === ' ' || key === 'k' || (alt && key === 'k')) {
- e.preventDefault();
- if (video.paused) {
- video.play();
- announce('Video oynatılıyor.');
- } else {
- video.pause();
- announce('Video duraklatıldı.');
- }
- }
- // Seek 10s Back / Forward (Alt+J / Alt+L or J / L)
- else if (key === 'j' || (alt && key === 'j')) {
- e.preventDefault();
- video.currentTime = Math.max(0, video.currentTime - 10);
- announce('10 saniye geri sarıldı. Konum: ' + formatTime(video.currentTime));
- } else if (key === 'l' || (alt && key === 'l')) {
- e.preventDefault();
- video.currentTime = Math.min(video.duration || 99999, video.currentTime + 10);
- announce('10 saniye ileri sarıldı. Konum: ' + formatTime(video.currentTime));
- }
- // Seek 5s Back / Forward (ArrowLeft / ArrowRight or Alt+Left/Right)
- else if (e.key === 'ArrowLeft' || (alt && e.key === 'ArrowLeft')) {
- e.preventDefault();
- video.currentTime = Math.max(0, video.currentTime - 5);
- announce('5 saniye geri sarıldı. Konum: ' + formatTime(video.currentTime));
- } else if (e.key === 'ArrowRight' || (alt && e.key === 'ArrowRight')) {
- e.preventDefault();
- video.currentTime = Math.min(video.duration || 99999, video.currentTime + 5);
- announce('5 saniye ileri sarıldı. Konum: ' + formatTime(video.currentTime));
- }
- // Volume Up / Down (ArrowUp / ArrowDown or Alt+Up/Down)
- else if (e.key === 'ArrowUp' || (alt && e.key === 'ArrowUp')) {
- e.preventDefault();
- video.volume = Math.min(1, (video.volume || 1) + 0.05);
- announce('Ses seviyesi yüzde ' + Math.round(video.volume * 100));
- } else if (e.key === 'ArrowDown' || (alt && e.key === 'ArrowDown')) {
- e.preventDefault();
- video.volume = Math.max(0, (video.volume || 1) - 0.05);
- announce('Ses seviyesi yüzde ' + Math.round(video.volume * 100));
- }
- // Mute (Alt+M or M)
- else if (key === 'm' || (alt && key === 'm')) {
- e.preventDefault();
- video.muted = !video.muted;
- announce(video.muted ? 'Ses kapatıldı (Sessiz).' : 'Ses açıldı.');
- }
- // Fullscreen (Alt+F or F)
- else if (key === 'f' || (alt && 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ı.');
- }
- }
- // Theater Mode (Alt+T or T)
- else if (key === 't' || (alt && key === 't')) {
- e.preventDefault();
- document.body.classList.toggle('yaktube-theater-mode');
- var isTheater = document.body.classList.contains('yaktube-theater-mode');
- announce(isTheater ? 'Sinema modu açıldı.' : 'Sinema modundan çıkıldı.');
- }
- // Quick Video Info (Alt+I or I)
- else if (key === 'i' || (alt && key === 'i')) {
- e.preventDefault();
- showQuickVideoInfo();
- }
- // Subtitles (Alt+C or C)
- else if (key === 'c' || (alt && 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.');
- }
- }
- // Speed Controls (Alt+. / Alt+, or > / <)
- else if ((alt && (e.key === '.' || e.key === '>')) || e.key === '>') {
- e.preventDefault();
- adjustPlaybackSpeed(true);
- } else if ((alt && (e.key === ',' || e.key === '<')) || e.key === '<') {
- e.preventDefault();
- adjustPlaybackSpeed(false);
- }
- // Percentage Jumps (0 - 9)
- 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ı. Konum: ' + 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() {
+ // Persist active live stream state in sessionStorage
try {
- sessionStorage.removeItem('yaktube_active_live');
+ sessionStorage.setItem(
+ 'yaktube_active_live',
+ JSON.stringify({
+ url: url,
+ title: videoTitle,
+ videoId: videoId
+ })
+ );
} catch (e) {}
- if (liveContainer && liveContainer.parentNode) {
- var ifr = liveContainer.querySelector('iframe');
- if (ifr) ifr.src = '';
- liveContainer.remove();
+
+ 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);
}
- 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();
+ 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 closeBtn = document.getElementById('yaktube-close-live-theater');
- if (closeBtn) closeBtn.addEventListener('click', closeLiveTheater);
- document.addEventListener('keydown', handleEsc);
- }
+ 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 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);
+ 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;
}
- } 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ı.');
+ function fetchComments(token) {
+ if (!token) {
+ toggleCommentsBtn.disabled = true;
+ toggleCommentsBtn.textContent = '⏳ Yorumlar Y\u00fckleniyor...';
+ } else {
+ moreCommentsBtn.disabled = true;
+ moreCommentsBtn.textContent = '⏳ Y\u00fckleniyor...';
}
- 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 +
- ')' +
- ' ' +
- '
';
+ 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 =
'' +
- '
' +
- cardsHtml +
- '
' +
- loadMoreHtml;
+ '
';
+ 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);
- var sBtn = document.getElementById('yaktube-open-shortcuts');
- if (sBtn) {
- sBtn.addEventListener('click', toggleShortcutsModal);
- }
+ function render() {
+ var visibleResults = uniqueResults.slice(0, visibleCount);
+ var cardsHtml = '';
+ visibleResults.forEach(function (item) {
+ var isLocal = !!item.isDownloaded;
+ var isLive = !!item.isLive;
- 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.');
+ var statusBadge = '';
+ if (isLive) {
+ statusBadge =
+ '
';
+ } else if (isLocal) {
+ statusBadge =
+ '
";
+ }
+
+ var actionButton = '';
+ if (isLive) {
+ actionButton =
+ '
';
+ } else if (isLocal) {
+ actionButton =
+ '
";
+ } else {
+ actionButton =
+ '
";
+ }
+
+ 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 +=
+ '
';
+ });
+
+ var loadMoreHtml = '';
+ if (visibleCount < count) {
+ loadMoreHtml =
+ '
';
+ }
+
+ container.innerHTML =
+ '' +
+ '
' +
+ 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);
+ });
});
}
- 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;
+ });
+ }
- render();
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // --------------------------------------------------------------------------
+ // 8. FULL YOUTUBE SEARCH & VOICE MODAL ENGINE (v1.3.3 - Guaranteed Close Fix)
+ // --------------------------------------------------------------------------
+ var activeVoiceRec = null;
+ var isVoiceListening = false;
+
+ // Dynamic Search History & Trending Helpers
+ function getRecentSearches() {
+ try {
+ var data = localStorage.getItem('yaktube_recent_searches');
+ if (data) {
+ var parsed = JSON.parse(data);
+ if (Array.isArray(parsed) && parsed.length > 0) return parsed;
}
- })
- .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;
- });
- }
+ } catch (e) {}
+ // Default initial recent searches for first-time visitors
+ var defaults = ['Tarkan', 'Barış Manço', 'Yapay Zeka', 'Canlı Haber'];
+ try {
+ localStorage.setItem('yaktube_recent_searches', JSON.stringify(defaults));
+ } catch (e) {}
+ return defaults;
+ }
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // 8. FULL YOUTUBE SEARCH & VOICE MODAL ENGINE (v1.3.3 - Guaranteed Close Fix)
- // --------------------------------------------------------------------------
- var activeVoiceRec = null;
- var isVoiceListening = false;
+ function saveRecentSearch(query) {
+ if (!query || query.trim().length < 2) return;
+ var q = query.trim();
+ try {
+ var list = getRecentSearches();
+ list = list.filter(function (item) {
+ return item.toLowerCase() !== q.toLowerCase();
+ });
+ list.unshift(q);
+ if (list.length > 8) list = list.slice(0, 8);
+ localStorage.setItem('yaktube_recent_searches', JSON.stringify(list));
+ } catch (e) {}
+ }
- // Dynamic Search History & Trending Helpers
- function getRecentSearches() {
- try {
- var data = localStorage.getItem('yaktube_recent_searches');
- if (data) {
- var parsed = JSON.parse(data);
- if (Array.isArray(parsed) && parsed.length > 0) return parsed;
- }
- } catch (e) {}
- // Default initial recent searches for first-time visitors
- var defaults = ['Tarkan', 'Barış Manço', 'Yapay Zeka', 'Canlı Haber'];
- try {
- localStorage.setItem('yaktube_recent_searches', JSON.stringify(defaults));
- } catch (e) {}
- return defaults;
- }
+ function clearRecentSearches() {
+ try {
+ localStorage.removeItem('yaktube_recent_searches');
+ } catch (e) {}
+ renderDynamicSearchChips();
+ announce('Arama geçmişi temizlendi.');
+ }
- function saveRecentSearch(query) {
- if (!query || query.trim().length < 2) return;
- var q = query.trim();
- try {
- var list = getRecentSearches();
- list = list.filter(function (item) {
- return item.toLowerCase() !== q.toLowerCase();
- });
- list.unshift(q);
- if (list.length > 8) list = list.slice(0, 8);
- localStorage.setItem('yaktube_recent_searches', JSON.stringify(list));
- } catch (e) {}
- }
+ var popularTrendingQueries = [
+ { title: '🎵 Türkçe Pop', q: 'Türkçe Pop' },
+ { title: '🎸 Anadolu Rock', q: 'Anadolu Rock' },
+ { title: '🤖 Yapay Zeka', q: 'Yapay Zeka' },
+ { title: '💻 Yazılım Dersleri', q: 'Yazılım Dersleri' },
+ { title: '🎧 Sesli Kitap & Radyo Tiyatrosu', q: 'Sesli Kitap' },
+ { title: '📺 Canlı Haber', q: 'Canlı Haber' },
+ { title: '🌍 Bilim & Belgesel', q: 'Bilim Belgeseli' },
+ { title: '🎼 Akustik Canlı Performans', q: 'Akustik Canlı' },
+ { title: '🎙️ Podcast & Söyleşi', q: 'Podcast Türkçe' }
+ ];
- function clearRecentSearches() {
- try {
- localStorage.removeItem('yaktube_recent_searches');
- } catch (e) {}
- renderDynamicSearchChips();
- announce('Arama geçmişi temizlendi.');
- }
+ // Auto capture search query from URL into recent searches
+ function captureUrlSearchQuery() {
+ try {
+ var params = new URLSearchParams(window.location.search);
+ var q = params.get('search') || params.get('q');
+ if (q && q.trim().length >= 2) {
+ saveRecentSearch(q.trim());
+ }
+ } catch (e) {}
+ }
+ captureUrlSearchQuery();
+ window.addEventListener('popstate', captureUrlSearchQuery);
- var popularTrendingQueries = [
- { title: '🎵 Türkçe Pop', q: 'Türkçe Pop' },
- { title: '🎸 Anadolu Rock', q: 'Anadolu Rock' },
- { title: '🤖 Yapay Zeka', q: 'Yapay Zeka' },
- { title: '💻 Yazılım Dersleri', q: 'Yazılım Dersleri' },
- { title: '🎧 Sesli Kitap & Radyo Tiyatrosu', q: 'Sesli Kitap' },
- { title: '📺 Canlı Haber', q: 'Canlı Haber' },
- { title: '🌍 Bilim & Belgesel', q: 'Bilim Belgeseli' },
- { title: '🎼 Akustik Canlı Performans', q: 'Akustik Canlı' },
- { title: '🎙️ Podcast & Söyleşi', q: 'Podcast Türkçe' }
- ];
+ function renderDynamicSearchChips() {
+ var modal = document.getElementById('yaktube-full-search-modal');
+ if (!modal) return;
- // Auto capture search query from URL into recent searches
- function captureUrlSearchQuery() {
- try {
- var params = new URLSearchParams(window.location.search);
- var q = params.get('search') || params.get('q');
- if (q && q.trim().length >= 2) {
- saveRecentSearch(q.trim());
- }
- } catch (e) {}
- }
- captureUrlSearchQuery();
- window.addEventListener('popstate', captureUrlSearchQuery);
+ var container = modal.querySelector('#yaktube-modal-dynamic-chips-section');
+ if (!container) return;
- function renderDynamicSearchChips() {
- var modal = document.getElementById('yaktube-full-search-modal');
- if (!modal) return;
+ var recent = getRecentSearches();
+ var html = '';
- var container = modal.querySelector('#yaktube-modal-dynamic-chips-section');
- if (!container) return;
-
- var recent = getRecentSearches();
- var html = '';
-
- // 1. Recent searches section (if any)
- if (recent.length > 0) {
- html +=
- '