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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
- 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