Getting a video from S3 and Uploading to YouTube in PHP

旧巷老猫 提交于 2019-12-03 03:31:36

This is an old question but i believe i have a better answer.

You don't have to write video to HDD and you can't keep the whole thing in RAM (I assume it is a big file).

You can use PHP AWS SDK and Google Client libraries to buffer file from S3 and send it to YouTube on the fly. Use registerStreamWrapper method to register S3 as file system and use resumable uploads from YouTube API. Then all you have to do is reading chunks from S3 with fread and sending them to YouTube. This way you can even limit the RAM usage.

I assume you created the video object ($video in code) from Google_Video class. This is a complete code.

<?php
require_once 'path/to/libraries/aws/vendor/autoload.php';
require_once 'path/to/libraries/google-client-lib/autoload.php';

use Aws\S3\S3Client;

$chunkSizeBytes = 2 * 1024 * 1024; // 2 mb
$streamName = 's3://bucketname/video.mp4';

$s3client = S3Client::factory(array(
                    'key'    => S3_ACCESS_KEY,
                    'secret' => S3_SECRET_KEY,
                    'region' => 'eu-west-1' // if you need to set.
                ));
$s3client->registerStreamWrapper();

$client = new Google_Client();
$client->setClientId(YOUTUBE_CLIENT_ID);
$client->setClientSecret(YOUTUBE_CLIENT_SECRET);
$client->setAccessToken(YOUTUBE_TOKEN);

$youtube = new Google_YoutubeService($client);
$media = new Google_MediaFileUpload('video/*', null, true, $chunkSizeBytes);

$filesize = filesize($streamName); // use it as a reguler file.
$media->setFileSize($filesize);

$insertResponse = $youtube->videos->insert("status,snippet", $video, array('mediaUpload' => $media));
$uploadStatus = false;

$handle = fopen($streamName, "r");
$totalReceived = 0;
$chunkBuffer = '';
while (!$uploadStatus && !feof($handle)) {
    $chunk = fread($handle, $chunkSizeBytes);
    $chunkBuffer .= $chunk;
    $chunkBufferSize = strlen($chunkBuffer);
    if($chunkBufferSize > $chunkSizeBytes) {
        $fullChunk = substr($chunkBuffer, 0, $chunkSizeBytes);
        $leapChunk = substr($chunkBuffer, $chunkSizeBytes);
        $uploadStatus = $media->nextChunk($insertResponse, $fullChunk);
        $totalSend += strlen($fullChunk);

        $chunkBuffer = $leapChunk;
        echo PHP_EOL.'Status: '.($totalReceived).' / '.$filesize.' (%'.(($totalReceived / $filesize) * 100).')'.PHP_EOL;
    }

    $totalReceived += strlen($chunk);
}

$extraChunkLen = strlen($chunkBuffer);
$uploadStatus = $media->nextChunk($insertResponse, $chunkBuffer);
$totalSend += strlen($chunkBuffer);
fclose($handle);

The "MediaFileSource" must be a real file. It won't take a URL, so you will need to copy the videos to your server from S3, before sending them to YouTube.

You can probably get away with the "shell_exec" if your usage is light, but for a variety of reasons its probably better to use either the Zend S3 Service, or cURL to pull files from S3.

$chunkSizeBytes = 2 * 1024 * 1024; // 2 mb

    $s3client = $this->c_aws->getS3Client();
    $s3client->registerStreamWrapper();

    try {

        $client = new \Google_Client();

        $client->setAccessType("offline");
        $client->setApprovalPrompt('force');

        $client->setClientId(GOOGLE_CLIENT_ID);
        $client->setClientSecret(GOOGLE_CLIENT_SECRET);
        $token = $client->fetchAccessTokenWithRefreshToken(GOOGLE_REFRESH_TOKEN);


        $client->setAccessToken($token);

        $youtube = new \Google_Service_YouTube($client);

        // Create a snippet with title, description, tags and category ID
        // Create an asset resource and set its snippet metadata and type.
        // This example sets the video's title, description, keyword tags, and
        // video category.
        $snippet = new \Google_Service_YouTube_VideoSnippet();
        $snippet->setTitle($title);
        $snippet->setDescription($summary);
        $snippet->setTags(explode(',', $keywords));

        // Numeric video category. See
        // https://developers.google.com/youtube/v3/docs/videoCategories/list

// $snippet->setCategoryId("22");

        // Set the video's status to "public". Valid statuses are "public",
        // "private" and "unlisted".
        $status = new \Google_Service_YouTube_VideoStatus();
        $status->privacyStatus = "public";


        // Associate the snippet and status objects with a new video resource.
        $video = new \Google_Service_YouTube_Video();
        $video->setSnippet($snippet);
        $video->setStatus($status);

        // Setting the defer flag to true tells the client to return a request which can be called
        // with ->execute(); instead of making the API call immediately.
        $client->setDefer(true);

        $insertRequest = $youtube->videos->insert("status,snippet", $video);

        $media = new \Google_Http_MediaFileUpload(
            $client,
            $insertRequest,
            'video/*',
            null,
            true,
            $chunkSizeBytes
        );

        $result = $this->c_aws->getAwsFile($aws_file_path);

        $media->setFileSize($result['ContentLength']);

        $uploadStatus = false;

        // Seek to the beginning of the stream
        $result['Body']->rewind();

        // Read the body off of the underlying stream in chunks
        while (!$uploadStatus && $data = $result['Body']->read($chunkSizeBytes)) {

            $uploadStatus = $media->nextChunk($data);

        }
        $client->setDefer(false);
        if ($uploadStatus->status['uploadStatus'] == 'uploaded') {
            // Actions to perform for a successful upload
             $uploaded_video_id = $uploadStatus['id'];
            return ($uploadStatus['id']);
        }
    }catch (\Google_Service_Exception $exception){
        return '';
        print_r($exception);
    }
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!