300 lines
7.8 KiB
PHP
300 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
* VideoPress Uploader
|
|
*
|
|
* @package automattic/jetpack-videopress
|
|
*/
|
|
|
|
namespace Automattic\Jetpack\VideoPress;
|
|
|
|
use Jetpack_Options;
|
|
use VideoPressUploader\File_Exception;
|
|
use VideoPressUploader\Tus_Client;
|
|
|
|
/**
|
|
* VideoPress Uploader class
|
|
*
|
|
* Handles the upload from the Media Library to VideoPress servers
|
|
*/
|
|
class Uploader {
|
|
|
|
/**
|
|
* The key of the post meta that holds the ID of the attachment that holds the VideoPress video, in case this attachment was uploaded before.
|
|
*
|
|
* @var string
|
|
*/
|
|
const UPLOADED_KEY = '_videopress_uploaded_id';
|
|
|
|
/**
|
|
* The chunk size of each upload step
|
|
*
|
|
* @var int
|
|
*/
|
|
const CHUNK_SIZE = 5000000;
|
|
|
|
/**
|
|
* The Tus Client instance
|
|
*
|
|
* @var Tus_Client
|
|
*/
|
|
protected $client = null;
|
|
|
|
/**
|
|
* The attachment ID
|
|
*
|
|
* @var int
|
|
*/
|
|
protected $attachment_id;
|
|
|
|
/**
|
|
* Checks whether this feature is supported by the server
|
|
*
|
|
* @param int $attachment_id The ID of the video attachment we want to upload to VideoPress.
|
|
* @return boolean
|
|
*/
|
|
public static function is_valid_attachment_id( $attachment_id ) {
|
|
$file_path = get_attached_file( $attachment_id );
|
|
if ( ! $file_path || ! is_readable( $file_path ) ) {
|
|
return false;
|
|
}
|
|
if ( ! str_starts_with( get_post_mime_type( $attachment_id ), 'video/' ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Constructs the object
|
|
*
|
|
* @throws Upload_Exception If attachment is invalid or server does not support it.
|
|
* @param int $attachment_id The ID of the video attachment we want to upload to VideoPress.
|
|
*/
|
|
public function __construct( $attachment_id ) {
|
|
$this->attachment_id = $attachment_id;
|
|
if ( ! $this->get_file_path() ) {
|
|
throw new Upload_Exception( __( 'Invalid attachment ID', 'jetpack-videopress-pkg' ), Upload_Exception::ERROR_INVALID_ATTACHMENT_ID );
|
|
}
|
|
if ( ! is_readable( $this->get_file_path() ) ) {
|
|
throw new Upload_Exception( __( 'File not found', 'jetpack-videopress-pkg' ), Upload_Exception::ERROR_FILE_NOT_FOUND );
|
|
}
|
|
if ( ! $this->file_has_supported_mime_type() ) {
|
|
throw new Upload_Exception( __( 'Mime type not supported', 'jetpack-videopress-pkg' ), Upload_Exception::ERROR_MIME_TYPE_NOT_SUPPORTED );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the path of the video file
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_file_path() {
|
|
return get_attached_file( $this->attachment_id );
|
|
}
|
|
|
|
/**
|
|
* Gets the mime type of the attachment
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_file_mime_type() {
|
|
return get_post_mime_type( $this->attachment_id );
|
|
}
|
|
|
|
/**
|
|
* Gets the name of the video file
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_file_name() {
|
|
return basename( $this->get_file_path() );
|
|
}
|
|
|
|
/**
|
|
* Gets the size of the video file
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_file_size() {
|
|
return filesize( $this->get_file_path() );
|
|
}
|
|
|
|
/**
|
|
* Checks if the mime type of the attachment is supported to be uploaded
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function file_has_supported_mime_type() {
|
|
return str_starts_with( $this->get_file_mime_type(), 'video/' );
|
|
}
|
|
|
|
/**
|
|
* Gets the VideoPress upload token
|
|
*
|
|
* @throws Upload_Exception If it fails to fetch the token.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_upload_token() {
|
|
return VideoPressToken::videopress_upload_jwt();
|
|
}
|
|
|
|
/**
|
|
* Gets a unique upload key for this attachment
|
|
*
|
|
* @return string
|
|
*/
|
|
public function get_key() {
|
|
return sprintf( 's-%d-v-%d', Jetpack_Options::get_option( 'id' ), $this->attachment_id );
|
|
}
|
|
|
|
/**
|
|
* Sets the current attachment as uploaded and stores the ID of the VideoPress video attachment ID
|
|
*
|
|
* @param int $new_attachment_id The ID of the new attachment created to hold the VideoPress video.
|
|
* @return void
|
|
*/
|
|
protected function mark_as_uploaded( $new_attachment_id ) {
|
|
update_post_meta( $this->attachment_id, self::UPLOADED_KEY, $new_attachment_id );
|
|
}
|
|
|
|
/**
|
|
* Sets the current attachment as not being uploaded before. Deletes the reference to the videopress attachment
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function unmark_as_uploaded() {
|
|
delete_post_meta( $this->attachment_id, self::UPLOADED_KEY );
|
|
}
|
|
|
|
/**
|
|
* Checks whether this attachment was uploaded before
|
|
*
|
|
* @return boolean
|
|
*/
|
|
public function is_uploaded() {
|
|
return ! empty( $this->get_uploaded_attachment_id() );
|
|
}
|
|
|
|
/**
|
|
* Gets the ID of the VideoPress video attachment in case this attachment was uploaded before
|
|
*
|
|
* @return boolean|string False if value is absent. Post ID on success.
|
|
*/
|
|
public function get_uploaded_attachment_id() {
|
|
return get_post_meta( $this->attachment_id, self::UPLOADED_KEY, true );
|
|
}
|
|
|
|
/**
|
|
* Retrieves the instance of the Tus_Client
|
|
*
|
|
* @return Tus_Client
|
|
*/
|
|
public function get_client() {
|
|
if ( $this->client !== null ) {
|
|
return $this->client;
|
|
}
|
|
|
|
$this->client = new Tus_Client( $this->get_key(), $this->get_upload_token(), Jetpack_Options::get_option( 'id' ) );
|
|
|
|
return $this->client;
|
|
}
|
|
|
|
/**
|
|
* Uploads a chunk of the file
|
|
*
|
|
* @return array With the status of the upload
|
|
*/
|
|
public function upload() {
|
|
if ( $this->is_uploaded() ) {
|
|
return $this->check_status();
|
|
}
|
|
try {
|
|
$this->get_client()->file( $this->get_file_path(), $this->get_file_name() );
|
|
|
|
$bytes_uploaded = $this->get_client()->upload( self::CHUNK_SIZE );
|
|
|
|
if ( $bytes_uploaded === $this->get_file_size() ) {
|
|
$this->mark_as_uploaded( $this->get_client()->get_uploaded_video_details()['media_id'] );
|
|
return array(
|
|
'status' => 'complete',
|
|
'bytes_uploaded' => $bytes_uploaded,
|
|
'file_size' => $this->get_file_size(),
|
|
'file_name' => $this->get_file_name(),
|
|
'upload_key' => $this->get_key(),
|
|
'uploaded_details' => $this->get_client()->get_uploaded_video_details(),
|
|
);
|
|
}
|
|
|
|
return array(
|
|
'status' => 'uploading',
|
|
'bytes_uploaded' => $bytes_uploaded,
|
|
'file_size' => $this->get_file_size(),
|
|
'file_name' => $this->get_file_name(),
|
|
'upload_key' => $this->get_key(),
|
|
);
|
|
} catch ( \Exception $e ) {
|
|
return array(
|
|
'status' => 'error',
|
|
'bytes_uploaded' => -1,
|
|
'file_size' => $this->get_file_size(),
|
|
'file_name' => $this->get_file_name(),
|
|
'upload_key' => $this->get_key(),
|
|
'error' => $e->getCode() . ': ' . $e->getMessage(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks the status of the upload of this attachment
|
|
*
|
|
* @return array
|
|
*/
|
|
public function check_status() {
|
|
|
|
if ( $this->is_uploaded() ) {
|
|
$uploaded_attachment_id = $this->get_uploaded_attachment_id();
|
|
$uploaded_video_guid = get_post_meta( $uploaded_attachment_id, 'videopress_guid', true );
|
|
if ( $uploaded_video_guid ) {
|
|
return array(
|
|
'status' => 'uploaded',
|
|
'upload_key' => $this->get_key(),
|
|
'uploaded_post_id' => $uploaded_attachment_id,
|
|
'uploaded_video_guid' => $uploaded_video_guid,
|
|
);
|
|
} else {
|
|
// VideoPress attachment is gone, allow user to upload it again.
|
|
$this->unmark_as_uploaded();
|
|
}
|
|
}
|
|
|
|
try {
|
|
$offset = $this->get_client()->get_offset();
|
|
$status = false !== $offset ? 'resume' : 'new';
|
|
$offset = false === $offset ? 0 : $offset;
|
|
|
|
return array(
|
|
'status' => $status,
|
|
'bytes_uploaded' => $offset,
|
|
'file_size' => $this->get_file_size(),
|
|
'file_name' => $this->get_file_name(),
|
|
'upload_key' => $this->get_key(),
|
|
);
|
|
} catch ( File_Exception $e ) {
|
|
return array(
|
|
'status' => 'resume',
|
|
'bytes_uploaded' => 0,
|
|
'file_size' => $this->get_file_size(),
|
|
'file_name' => $this->get_file_name(),
|
|
'upload_key' => $this->get_key(),
|
|
);
|
|
} catch ( \Exception $e ) {
|
|
return array(
|
|
'status' => 'error',
|
|
'bytes_uploaded' => -1,
|
|
'file_size' => $this->get_file_size(),
|
|
'file_name' => $this->get_file_name(),
|
|
'message' => $e->getMessage(),
|
|
);
|
|
}
|
|
}
|
|
}
|