Skip to content

Instantly share code, notes, and snippets.

@abiusx
Created December 10, 2018 21:57
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abiusx/a3e5b2ef6d54866a5a1eba71021f8c2a to your computer and use it in GitHub Desktop.
Save abiusx/a3e5b2ef6d54866a5a1eba71021f8c2a to your computer and use it in GitHub Desktop.
Youtube Video Updater in Pure PHP
<?php
/**
* This script can be used to modify videos on Youtube programatically.
* It does not need Google API libraries, it merely uses PHP's CURL.
*
* Before starting to work with this, read the comments below for oAuth_token()
* function. It requires you do 3 steps (twice run this code while uncommenting,
* once login on your browser). Once you have done that and updated the constants
* below, you're good to go!
* @author abiusx
*/
/**
* API KEY is needed for quota management
*/
const API_KEY='...TODO...';
/**
* Create a pair by visiting https://console.developers.google.com/apis/credentials
*/
const CLIENT_ID='...TODO...';
const CLIENT_SECRET='...TODO...';
/**
* Update these as necessary, based on the process listed in the comments of oAuth_token()
*/
const AUTH_CODE='...TODO...';
const REFRESH_TOKEN="...TODO...";
/**
* This function is used as a callback send to update_videos below.
* to modify a single video snippet and use it to update youtube
* @param object $video youtube video snippet
* @return object modified or unmodified snippet
*/
function modify_video($video){
$str="...TODO...";
if (strpos($video->description,$str)===false)
$video->description=$str.PHP_EOL.PHP_EOL.$video->description;
return $video;
}
// Update all videos using the modify function
update_videos("modify_video");
/**
* Returns an oAuth access token.
*
* If it's not working, uncomment the first die command, it will generate a URL.
* Use that URL in the browser to login with the owning account (currently has youtube scopes in it,
* add other scopes if needed).
* Once logged in, will give you an AUTH_CODE. Use that AUTH_CODE to update the constant above.
*
* Uncomment the second request and die command, it will use the AUTH_CODE to generate a REFRESH_TOKEN
* Use that REFRESH_TOKEN to update the const above, and you should be golden.
*
* This function will use the REFRESH TOKEN to generate ACCESS_TOKENs on every app launch.
* @return string
*/
function oAuth_token()
{
/// Generates a url, visit that to login and get token
// die("https://accounts.google.com/o/oauth2/auth?".http_build_query(["client_id"=>CLIENT_ID,"redirect_uri"=>"urn:ietf:wg:oauth:2.0:oob","response_type"=>"code","scope"=>"https://www.googleapis.com/auth/youtube https://www.googleapis.com/auth/youtube.force-ssl https://www.googleapis.com/auth/youtube.upload https://www.googleapis.com/auth/youtube.readonly https://www.googleapis.com/auth/youtubepartner https://www.googleapis.com/auth/youtubepartner-channel-audit"]));
static $access_token;
if ($access_token===null)
{
///Only once, to get the refresh token et. al.
// $r=request("https://accounts.google.com/o/oauth2/token","POST",[
// "code"=>AUTH_CODE,
// "client_id"=>CLIENT_ID,
// "client_secret"=>CLIENT_SECRET,
// "grant_type"=>"authorization_code",
// "redirect_uri"=>"urn:ietf:wg:oauth:2.0:oob",
// ]);
// print_r($r);die();
$r=request("https://accounts.google.com/o/oauth2/token","POST",[
"refresh_token"=>REFRESH_TOKEN,
"client_id"=>CLIENT_ID,
"client_secret"=>CLIENT_SECRET,
"grant_type"=>"refresh_token",
"redirect_uri"=>"urn:ietf:wg:oauth:2.0:oob",
]);
$obj=json($r->body);
$access_token=$obj->access_token;
}
return $access_token;
}
/**
* Returns playlistId of my default upload channel
* @return string
*/
function getMyChannel()
{
$r=request("https://www.googleapis.com/youtube/v3/channels","GET",[
"part"=>"contentDetails",
"access_token" => oAuth_token(),
"mine"=>"true",
"key"=>API_KEY,
]);
$channels=json($r->body);
// Find the 'uploads' channel which includes all videos
return $channels->items[0]->contentDetails->relatedPlaylists->uploads;
}
/**
* Returns videos in a playlist
*
* By default returns 50 at a time
* @param string $playlistId
* @param string $pageToken optional: if provided returns a certain page
* @return object
*/
function getVideos($playlistId,$pageToken=null)
{
$r=request("https://www.googleapis.com/youtube/v3/playlistItems","GET",[
"key"=>API_KEY,
"part"=>"snippet",
"playlistId"=>$playlistId,
"maxResults"=>50, // Max supported
"pageToken"=>$pageToken
]);
if ($r->status!=200)
return false;
return json($r->body);
}
/**
* Loops through all my videos and updates them
* based on the modify function (which receives each video snippet)
* @param callable $modify_video receives one video snippet input
*/
function update_videos(callable $modify_video)
{
$pageIndex=$videoIndex=0;
$pageToken="";
$channel=getMyChannel();
while(true)
{
$page=getVideos($channel,$pageToken);
$total=$page->pageInfo->totalResults;
if (!$page)
{
echo "Failed on page {$pageIndex}. Retrying...",PHP_EOL;
continue;
}
foreach ($page->items as $video)
{
$videoIndex++;
$id=$video->snippet->resourceId->videoId;
/// Use the following to get CategoryID
// $r=request("https://www.googleapis.com/youtube/v3/videos","GET",[
// "key"=>API_KEY,
// "part"=>"snippet",
// "id"=>$id,
// ]);
// print_r($video);
$categoryId=1;
$snippet=$video->snippet;
$snippet->categoryId=$categoryId;
$new_snippet=$modify_video(clone $snippet);
if ($new_snippet!=$snippet) // Update
{
$r=request("https://www.googleapis.com/youtube/v3/videos?part=snippet","PUT",json([
"id"=>$id,
"snippet"=>$new_snippet,
]),
[
"Authorization"=> "Bearer ".oAuth_token(),
"Content-Type" => "application/json",
]);
$success=($r->status==200);
if ($success)
$status="updated";
else
$status="failed to update";
}
else
$status="not touched";
echo "({$videoIndex}/{$total}) {$status}. \thttps://www.youtube.com/watch?v={$id}",PHP_EOL;
}
$pageIndex++;
$pageToken=$page->nextPageToken;
}
}
function json($in)
{
$flags=JSON_PRETTY_PRINT;
$encode=false;
if (is_string($in))
{
$out=json_decode($in);
$err=json_last_error();
if ($err!==JSON_ERROR_NONE)
$encode=true;
}
else
$encode=true;
if ($encode)
{
$out=json_encode($in,$flags);
$err=json_last_error();
if ($err!==JSON_ERROR_NONE)
throw new Exception(json_last_error_msg());
}
return $out;
}
function request($url,$method="GET",$data=[],$headers=[],$additional_opts=[])
{
$response_headers=[];
$opts=[
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_COOKIEJAR => 'stdlib.cookie',
CURLOPT_COOKIEFILE => 'stdlib.cookie',
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_TIMEOUT => 5,
CURLOPT_CONNECTTIMEOUT => 2,
CURLOPT_USERAGENT => 'cURL',
CURLOPT_HEADERFUNCTION =>
function($curl, $header) use (&$response_headers)
{
$len = strlen($header);
$header = explode(':', $header, 2);
if (count($header) < 2) // ignore invalid headers
return $len;
$name = strtolower(trim($header[0]));
if (!array_key_exists($name, $response_headers))
$response_headers[$name] = trim($header[1]);
elseif (is_array($response_headers[$name]))
$response_headers[$name][] = trim($header[1]);
else
$response_headers[$name] = [$response_headers[$name], trim($header[1])];
return $len;
}
];
$final_headers=[];
if (!empty($headers))
foreach ($headers as $key=>$value)
if (is_numeric($key))
$final_headers[]=$value;
else
$final_headers[]="{$key}: {$value}";
$opts[CURLOPT_HTTPHEADER]=$final_headers;
if (is_array($additional_opts))
foreach ($additional_opts as $k=>$v)
$opts[$k]=$v;
if ($data)
{
if (!is_string($data))
$data=http_build_query($data);
if ($method=="GET")
{
$url=$opts[CURLOPT_URL];
if (strpos($url,"?")===false)
$url.="?{$data}";
else
$url.="&{$data}";
$opts[CURLOPT_URL]=$url;
}
else
$opts[CURLOPT_POSTFIELDS]=$data;
}
$curl = curl_init();
curl_setopt_array($curl, $opts);
$res = curl_exec($curl);
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
$out=(object)["status"=>$httpcode, "body"=>$res, "header"=>$response_headers];
// $out->status_code=&$out->status;
// $out->code=&$out->status;
// $out->content=&$out->body;
// $out->headers=&$out->header;
return $out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment