jsonFactory->create(); try { if (!$this->config->isEnabled()) { throw new LocalizedException(__('Video upload is disabled.')); } $title = trim((string)$this->getRequest()->getParam('title')); if ($title === '') { throw new LocalizedException(__('Title is required.')); } $uploadId = preg_replace('/[^a-zA-Z0-9_-]/', '', (string)$this->getRequest()->getParam('upload_id')); $index = (int)$this->getRequest()->getParam('index'); $total = (int)$this->getRequest()->getParam('total'); $name = basename((string)$this->getRequest()->getParam('name')); if ($uploadId === '' || $index < 0 || $total < 1 || $index >= $total || strtolower(pathinfo($name, PATHINFO_EXTENSION)) !== 'mp4') { throw new LocalizedException(__('Invalid MP4 upload request.')); } if (!isset($_FILES['chunk']) || (int)$_FILES['chunk']['error'] !== UPLOAD_ERR_OK) { throw new LocalizedException(__('The video chunk was not uploaded.')); } $var = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); $chunkDir = 'esun_video/chunks/' . $uploadId; $var->create($chunkDir); $var->writeFile($chunkDir . '/' . $index . '.part', (string)file_get_contents($_FILES['chunk']['tmp_name'])); if ($index + 1 < $total) { return $result->setData(['success' => true, 'completed' => false, 'next' => $index + 1]); } $assembled = 'esun_video/assembled/' . $uploadId . '.mp4'; $var->create(dirname($assembled)); $absolute = $var->getAbsolutePath($assembled); $handle = fopen($absolute, 'wb'); if ($handle === false) { throw new LocalizedException(__('Unable to assemble the uploaded video.')); } try { for ($part = 0; $part < $total; $part++) { $partPath = $chunkDir . '/' . $part . '.part'; if (!$var->isExist($partPath)) { throw new LocalizedException(__('Video chunk %1 is missing.', $part)); } $input = fopen($var->getAbsolutePath($partPath), 'rb'); if ($input === false) { throw new LocalizedException(__('Unable to read video chunk %1.', $part)); } stream_copy_to_stream($input, $handle); fclose($input); } } finally { fclose($handle); } $metadata = $this->ffprobe->inspect($absolute); $cover = $this->saveCover($uploadId, $absolute); $safeName = preg_replace('/[^a-zA-Z0-9_-]+/', '-', pathinfo($name, PATHINFO_FILENAME)); $videoPath = $this->config->getMediaPath() . '/videos/' . date('Y/m') . '/' . trim((string)$safeName, '-') . '-' . substr($uploadId, 0, 12) . '.mp4'; $media = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $media->create(dirname($videoPath)); $var->renameFile($assembled, $videoPath, $media); $video = $this->videoFactory->create(); $video->setData([ 'title' => $title, 'description' => trim((string)$this->getRequest()->getParam('description')), 'video_path' => $videoPath, 'cover_path' => $cover['permanent_path'], 'status' => $this->getRequest()->getParam('status', '1') === '0' ? 0 : 1, 'duration' => $metadata['duration'], 'size' => $metadata['size'], 'width' => $metadata['width'], 'height' => $metadata['height'], 'resolution' => $metadata['resolution'], 'original_name' => $name, ])->save(); $var->delete($chunkDir); $mediaUrl = $this->storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_MEDIA); return $result->setData([ 'success' => true, 'completed' => true, 'video' => [ 'id' => (int)$video->getId(), 'title' => $title, 'description' => (string)$video->getData('description'), 'video_url' => $mediaUrl . ltrim($videoPath, '/'), 'cover_url' => $cover['url'], 'gallery_file' => $cover['gallery_file'], 'metadata' => $metadata, 'disabled' => (int)!$video->getData('status'), ], ]); } catch (\Throwable $e) { return $result->setHttpResponseCode(400)->setData(['success' => false, 'message' => $e->getMessage()]); } } private function saveCover(string $uploadId, string $absoluteVideo): array { if (isset($_FILES['cover']) && (int)$_FILES['cover']['error'] === UPLOAD_ERR_OK) { $uploader = $this->uploaderFactory->create(['fileId' => 'cover']); $uploader->setAllowedExtensions(['jpg', 'jpeg', 'png', 'gif']); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(true); $media = $this->filesystem->getDirectoryRead(DirectoryList::MEDIA); $saved = $uploader->save($media->getAbsolutePath($this->productMediaConfig->getBaseTmpMediaPath())); if (!is_array($saved) || empty($saved['file'])) { throw new LocalizedException(__('Unable to save the cover image.')); } $galleryFile = (string)$saved['file']; } else { $galleryFile = '/e/s/esun-video-' . substr($uploadId, 0, 12) . '.jpg'; $tmpPath = $this->productMediaConfig->getTmpMediaPath($galleryFile); $var = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR); $generated = 'esun_video/generated_covers/' . $uploadId . '.jpg'; $var->create(dirname($generated)); $this->ffmpeg->createCover($absoluteVideo, $var->getAbsolutePath($generated)); $media = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $media->create(dirname($tmpPath)); $media->writeFile($tmpPath, $var->readFile($generated)); $var->delete($generated); } $source = $this->productMediaConfig->getTmpMediaPath($galleryFile); $extension = strtolower(pathinfo($galleryFile, PATHINFO_EXTENSION)) ?: 'jpg'; $permanent = $this->config->getMediaPath() . '/covers/' . date('Y/m') . '/' . substr($uploadId, 0, 20) . '.' . $extension; $mediaWrite = $this->filesystem->getDirectoryWrite(DirectoryList::MEDIA); $mediaWrite->create(dirname($permanent)); $mediaWrite->writeFile($permanent, $mediaWrite->readFile($source)); return [ 'gallery_file' => $galleryFile . '.tmp', 'permanent_path' => $permanent, 'url' => $this->productMediaConfig->getTmpMediaUrl($galleryFile), ]; } }