Explorar el Código

新增导出全部分镜并打包的接口

lh hace 3 meses
padre
commit
0127139db6
Se han modificado 2 ficheros con 178 adiciones y 0 borrados
  1. 175 0
      app/Http/Controllers/Anime/AnimeController.php
  2. 3 0
      routes/api.php

+ 175 - 0
app/Http/Controllers/Anime/AnimeController.php

@@ -1051,6 +1051,181 @@ class AnimeController extends BaseController
     }
 
     /**
+     * 导出分集的全部图片(下载并打包)
+     */
+    public function exportEpisodeImages(Request $request) {
+        // 忽略所有超时限制
+        set_time_limit(0);
+        ini_set('max_execution_time', '0');
+        ini_set('memory_limit', '512M');
+
+        $data = $request->all();
+        
+        // 验证参数
+        $validator = Validator::make($data, [
+            'anime_id' => 'required|string',
+            'episode_id' => 'required|string',
+        ], [
+            'anime_id.required' => '动漫ID不能为空',
+            'episode_id.required' => '剧集ID不能为空',
+        ]);
+        
+        if ($validator->fails()) {
+            Utils::throwError('1002:' . $validator->errors()->first());
+        }
+        
+        $animeId = $data['anime_id'];
+        $episodeId = $data['episode_id'];
+        
+        try {
+            // 获取剧集信息
+            $episode = DB::table('mp_anime_episodes')
+                ->where('anime_id', $animeId)
+                ->where('id', $episodeId)
+                ->select('episode_number', 'title')
+                ->first();
+            
+            if (!$episode) {
+                Utils::throwError('20003:未找到剧集信息');
+            }
+            
+            // 获取所有分镜图片
+            $segments = DB::table('mp_episode_segments')
+                ->where('anime_id', $animeId)
+                ->where('episode_id', $episodeId)
+                ->whereNotNull('img_url')
+                ->where('img_url', '!=', '')
+                ->orderBy('segment_number')
+                ->select('segment_id', 'segment_number', 'img_url', 'act_number', 'act_title')
+                ->get();
+            
+            if ($segments->isEmpty()) {
+                Utils::throwError('20003:该剧集暂无图片可导出');
+            }
+            
+            // 创建临时目录
+            $tempDir = storage_path('app/temp/episode_images_' . time() . '_' . mt_rand(1000, 9999));
+            if (!file_exists($tempDir)) {
+                mkdir($tempDir, 0755, true);
+            }
+            
+            // 下载图片
+            $downloadedFiles = [];
+            foreach ($segments as $segment) {
+                try {
+                    $imgUrl = $segment->img_url;
+                    if (empty($imgUrl)) {
+                        continue;
+                    }
+                    
+                    // 获取图片扩展名
+                    $extension = pathinfo(parse_url($imgUrl, PHP_URL_PATH), PATHINFO_EXTENSION);
+                    if (empty($extension)) {
+                        $extension = 'jpg';
+                    }
+                    
+                    // 构建文件名:分镜序号.扩展名
+                    $fileName = sprintf(
+                        '%03d.%s',
+                        $segment->segment_number,
+                        $extension
+                    );
+                    $filePath = $tempDir . '/' . $fileName;
+                    
+                    // 下载图片(使用file_get_contents,兼容性更好)
+                    $context = stream_context_create([
+                        'http' => [
+                            'timeout' => 30,
+                            'follow_location' => 1,
+                            'ignore_errors' => true
+                        ],
+                        'ssl' => [
+                            'verify_peer' => false,
+                            'verify_peer_name' => false
+                        ]
+                    ]);
+                    
+                    $imageData = @file_get_contents($imgUrl, false, $context);
+                    
+                    if ($imageData !== false && !empty($imageData)) {
+                        file_put_contents($filePath, $imageData);
+                        $downloadedFiles[] = $filePath;
+                    } else {
+                        dLog('anime')->warning('图片下载失败', [
+                            'segment_id' => $segment->segment_id,
+                            'img_url' => $imgUrl
+                        ]);
+                    }
+                    
+                } catch (\Exception $e) {
+                    dLog('anime')->error('下载图片异常', [
+                        'segment_id' => $segment->segment_id,
+                        'img_url' => $segment->img_url,
+                        'error' => $e->getMessage()
+                    ]);
+                    continue;
+                }
+            }
+            
+            if (empty($downloadedFiles)) {
+                // 清理临时目录
+                if (file_exists($tempDir)) {
+                    array_map('unlink', glob("$tempDir/*"));
+                    rmdir($tempDir);
+                }
+                Utils::throwError('20003:没有成功下载任何图片');
+            }
+            
+            // 创建zip文件
+            $zipFileName = sprintf(
+                '%s.zip',
+                $episode->title ?: '未命名'
+            );
+            $zipFilePath = storage_path('app/temp/' . $zipFileName);
+            
+            $zip = new \ZipArchive();
+            if ($zip->open($zipFilePath, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
+                // 清理临时文件
+                array_map('unlink', $downloadedFiles);
+                rmdir($tempDir);
+                Utils::throwError('20003:创建ZIP文件失败');
+            }
+            
+            // 添加文件到zip
+            foreach ($downloadedFiles as $file) {
+                $zip->addFile($file, basename($file));
+            }
+            
+            $zip->close();
+            
+            // 清理临时图片文件
+            array_map('unlink', $downloadedFiles);
+            rmdir($tempDir);
+            
+            // 返回文件下载响应
+            return response()->download($zipFilePath, $zipFileName)->deleteFileAfterSend(true);
+            
+        } catch (\Exception $e) {
+            dLog('anime')->error('导出分集图片失败', [
+                'anime_id' => $animeId,
+                'episode_id' => $episodeId,
+                'error' => $e->getMessage()
+            ]);
+            
+            // 清理可能存在的临时文件
+            if (isset($tempDir) && file_exists($tempDir)) {
+                array_map('unlink', glob("$tempDir/*"));
+                rmdir($tempDir);
+            }
+            if (isset($zipFilePath) && file_exists($zipFilePath)) {
+                unlink($zipFilePath);
+            }
+            
+            throw $e;
+        }
+    }
+
+    /**
      * 监控分镜图片和音频生成任务进度(SSE)
      */
     public function monitorSegmentTasks(Request $request) {

+ 3 - 0
routes/api.php

@@ -170,6 +170,9 @@ Route::group(['middleware' => ['bindToken', 'bindExportToken', 'checkLogin']], f
         
         // 监控分镜图片和音频生成任务进度(SSE)
         Route::get('segmentPicsInfo', [AnimeController::class, 'monitorSegmentTasks']);
+        
+        // 导出全部分镜
+        Route::get('exportEpisodeImages', [AnimeController::class, 'exportEpisodeImages']);
     });
     
 });