220
* Queues a request for a Helioviewer.org movie
222
public function reQueueMovie($silent=false) {
223
include_once 'lib/alphaID/alphaID.php';
224
include_once 'lib/Resque.php';
225
include_once 'lib/Redisent/Redisent.php';
226
include_once 'src/Helper/HelioviewerLayers.php';
227
include_once 'src/Helper/HelioviewerEvents.php';
228
include_once 'src/Database/MovieDatabase.php';
229
include_once 'src/Database/ImgIndex.php';
230
include_once 'src/Movie/HelioviewerMovie.php';
233
$redis = new Redisent('localhost');
235
// If the queue is currently full, don't process the request
236
$queueSize = Resque::size('on_demand_movie');
237
if ( $queueSize >= MOVIE_QUEUE_MAX_SIZE ) {
239
'Sorry, due to current high demand, we are currently unable ' .
240
'to process your request. Please try again later.', 40);
243
// Get current number of on_demand_movie workers
244
$workers = Resque::redis()->smembers('workers');
245
$movieWorkers = array_filter($workers, function ($elem) {
246
return strpos($elem, 'on_demand_movie') !== false;
254
$options = array_replace($defaults, $this->_params);
256
// Convert public alpha-numeric id to integer
257
$movieId = alphaId($this->_params['id'], true, 5, HV_MOVIE_ID_PASS);
258
$movieId = intval($movieId);
260
if ( $movieId <= 0 ) {
262
'Value of movie "id" parameter is invalid.', 25);
265
// Check if movie exists on disk before re-queueing
266
if ( $options['force'] === false ) {
267
$helioviewerMovie = new Movie_HelioviewerMovie(
268
$this->_params['id'], $options['format']);
269
$filepath = $helioviewerMovie->getFilepath();
271
$path_parts = pathinfo($filepath);
272
$extension = '.' . $path_parts['extension'];
274
foreach ( array('.mp4', '.flv', '.webm') as $ext ) {
275
$path = str_replace($extension, $ext, $filepath);
276
if ( @file_exists($path) ) {
277
$url = str_replace(HV_CACHE_DIR, HV_CACHE_URL, $path);
279
'Movie file already exists: '.$url, 44);
284
// Get movie metadata from database
285
$movieDatabase = new Database_MovieDatabase();
286
$movie = $movieDatabase->getMovieMetadata($movieId);
289
// Check if movie is already in the queue (status=0)
290
// or is already being processed (status=1) before re-queueing.
291
// This prevents a spider, bot, or other automated user-agent
292
// from stuffing the queue with redundant regeneration requests.
293
// As such, the optional 'force' parameter will NOT override
295
// However, if the movie status is considered stale, then
296
// a Queued or Processing status is ignored and re-queueing
297
// is allowed to proceed.
298
$movieFormats = $movieDatabase->getMovieFormats($movieId);
299
foreach ( $movieFormats as $movieFormat ) {
300
$seconds_ago = time() - strtotime($movieFormat['modified']);
301
$stale = 60 * 60 * 2; // 2 hours
303
if ( $movieFormat['status'] == 0
304
&& $seconds_ago < $stale ) {
308
else if ( $movieFormat['status'] == 1
309
&& $seconds_ago < $stale ) {
315
$numPixels = $movie['width'] * $movie['height'];
316
$maxFrames = min($this->_getMaxFrames($queueSize),
317
$movie['maxFrames']);
320
// Create a connection to the database
321
$db = new Database_ImgIndex();
323
// Limit movies to three layers
324
$layers = new Helper_HelioviewerLayers($movie['dataSourceString']);
325
if ( $layers->length() < 1 || $layers->length() > 3 ) {
327
'Invalid layer choices! You must specify 1-3 comma-separated '.
331
// Estimate the number of frames
332
$numFrames = $this->_estimateNumFrames($db, $layers,
333
$movie['startDate'], $movie['endDate']);
334
$numFrames = min($numFrames, $maxFrames);
336
// Estimate the time to create movie frames
337
// @TODO 06/2012: Factor in total number of workers and number of
338
// workers that are currently available?
339
$estBuildTime = $this->_estimateMovieBuildTime($movieDatabase,
340
$numFrames, $numPixels, $options['format']);
342
// If all workers are in use, increment and use estimated wait counter
343
if ( $queueSize +1 >= sizeOf($movieWorkers) ) {
344
$eta = $redis->incrby('helioviewer:movie_queue_wait',
346
$updateCounter = true;
349
// Otherwise simply use the time estimated for the single movie
350
$eta = $estBuildTime;
351
$updateCounter = false;
354
// Get datasource bitmask
355
$bitmask = bindec($layers->getBitMask());
357
$publicId = $this->_params['id'];
359
// Queue movie request
361
'movieId' => $publicId,
362
'eta' => $estBuildTime,
363
'format' => $options['format'],
364
'counter' => $updateCounter
366
$token = Resque::enqueue('on_demand_movie', 'Job_MovieBuilder',
369
// Create entries for each version of the movie in the movieFormats
371
$movieDatabase->deleteMovieFormats($movieId);
372
foreach(array('mp4', 'webm') as $format) {
373
$movieDatabase->insertMovieFormat($movieId, $format);
380
'queue' => max(0, $queueSize + 1 - sizeOf($movieWorkers)),
385
$this->_printJSON(json_encode($response));
220
390
* Estimates the amount of time (in seconds) it will take to build the
221
391
* requested movie using information about the most recent n movies
440
608
// Return movie data
441
609
echo @file_get_contents($filepath);
444
// Otherwise return an error
446
header('Content-type: application/json');
447
$response = array('error' => 'The movie you requested is either '.
448
'being processed or does not exist.');
449
print json_encode($response);
612
switch ($movie->status) {
614
header('Content-type: application/json');
616
'error' => 'Movie '.$movie->publicId.' ('.$movie->id.') '
617
. 'is queued for processing. '
618
. 'Please wait for it to complete.');
619
print json_encode($response);
622
header('Content-type: application/json');
624
'error' => 'Movie '.$movie->publicId.' ('.$movie->id.') '
625
. 'is currently being processed. '
626
. 'Please wait for it to complete.');
627
print json_encode($response);
630
header('Content-type: application/json');
632
'error' => 'Movie '.$movie->publicId.' ('.$movie->id.') '
633
. 'was not generated successfully.');
634
print json_encode($response);
637
header('Content-type: application/json');
639
'error' => 'Movie '.$movie->publicId.' ('.$movie->id.') '
640
. 'has an unknown status.');
641
print json_encode($response);
648
* Grab the textual equivalent of a movie status code.
652
public function getStatusLabel($statusCode) {
653
switch ($statusCode) {
655
$statusLabel = 'Queued';
658
$statusLabel = 'Processing';
661
$statusLabel = 'Completed';
664
$statusLabel = 'Invalid';
667
$statusLabel = 'Unknown';
465
688
$verbose = isset($this->_options['verbose']) ?
466
689
$this->_options['verbose'] : false;
469
if ($movie->status == 2) {
692
if ($movie->status == 0) {
695
'status' => $movie->status,
696
'statusLabel' => $this->getStatusLabel($movie->status),
697
'queuePosition' => $queueNum,
701
else if ($movie->status == 1) {
702
$current_frame = $movie->getCurrentFrame();
703
$progress = $current_frame / $movie->numFrames;
704
$progress = (float)number_format($progress, 3);
707
'status' => $movie->status,
708
'statusLabel' => $this->getStatusLabel($movie->status),
709
'currentFrame' => $current_frame,
710
'numFrames' => $movie->numFrames,
711
'progress' => $progress,
712
'queuePosition' => $queueNum
715
else if ($movie->status == 2) {
470
717
$response = $movie->getCompletedMovieInformation($verbose);
718
$response['statusLabel'] =
719
$this->getStatusLabel($response['status']);
472
721
else if ($movie->status == 3) {
474
723
$response = array(
724
'status' => $movie->status,
725
'statusLabel' => $this->getStatusLabel($movie->status),
476
726
'error' => 'Sorry, we are unable to create your movie at '.
477
727
'this time. Please try again later.'
480
else if ($movie->status == 0) {
482
if ( isset($this->_options['token']) ) {
483
require_once 'lib/Resque.php';
487
// NOTE: since resque token is only useful for determining
488
// the general status of a job (e.g. QUEUED) and queue
489
// position can be found using the movie id, the tokenId
490
// can probably be removed.
491
//$queueNum = $this->_getQueueNum("on_demand_movie",
492
// $this->_options['token']);
493
$queueNum = $this->_getQueueNum('on_demand_movie',
494
$this->_params['id']);
495
$queueSize = Resque::size('on_demand_movie');
499
'position' => $queueNum,
500
'total' => $queueSize
505
$response = array('status' => 0);
510
731
$response = array(
732
'status' => $movie->status,
733
'statusLabel' => $this->getStatusLabel($movie->status),
734
'queuePosition' => $queueNum
921
public function _verifyMediaExists($movie, $allowRegeneration=true) {
923
// Check for missing movie or preview images
924
$media_exists = true;
925
$info = $movie->getCompletedMovieInformation(true);
926
$url_array = $info['thumbnails'];
927
array_push($url_array, $info['url']);
928
foreach ($url_array as $key => $url) {
929
$path = str_replace(HV_CACHE_URL, HV_CACHE_DIR, $url);
930
if ( !@file_exists($path) ) {
931
$media_exists = false;
934
if ( !$media_exists && $allowRegeneration ) {
936
// Attempt to re-generate the movie because one or more
937
// of the thumbnail images or movie files is missing.
938
// Use the 'force' option to overwrite any of
939
// the associated movie files that may still exist
941
$id = $this->_params['id'];
942
$this->_params = array();
943
$this->_params['action'] = 'reQueueMovie';
944
$this->_params['id'] = $id;
945
$this->_params['force'] = true;
946
$this->_params['force'] = false;
947
$this->reQueueMovie($silent=true);
949
catch (Exception $e) {
950
error_log(json_encode($e->getMessage()));
954
return $media_exists;
695
958
* Generates HTML for a video player with the specified movie loaded