Add sports-match type, device tracking, profile visits, and share refactor

- New SportsMatch model/controller and sports UI components/modal
- Move share-modal to a reusable x-share-modal/x-share-button component
- Add VideoSharedWithUser notification and share-to-members flow
- Device/user-agent tracking on views, downloads, share accesses
- ProfileVisit model + migration; subscription source tracking
- Email thumbnail support; remove stale TODO files
This commit is contained in:
ghassan committed 2026-05-29 01:50:28 +03:00
1 parent 6aae6f86b6
commit 73527f3781
61 files changed
+4014 -636

No files matched your search

@@ -77,14 +77,11 @@
<svg class="ytp-svg-pause" viewBox="0 0 24 24" style="display:none"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
</button>
@if(isset($previousVideo) && $prevUrl)
<button class="ytp-button" title="Previous" onclick="window.location.href='{{ $prevUrl }}'">
@if(isset($playlist) && $playlist)
<button class="ytp-button ytp-prev-btn" title="Previous" onclick="if(window.plPrev)window.plPrev();">
<svg viewBox="0 0 24 24"><path d="M6 6h2v12H6zm3.5 6 8.5 6V6z"/></svg>
</button>
@endif
@if(isset($nextVideo) && $nextUrl)
<button class="ytp-button" title="Next" onclick="window.location.href='{{ $nextUrl }}'">
<button class="ytp-button ytp-next-btn" title="Next" onclick="if(window.plNext)window.plNext();">
<svg viewBox="0 0 24 24"><path d="m6 18 8.5-6L6 6v12zM16 6v12h2V6h-2z"/></svg>
</button>
@endif
@@ -224,12 +221,16 @@
/* ══ Full ytp styles ══ */
.ytp-wrap {
position: relative; width: 100%; background: #000;
position: relative; width: 100% !important; background: #000;
border-radius: 12px; overflow: hidden;
aspect-ratio: 16/9;
aspect-ratio: 16/9 !important;
height: auto !important;
max-height: none !important;
min-height: 0 !important;
}
.ytp {
.ytp, .audio-ytp {
position: relative; width: 100%; height: 100%;
aspect-ratio: 16/9;
background: #000; outline: none;
user-select: none; overflow: hidden;
font-family: Roboto, Arial, sans-serif;
@@ -1063,6 +1064,9 @@ window._audioPlayerUpdate = function(d) {
var langPopup = document.getElementById('ytpLangPopup');
if (!langWrap || !langPopup || !langBtn) return;
// New song loaded → back to its primary track, so shares don't carry a stale track id.
window._ytpTrackId = 0;
function flagHtml(flag, size) {
var s = size === 'sm' ? 'width:22px;height:16px;border-radius:2px;display:inline-block;flex-shrink:0;'
: 'width:22px;height:16px;border-radius:2px;display:inline-block;';
@@ -1143,6 +1147,8 @@ window._audioPlayerUpdate = function(d) {
var url = opt.dataset.langUrl;
var flag = opt.dataset.langFlag;
var curTime = audio.currentTime;
// Track the selected version so "Share" links to this exact language (0 = primary).
window._ytpTrackId = parseInt(opt.dataset.langId, 10) || 0;
langPopup.querySelectorAll('.ytp-lang-option').forEach(function(o) { o.classList.remove('active'); });
opt.classList.add('active');
langPopup.classList.remove('open');