1+ <?php
2+
3+ /**
4+ * This sample creates and manages caption tracks by:
5+ *
6+ * 1. Uploading a caption track for a video via "captions.insert" method.
7+ * 2. Getting the caption tracks for a video via "captions.list" method.
8+ * 3. Updating an existing caption track via "captions.update" method.
9+ * 4. Download a caption track via "captions.download" method.
10+ * 5. Deleting an existing caption track via "captions.delete" method.
11+ *
12+ * @author Ibrahim Ulukaya
13+ */
14+
15+ $ htmlBody = <<<END
16+ <form method="GET">
17+ <div>
18+ Action:
19+ <select id="action" name="action">
20+ <option value="upload">Upload - Fill in: video ID, caption track name, language and file</option>
21+ <option value="list">List - Fill in: video ID</option>
22+ <option value="update">Update - Fill in: caption track ID, (optional - caption track file)</option>
23+ <option value="download">Download - Fill in: caption track ID</option>
24+ <option value="delete">Delete - Fill in: caption track ID</option>
25+ <option value="all">All - Fill in: video ID, caption track name, language and file</option>
26+ </select>
27+ </div>
28+ <br>
29+ <div>
30+ Video ID: <input type="text" id="videoId" name="videoId" placeholder="Enter Video ID">
31+ </div>
32+ <br>
33+ <div>
34+ Caption Track Name: <input type="text" id="captionName" name="captionName" placeholder="Enter Caption Track Name">
35+ </div>
36+ <br>
37+ <div>
38+ Caption Track Language: <input type="text" id="captionLanguage" name="captionLanguage" placeholder="Enter Caption Track Language">
39+ </div>
40+ <br>
41+ <div>
42+ File: <input type="file" id ="captionFile" name="captionFile" accept="*/*">
43+ </div>
44+ <br>
45+ <div>
46+ Caption Track Id: <input type="text" id="captionId" name="captionId" placeholder="Enter Caption Track ID">
47+ </div>
48+ <br>
49+ <input type="submit" value="GO!">
50+ </form>
51+ END ;
52+
53+ // Call set_include_path() as needed to point to your client library.
54+ require_once 'Google/Client.php ' ;
55+ require_once 'Google/Service/YouTube.php ' ;
56+ session_start ();
57+
58+
59+ /*
60+ * You can acquire an OAuth 2.0 client ID and client secret from the
61+ * {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
62+ * For more information about using OAuth 2.0 to access Google APIs, please see:
63+ * <https://developers.google.com/youtube/v3/guides/authentication>
64+ * Please ensure that you have enabled the YouTube Data API for your project.
65+ */
66+ $ OAUTH2_CLIENT_ID = 'REPLACE_ME ' ;
67+ $ OAUTH2_CLIENT_SECRET = 'REPLACE_ME ' ;
68+
69+ $ action = $ _GET ['action ' ];
70+ $ videoId = $ _GET ['videoId ' ];
71+ $ captionFile = $ _GET ['captionFile ' ];
72+ $ captionName = $ _GET ['captionName ' ];
73+ $ captionLanguage = $ _GET ['captionLanguage ' ];
74+ $ captionId = $ _GET ['captionId ' ];
75+
76+ $ client = new Google_Client ();
77+ $ client ->setClientId ($ OAUTH2_CLIENT_ID );
78+ $ client ->setClientSecret ($ OAUTH2_CLIENT_SECRET );
79+
80+ /*
81+ * This OAuth 2.0 access scope allows for full read/write access to the
82+ * authenticated user's account and requires requests to use an SSL connection.
83+ */
84+ $ client ->setScopes ('https://www.googleapis.com/auth/youtube.force-ssl ' );
85+ $ redirect = filter_var ('http:// ' . $ _SERVER ['HTTP_HOST ' ] . $ _SERVER ['PHP_SELF ' ],
86+ FILTER_SANITIZE_URL );
87+ $ client ->setRedirectUri ($ redirect );
88+
89+ // Define an object that will be used to make all API requests.
90+ $ youtube = new Google_Service_YouTube ($ client );
91+
92+ if (isset ($ _GET ['code ' ])) {
93+ if (strval ($ _SESSION ['state ' ]) !== strval ($ _GET ['state ' ])) {
94+ die ('The session state did not match. ' );
95+ }
96+
97+ $ client ->authenticate ($ _GET ['code ' ]);
98+ $ _SESSION ['token ' ] = $ client ->getAccessToken ();
99+ header ('Location: ' . $ redirect );
100+ }
101+
102+ if (isset ($ _SESSION ['token ' ])) {
103+ $ client ->setAccessToken ($ _SESSION ['token ' ]);
104+ }
105+
106+ // Check to ensure that the access token was successfully acquired.
107+ if ($ client ->getAccessToken ()) {
108+ // This code executes if the user enters an action in the form
109+ // and submits the form. Otherwise, the page displays the form above.
110+ if ($ _GET ['action ' ]) {
111+ try {
112+ switch ($ action ) {
113+ case 'upload ' :
114+ uploadCaption ($ youtube , $ client , $ videoId , $ captionFile ,
115+ $ captionName , $ captionLanguage , $ htmlBody );
116+ break ;
117+ case 'list ' :
118+ $ captions = listCaptions ($ youtube , $ videoId , $ htmlBody );
119+ break ;
120+ case 'update ' :
121+ updateCaption ($ youtube , $ client , $ captionId , $ htmlBody , $ captionFile );
122+ break ;
123+ case 'download ' :
124+ downloadCaption ($ youtube , $ captionId , $ htmlBody );
125+ break ;
126+ case 'delete ' :
127+ deleteCaption ($ youtube , $ captionId , $ htmlBody );
128+ break ;
129+ default :
130+ # All the available methods are used in sequence just for the sake of an example.
131+ uploadCaption ($ youtube , $ client , $ videoId , $ captionFile ,
132+ $ captionName , $ captionLanguage , $ htmlBody );
133+
134+ $ captions = listCaptions ($ youtube , $ videoId , $ htmlBody );
135+
136+ if (empty ($ captions )) {
137+ $ htmlBody .= "<h3>Can't get video caption tracks.</h3> " ;
138+ } else {
139+ $ firstCaptionId = $ captions [0 ]['id ' ];
140+ updateCaption ($ youtube , $ client , $ firstCaptionId , $ htmlBody , null );
141+ downloadCaption ($ youtube , $ firstCaptionId , $ htmlBody );
142+ deleteCaption ($ youtube , $ firstCaptionId , $ htmlBody );
143+ }
144+ }
145+ } catch (Google_Service_Exception $ e ) {
146+ $ htmlBody .= sprintf ('<p>A service error occurred: <code>%s</code></p> ' ,
147+ htmlspecialchars ($ e ->getMessage ()));
148+ } catch (Google_Exception $ e ) {
149+ $ htmlBody .= sprintf ('<p>An client error occurred: <code>%s</code></p> ' ,
150+ htmlspecialchars ($ e ->getMessage ()));
151+ }
152+ }
153+ $ _SESSION ['token ' ] = $ client ->getAccessToken ();
154+ } else {
155+ // If the user hasn't authorized the app, initiate the OAuth flow
156+ $ state = mt_rand ();
157+ $ client ->setState ($ state );
158+ $ _SESSION ['state ' ] = $ state ;
159+
160+ $ authUrl = $ client ->createAuthUrl ();
161+ $ htmlBody = <<<END
162+ <h3>Authorization Required</h3>
163+ <p>You need to <a href=" $ authUrl">authorize access</a> before proceeding.<p>
164+ END ;
165+ }
166+
167+ /**
168+ * Uploads a caption track in draft status that matches the API request parameters.
169+ * (captions.insert)
170+ *
171+ * @param Google_Service_YouTube $youtube YouTube service object.
172+ * @param Google_Client $client Google client.
173+ * @param $videoId the YouTube video ID of the video for which the API should
174+ * return caption tracks.
175+ * @param $captionLanguage language of the caption track.
176+ * @param $captionName name of the caption track.
177+ * @param $captionFile caption track binary file.
178+ * @param $htmlBody html body.
179+ */
180+ function uploadCaption (Google_Service_YouTube $ youtube , Google_Client $ client , $ videoId ,
181+ $ captionFile , $ captionName , $ captionLanguage , &$ htmlBody ) {
182+ # Insert a video caption.
183+ # Create a caption snippet with video id, language, name and draft status.
184+ $ captionSnippet = new Google_Service_YouTube_CaptionSnippet ();
185+ $ captionSnippet ->setVideoId ($ videoId );
186+ $ captionSnippet ->setLanguage ($ captionLanguage );
187+ $ captionSnippet ->setName ($ captionName );
188+
189+ # Create a caption with snippet.
190+ $ caption = new Google_Service_YouTube_Caption ();
191+ $ caption ->setSnippet ($ captionSnippet );
192+
193+ // Specify the size of each chunk of data, in bytes. Set a higher value for
194+ // reliable connection as fewer chunks lead to faster uploads. Set a lower
195+ // value for better recovery on less reliable connections.
196+ $ chunkSizeBytes = 1 * 1024 * 1024 ;
197+
198+ // Setting the defer flag to true tells the client to return a request which can be called
199+ // with ->execute(); instead of making the API call immediately.
200+ $ client ->setDefer (true );
201+
202+ // Create a request for the API's captions.insert method to create and upload a caption.
203+ $ insertRequest = $ youtube ->captions ->insert ("snippet " , $ caption );
204+
205+ // Create a MediaFileUpload object for resumable uploads.
206+ $ media = new Google_Http_MediaFileUpload (
207+ $ client ,
208+ $ insertRequest ,
209+ '*/* ' ,
210+ null ,
211+ true ,
212+ $ chunkSizeBytes
213+ );
214+ $ media ->setFileSize (filesize ($ captionFile ));
215+
216+
217+ // Read the caption file and upload it chunk by chunk.
218+ $ status = false ;
219+ $ handle = fopen ($ captionFile , "rb " );
220+ while (!$ status && !feof ($ handle )) {
221+ $ chunk = fread ($ handle , $ chunkSizeBytes );
222+ $ status = $ media ->nextChunk ($ chunk );
223+ }
224+
225+ fclose ($ handle );
226+
227+ // If you want to make other calls after the file upload, set setDefer back to false
228+ $ client ->setDefer (false );
229+
230+ $ htmlBody .= "<h2>Inserted video caption track for</h2><ul> " ;
231+ $ captionSnippet = $ status ['snippet ' ];
232+ $ htmlBody .= sprintf ('<li>%s(%s) in %s language, %s status.</li> ' ,
233+ $ captionSnippet ['name ' ], $ status ['id ' ], $ captionSnippet ['language ' ],
234+ $ captionSnippet ['status ' ]);
235+ $ htmlBody .= '</ul> ' ;
236+ }
237+
238+ /**
239+ * Returns a list of caption tracks. (captions.listCaptions)
240+ *
241+ * @param Google_Service_YouTube $youtube YouTube service object.
242+ * @param string $videoId The videoId parameter instructs the API to return the
243+ * caption tracks for the video specified by the video id.
244+ * @param $htmlBody - html body.
245+ */
246+ function listCaptions (Google_Service_YouTube $ youtube , $ videoId , &$ htmlBody ) {
247+ // Call the YouTube Data API's captions.list method to retrieve video caption tracks.
248+ $ captions = $ youtube ->captions ->listCaptions ("snippet " , $ videoId );
249+
250+ $ htmlBody .= "<h3>Video Caption Tracks</h3><ul> " ;
251+ foreach ($ captions as $ caption ) {
252+ $ htmlBody .= sprintf ('<li>%s(%s) in %s language</li> ' , $ caption ['snippet ' ]['name ' ],
253+ $ caption ['id ' ], $ caption ['snippet ' ]['language ' ]);
254+ }
255+ $ htmlBody .= '</ul> ' ;
256+
257+ return $ captions ;
258+ }
259+
260+ /**
261+ * Updates a caption track's draft status to publish it.
262+ * Updates the track with a new binary file as well if it is present. (captions.update)
263+ *
264+ * @param Google_Service_YouTube $youtube YouTube service object.
265+ * @param Google_Client $client Google client.
266+ * @param string $captionId The id parameter specifies the caption ID for the resource
267+ * that is being updated. In a caption resource, the id property specifies the
268+ * caption track's ID.
269+ * @param $htmlBody - html body.
270+ * @param $captionFile caption track binary file.
271+ */
272+ function updateCaption (Google_Service_YouTube $ youtube , Google_Client $ client ,
273+ $ captionId , &$ htmlBody , $ captionFile ) {
274+ // Modify caption's isDraft property to unpublish a caption track.
275+ $ updateCaptionSnippet = new Google_Service_YouTube_CaptionSnippet ();
276+ $ updateCaptionSnippet ->setIsDraft (true );
277+
278+ # Create a caption with snippet.
279+ $ updateCaption = new Google_Service_YouTube_Caption ();
280+ $ updateCaption ->setSnippet ($ updateCaptionSnippet );
281+ $ updateCaption ->setId ($ captionId );
282+
283+ if ($ captionFile == '' )
284+ {
285+ // Call the YouTube Data API's captions.update method to update an existing caption track.
286+ $ captionUpdateResponse = $ youtube ->captions ->update ("snippet " , $ updateCaption );
287+
288+ $ htmlBody .= "<h2>Updated caption track</h2><ul> " ;
289+ $ htmlBody .= sprintf ('<li>%s(%s) draft status: %s</li> ' ,
290+ $ captionUpdateResponse ['snippet ' ]['name ' ],
291+ $ captionUpdateResponse ['id ' ], $ captionUpdateResponse ['snippet ' ]['isDraft ' ]);
292+ $ htmlBody .= '</ul> ' ;
293+ } else {
294+ // Specify the size of each chunk of data, in bytes. Set a higher value for
295+ // reliable connection as fewer chunks lead to faster uploads. Set a lower
296+ // value for better recovery on less reliable connections.
297+ $ chunkSizeBytes = 1 * 1024 * 1024 ;
298+
299+ // Setting the defer flag to true tells the client to return a request which can be called
300+ // with ->execute(); instead of making the API call immediately.
301+ $ client ->setDefer (true );
302+
303+ // Create a request for the YouTube Data API's captions.update method to update
304+ // an existing caption track.
305+ $ captionUpdateRequest = $ youtube ->captions ->update ("snippet " , $ updateCaption );
306+
307+ // Create a MediaFileUpload object for resumable uploads.
308+ $ media = new Google_Http_MediaFileUpload (
309+ $ client ,
310+ $ captionUpdateRequest ,
311+ '*/* ' ,
312+ null ,
313+ true ,
314+ $ chunkSizeBytes
315+ );
316+ $ media ->setFileSize (filesize ($ captionFile ));
317+
318+ // Read the caption file and upload it chunk by chunk.
319+ $ status = false ;
320+ $ handle = fopen ($ captionFile , "rb " );
321+ while (!$ status && !feof ($ handle )) {
322+ $ chunk = fread ($ handle , $ chunkSizeBytes );
323+ $ status = $ media ->nextChunk ($ chunk );
324+ }
325+
326+ fclose ($ handle );
327+
328+ // If you want to make other calls after the file upload, set setDefer back to false
329+ $ client ->setDefer (false );
330+
331+ $ htmlBody .= "<h2>Updated caption track</h2><ul> " ;
332+ $ htmlBody .= sprintf ('<li>%s(%s) draft status: %s and updated the track with
333+ the new uploaded file.</li> ' ,
334+ $ status ['snippet ' ]['name ' ], $ status ['id ' ], $ status ['snippet ' ]['isDraft ' ]);
335+ $ htmlBody .= '</ul> ' ;
336+ }
337+ }
338+
339+ /**
340+ * Downloads a caption track for a YouTube video. (captions.download)
341+ *
342+ * @param Google_Service_YouTube $youtube YouTube service object.
343+ * @param string $captionId The id parameter specifies the caption ID for the resource
344+ * that is being downloaded. In a caption resource, the id property specifies the
345+ * caption track's ID.
346+ * @param $htmlBody - html body.
347+ */
348+ function downloadCaption (Google_Service_YouTube $ youtube , $ captionId , &$ htmlBody ) {
349+ // Call the YouTube Data API's captions.download method to download an existing caption.
350+ $ captionResouce = $ youtube ->captions ->download ($ captionId , array (
351+ 'tfmt ' => "srt " ,
352+ 'alt ' => "media "
353+ ));
354+
355+ $ htmlBody .= "<h2>Downloaded caption track</h2><ul> " ;
356+ $ htmlBody .= sprintf ('<li>%s</li> ' ,
357+ $ captionResouce );
358+ $ htmlBody .= '</ul> ' ;
359+ }
360+
361+ /**
362+ * Deletes a caption track for a YouTube video. (captions.delete)
363+ *
364+ * @param Google_Service_YouTube $youtube YouTube service object.
365+ * @param string $captionId The id parameter specifies the caption ID for the resource
366+ * that is being deleted. In a caption resource, the id property specifies the
367+ * caption track's ID.
368+ * @param $htmlBody - html body.
369+ */
370+ function deleteCaption (Google_Service_YouTube $ youtube , $ captionId , &$ htmlBody ) {
371+ // Call the YouTube Data API's captions.delete method to delete a caption.
372+ $ youtube ->captions ->delete ($ captionId );
373+
374+ $ htmlBody .= "<h2>Deleted caption track</h2><ul> " ;
375+ $ htmlBody .= sprintf ('<li>%s</li> ' ,$ captionId );
376+ $ htmlBody .= '</ul> ' ;
377+ }
378+ ?>
379+
380+ <!doctype html>
381+ <html>
382+ <head>
383+ <title>Create and manage video caption tracks</title>
384+ </head>
385+ <body>
386+ <?= $ htmlBody?>
387+ </body>
388+ </html>
0 commit comments