diff --git a/client.js b/client.js
index 40a4d9b..5bc714b 100644
--- a/client.js
+++ b/client.js
@@ -287,101 +287,78 @@ try {
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');
- }
+ // Always hide duplicate native login link in favor of unified YakNet component
+ 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';
+ 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 =
- '' +
- '';
+ 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');
+ 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);
- }
+ if (targetSibling && targetSibling.parentElement === headerRight) {
+ headerRight.insertBefore(widgetWrap, targetSibling);
} 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();
- }
- }
- }
+ headerRight.prepend(widgetWrap);
}
} 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 el = liveWidget.querySelector('yaknet-account');
+ if (el) {
+ var authAttr = isAuth ? 'true' : 'false';
+ if (el.getAttribute('authenticated') !== authAttr || el.getAttribute('user-name') !== displayName) {
+ el.setAttribute('authenticated', authAttr);
+ el.setAttribute('user-name', displayName);
+ el.setAttribute('user-email', emailStr);
+ if (typeof el.syncStateFromAttributes === 'function') {
+ el.syncStateFromAttributes();
+ el.render();
+ }
+ }
- 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';
+ 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
+ );
}
}
}
@@ -3019,8 +2996,8 @@ try {
(function initBackgroundPlaybackEngine() {
var videoState = {
hasPlayed: false,
- pausedByUser: false,
- pausedAt: null
+ explicitlyPausedByClick: false,
+ lastPlayTime: 0
};
function attachVideoListeners(video) {
@@ -3029,21 +3006,14 @@ try {
video.addEventListener('play', function () {
videoState.hasPlayed = true;
- videoState.pausedByUser = false;
+ videoState.explicitlyPausedByClick = false;
+ videoState.lastPlayTime = Date.now();
updateMediaSessionMetadata(video);
});
- video.addEventListener('pause', function () {
- videoState.pausedAt = Date.now();
- // If document is visible when paused, it was paused manually by the user
- if (!document.hidden) {
- videoState.pausedByUser = true;
- }
- });
-
video.addEventListener('ended', function () {
videoState.hasPlayed = false;
- videoState.pausedByUser = true;
+ videoState.explicitlyPausedByClick = true;
});
video.addEventListener('timeupdate', function () {
@@ -3051,30 +3021,50 @@ try {
});
}
- function handleVisibilityChange() {
- if (!document.hidden) return; // Screen is active
+ // Hook manual play/pause buttons
+ document.addEventListener(
+ 'click',
+ function (e) {
+ var target = e.target;
+ if (!target) return;
+ var btn = target.closest(
+ '.vjs-play-control, button[title*="Duraklat"], button[aria-label*="Duraklat"], #yaktube-bar-play-btn'
+ );
+ if (btn) {
+ var video = getVideoElement();
+ if (video && !video.paused) {
+ videoState.explicitlyPausedByClick = true;
+ }
+ }
+ },
+ true
+ );
+ function handleVisibilityChange() {
var video = getVideoElement();
if (!video) return;
- // If user hasn't played or deliberately paused, do not auto-resume
- if (!videoState.hasPlayed || videoState.pausedByUser) return;
-
- var now = Date.now();
- if (videoState.pausedAt && now - videoState.pausedAt > 1500 && videoState.pausedByUser) {
- return;
- }
-
- // Resume playback when screen locks or tab switches
- setTimeout(function () {
- if (video.paused && !videoState.pausedByUser) {
- video.play().catch(function () {});
+ // When screen turns off / tab is hidden:
+ if (document.hidden || document.webkitHidden) {
+ if (videoState.hasPlayed && !videoState.explicitlyPausedByClick) {
+ // Unconditionally keep audio stream active
+ setTimeout(function () {
+ if (video.paused && !videoState.explicitlyPausedByClick) {
+ video.play().catch(function () {});
+ }
+ }, 100);
+ setTimeout(function () {
+ if (video.paused && !videoState.explicitlyPausedByClick) {
+ video.play().catch(function () {});
+ }
+ }, 300);
}
- }, 50);
+ }
}
document.addEventListener('visibilitychange', handleVisibilityChange, false);
document.addEventListener('webkitvisibilitychange', handleVisibilityChange, false);
+ window.addEventListener('pagehide', handleVisibilityChange, false);
// MediaSession API Integration (Lock Screen, Bluetooth, Smart Watches)
function updateMediaSessionMetadata(video) {
diff --git a/package.json b/package.json
index 05e1879..7f4607b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "peertube-plugin-yaktube-ondemand",
- "version": "1.4.10",
+ "version": "1.4.11",
"description": "Accessible On-Demand YouTube Import, Live Streams, Smart Recommendations and A11y Engine for PeerTube",
"main": "main.js",
"library": "./main.js",
diff --git a/style.css b/style.css
index 152b356..8a55606 100644
--- a/style.css
+++ b/style.css
@@ -1,3 +1,29 @@
+/* Permanent Aggressive Suppression of Generic JoinPeerTube / Framasoft Open-in-App Banners */
+my-open-app,
+my-open-in-app,
+my-client-app-banner,
+.open-app-container,
+.app-banner,
+[class*='open-app'],
+[class*='open-in-app'],
+.mobile-app-banner,
+.app-promotion,
+.client-app-banner,
+a[href*='play.google.com/store/apps/details?id=app.joinpeertube'],
+a[href*='f-droid.org'],
+a[href*='joinpeertube'] {
+ display: none !important;
+ visibility: hidden !important;
+ height: 0 !important;
+ width: 0 !important;
+ margin: 0 !important;
+ padding: 0 !important;
+ pointer-events: none !important;
+ opacity: 0 !important;
+ position: absolute !important;
+ z-index: -99999 !important;
+}
+
/* YakTube Accessibility & On-Demand CSS */
:focus-visible {