29 Commits

Author SHA1 Message Date
ghassan
04d63cccdb VS intro screen (arena design), card VS mini + live scorebar, full country names, sports-match edit fix
Match player + preview
- Rebuild VS intro as a 1920×1080 scaled canvas (arena design from drafts/):
  angled RED/BLUE panels with clip-paths, slam-in VS with pulse+shine,
  event/stage/weight header, Match/Court/Referee chips, per-fighter
  Record/Rank/Stats chip row. Every placeholder from the artifact is
  always in the DOM; empty ones are hidden by `.vs-nullable:empty`
  and `.vs-nullable-hide` so the layout adapts without losing the
  design's HTML shape. Country codes always render as full country
  names (via new App\Data\Countries::name()).
- Real-time 6s countdown Skip button; video pinned at t=0 while
  the intro runs, released to play at zero or on Skip.
- Standalone preview page at /videos/{video}/vs-preview.

Video cards (home + everywhere)
- Match cards get a `vs-mini` overlay of the same arena design
  (fixed canvas, per-card ResizeObserver, animations replay every
  time the mouse leaves the thumb). On hover the mini explodes
  outward (panels fly out, VS scales+blurs+fades) and the hover
  video plays over the cleared thumb.
- Match cards also render a `scorebar-mini` overlay (verbatim of
  the full-player msb-scale scorebar + msb-feed) that shows
  during hover playback. Live-scoring is wired per-card via a
  data-sbm-state payload of rounds+points; RED/BLUE score, round
  label, per-round clock, and the top-right Live Scoring ticker
  (4 entries, sport-aware Yuko/Waza-ari/Ippon or Punch/Body
  kick/… labels) all update from the mini video's timeupdate.

Bug fixes
- Hover video wasn't playing sound: dropped the `muted` attribute
  I'd added while debugging match previews.
- White flash strobing on the left of match cards: removed the
  `.vs-mini-flash` element (intro-only flourish that fired on
  every mouseleave replay).
- Sports-match modal was showing "Please complete the required
  fields" when saving basic info for match videos that had no
  SportsMatch row yet: the submit gate only checked matchId, not
  the attached videoId; now it correctly skips uploadVideoFirst()
  in both edit and attach-existing-video modes.

Country names project-wide
- New helper App\Data\Countries::name($iso2) → full country name.
- Swapped `?? country` fallbacks to `?? Countries::name(country)`
  in admin dashboard, video-analytics, video-insights payloads
  (VideoController + SuperAdminController), and the VS partials.
  Now user-visible country labels always show "Bahrain" instead
  of "BH", including chart tooltips and modal titles.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-10 18:34:31 +03:00
ghassan
2b5e480c9a Remove VS screen; fix cropper + sports edit save + headshot/logo mapping
- Remove VS intro from player and thumbnail VS card from match video cards.
  All references (`msb-vs*`, `initVsIntro`, `setVsImg`, `HAS_VS`, `$vs`,
  `$msbThumbVs`, `$hasMatchMeta`) are stripped from scoreboard partials,
  video-card component, and scoreboard script. Related CSS keyframes
  (`msbFadeIn/Out`, `msbDriftA/B`, `msbSweep`) removed.

- Image cropper (resources/views/components/image-cropper.blade.php):
  replace unreliable third-party Cropme integration with a DIY cropper.
  Pan/zoom/rotate wired directly with pointer + wheel events; on save,
  the visible viewport is rendered to an offscreen canvas at the configured
  output-width (with circular clip for `shape="circle"`). Also reparent the
  overlay to <body> on open to escape any transformed Bootstrap-modal
  ancestor's stacking context that clipped it.

- Sports match modal (resources/views/layouts/partials/sports-match-modal.blade.php):
  set fighter photo croppers to 3:4 portrait (285x380) to match the VS
  card's 228x304 frame; club logos + referee stay 1:1 square.

- SportsMatchController::fillFromRequest (line 174): coerce
  `$this->clean($request->input('media', []))` to `[]` when it returns null
  so array_merge doesn't crash under PHP 8's stricter types.

- SportsMatch::headerData(): read fighter headshots + club logos from the
  canonical media.* keys (participant1_photo / participant2_photo /
  club1_logo / club2_logo) that the uploader modal actually saves, with the
  older p1_* / p2_* names kept as a secondary fallback.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-09 23:47:59 +03:00
ghassan
ad6cbaf742 Match highlights: DB-backed rounds/points, draggable point capture, sports sheet Edit
Match highlights sidebar (videos/types/match.blade.php)
- Replaced hardcoded 3-round/5-point/3-review mock with server-rendered loops
  over $video->matchRounds (with points) and $video->coachReviews. Owner-only
  buttons carry real DB ids to the existing JS handlers.
- Fixed savePoint create branch: was doing parseInt(rawMmSs) which truncated
  "1.15" -> 1 second. Now sends the parsed value that edit already used.
- Added a point-capture bar: clicking + on a round pauses the video and shows a
  bottom bar with a big draggable red marker + nudge buttons. Dragging seeks
  the video live; Confirm reads video.currentTime and opens the Add Point modal
  with mm.ss pre-filled and Action focused. Fixed both server- and JS-rendered
  round buttons so dynamic reloads keep the new flow.

Edit → sports sheet routing
- Added sports_match_id to /videos/{video}/edit JSON.
- openEditVideoModal delegates type=match videos to openSportsMatchModal —
  edit mode when a SportsMatch is linked, create-with-attached-video mode
  when the video is match-typed but has no SportsMatch row yet.
- Sports sheet gained attachExistingVideo() so create-mode can be seeded with
  a video that's already in the library (skips the upload dropzone).

Upload chooser mobile bottom-nav
- Bottom nav "Upload" now opens the type chooser (bottom sheet on mobile,
  centred modal on desktop) instead of hard-navigating to /videos/create.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-08 04:01:06 +03:00
ghassan
76f5ef0c84 Fix match-video playback: HEVC → H.264 transcode + correct HLS URL
- CompressVideoJob: rewrite to exec ffmpeg directly. php-ffmpeg's X264
  format class validates the codec name and only accepts libx264, so
  every job dispatched with h264_nvenc had been throwing within ~1s and
  leaving the source untouched. The job now honours the GPU encoder
  settings, and always replaces the source when the codec is HEVC/H.265
  so downloads and the MP4 fallback stay playable.
- VideoController + video-player component: point HLS URLs at
  playlist.m3u8 (the actual master file GenerateHlsJob writes) instead
  of the non-existent master.m3u8, which was 404-ing and forcing the
  player back to the raw MP4.
- VideoController@store: on the NAS-success branch, flip status to
  'ready' and populate duration/is_shorts before dispatching
  GenerateHlsJob, so the job no longer silently no-ops.
- Upload chooser: render as a bottom sheet on mobile, and forward the
  picked type to /videos/create?type= so the create page pre-selects it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-08 02:08:25 +03:00
ghassan
e0aa6e4817 Drag-and-drop reordering for tracks in the edit modal
Replaces the up/down arrow buttons on each track card with a grip
handle. Dragging a card shows a red insertion indicator on the target
card's top or bottom edge and drops it into the closest slot on
release, including gaps between cards or past the last card.

The card is only marked draggable while the grip handle is being held,
so text selection and button clicks inside the card body behave
normally. Existing promote_track_id logic (secondary at position 1
becomes primary on save) is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-02 02:17:24 +03:00
ghassan
3d8d7b8efe Allow converting a video to a music track without losing views/URL
VideoController@update() now handles a replacement media file: if the
new file is audio the row is forced to type=music and, when the on-disk
type folder differs from the declared type (e.g. a video sitting under
users/{u}/videos/ that was later marked music), the media is relocated
into the canonical users/{u}/music/{slug}/tracks/{lang}-{id}/audio.ext
layout. Old primary file and stale meta.json are deleted from NAS; HLS
and slideshow caches are reset. The same relocation is applied by
replaceFile() so the mobile "Replace Media File" flow behaves the same.

Slide- and audio-track-management gates in update() also switched from
isAudioOnlyFile() (extension-based) to the declared type, so secondary
tracks and cover slides added mid-conversion are no longer silently
dropped. The edit modal now renders existing secondary tracks whenever
type=music regardless of the primary file extension.

Also carries an unrelated app.blade.php tweak: the mobile filter bar's
sticky reset moved from .yt-filter-bar to its wrapper, with padding
kept on the inner bar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-08-01 14:39: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
ba8ab11ce4 Chunked video upload, persistent track order, per-track playlist entries
Chunked uploads: bypass Cloudflare's 100 MB request cap by slicing the
video/audio into 8 MB chunks and reassembling server-side before the
normal store flow runs.

Track reorder: audio tracks gain a `position` column so a user's edit-
modal ordering survives reload. `Video::audioTracks()` now orders by
position, `promote_track_id` remembers the swapped row, and freshly
uploaded tracks append to the end.

Playlist per-track pinning: `playlist_videos.audio_track_id` remembers
which language the user pinned when adding a song. Same song with a
different track becomes a separate row (Spotify-style duplicates).
Player-data exposes `active_stream_url` + `active_track_id`, sidebar
cards render `?track=` from the pivot, and both `plTransitionTo` and
initial-load code activate the corresponding language option.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-31 02:42:25 +03:00
ghassan
af276f2cd1 Wire match header to real SportsMatch data; add Match#/Court + country flags
The match page header rendered hard-coded demo content (Sami Al Manea vs Hassan
Al Shallan, Match# 103, referee Ghassan Yusuf, external takeone-dev links) on
EVERY match video, ignoring the SportsMatch record the create form saves.

- Video::sportsMatch() hasOne relationship.
- SportsMatch::headerData() maps the record into the header's shape (fighters +
  country flags, championship, weight class, referee, venue, match#/court),
  null-safe, with a country-name/ISO2 -> flag-icons resolver.
- match.blade header now renders from headerData(): real names/flags, no
  external links, and degrades gracefully to just title/views/date when a video
  has no match data (instead of the fake card).
- sports-match-modal: add Match # and Court fields (stored in the existing
  competition JSON, no migration) and convert fighter/referee country inputs to
  the mandated <x-country-select> so header flags resolve from ISO2.
- Tracker updated for the new country-select usages.

Verified: empty state (no SportsMatch) shows only title/views/date; a populated
record renders fighters, flags (bh/us), championship, Match# 42, Court 3, U21,
referee; modal compiles with the new fields.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-29 01:57:07 +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
6aae6f86b6 Add upload type chooser and redesign upload modal
Clicking Create now opens a card-based chooser (Generic / Music / Sports)
before the upload modal; the chosen type is applied and its Content Type
dropdown is hidden as redundant.

Per type:
- Generic/Match show their fields inline in the modal (no card/popup);
  Music keeps the track-card + Track Editor popup for multi-language tracks.
- "Language Track" wording stays music-only; a single Language field is now
  available for generic/match too (mirrored on the mobile create page with
  name-swapping so only the active picker submits).

Also unifies all modal controls (dropdowns, selects, inputs) to one larger,
red-accented dark style scoped to #uploadModal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 14:12:08 +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
ghassan
f850f40f78 all is working great 2026-03-15 04:06:35 +03:00
ghassan
69f5df163a update the match view 2026-03-12 03:59:52 +03:00
ghassan
062c0e896f latest update 2026-03-11 11:21:33 +03:00
ghassan
79bcd95d36 Hide header upload button on mobile - use bottom nav instead 2026-03-03 19:51:13 +03:00
ghassan
a28023c29b admin panel added and comments are working and likes are working 2026-03-03 17:36:19 +03:00
ghassan
72e9439727 made the video cards components 2026-03-02 02:16:28 +03:00
ghassan
3aa49d638d latest update my Video Platform is working Great 2026-02-26 22:35:52 +03:00
ghassan
dcdcafe0ba latest update my Video Platform is working Great 2026-02-26 21:29:52 +03:00
ghassan
b38f1a93bb latest update youtube replica 2026-02-25 00:47:59 +00:00
ghassan
5253f89b63 Add video platform features: authentication, video management, user profiles, likes/views tracking
- Added authentication controllers (Login, Register)
- Added UserController for user profile management
- Added VideoController with full CRUD operations
- Added Video model with relationships (user, likes, views)
- Added User model enhancements (avatar, video relationships)
- Added database migrations for video_likes, video_views, user_avatar, video_visibility
- Added CompressVideoJob for video processing
- Added VideoUploaded mail notification
- Added authentication routes
- Updated web routes with video and user routes
- Added layout templates (app, plain, partials)
- Added user views (profile, settings, channel, history, liked)
- Added video views (create, edit, index, show)
- Added email templates
2026-02-25 00:03:02 +00:00