Skip to content

Instantly share code, notes, and snippets.

@dwaligora
Created July 13, 2013 13:42
Show Gist options
  • Save dwaligora/5990756 to your computer and use it in GitHub Desktop.
Save dwaligora/5990756 to your computer and use it in GitHub Desktop.
<?php
namespace Slate\Media\CommonsBundle\Manager;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher;
use Webility\Bundle\remoteStorageBundle\Services\Storage;
use Webility\Bundle\WebilityBundle\Entity\Repository\File;
use Webility\Bundle\WebilityBundle\Entity\Superclasses\Entity;
use Slate\AppBundle\Entity\StreamedMedia\StreamType;
use Slate\Media\CommonsBundle\Entity\StreamedMedia\Stream;
use Slate\Media\CommonsBundle\StreamConverter\EncodingComStreamTypeConverter;
use Slate\Media\CommonsBundle\Event\OriginalFileUploadedEvent;
use Slate\Media\CommonsBundle\Event\ClipStreamEncodedEvent;
use Slate\Media\CommonsBundle\Entity\StreamedMediaInterface;
use Slate\Media\CommonsBundle\Manager\MediaManager;
class StreamedMediaManager extends MediaManager
{
/**********************************************************
* THOSE PROPERTIES ARE MIXED FOR ALLOWING FLEXIBLE
* CHANGES OF REMOTE STORAGE PROVIDER, remote, S3, etc.
**********************************************************/
/**
* @var mixed
*/
protected $encoder;
/**
* @var mixed
*/
protected $remote_storage;
/**
* @var mixed
*/
protected $remote_uploader;
/**
* @var string Repository instance
*/
protected $repository_class = 'SlateMediaCommonsBundle:StreamedMedia\Stream';
public function setEncoder($encoder)
{
$this->encoder = $encoder;
}
public function setRemoteStorage($remote_storage)
{
$this->remote_storage = $remote_storage;
}
public function setRemoteUploader($remote_uploader)
{
$this->remote_uploader = $remote_uploader;
}
public function setRepositoryClass($repository)
{
$this->repository_class = $repository;
}
public function getRepository()
{
return $this->repository_class;
}
public function getOriginalStream(StreamedMediaInterface $media)
{
return $this->getObjectManager()->getRepository($this->repository_class)
->getOriginalStream($media->getId());
}
public function updateOrCreateOriginalStream(StreamedMediaInterface $media)
{
$om = $this->getObjectManager();
$original_stream = $this->getOriginalStream($media);
if (null === $original_stream) {
$original_stream = new Stream();
$original_stream->setStremedMedia($media);
$original_stream->setIsOriginal(true);
$media->addStream($original_stream);
}
// @todo
// setting media original file again in case of changing file
$original_stream->setFile($media->getOriginalFile());
$original_stream->setFileId($media->getOriginalFile()->getId());
$om->persist($original_stream);
return $original_stream;
}
public function isUploaded(StreamedMediaInterface $media)
{
if (null === $media->getOriginalFile()) {
throw new \LogicException(
sprintf(
'There are no original file or orignal stream for media [id: %s]. Please set is, in order to upload file to remote storage!',
$media->getId()
)
);
}
if ($media->getOriginalFile()->isRemote()) {
return true;
}
return false;
}
public function upload(StreamedMediaInterface $media)
{
try {
if (!$this->isUploaded($media)) {
$file = $media->getOriginalFile();
$this->remote_uploader->upload($file);
$this->getObjectManager()->persist($file);
$this->getObjectManager()->flush();
\Webility\Storage::unlink($file->getRootFilePath());
}
} catch(\Exception $e) {
throw new \RuntimeException($e->getMessage());
}
}
/**
* MP
*
* @param StreamedMediaInterface $media
* @param $stream_status_update_url
* @return bool
*/
public function encode(StreamedMediaInterface $media, $stream_status_update_url)
{
set_time_limit(0);
$original_file = $media->getOriginalFile();
// prepare all streams
$streams_by_stream_type = array();
foreach ($media->getStreams() as $stream) {
/* @var $stream Stream */
$stream_type = $stream->getStreamType();
if (null !== $stream_type) {
$streams_by_stream_type[$stream_type->getId()] = $stream;
}
}
/* @var $original_stream_file File */
//@todo need to move it somewhere
$param_converter = new EncodingComStreamTypeConverter();
//detect not encoded streams
$ordering = 0;
$formats = array();
$streams = array();
$base_remote_url = 'http://' . $this->remote_storage->getLogin() . ':' . $this->remote_storage->getApiKey() . '@storage.cloudfiles.com/' . $this->remote_storage->getContainerName() . '/';
foreach ($media->getStreamTypes() as $stream_type) {
/* @var $stream_type StreamType */
// verify if stream of given stream type exists, if no create new one.
if (!isset($streams_by_stream_type[$stream_type->getId()])
|| in_array($streams_by_stream_type[$stream_type->getId()]->getStatus(), array(Stream::STATUS_ERROR, null))
) {
if (!isset($streams_by_stream_type[$stream_type->getId()])) {
$stream = new Stream();
$stream->setStreamType($stream_type);
$stream->setStremedMedia($media);
$media->addStream($stream);
} else {
$stream = $streams_by_stream_type[$stream_type->getId()];
}
$stream->setStatus(Stream::STATUS_IN_PROGRESS);
$stream->setEncodeTaskOrder($ordering);
$new_filename = $stream_type->getFileNameFromPattern($original_file, $stream);
$stream_file = new File();
$stream_file->setName($new_filename);
$stream->setFile($stream_file);
// destination - url where encoded files should be moved
$encoding_parameters = $param_converter->convert($stream_type);
$encoding_parameters['destination'] = $base_remote_url . $new_filename;
$formats[] = $encoding_parameters;
$streams[] = $stream;
$ordering++;
}
}
if (count($formats) > 0) {
if(method_exists($media, 'getGeneratedThumbnail')){
//add image thumb format
$image_format = array(
'output' => 'thumbnail',
'time' => '50%',
'destination' => $base_remote_url . $media->getUrlname().'.jpg'
);
}
$formats[] = $image_format;
//send to encode
$accetped = false;
$attempt = 1;
do {
$media_id = $this->encoder->addEncodings($original_file->getRemoteAddress(), $formats, $stream_status_update_url);
if (ctype_digit($media_id)) {
$accetped = true;
} else {
if ($media_id == 'Request rate over limit') {
//too many requests sleep and try again later
sleep(1);
$attempt++;
} else {
//other error, allow script to go on
$stream->setStatus(Stream::STATUS_ERROR);
//exit attempts loop
break;
}
}
} while ($accetped === false && $attempt <= 5);
//update streams data
foreach ($streams as $sent_stream) {
if (!$accetped) {
//other error, allow script to go on
$sent_stream->setStatus(Stream::STATUS_ERROR);
}
$sent_stream->setExternalMediaId($media_id);
$sent_stream->dbPersist();
}
}
//perform additional tasks, like generate WAVe forms, etc.
$original_file_uploaded_event = new OriginalFileUploadedEvent($media);
$this->getEventDispatcher()->dispatch('media.original_file.uploaded', $original_file_uploaded_event);
$this->getObjectManager()->flush();
return true;
}
/**
* MP
*
* Updates clip streams based on remote response stream
*
* @param string $response_string
* @return Clip
*/
public function updateStreams($response_string)
{
$response = new \SimpleXMLElement($response_string);
/* @var $streams_repository StreamRepository */
$streams_repository = $this->entity_manager->getRepository('SlateMediaCommonsBundle:StreamedMedia\Stream');
$streams = $streams_repository->getStreamsByMediaId((int) $response->mediaid . '');
$formats = $response->format;
$clip = null;
for ($i = 0, $iterations = min(count($formats), count($streams)); $i < $iterations; $i++) { //skip formats which aren't video streams
/* @var $stream Stream */
$stream = $streams[$i];
$format = $formats[$i];
if ($clip === null) {
$clip = $stream->getStreamedMedia();
}
if ($stream->getStatus() == Stream::STATUS_IN_PROGRESS) {
if ($format->status == 'Finished') {
$stream->setStatus(Stream::STATUS_ENCODED);
$uploaded_file_name = $format->destination;
/* @var $stream_file File */
$stream_file = $stream->getFile();
$container_name = basename(\Webility\Storage::extractPath($uploaded_file_name));
$this->remote_storage->setContainer($container_name);
$remote_object = $this->remote_storage->getContainer()->get_object(\Webility\Storage::extractFileName($uploaded_file_name));
$stream_file->setIsRemote(true);
$stream_file->setRemoteOrigin('remote.' . $container_name);
$stream_file->setRemoteAddress($remote_object->public_uri());
$stream_file->setRemoteStreamingAddress($remote_object->public_streaming_uri());
$stream_file->dbPersist();
} else {
$stream->setStatus(Stream::STATUS_ERROR);
$stream->setEncodingError($format->description);
}
$stream->dbPersist();
$this->entity_manager->flush();
$event = new ClipStreamEncodedEvent($stream);
$this->_event_dispatcher->dispatch('media.stream.encoded', $event);
}
}
if($iterations+1 == count($formats)){ //check if image format exist
$image_format = $formats[$iterations];
if($clip !== null && method_exists($clip, 'getGeneratedThumbnail')){
$base_name = \Webility\Storage::extractFileName($image_format->destination);
$container_name = basename(\Webility\Storage::extractPath($image_format->destination));
$this->remote_storage->setContainer($container_name);
$remote_object = $this->remote_storage->getContainer()->get_object($base_name);
$file = new File();
$file->setName($base_name);
$file->setRemoteAddress($remote_object->public_uri());
$file->setIsRemote(true);
$clip->setGeneratedThumbnail($file);
$file->dbPersist();
$clip->dbPersist();
$this->entity_manager->flush();
}
}
return $clip;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment