184 lines
8.0 KiB
PHP
184 lines
8.0 KiB
PHP
<?php
|
|
|
|
namespace App\Jobs;
|
|
|
|
use App\Models\Setting;
|
|
use App\Models\User;
|
|
use App\Models\Video;
|
|
use App\Services\NasSyncService;
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class NasToLocalMigrationJob implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
public int $tries = 1;
|
|
public int $timeout = 7200; // 2 hours
|
|
|
|
private function updateProgress(array $data): void
|
|
{
|
|
Cache::put('nas_disable_progress', json_encode($data), 3600);
|
|
}
|
|
|
|
public function handle(NasSyncService $nas): void
|
|
{
|
|
$progress = [
|
|
'current' => 0,
|
|
'total' => 0,
|
|
'phase' => 'Counting files...',
|
|
'done' => false,
|
|
'error' => null,
|
|
];
|
|
$this->updateProgress($progress);
|
|
|
|
try {
|
|
// ── Count all items ───────────────────────────────────────────────
|
|
$videos = Video::where('path', 'like', 'users/%')->get();
|
|
|
|
$slides = \DB::table('video_slides')
|
|
->where('filename', 'like', 'users/%')
|
|
->get();
|
|
|
|
$usersWithAvatar = User::where('avatar', 'like', 'users/%')->get();
|
|
$usersWithBanner = User::where('banner', 'like', 'users/%')->get();
|
|
|
|
$postImages = \DB::table('post_images')
|
|
->where('filename', 'like', 'users/%')
|
|
->get();
|
|
|
|
// Count thumbnails separately (they're additional per-video downloads)
|
|
$videoThumbs = $videos->filter(fn($v) => $v->thumbnail && str_starts_with($v->thumbnail, 'users/'));
|
|
|
|
$total = $videos->count()
|
|
+ $videoThumbs->count()
|
|
+ $slides->count()
|
|
+ $usersWithAvatar->count()
|
|
+ $usersWithBanner->count()
|
|
+ $postImages->count();
|
|
|
|
$progress['total'] = $total;
|
|
$progress['phase'] = 'Downloading files from NAS...';
|
|
$this->updateProgress($progress);
|
|
|
|
// ── Download videos ───────────────────────────────────────────────
|
|
foreach ($videos as $video) {
|
|
$nasPath = $video->path;
|
|
$localPath = storage_path('app/' . $nasPath);
|
|
|
|
try {
|
|
$nas->ensureLocalAsset($localPath, $nasPath);
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: failed to download video #' . $video->id . ' path=' . $nasPath . ': ' . $e->getMessage());
|
|
}
|
|
|
|
$progress['current']++;
|
|
$progress['phase'] = 'Downloading videos... (' . $progress['current'] . '/' . $total . ')';
|
|
$this->updateProgress($progress);
|
|
}
|
|
|
|
// ── Download thumbnails ───────────────────────────────────────────
|
|
foreach ($videoThumbs as $video) {
|
|
$nasPath = $video->thumbnail;
|
|
$localPath = storage_path('app/' . $nasPath);
|
|
|
|
try {
|
|
$nas->ensureLocalAsset($localPath, $nasPath);
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: failed to download thumbnail for video #' . $video->id . ' path=' . $nasPath . ': ' . $e->getMessage());
|
|
}
|
|
|
|
$progress['current']++;
|
|
$progress['phase'] = 'Downloading thumbnails... (' . $progress['current'] . '/' . $total . ')';
|
|
$this->updateProgress($progress);
|
|
}
|
|
|
|
// ── Download slides ───────────────────────────────────────────────
|
|
foreach ($slides as $slide) {
|
|
$nasPath = $slide->filename;
|
|
$localPath = storage_path('app/' . $nasPath);
|
|
|
|
try {
|
|
$nas->ensureLocalAsset($localPath, $nasPath);
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: failed to download slide id=' . $slide->id . ' path=' . $nasPath . ': ' . $e->getMessage());
|
|
}
|
|
|
|
$progress['current']++;
|
|
$progress['phase'] = 'Downloading audio slides... (' . $progress['current'] . '/' . $total . ')';
|
|
$this->updateProgress($progress);
|
|
}
|
|
|
|
// ── Download user avatars ─────────────────────────────────────────
|
|
foreach ($usersWithAvatar as $user) {
|
|
$nasPath = $user->avatar;
|
|
$localPath = storage_path('app/' . $nasPath);
|
|
|
|
try {
|
|
$nas->ensureLocalAsset($localPath, $nasPath);
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: failed to download avatar for user #' . $user->id . ' path=' . $nasPath . ': ' . $e->getMessage());
|
|
}
|
|
|
|
$progress['current']++;
|
|
$progress['phase'] = 'Downloading avatars... (' . $progress['current'] . '/' . $total . ')';
|
|
$this->updateProgress($progress);
|
|
}
|
|
|
|
// ── Download user banners ─────────────────────────────────────────
|
|
foreach ($usersWithBanner as $user) {
|
|
$nasPath = $user->banner;
|
|
$localPath = storage_path('app/' . $nasPath);
|
|
|
|
try {
|
|
$nas->ensureLocalAsset($localPath, $nasPath);
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: failed to download banner for user #' . $user->id . ' path=' . $nasPath . ': ' . $e->getMessage());
|
|
}
|
|
|
|
$progress['current']++;
|
|
$progress['phase'] = 'Downloading banners... (' . $progress['current'] . '/' . $total . ')';
|
|
$this->updateProgress($progress);
|
|
}
|
|
|
|
// ── Download post images ──────────────────────────────────────────
|
|
foreach ($postImages as $img) {
|
|
$nasPath = $img->filename;
|
|
$localPath = storage_path('app/' . $nasPath);
|
|
|
|
try {
|
|
$nas->ensureLocalAsset($localPath, $nasPath);
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: failed to download post image id=' . $img->id . ' path=' . $nasPath . ': ' . $e->getMessage());
|
|
}
|
|
|
|
$progress['current']++;
|
|
$progress['phase'] = 'Downloading post images... (' . $progress['current'] . '/' . $total . ')';
|
|
$this->updateProgress($progress);
|
|
}
|
|
|
|
// ── Disable NAS ───────────────────────────────────────────────────
|
|
Setting::set('nas_sync_enabled', 'false');
|
|
|
|
$progress['done'] = true;
|
|
$progress['phase'] = 'Complete';
|
|
$this->updateProgress($progress);
|
|
|
|
Log::info('NasToLocalMigrationJob: completed. ' . $total . ' files migrated. NAS disabled.');
|
|
|
|
} catch (\Throwable $e) {
|
|
Log::error('NasToLocalMigrationJob: fatal error: ' . $e->getMessage(), [
|
|
'trace' => $e->getTraceAsString(),
|
|
]);
|
|
|
|
$progress['error'] = $e->getMessage();
|
|
$this->updateProgress($progress);
|
|
}
|
|
}
|
|
}
|