first(); if ($video) { $dir = $nas->resolveVideoDir($video); $ext = pathinfo($filename, PATHINFO_EXTENSION) ?: 'jpg'; foreach (["thumb.webp", "thumb.{$ext}"] as $nasFile) { if ($nas->ensureLocalAsset($local, "{$dir}/{$nasFile}")) break; } } // Might be a slide if (! file_exists($local)) { $slide = VideoSlide::where('filename', $filename)->with('video')->first(); if ($slide && $slide->video) { $dir = $nas->resolveVideoDir($slide->video); $ext = pathinfo($filename, PATHINFO_EXTENSION) ?: 'jpg'; $nas->ensureLocalAsset($local, "{$dir}/slides/{$slide->position}.{$ext}"); } } // Might be a playlist thumbnail if (! file_exists($local)) { $nas->ensureLocalAsset($local, $filename); } if (! file_exists($local)) abort(404); } return $this->fileResponse($local); } // Legacy flat filename format $local = storage_path('app/public/thumbnails/' . $filename); if (! file_exists($local)) { // Find the video that owns this thumbnail and pull from NAS $video = Video::where('thumbnail', $filename)->first(); if ($video) { $dir = $nas->resolveVideoDir($video); $nasPath = "{$dir}/thumb.webp"; $nas->ensureLocalAsset($local, $nasPath); } // Not found via video — might be a slide if (! file_exists($local)) { $slide = VideoSlide::where('filename', $filename)->with('video')->first(); if ($slide && $slide->video) { $dir = $nas->resolveVideoDir($slide->video); $ext = pathinfo($filename, PATHINFO_EXTENSION) ?: 'jpg'; $nasPath = "{$dir}/slides/{$slide->position}.{$ext}"; $nas->ensureLocalAsset($local, $nasPath); } } if (! file_exists($local)) { abort(404); } } return $this->fileResponse($local); } public function avatar(string $filename, NasSyncService $nas): Response { // New format: "users/{slug}/profile/avatar.{ext}" if (str_starts_with($filename, 'users/')) { $local = storage_path('app/' . $filename); if (! file_exists($local)) { @mkdir(dirname($local), 0755, true); $user = User::where('avatar', $filename)->first(); if ($user) { $dir = "users/{$nas->userSlug($user)}/profile"; $ext = pathinfo($filename, PATHINFO_EXTENSION) ?: 'webp'; foreach (["avatar.webp", "avatar.{$ext}"] as $nasFile) { if ($nas->ensureLocalAsset($local, "{$dir}/{$nasFile}")) break; } } if (! file_exists($local)) abort(404); } return $this->fileResponse($local); } // Legacy flat format $local = storage_path('app/public/avatars/' . $filename); if (! file_exists($local)) { $user = User::where('avatar', $filename)->first(); if ($user) { $dir = "users/{$nas->userSlug($user)}/profile"; $nasPath = "{$dir}/avatar.webp"; $nas->ensureLocalAsset($local, $nasPath); } if (! file_exists($local)) abort(404); } return $this->fileResponse($local); } public function banner(string $filename, NasSyncService $nas): Response { // New format: "users/{slug}/profile/cover.{ext}" if (str_starts_with($filename, 'users/')) { $local = storage_path('app/' . $filename); if (! file_exists($local)) { @mkdir(dirname($local), 0755, true); $user = User::where('banner', $filename)->first(); if ($user) { $dir = "users/{$nas->userSlug($user)}/profile"; $ext = pathinfo($filename, PATHINFO_EXTENSION) ?: 'webp'; foreach (["cover.webp", "cover.{$ext}"] as $nasFile) { if ($nas->ensureLocalAsset($local, "{$dir}/{$nasFile}")) break; } } if (! file_exists($local)) abort(404); } return $this->fileResponse($local); } // Legacy flat format $local = storage_path('app/public/banners/' . $filename); if (! file_exists($local)) { $user = User::where('banner', $filename)->first(); if ($user) { $dir = "users/{$nas->userSlug($user)}/profile"; $nasPath = "{$dir}/cover.webp"; $nas->ensureLocalAsset($local, $nasPath); } if (! file_exists($local)) abort(404); } return $this->fileResponse($local); } public function postImage(string $filename, NasSyncService $nas): Response { // New format: "users/{slug}/posts/{id}/{seq}.{ext}" if (str_starts_with($filename, 'users/')) { $local = storage_path('app/' . $filename); if (! file_exists($local)) { @mkdir(dirname($local), 0755, true); // NAS path is identical to the relative path stored in DB $nas->ensureLocalAsset($local, $filename); if (! file_exists($local)) abort(404); } return $this->fileResponse($local); } // Legacy flat format $local = storage_path('app/public/post_images/' . $filename); if (! file_exists($local)) abort(404); return $this->fileResponse($local); } // ── Helper ──────────────────────────────────────────────────────────────── private function fileResponse(string $path): Response { $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); $mime = match ($ext) { 'webp' => 'image/webp', 'png' => 'image/png', 'gif' => 'image/gif', default => 'image/jpeg', }; return response(file_get_contents($path), 200, [ 'Content-Type' => $mime, 'Cache-Control' => 'public, max-age=86400', 'Last-Modified' => gmdate('D, d M Y H:i:s', filemtime($path)) . ' GMT', ]); } }