1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
|
<?php
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
/**
* Movie_YouTube Class Definition
*
* TODO 2011/01/09 Check for other restricted characters (e.g. '<' and '>')
* word limits (e.g. keywords), etc. See reference below.
*
*
* PHP version 5
*
* @category Movie
* @package Helioviewer
* @author Keith Hughitt <keith.hughitt@nasa.gov>
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
* @link http://launchpad.net/helioviewer.org
*/
/**
* Uploads user-created movies to YouTube
*
* @category Movie
* @package Helioviewer
* @author Keith Hughitt <keith.hughitt@nasa.gov>
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
* @link http://launchpad.net/helioviewer.org
*/
class Movie_YouTube
{
private $_appId;
private $_clientId;
private $_testURL;
private $_uploadURL;
private $_httpClient;
private $_youTube;
/**
* Creates a new YouTube instance
*
* @return void
*/
public function __construct()
{
include_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
$this->_appId = "Helioviewer.org User Video Uploader";
$this->_clientId = "Helioviewer.org (2.3.0)";
$this->_testURL = "http://gdata.youtube.com/feeds/api/users/default/uploads?max-results=1";
$this->_uploadURL = "http://uploads.gdata.youtube.com/feeds/api/users/default/uploads";
if(!isset($_SESSION)) {
# Note: If same user begins upload, and then shortly after tried
# to upload a video again, PHP may hang when attempting to call
# session_start(). May need a better way to make sure nothing else
# is going on? (e.g. check for video entry in YouTube)
session_start();
}
}
/**
* Authenticates user and uploads video to YouTube
*
* @param Helioviewer_Movie A Movie object
*
* @return void
*/
public function uploadVideo($movie, $id, $title, $description, $tags, $share, $html)
{
// Re-confirm authorization and convert single-use token to session
// token if applicable
$this->_checkAuthorization();
// Once we have a session token get an AuthSubHttpClient
$this->_httpClient = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);
// Increase timeout time to prevent client from timing out during uploads
$this->_httpClient->setConfig(array( 'timeout' => 600 ));
// Creates an instance of the Youtube GData object
$this->_youTube = $this->_getYoutubeInstance();
// If authorization is expired, reauthorize
if (!$this->_authorizationIsValid()) {
$this->getYouTubeAuth($movie->id);
}
$filepath = $movie->getFilepath(true);
$videoEntry = $this->_createGDataVideoEntry($filepath, $title, $description, $tags, $share);
$this->_uploadVideoToYouTube($videoEntry, $id, $title, $description, $tags, $share, $html);
}
/**
* Checks to see if a user is Helioveiwer.org is currently authorized to interact with a user's YouTube account.
*
* @return bool Returns true if the user has been authenticated by YouTube
*/
public function checkYouTubeAuth()
{
if (!isset($_SESSION['sessionToken'])) {
return false;
}
$this->_httpClient = Zend_Gdata_AuthSub::getHttpClient($_SESSION['sessionToken']);
$this->_youTube = $this->_getYoutubeInstance();
return $this->_authorizationIsValid();
}
/**
* Requests authorization for Helioviewer.org to upload videos on behalf
* of the user.
*/
public function getYouTubeAuth($id)
{
// Post-auth upload URL
$uploadURL = HV_API_ROOT_URL . "?action=uploadMovieToYouTube&id=$id&html=true";
// Get URL for authorization
$authURL = Zend_Gdata_AuthSub::getAuthSubTokenUri(
$uploadURL, "http://gdata.youtube.com", false, true
);
// Redirect user to YouTube authorization page
header("Location: $authURL");
}
/**
* Authorizes Helioviewer to upload videos to the user's account.
*
* Function first checks to see if a session token already exists. If none
* is found, the user is either redirected to an authentication URL, or
* if stores sessions token if it was just retrieved.
*
* @param string $url Upload query URL
*
* @return void
*/
private function _checkAuthorization()
{
if (!isset($_SESSION['sessionToken'])) {
// If no session token exists, check for single-use URL token
if (isset($_GET['token'])) {
$_SESSION['sessionToken'] = Zend_Gdata_AuthSub::getAuthSubSessionToken($_GET['token']);
} else {
// Otherwise, send user to authorization page
throw new Exception("Authorization required before movie can be uploaded.");
}
}
}
/**
* Checks to see if the user is currently authenticated, and that any previous authentication is not expired
*
* @return bool Returns true if the user is authenticated and that
* authentication is still good, and false otherwise
*/
private function _authorizationIsValid()
{
// Attempt a simple query to make sure session token has not expired
try {
$this->_youTube->getVideoFeed($this->_testURL);
} catch (Exception $e) {
//Zend_Gdata_App_HttpException
include_once "src/Helper/ErrorHandler.php";
logErrorMsg($msg, "Youtube_");
unset($_SESSION['sessionToken']); // Discard expired authorization
return false;
}
return true;
}
/**
* Creates an instance of a Zend_Gdata_YouTube_VideoEntry using the user-submitted values
*
* @param string $filepath Path to the video
*
* @return Zend_Gdata_YouTube_VideoEntry Video entry
*/
private function _createGDataVideoEntry($filepath, $title, $description, $tags, $share)
{
// Create a new VideoEntry object
$videoEntry = new Zend_Gdata_YouTube_VideoEntry();
// Create a new FileSource object
$fileSource = $this->_createMediaFileSource($filepath);
// add the filesource to the video entry
$videoEntry->setMediaSource($fileSource);
$videoEntry->setVideoTitle($title);
$videoEntry->setVideoDescription($description);
$videoEntry->setVideoCategory('Tech');
// Set keywords. Please note that this must be a comma-separated string
// and that individual keywords cannot contain whitespace
$videoEntry->SetVideoTags($tags);
// Add Helioviewer.org developer tag
$videoEntry->setVideoDeveloperTags(array('Helioviewer.org'));
return $videoEntry;
}
/**
* Creates an instance of a Zend_Gdata_App_MediaFileSource
*
* @param string $filepath Path of the video file
*
* @return Zend_Gdata_App_MediaFileSource media source associated with the video to be uploaded
*/
private function _createMediaFileSource($filepath)
{
// Create a new Zend_Gdata_App_MediaFileSource object
$filesource = $this->_youTube->newMediaFileSource($filepath);
$filesource->setContentType('video/mp4');
// Set slug header
// http://code.google.com/apis/youtube/2.0/developers_guide_protocol_captions.html#Create_Caption_Track
$filesource->setSlug($filepath);
return $filesource;
}
/**
* Initializes a YouTube GData object instance
*
* @return Zend_Gdata_YouTube A YouTube object instance
*/
private function _getYoutubeInstance()
{
// Load YouTube class
Zend_Loader::loadClass('Zend_Gdata_YouTube');
// Instantiate Youtube object
$yt = new Zend_Gdata_YouTube(
$this->_httpClient, $this->_appId, $this->_clientId,
HV_YOUTUBE_DEVELOPER_KEY
);
$yt->setMajorProtocolVersion(2); // Use API version 2
return $yt;
}
/**
* Uploads a single video to YouTube
*
* @param int $id Movie id
* @param array $options Movie options
* @param Zend_Gdata_YouTube_VideoEntry $videoEntry A video entry object
* describing the video to be uploaded
*
* Note: Content-length and Connection: close headers are sent so that
* process can be run in the background without the user having to wait,
* and the database entry will be updated even if the user closes the
* browser window.
*
* See: http://www.zulius.com/how-to/close-browser-connection-continue-execution/
*
* @return Zend_Gdata_YouTube_VideoEntry
*/
private function _uploadVideoToYouTube ($videoEntry, $id, $title, $description, $tags, $share, $html)
{
include_once 'src/Database/MovieDatabase.php';
include_once 'lib/alphaID/alphaID.php';
$movies = new Database_MovieDatabase();
// Add movie entry to YouTube table if entry does not already exist
$movieId = alphaID($id, true, 5, HV_MOVIE_ID_PASS);
if (!$movies->insertYouTubeMovie($movieId, $title, $description, $tags, $share)) {
throw new Exception("Movie has already been uploaded. Please allow several minutes for your video to appear on YouTube.", 1);
// 12/14/2011: Tracking down upload error
// $log = HV_LOG_DIR . "/upload-" . date("Ymd_His") . ".log";
// $msg = "id: $movieId\n" . "title: $title\n". "desc: $description\n" .
// "tags: $tags\n" . "share: $share\n\n" .
// "REQUEST: " . print_r($_REQUEST, true) . "\n\n" .
// "SESSION: " . print_r($_SESSION, true);
// file_put_contents($log, $msg);
}
// buffer all upcoming output
ob_start();
// let user know that upload is in progress
if ($html) {
?>
<!DOCTYPE html>
<html lang="en">
<head>
<title>Helioviewer.org - YouTube Upload In Progress</title>
<link rel="shortcut icon" href="../favicon.ico">
<meta charset="utf-8" />
</head>
<body style='text-align: center;'>
<div style='margin-top: 200px;'>
<span style='font-size: 32px;'>Upload processing</span><br />
Your video should appear on YouTube in 1-2 minutes.
</div>
</body>
<?php
} else {
header('Content-type: application/json');
echo json_encode(array("status" => "upload in progress."));
}
// get the size of the output
$size = ob_get_length();
// send headers to tell the browser to close the connection
header("Content-Length: $size");
header('Connection: close');
// flush all output
ob_end_flush();
ob_flush();
flush();
// close current session
if (session_id()) session_write_close();
// Begin upload
try {
$newEntry = $this->_youTube->insertEntry(
$videoEntry, $this->_uploadURL, 'Zend_Gdata_YouTube_VideoEntry'
);
} catch (Zend_Gdata_App_HttpException $httpException) {
throw($httpException);
} catch (Zend_Gdata_App_Exception $e) {
throw($e);
}
// When upload finishes, get youtube id
$newEntry->setMajorProtocolVersion(2);
$youtubeId = $newEntry->getVideoId();
// Update database entry and return result
$movies->updateYouTubeMovie($movieId, $youtubeId);
return $newEntry;
}
}
?>
|