12 Commits

Author SHA1 Message Date
ghassan
1c4e4986b5 Frame-accurate scrubbing + mobile highlights UX + collapsed action menu
Frame-accurate timestamps (end-to-end)
- Migration 2026_08_08_000002 promotes match_rounds.start_time_seconds,
  match_points.timestamp_seconds, coach_reviews.start_time_seconds and
  coach_reviews.end_time_seconds from INTEGER to decimal(10,3).
- Model $casts updated (float). MatchEventController validators relaxed
  from `integer` to `numeric|min:0` on all four fields.
- Blade SSR data-time-{start,end} attributes cast to (float) so the
  first paint carries frame precision.
- Point + review capture strips: slider step = 1/fps, snapToFrame()
  applied to every seek/nudge/input commit. Clock now shows SMPTE
  MM:SS.FF; parsePcbTimeInput accepts MM:SS.FF, MM:SS, MM.SS or seconds.
- Default fps is 30; override via window.matchFPS.
- confirmPointCapture no longer Math.round()s currentTime — sends the
  exact frame boundary.

Point + review UX
- Video pauses aggressively on scrubber grab (mousedown/pointerdown/
  touchstart) AND on every input, with a 30ms follow-up to beat HLS.js
  race conditions.
- Zoom buttons now scope by data-pcs-zoom / data-rcb-zoom so clicks on
  the review-strip zoom don't clobber the point-strip zoom (root cause
  of the "resets while button still on 20x" bug).
- Point cards now play a preroll/postroll clip at 1× then replay at
  the chosen slow-mo rate, then resume normal playback.
- REPLAY ×N badge shown in the top-left of the video during replays,
  swapping palette when slow-mo kicks in.
- Slow-mo picker (¼× ½× ¾×) in the tab-header — window.slowmoRate is
  the source of truth for both point and review replays.
- Clicking a card hides the player chrome (controls-hidden re-applied
  across 0/10/60/200/500ms to beat pause/seek/play showControls races);
  mousemove over the video brings them back instantly.
- Review-tools slow-mo button removed — the card click IS the trigger.

Coach review specific
- Dual-thumb scrubber on a shared track with a red fill between the
  thumbs (visualises the note's range). Start clamps to ≤ end and
  vice-versa; nudges act on the last-touched thumb.
- Note overlay live-previews as user types and is drag-to-position;
  overlay position persists (position_x/position_y decimal(6,4)).
- Overlay uses container-query units (cqi) so text scales with the
  player width and position stays proportional on any resize.
- Timeline card design (chapter-style time label + subtle card with
  emoji, note, coach name, tools) — nothing else selected.

Sidebar
- "Rounds & points" / "Private notes" section labels removed; only
  the owner-only + Add Round / + Add Note button remains.
- Points that share a timestamp within a round collapse into ONE card
  with a chip per side (equal-width Blue/Red pills), one edit/delete
  pair, and a coloured score line (yellow ROUND N, blue/red score
  badges — background pills with white numerals).
- On mobile the highlights sheet only closes via its own toggle now.
  Backdrop is pointer-events: none so taps pass through to the video.

Mobile capture strip
- Renders below the video on mobile portrait so the paused frame is
  visible while typing. Wider inner padding (10px 20px 14px) so
  content doesn't sit on the edges.
- .pcs-entry uses flex-wrap: nowrap and Action input shrinks to
  fit — the row stays on one line at any width.

Collapsed action menu (video-actions component)
- Every viewport now shows the single  Action dropdown; individual
  desktop-action buttons are hidden by CSS across the board.

SPA navigation fixes
- window.videoId + isOwner now live on window so navigation to a new
  match video via Up Next can update them via reloadMatchVideoState.
- Tabs, event-item clicks, highlights toggle and sidebar-height sync
  re-hydrate on each SPA swap.
- Blade point-time regression: "{{ '@' . $fmtTime(...) }}" instead of
  the misused "@{{ ... }}" escape directive.

Backend
- Point-score recompute (recomputeRoundScores) already sums by
  (timestamp, id) order — works fine with the new decimal columns.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-09 02:26:19 +03:00
ghassan
8d27520bdb Video merge feature, default avatar, video-redirects table, misc UI tweaks
Bundled pre-existing changes on the branch:
- Video merge: controller, service, admin merge modal, and a repair
  console command; new video_redirects table (with source_folder)
  so merged/moved videos keep resolving under their old keys.
- Default avatar SVG for users without a profile picture.
- Assorted view tweaks across profile, video actions/comments/insights,
  admin layout, video-details, and the app layout.
- Small touch-ups in SuperAdminController, User model, NasSyncService.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-31 02:42:43 +03:00
ghassan
6b43a7060a Fix player UI: sports Highlights pane, scrubber knob, volume knob, description + save-to-playlist
Player/UI fixes:
- Sports (match) Highlights pane: move the toggle click-handler script out of
  the always-false @if(false ...) legacy block so the "Highlights" button opens,
  and emit videoId/isOwner with @json instead of {{ json_encode() }} (escaped
  quotes crashed the data/tab/CRUD block once route keys became hashid strings).
- Progress scrubber knob (video + audio players): center on the track line with
  translate(-50%, -50%); drop the margin-top hack that floated it above the line.
- Music player volume: give the slider wrap height so overflow:hidden no longer
  crops the knob; add a subtle thumb shadow for visibility.
- Music language menu: cap height to available space above the header, sticky
  header, internal scroll; keep controls from auto-hiding while the menu is open.
- Description box: re-check "Show more" overflow at every settle point (fonts,
  images, rAF, tab reopen) so SPA autonext keeps the expand button.

Also bundles pending work: save-to-playlist button component, playlist/channel
views, PlaylistController + NasSyncService, and component-usage tracker updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 22:12:58 +03:00
ghassan
f98e5415a3 Add lyrics pipeline, playlist views, admin toggles, and player polish
Lyrics pipeline (Whisper + Demucs + description alignment):
- New GenerateLyricsJob runs WhisperX with VAD filtering and forced word
  alignment, writes per-track JSON to NAS.
- New DecorateLyricsJob calls the active LLM provider to bake one to
  several emojis into each line (heavy decoration prompt).
- LyricsDescriptionParser strips heading content, section markers, and
  emoji-decoration from a song's description while preserving every
  language verbatim.
- correct_whisper_with_description aligner: strong-match anchors only,
  vocal-region-aware gap-fill so missing verses land on actual singing.
- Owner UI for generate/regenerate/edit/delete in the player gear.

Admin pages:
- /admin/lyrics    toggles for VAD, vocal gap-fill, Demucs, master
- /admin/gpu       extracted GPU section, encoder picker, FFmpeg path
- /admin/backup    extracted users-and-settings export/import
- /admin/settings  now AI/LLM only with provider list and Test button
- /admin/nas-storage hosts NAS settings, repair, disable flow, browser
- Shared partials/settings-styles for a uniform look across pages.

Playlist view tracking:
- Migration adds playlists.view_count and playlist_views dedup table.
- Playlist::bumpViewIfNew increments per device with a one-hour window.
- Tracked from /playlists/{id}, /playlists/share/{token}, /ps/{token},
  and /videos/{id}?playlist={token}.  Dispatched after-response so it
  never blocks the page render.
- Loading a playlist on the video page now runs one query instead of
  the four the old getNextVideo/getPreviousVideo path triggered.
- View counts shown on every playlist card and the playlist hero.

Player polish:
- Floating mini-player is draggable, persists its position in
  localStorage, clamps to viewport on resize.
- Mini disabled entirely on mobile (less than 768px).
- New gear-menu Mini Player toggle (persists in localStorage) lets the
  user disable both scroll-activation and SPA-nav-activation.
- Close button keeps media playing when used on the player's own page.
- SPA navigator now swaps a #page-scripts container so per-page JS
  (channel tabs, etc.) gets re-executed after content swaps.

Storage layout:
- Runtime data moved from /storage/* to /data/* and gitignored.
- /ml/venv, /ml/cache, /ml/__pycache__ excluded.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-31 22:01:47 +03:00
ghassan
73527f3781 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
2026-05-29 01:50:28 +03:00
ghassan
d9959c4452 Add share-video-by-email feature
New POST /videos/{video}/share/email route (auth + throttled) handled by
VideoController@shareByEmail, sending the VideoShared mailable rendered from
emails/video-shared.blade.php. Wired into the share modal and video-actions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 14:12:01 +03:00
ghassan
a4384113c2 Audio songs: one-folder storage, version-aware download/share, GPU-checked renders
Storage structure
- All audio tracks (primary + per-language) now live in one folder per song with
  unique lowercase names ({slug}-{lang}-{id}); no more tracks/ subfolder.
- Generated renders (download video + HLS) moved into the song's local-only cache/
  subfolder, separated from source files (never synced to NAS, safe to wipe).
- tracks:reorganize artisan command (dry-run default) consolidates legacy files,
  updates DB paths, and deletes orphans + empty folders.
- CLAUDE.md documents the canonical layout as a global rule (identical local + NAS).

Version-aware download & share
- Download MP3/Video and Share now act on the version being played; ?track={id}
  is carried through share links and auto-selects audio + title + flag + about +
  OG/meta on open.

GPU + visualizer
- Setting::gpuUsable() runs a cached health probe (nvidia-smi + nvenc smoke test,
  256x144) before sending any encode to the GPU; falls back to CPU otherwise.
- Visualizer "Download Video" bakes in equal-width, cover-coloured, translucent
  frequency bars; loop-filter rebuild makes generation ~25x faster.

Image cropper
- result-callback mode + per-song cover-slide cropper in upload/edit (modal + mobile).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 14:03:43 +03:00
ghassan
66fd78c10f Add multi-language audio tracks and self-hosted flag-icons
Introduce per-video language support and multiple audio tracks
(VideoAudioTrack model + migrations for language, description, title),
a reusable language-select component, and a track-editor form. Bundle
the self-hosted flag-icons v7.2.3 library and a NAS auto-sync command.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 21:32:52 +03:00
ghassan
c160242dbc WIP: storage-fix-local-nas work before playlist controls feature
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 11:15:20 +03:00
ghassan
0b2e95ea65 Add NAS file manager integration and all pending platform changes
- Installed p7h/nas-file-manager package via private VCS repo
- Published config/nas-file-manager.php with super_admin middleware restriction
- Added NAS env vars to .env.example
- Created admin/nas-storage page with connection info panel and file browser widget
- Added NAS Storage link to admin sidebar (super_admin only)
- Added SuperAdminController@nasStorage method and admin.nas-storage route
- Includes all accumulated branch changes: profile wall, 2FA, audit logs,
  settings panel, country/phone/timezone components, posts, slideshow,
  playlist shares, video downloads/shares, comment likes, notifications,
  social links, and more

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 13:24:32 +03:00
ghassan
2a562b99f1 latest update 2026-04-05 03:30:22 +03:00
ghassan
84fcbd84dc latest update 2026-03-21 02:24:27 +03:00