WIP: storage-fix-local-nas work before playlist controls feature

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
ghassanandClaude Sonnet 4.6 committed 2026-05-16 11:15:20 +03:00
1 parent 6b3ab5b65e
commit c160242dbc
46 files changed
+5365 -815

No files matched your search

+120 -4
View File
@@ -478,11 +478,15 @@
</button>
</form>
<!-- Edit Button - Only for video owner -->
<!-- Edit / Delete Buttons - Only for video owner -->
@if (Auth::id() === $video->user_id)
<button class="yt-action-btn" onclick="openEditVideoModal('{{ $video->getRouteKey() }}')">
<i class="bi bi-pencil"></i> Edit
</button>
<button class="yt-action-btn" onclick="openVideoDeleteDialog()"
style="color:#ef4444;">
<i class="bi bi-trash"></i> Delete
</button>
@endif
@else
<a href="{{ route('login') }}" class="yt-action-btn">
@@ -696,7 +700,7 @@
style="{{ $isCurrent ? 'cursor:default;' : 'cursor:pointer;' }}">
<div class="sidebar-thumb" style="position: relative;">
@if ($playlistVideo->thumbnail)
<img src="{{ asset('storage/thumbnails/' . $playlistVideo->thumbnail) }}"
<img src="{{ route('media.thumbnail', $playlistVideo->thumbnail) }}"
alt="{{ $playlistVideo->title }}">
@else
<img src="https://picsum.photos/seed/{{ $playlistVideo->id }}/320/180"
@@ -751,7 +755,7 @@
onclick="window.location.href='{{ route('videos.show', $recVideo) }}'">
<div class="sidebar-thumb" style="position: relative;">
@if ($recVideo->thumbnail)
<img src="{{ asset('storage/thumbnails/' . $recVideo->thumbnail) }}"
<img src="{{ route('media.thumbnail', $recVideo->thumbnail) }}"
alt="{{ $recVideo->title }}">
@else
<img src="https://picsum.photos/seed/{{ $recVideo->id }}/320/180"
@@ -822,7 +826,12 @@
</button>
@auth
@if (Auth::id() !== $video->user_id)
@if (Auth::id() === $video->user_id)
<button class="yt-action-btn" onclick="openVideoDeleteDialog()"
style="flex:1;color:#ef4444;">
<i class="bi bi-trash"></i><span>Delete</span>
</button>
@else
<button class="yt-action-btn" style="flex:1;background:var(--brand-red);color:white;">
<i class="bi bi-bell"></i><span>Subscribe</span>
</button>
@@ -886,6 +895,113 @@
}
});
</script>
@auth
@if(Auth::id() === $video->user_id)
@php $owner2fa = Auth::user()->two_factor_enabled && Auth::user()->two_factor_secret; @endphp
{{-- Delete confirmation dialog --}}
<div id="videoDeleteDialog" style="display:none;position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.7);backdrop-filter:blur(4px);align-items:center;justify-content:center;padding:16px;" onclick="if(event.target===this)closeVideoDeleteDialog()">
<div style="background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:16px;width:100%;max-width:420px;overflow:hidden;box-shadow:0 24px 60px rgba(0,0,0,.6);">
<div style="padding:20px 24px 16px;border-bottom:1px solid var(--border-color);display:flex;align-items:center;justify-content:space-between;">
<div style="display:flex;align-items:center;gap:10px;font-size:16px;font-weight:600;color:#ef4444;">
<i class="bi bi-trash"></i> Delete Video
</div>
<button onclick="closeVideoDeleteDialog()" style="background:none;border:none;color:var(--text-secondary);cursor:pointer;font-size:18px;line-height:1;padding:4px;"><i class="bi bi-x-lg"></i></button>
</div>
<div style="padding:20px 24px;">
<p style="margin:0 0 12px;font-size:14px;color:var(--text-primary);">
You are about to permanently delete <strong>{{ $video->title }}</strong>.
</p>
<div style="background:rgba(239,68,68,.1);border:1px solid rgba(239,68,68,.25);border-radius:8px;padding:10px 14px;font-size:13px;color:#fca5a5;display:flex;gap:8px;align-items:flex-start;">
<i class="bi bi-exclamation-triangle-fill" style="flex-shrink:0;margin-top:1px;"></i>
<span>All views, likes, comments, and HLS files will also be deleted. This cannot be undone.</span>
</div>
@if($owner2fa)
<div style="margin-top:16px;">
<label style="font-size:13px;color:var(--text-secondary);display:flex;align-items:center;gap:6px;margin-bottom:8px;">
<i class="bi bi-shield-lock-fill" style="color:#a78bfa;"></i>
Enter your <strong style="color:var(--text-primary);">2FA code</strong> to confirm
</label>
<input type="text" id="delVideoOtp" inputmode="numeric" pattern="[0-9]*"
maxlength="6" autocomplete="one-time-code" placeholder="000000"
style="width:100%;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:8px;padding:10px 14px;color:#fff;font-size:22px;letter-spacing:.3em;text-align:center;box-sizing:border-box;">
</div>
@endif
<div id="delVideoError" style="display:none;margin-top:12px;padding:8px 12px;background:rgba(239,68,68,.12);border:1px solid rgba(239,68,68,.3);border-radius:6px;color:#f87171;font-size:13px;"></div>
</div>
<div style="padding:12px 24px 20px;display:flex;gap:10px;justify-content:flex-end;">
<button onclick="closeVideoDeleteDialog()" class="yt-action-btn">Cancel</button>
<button id="delVideoConfirmBtn" onclick="confirmVideoDelete()" class="yt-action-btn" style="background:#ef4444;color:#fff;border-color:#ef4444;">
<i class="bi bi-trash"></i> Delete
</button>
</div>
</div>
</div>
<script>
const _owner2fa = {{ $owner2fa ? 'true' : 'false' }};
const _videoDeleteUrl = '{{ route('videos.destroy', $video) }}';
const _videoCsrf = '{{ csrf_token() }}';
function openVideoDeleteDialog() {
const dlg = document.getElementById('videoDeleteDialog');
dlg.style.display = 'flex';
dlg.style.alignItems = 'center';
dlg.style.justifyContent = 'center';
document.getElementById('delVideoError').style.display = 'none';
if (_owner2fa) { document.getElementById('delVideoOtp').value = ''; setTimeout(() => document.getElementById('delVideoOtp').focus(), 100); }
}
function closeVideoDeleteDialog() {
document.getElementById('videoDeleteDialog').style.display = 'none';
}
function confirmVideoDelete() {
const btn = document.getElementById('delVideoConfirmBtn');
const errEl = document.getElementById('delVideoError');
const otpCode = _owner2fa ? document.getElementById('delVideoOtp').value.replace(/\s/g,'') : '';
if (_owner2fa && otpCode.length !== 6) {
errEl.textContent = 'Please enter your 6-digit 2FA code.';
errEl.style.display = 'block';
document.getElementById('delVideoOtp').focus();
return;
}
btn.disabled = true;
btn.innerHTML = '<i class="bi bi-hourglass-split"></i> Deleting…';
errEl.style.display = 'none';
const body = new URLSearchParams({ '_token': _videoCsrf, '_method': 'DELETE' });
if (_owner2fa) body.append('otp_code', otpCode);
fetch(_videoDeleteUrl, {
method: 'POST',
headers: { 'Accept': 'application/json', 'Content-Type': 'application/x-www-form-urlencoded' },
body: body.toString()
})
.then(r => r.json())
.then(data => {
if (data.success) {
window.location.href = '/';
} else {
errEl.textContent = data.message || 'Delete failed.';
errEl.style.display = 'block';
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-trash"></i> Delete';
if (_owner2fa) { document.getElementById('delVideoOtp').value = ''; document.getElementById('delVideoOtp').focus(); }
}
})
.catch(() => {
errEl.textContent = 'An error occurred. Please try again.';
errEl.style.display = 'block';
btn.disabled = false;
btn.innerHTML = '<i class="bi bi-trash"></i> Delete';
});
}
document.addEventListener('keydown', e => { if (e.key === 'Escape') closeVideoDeleteDialog(); });
</script>
@endif
@endauth
@endsection