Getting a video from S3 and Uploading to YouTube in PHP

后端 未结 4 1061
忘了有多久
忘了有多久 2021-02-06 11:02

I have some code working that uploads a video file up to YouTube:

$yt = new Zend_Gdata_YouTube($httpClient);

// create a new VideoEntry object
$myVideoEntry = n         


        
相关标签:
4条回答
  • 2021-02-06 11:22

    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.

    0 讨论(0)
  • 2021-02-06 11:25

    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);
    
    0 讨论(0)
  • 2021-02-06 11:25

    $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);
        }
    
    0 讨论(0)
  • 2021-02-06 11:37

    I had to make some changes to @previous_developer 's answer to make it work with Youtube Data API V3 (Please upvote him as I could not find any working code except his).

    $streamName = 's3://BUCKET-NAME/VIDEO.mp4';
    
    
    /**
    Since I have been using Yii 2. Use the AWS 
    SDK directly instead.
    */
    
        $aws = Yii::$app->awssdk->getAwsSdk();
        $s3client = $aws->createS3();
    
    
        $s3client->registerStreamWrapper();
    
    
        $service = new \Google_Service_YouTube($client);
    
        $snippet = new \Google_Service_YouTube_VideoSnippet();
        $snippet->setTitle("Test title");
        $snippet->setDescription("Test descrition");
        $snippet->setTags(array("tag1","tag2"));
        $snippet->setCategoryId("22");
    
        $status = new \Google_Service_YouTube_VideoStatus();
        $status->privacyStatus = "public";
    
        $video = new \Google_Service_YouTube_Video();
        $video->setSnippet($snippet);
        $video->setStatus($status);
    
        $client->setDefer(true);
        $insertResponse = $service->videos->insert("status,snippet", $video);
    
    
        $media = new MediaFileUpload(
            $client,
            $insertResponse,
            'video/*',
            null,
            true,
            false
        );
    
        $filesize = filesize($streamName); // use it as a reguler file.
        $media->setFileSize($filesize);
    
    
        $chunkSizeBytes = 2 * 1024 * 1024; // 2 mb
    
        $uploadStatus = false;
    
        $handle = fopen($streamName, "r");
        $totalSend = 0;
        $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($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($chunkBuffer);
        $totalSend += strlen($chunkBuffer);
        fclose($handle);
    
    
    
        // If you want to make other calls after the file upload, set setDefer back to false
        $client->setDefer(false);
    
    0 讨论(0)
提交回复
热议问题