Use NAS as primary storage — direct upload when enabled
When NAS storage is enabled, uploaded files go directly to the NAS share
(users/{username}/videos/{title-slug}/) with no permanent local copy kept.
Thumbnails and video are fetched from NAS on demand for streaming/playback.
When NAS is disabled, files are organised into the same directory schema
in local storage.
- VideoController: branch upload flow on NAS enabled/disabled
- NasSyncService: add uploadDirectToNas() for direct NAS writes,
organizeLocalFiles() for local NAS-schema, localVideoDir() resolver,
deleteLocalAssets() for post-sync cleanup
- GenerateHlsJob: download from NAS via ensureLocalCopy() when local
file is absent (NAS-primary mode); clean up temp after HLS generation
- CompressVideoJob: place compressed file alongside original (any dir)
- Video/VideoSlide models: localVideoPath(), localThumbnailPath(),
thumbnailStorageKey(), localPath(), storageKey() helpers for
format-agnostic path resolution (old flat paths + new NAS-schema paths)
- MediaController: serve thumbnails from NAS-mirrored paths with NAS fallback
- SuperAdminController: use model path helpers for file deletion
- NasFreeLocalStorage: scan new users/ tree in addition to legacy flat dirs
- Settings: rename "NAS Storage Sync" tab to "NAS Storage", update description
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
1 parent
296d605864
commit
6b3ab5b65e
11 files changed
+869
-125
No files matched your search
@@ -317,6 +317,51 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── NAS Storage ───────────────────────────────────────────── --}}
|
||||
<div class="settings-section">
|
||||
<div class="settings-section-header">
|
||||
<i class="bi bi-hdd-network"></i>
|
||||
NAS Storage
|
||||
@if($settings['nas_sync_enabled'] === 'true')
|
||||
<span class="chip chip-green" style="margin-left:6px;"><span class="chip-dot"></span> Enabled</span>
|
||||
@else
|
||||
<span class="chip chip-red" style="margin-left:6px;"><span class="chip-dot"></span> Disabled</span>
|
||||
@endif
|
||||
</div>
|
||||
<div class="settings-section-body">
|
||||
|
||||
<div class="setting-row" style="padding-top:0;">
|
||||
<div class="setting-label">
|
||||
<strong>Use NAS as primary storage</strong>
|
||||
<small>
|
||||
When enabled, uploads go <strong>directly to the NAS</strong> — no permanent local copy is kept.
|
||||
Files are stored at <code>users/{username}/videos/{title-slug}/</code> on the NAS share.
|
||||
Thumbnails and video are fetched from NAS on demand for streaming and playback.
|
||||
When disabled, files are stored in local storage using the same directory schema.
|
||||
Requires the NAS connection to be configured under
|
||||
<a href="{{ route('admin.nas-storage') }}" style="color:var(--brand)">NAS Storage</a>.
|
||||
</small>
|
||||
</div>
|
||||
<div class="setting-control">
|
||||
<label class="toggle-wrap">
|
||||
<div class="toggle-switch">
|
||||
<input type="checkbox" id="nasSyncInput" name="nas_sync_enabled_check"
|
||||
{{ $settings['nas_sync_enabled'] === 'true' ? 'checked' : '' }}>
|
||||
<div class="toggle-track"></div>
|
||||
<div class="toggle-thumb"></div>
|
||||
</div>
|
||||
<span class="toggle-label" id="nasSyncLabel">
|
||||
{{ $settings['nas_sync_enabled'] === 'true' ? 'Enabled' : 'Disabled' }}
|
||||
</span>
|
||||
</label>
|
||||
<input type="hidden" name="nas_sync_enabled" id="nasSyncHidden"
|
||||
value="{{ $settings['nas_sync_enabled'] }}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- ── Save ─────────────────────────────────────────────────── --}}
|
||||
<div class="save-bar">
|
||||
<a href="{{ route('admin.dashboard') }}" class="adm-btn">Cancel</a>
|
||||
@@ -347,6 +392,15 @@ function selectEncoder(el) {
|
||||
document.getElementById('gpuPresetSelect').value = isCpu ? 'fast' : 'p4';
|
||||
}
|
||||
|
||||
// ── NAS sync toggle ───────────────────────────────────────────
|
||||
const nasToggle = document.getElementById('nasSyncInput');
|
||||
const nasHidden = document.getElementById('nasSyncHidden');
|
||||
const nasLabel = document.getElementById('nasSyncLabel');
|
||||
nasToggle.addEventListener('change', () => {
|
||||
nasHidden.value = nasToggle.checked ? 'true' : 'false';
|
||||
nasLabel.textContent = nasToggle.checked ? 'Enabled' : 'Disabled';
|
||||
});
|
||||
|
||||
// ── GPU toggle ────────────────────────────────────────────────
|
||||
const gpuToggle = document.getElementById('gpuEnabledInput');
|
||||
const gpuHidden = document.getElementById('gpuEnabledHidden');
|
||||
|
||||
Reference in new issue
Block a user