Git Komut Rehberi & Terminal Asistanı
Sıfırdan Yeni Bir Depo Başlatın:
Mevcut Bir Git Deposu veya Klasörü Gönderin:
Hataları Geri Alma, İptal & Temizlik:
Son commit'i geri al (yapılan değişiklikleri korur):
git reset --soft HEAD~1
Yapılan yerel değişiklikleri iptal et (çalışma ağacını temizler):
git restore .
Takip edilmeyen gereksiz dosyaları sil:
git clean -fd
Değişiklikleri geçici sakla ve geri getir (stash):
git stash git stash pop
Dal (Branch) ve Sürüm Etiketleri:
Yeni dal aç ve geçiş yap:
git checkout -b yeni-ozellik git push -u origin yeni-ozellik
Sürüm etiketi (tag) oluştur ve gönder:
git tag -a v1.0.0 -m "Sürüm 1.0.0" git push origin --tags
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9ad6f12223 | ||
|
|
afdb78a479 |
@@ -15,7 +15,8 @@
|
||||
- **⚡ Live Web & YouTube On-Demand Search:** Seamlessly search YouTube directly within your instance search bar. If the video is already on your instance, it plays immediately; otherwise, users can import it in 1 click.
|
||||
- **🔥 Hybrid Smart Recommendations:** Intelligently discovers related content across local federated videos first, supplemented with relevant live discoveries.
|
||||
- **♿ Full Screen Reader Accessibility (A11y):**
|
||||
- Dynamic result counters with live polite announcements (`aria-live`).
|
||||
- Dynamic result counters with live polite and assertive announcements (`aria-live`).
|
||||
- Auto-clearing live regions after speech lifecycle (WCAG 2.2 AAA compliant, prevents persistent DOM clutter for virtual cursors).
|
||||
- Accessible keyboard navigation modal (`?` shortcut).
|
||||
- Auto-labeled player controls, buttons, and thumbnails.
|
||||
- **💬 Dynamic Live YouTube Comments:** View original YouTube community comments under imported videos on demand.
|
||||
|
||||
@@ -75,33 +75,66 @@ try {
|
||||
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);
|
||||
}
|
||||
// 1. Screen Reader Live Announcer (W3C WCAG 2.2 AAA Compliant Auto-Clearing Engine)
|
||||
function applySrOnlyStyles(el) {
|
||||
el.className = 'yaktube-sr-only';
|
||||
el.style.position = 'absolute';
|
||||
el.style.width = '1px';
|
||||
el.style.height = '1px';
|
||||
el.style.padding = '0';
|
||||
el.style.margin = '-1px';
|
||||
el.style.overflow = 'hidden';
|
||||
el.style.clip = 'rect(0, 0, 0, 0)';
|
||||
el.style.whiteSpace = 'nowrap';
|
||||
el.style.border = '0';
|
||||
}
|
||||
|
||||
function getLiveRegion(assertive) {
|
||||
var id = assertive ? 'yaktube-a11y-live-assertive' : 'yaktube-a11y-live-region';
|
||||
var region = document.getElementById(id);
|
||||
if (!region || !document.body.contains(region)) {
|
||||
region = document.createElement('div');
|
||||
region.id = id;
|
||||
region.setAttribute('aria-live', assertive ? 'assertive' : 'polite');
|
||||
region.setAttribute('aria-atomic', 'true');
|
||||
region.setAttribute('aria-relevant', 'additions text');
|
||||
applySrOnlyStyles(region);
|
||||
document.body.appendChild(region);
|
||||
}
|
||||
return liveRegion;
|
||||
return region;
|
||||
}
|
||||
|
||||
function announce(text, assertive) {
|
||||
var region = getLiveRegion();
|
||||
if (assertive) {
|
||||
region.setAttribute('aria-live', 'assertive');
|
||||
} else {
|
||||
region.setAttribute('aria-live', 'polite');
|
||||
if (!text || !String(text).trim()) return;
|
||||
var strText = String(text).trim();
|
||||
var region = getLiveRegion(assertive);
|
||||
|
||||
if (region._setTimer) {
|
||||
clearTimeout(region._setTimer);
|
||||
region._setTimer = null;
|
||||
}
|
||||
if (region._clearTimer) {
|
||||
clearTimeout(region._clearTimer);
|
||||
region._clearTimer = null;
|
||||
}
|
||||
|
||||
// Screen reader mutation trigger: clear first so repeat announcements are re-announced
|
||||
region.textContent = '';
|
||||
setTimeout(function () {
|
||||
region.textContent = text;
|
||||
|
||||
region._setTimer = setTimeout(function () {
|
||||
region.textContent = strText;
|
||||
|
||||
// Seslendirme yapıldıktan veya ekran okuyucu kuyruğuna alındıktan sonra
|
||||
// sayfanın en altında ya da sanal imleç gezintisinde eski metin kalmaması için
|
||||
// DOM'daki duyuru metnini temizle (Metin uzunluğuna göre 3 ile 7 saniye arası)
|
||||
var clearDelay = Math.min(7000, Math.max(3000, strText.length * 50));
|
||||
region._clearTimer = setTimeout(function () {
|
||||
if (region && document.body.contains(region)) {
|
||||
region.textContent = '';
|
||||
}
|
||||
region._clearTimer = null;
|
||||
}, clearDelay);
|
||||
region._setTimer = null;
|
||||
}, 50);
|
||||
}
|
||||
|
||||
@@ -3448,7 +3481,7 @@ try {
|
||||
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.setAttribute('aria-label', getInstanceName() + ' 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';
|
||||
@@ -3459,7 +3492,7 @@ try {
|
||||
deferredInstallPrompt.userChoice.then(function (choiceResult) {
|
||||
if (choiceResult.outcome === 'accepted') {
|
||||
installBtn.remove();
|
||||
announce('YakTube uygulaması cihazınıza yükleniyor.');
|
||||
announce(getInstanceName() + ' uygulaması cihazınıza yükleniyor.');
|
||||
}
|
||||
deferredInstallPrompt = null;
|
||||
});
|
||||
@@ -3469,12 +3502,19 @@ try {
|
||||
headerButtons.prepend(installBtn);
|
||||
}
|
||||
|
||||
function isYakTubeInstance() {
|
||||
return window.location.hostname.includes('yaktube.yakhub.com.tr') || getInstanceName() === 'YakTube';
|
||||
function isOfficialYakTubeServer() {
|
||||
var host = (window.location.hostname || '').toLowerCase();
|
||||
// Sadece ve sadece resmi YakTube alan adında veya yerel test ortamında çalışsın
|
||||
// Diğer PeerTube sunucularında yaktube.apk dosyası olmayacağı için ASLA gösterilmez
|
||||
return host === 'yaktube.yakhub.com.tr' || host === '127.0.0.1' || host === 'localhost';
|
||||
}
|
||||
|
||||
function injectApkDownloadButton() {
|
||||
if (!isYakTubeInstance()) return;
|
||||
if (!isOfficialYakTubeServer()) {
|
||||
var existBtnOther = document.getElementById('yaktube-apk-download-btn');
|
||||
if (existBtnOther) existBtnOther.remove();
|
||||
return;
|
||||
}
|
||||
// 1. If inside APK: NEVER show APK button
|
||||
if (isInsideYakTubeApp) {
|
||||
var existBtnApp = document.getElementById('yaktube-apk-download-btn');
|
||||
@@ -3519,7 +3559,11 @@ try {
|
||||
}
|
||||
|
||||
function injectSidebarApkLink() {
|
||||
if (!isYakTubeInstance()) return;
|
||||
if (!isOfficialYakTubeServer()) {
|
||||
var existLinkOther = document.getElementById('yaktube-sidebar-apk-link');
|
||||
if (existLinkOther) existLinkOther.remove();
|
||||
return;
|
||||
}
|
||||
// If inside APK: NEVER show in sidebar
|
||||
if (isInsideYakTubeApp) {
|
||||
var existLink = document.getElementById('yaktube-sidebar-apk-link');
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "peertube-plugin-yaktube-ondemand",
|
||||
"version": "1.4.30",
|
||||
"version": "1.4.32",
|
||||
"description": "Accessible On-Demand YouTube Import, Live Streams, Smart Recommendations and A11y Engine for PeerTube",
|
||||
"main": "main.js",
|
||||
"library": "./main.js",
|
||||
|
||||
Reference in New Issue
Block a user