|
|
@@ -1471,8 +1471,13 @@ class AnimeController extends BaseController
|
|
|
mkdir($tempDir, 0755, true);
|
|
|
}
|
|
|
|
|
|
- // 下载文件
|
|
|
+ // 并行下载文件(使用 cURL multi)
|
|
|
$downloadedFiles = [];
|
|
|
+ $multiHandle = curl_multi_init();
|
|
|
+ $curlHandles = [];
|
|
|
+ $fileInfos = [];
|
|
|
+
|
|
|
+ // 准备所有下载任务
|
|
|
foreach ($segments as $index => $segment) {
|
|
|
try {
|
|
|
if ($isAceMode) {
|
|
|
@@ -1504,59 +1509,86 @@ class AnimeController extends BaseController
|
|
|
}
|
|
|
$filePath = $tempDir . '/' . $fileName;
|
|
|
|
|
|
- // 下载文件
|
|
|
- $context = stream_context_create([
|
|
|
- 'http' => [
|
|
|
- 'timeout' => 30,
|
|
|
- 'follow_location' => 1,
|
|
|
- 'ignore_errors' => true
|
|
|
- ],
|
|
|
- 'ssl' => [
|
|
|
- 'verify_peer' => false,
|
|
|
- 'verify_peer_name' => false
|
|
|
- ]
|
|
|
- ]);
|
|
|
+ // 创建 cURL 句柄
|
|
|
+ $ch = curl_init($mediaUrl);
|
|
|
+ $fp = fopen($filePath, 'wb');
|
|
|
+
|
|
|
+ curl_setopt($ch, CURLOPT_FILE, $fp);
|
|
|
+ curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
|
|
|
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
|
|
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
|
|
+ curl_setopt($ch, CURLOPT_TIMEOUT, 60);
|
|
|
+ curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
|
|
|
|
|
|
- $fileData = @file_get_contents($mediaUrl, false, $context);
|
|
|
+ curl_multi_add_handle($multiHandle, $ch);
|
|
|
|
|
|
- if ($fileData !== false && !empty($fileData)) {
|
|
|
- file_put_contents($filePath, $fileData);
|
|
|
- $downloadedFiles[] = $filePath;
|
|
|
+ $curlHandles[(int)$ch] = [
|
|
|
+ 'handle' => $ch,
|
|
|
+ 'file' => $fp,
|
|
|
+ 'path' => $filePath,
|
|
|
+ 'url' => $mediaUrl,
|
|
|
+ 'segment' => $segment
|
|
|
+ ];
|
|
|
+
|
|
|
+ } catch (\Exception $e) {
|
|
|
+ $logData = ['error' => $e->getMessage()];
|
|
|
+ if ($isAceMode) {
|
|
|
+ $logData['act_id'] = $segment->act_id;
|
|
|
} else {
|
|
|
- $logData = [
|
|
|
- 'media_url' => $mediaUrl,
|
|
|
- 'type' => $isAceMode ? 'video' : (!empty($segment->video_url) ? 'video' : 'image')
|
|
|
- ];
|
|
|
-
|
|
|
- if ($isAceMode) {
|
|
|
- $logData['act_id'] = $segment->act_id;
|
|
|
- $logData['act_number'] = $segment->act_number;
|
|
|
- } else {
|
|
|
- $logData['segment_id'] = $segment->segment_id;
|
|
|
- $logData['segment_number'] = $segment->segment_number;
|
|
|
- }
|
|
|
-
|
|
|
- logDB('anime', 'warning', '文件下载失败', $logData);
|
|
|
+ $logData['segment_id'] = $segment->segment_id;
|
|
|
+ }
|
|
|
+ logDB('anime', 'error', '准备下载任务异常', $logData);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行并行下载
|
|
|
+ $running = null;
|
|
|
+ do {
|
|
|
+ curl_multi_exec($multiHandle, $running);
|
|
|
+ curl_multi_select($multiHandle, 0.1);
|
|
|
+ } while ($running > 0);
|
|
|
+
|
|
|
+ // 处理下载结果
|
|
|
+ foreach ($curlHandles as $info) {
|
|
|
+ $ch = $info['handle'];
|
|
|
+ $fp = $info['file'];
|
|
|
+ $filePath = $info['path'];
|
|
|
+ $segment = $info['segment'];
|
|
|
+
|
|
|
+ fclose($fp);
|
|
|
+
|
|
|
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
|
+
|
|
|
+ if ($httpCode == 200 && file_exists($filePath) && filesize($filePath) > 0) {
|
|
|
+ $downloadedFiles[] = $filePath;
|
|
|
+ } else {
|
|
|
+ // 删除失败的文件
|
|
|
+ if (file_exists($filePath)) {
|
|
|
+ @unlink($filePath);
|
|
|
}
|
|
|
|
|
|
- } catch (\Exception $e) {
|
|
|
$logData = [
|
|
|
- 'error' => $e->getMessage()
|
|
|
+ 'media_url' => $info['url'],
|
|
|
+ 'http_code' => $httpCode,
|
|
|
+ 'type' => $isAceMode ? 'video' : 'image'
|
|
|
];
|
|
|
|
|
|
if ($isAceMode) {
|
|
|
$logData['act_id'] = $segment->act_id;
|
|
|
- $logData['act_number'] = $segment->act_number;
|
|
|
} else {
|
|
|
$logData['segment_id'] = $segment->segment_id;
|
|
|
- $logData['segment_number'] = $segment->segment_number;
|
|
|
}
|
|
|
|
|
|
- logDB('anime', 'error', '下载文件异常', $logData);
|
|
|
- continue;
|
|
|
+ logDB('anime', 'warning', '文件下载失败', $logData);
|
|
|
}
|
|
|
+
|
|
|
+ curl_multi_remove_handle($multiHandle, $ch);
|
|
|
+ curl_close($ch);
|
|
|
}
|
|
|
|
|
|
+ curl_multi_close($multiHandle);
|
|
|
+
|
|
|
if (empty($downloadedFiles)) {
|
|
|
// 清理临时目录
|
|
|
if (file_exists($tempDir)) {
|
|
|
@@ -1714,7 +1746,11 @@ class AnimeController extends BaseController
|
|
|
Utils::throwError('20003:创建ZIP文件失败');
|
|
|
}
|
|
|
|
|
|
- // 添加文件到zip(使用完整路径确保文件正确添加)
|
|
|
+ // 设置压缩级别为最快(0=不压缩,1=最快,9=最好压缩)
|
|
|
+ // 对于视频和图片,压缩效果不明显,使用最快速度
|
|
|
+ $zip->setCompressionIndex(0, \ZipArchive::CM_STORE); // 不压缩,直接存储
|
|
|
+
|
|
|
+ // 添加文件到zip
|
|
|
foreach ($downloadedFiles as $file) {
|
|
|
if (file_exists($file)) {
|
|
|
$zip->addFile($file, basename($file));
|