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) <[email protected]>
This commit is contained in:
1 parent
66fd78c10f
commit
a4384113c2
24 files changed
+1738
-258
No files matched your search
@@ -11,6 +11,7 @@
|
||||
$outputWidth = (int) $attributes->get('output-width', 0); // final output px width (0 = viewport size)
|
||||
$targetInput = $attributes->get('target-input', ''); // form mode: ID of file input to set result on
|
||||
$previewImg = $attributes->get('preview-img', ''); // ID of img to update with preview
|
||||
$resultCallback = $attributes->get('result-callback', ''); // callback mode: JS fn called with the cropped File
|
||||
@endphp
|
||||
|
||||
@once
|
||||
@@ -202,8 +203,22 @@
|
||||
var outputWidth = {{ $outputWidth > 0 ? $outputWidth : 0 }};
|
||||
var targetInputId = '{{ $targetInput }}'; // form mode: ID of the file input to intercept
|
||||
var previewImgId = '{{ $previewImg }}';
|
||||
var resultCbName = '{{ $resultCallback }}'; // callback mode: name of a global fn given the cropped File
|
||||
|
||||
var isFormMode = targetInputId !== '';
|
||||
var isFormMode = targetInputId !== '';
|
||||
var isCallbackMode = resultCbName !== '';
|
||||
|
||||
// In callback mode the host function decides when to close / advance, so we
|
||||
// never auto-close here — we just hand the File back and reset the button.
|
||||
function deliverResult(file) {
|
||||
if (typeof window[resultCbName] === 'function') window[resultCbName](file);
|
||||
var sb = document.getElementById('tcSaveBtn_' + id);
|
||||
var st = document.getElementById('tcSaveBtnText_' + id);
|
||||
var ab = document.getElementById('tcAsIsBtn_' + id);
|
||||
if (sb) sb.disabled = false;
|
||||
if (ab) ab.disabled = false;
|
||||
if (st) st.textContent = 'Crop & Save';
|
||||
}
|
||||
|
||||
function getCsrf() {
|
||||
var m = document.querySelector('meta[name="csrf-token"]');
|
||||
@@ -343,6 +358,11 @@
|
||||
var cropOpts = outputWidth > 0 ? { type: 'base64', width: outputWidth } : { type: 'base64' };
|
||||
|
||||
cropperInst.crop(cropOpts).then(function (base64) {
|
||||
if (isCallbackMode) {
|
||||
var cbName = originalFile ? originalFile.name : 'cropped.png';
|
||||
deliverResult(base64ToFile(base64, cbName));
|
||||
return;
|
||||
}
|
||||
if (isFormMode) {
|
||||
var fname = originalFile ? originalFile.name : 'cropped.png';
|
||||
setOnTargetInput(base64ToFile(base64, fname));
|
||||
@@ -370,7 +390,9 @@
|
||||
window['tcUploadAsIs_' + id] = function () {
|
||||
if (!originalFile) { window.closeCropperModal(id); return; }
|
||||
|
||||
if (isFormMode) {
|
||||
if (isCallbackMode) {
|
||||
deliverResult(originalFile);
|
||||
} else if (isFormMode) {
|
||||
// Put the original (un-cropped) file on the target input so the form sees it.
|
||||
setOnTargetInput(originalFile);
|
||||
window.closeCropperModal(id);
|
||||
|
||||
Reference in new issue
Block a user