diff --git a/admin/rt-transcoder-handler.php b/admin/rt-transcoder-handler.php index c155f2e..e1c43bf 100755 --- a/admin/rt-transcoder-handler.php +++ b/admin/rt-transcoder-handler.php @@ -29,7 +29,7 @@ class RT_Transcoder_Handler { * @access protected * @var string $transcoding_api_url The URL of the api. */ - protected $transcoding_api_url = 'https://api.rtmedia.io/api/v1/'; + protected $transcoding_api_url = 'http://frappe-transcoder-api.rt.gw/api/'; /** * The URL of the EDD store. @@ -38,7 +38,7 @@ class RT_Transcoder_Handler { * @access protected * @var string $store_url The URL of the transcoder api. */ - protected $store_url = 'https://rtmedia.io/'; + protected $store_url = 'http://frappe-transcoder-api.rt.gw/api/'; /** * Contain uploaded media information. @@ -147,24 +147,24 @@ public function __construct( $no_init = false ) { $usage_info = get_site_option( 'rt-transcoding-usage' ); if ( isset( $usage_info ) && is_array( $usage_info ) && array_key_exists( $this->api_key, $usage_info ) ) { - if ( isset( $usage_info[ $this->api_key ]->plan->expires ) - && strtotime( $usage_info[ $this->api_key ]->plan->expires ) < time() ) { - $usage_info = $this->update_usage( $this->api_key ); - } + // if ( isset( $usage_info[ $this->api_key ]->plan->expires ) + // && strtotime( $usage_info[ $this->api_key ]->plan->expires ) < time() ) { + // $usage_info = $this->update_usage( $this->api_key ); + // } if ( array_key_exists( $this->api_key, $usage_info ) && is_object( $usage_info[ $this->api_key ] ) && isset( $usage_info[ $this->api_key ]->status ) && $usage_info[ $this->api_key ]->status ) { if ( isset( $usage_info[ $this->api_key ]->remaining ) && $usage_info[ $this->api_key ]->remaining > 0 ) { // Enable re-transcoding. include_once RT_TRANSCODER_PATH . 'admin/rt-retranscode-admin.php'; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingCustomConstant - if ( $usage_info[ $this->api_key ]->remaining < 524288000 && ! get_site_option( 'rt-transcoding-usage-limit-mail' ) ) { - $this->nearing_usage_limit( $usage_info ); - } elseif ( $usage_info[ $this->api_key ]->remaining > 524288000 && get_site_option( 'rt-transcoding-usage-limit-mail' ) ) { - update_site_option( 'rt-transcoding-usage-limit-mail', 0 ); - } - if ( strtotime( $usage_info[ $this->api_key ]->plan->expires ) > time() ) { - add_filter( 'wp_generate_attachment_metadata', array( $this, 'wp_media_transcoding' ), 21, 2 ); - } + // if ( $usage_info[ $this->api_key ]->remaining < 524288000 && ! get_site_option( 'rt-transcoding-usage-limit-mail' ) ) { + // $this->nearing_usage_limit( $usage_info ); + // } elseif ( $usage_info[ $this->api_key ]->remaining > 524288000 && get_site_option( 'rt-transcoding-usage-limit-mail' ) ) { + // update_site_option( 'rt-transcoding-usage-limit-mail', 0 ); + // } + // if ( strtotime( $usage_info[ $this->api_key ]->plan->expires ) > time() ) { + // add_filter( 'wp_generate_attachment_metadata', array( $this, 'wp_media_transcoding' ), 21, 2 ); + // } /* Do not let the user to upload non supported media types on localhost */ $blacklist = rtt_get_blacklist_ip_addresses(); @@ -183,6 +183,10 @@ public function __construct( $no_init = false ) { add_action( 'wp_ajax_rt_disable_transcoding', array( $this, 'disable_transcoding' ), 1 ); add_action( 'wp_ajax_rt_enable_transcoding', array( $this, 'enable_transcoding' ), 1 ); add_action( 'add_attachment', array( $this, 'after_upload_pdf' ) ); + add_filter( 'wp_generate_attachment_metadata', array( $this, 'wp_media_transcoding' ), 21, 2 ); + add_filter( 'rtmedia_plupload_files_filter', array( $this, 'allowed_types' ), 10, 1 ); + add_filter( 'rtmedia_allowed_types', array( $this, 'allowed_types_admin_settings' ), 10, 1 ); + add_filter( 'rtmedia_valid_type_check', array( $this, 'bypass_video_audio' ), 10, 2 ); } /** @@ -256,23 +260,29 @@ public function wp_media_transcoding( $wp_metadata, $attachment_id, $autoformat } } + $callback_url = RT_TRANSCODER_CALLBACK_URL; + + if ( ! defined( 'RT_TRANSCODER_CALLBACK_URL' ) || empty( RT_TRANSCODER_CALLBACK_URL ) ) { + return; + } + $args = array( 'method' => 'POST', 'sslverify' => false, 'timeout' => 60, // phpcs:ignore WordPressVIPMinimum.Performance.RemoteRequestTimeout.timeout_timeout 'body' => array( - 'api_token' => $this->api_key, - 'job_type' => $job_type, - 'job_for' => $job_for, - 'file_url' => rawurlencode( $url ), - 'callback_url' => rawurlencode( trailingslashit( home_url() ) . 'index.php' ), - 'force' => 0, - 'formats' => ( true === $autoformat ) ? ( ( 'video' === $type_array[0] ) ? 'mp4' : 'mp3' ) : $autoformat, - 'thumb_count' => $options_video_thumb, + 'api_token' => $this->api_key, + 'job_type' => $job_type, + 'job_for' => $job_for, + 'file_origin' => rawurlencode( $url ), + 'callback_url' => rawurlencode( $callback_url ), + 'force' => 0, + 'formats' => ( true === $autoformat ) ? ( ( 'video' === $type_array[0] ) ? 'mp4' : 'mp3' ) : $autoformat, + 'thumbnail_count' => $options_video_thumb, ), ); - $transcoding_url = $this->transcoding_api_url . 'job/'; + $transcoding_url = $this->transcoding_api_url . 'resource/Transcoder Job'; $upload_page = wp_remote_post( $transcoding_url, $args ); @@ -283,8 +293,9 @@ public function wp_media_transcoding( $wp_metadata, $attachment_id, $autoformat ) ) { $upload_info = json_decode( $upload_page['body'] ); - if ( isset( $upload_info->status ) && $upload_info->status && isset( $upload_info->job_id ) && $upload_info->job_id ) { - $job_id = $upload_info->job_id; + error_log( json_encode( $upload_info ) ); + if ( isset( $upload_info->data ) && isset( $upload_info->data->name ) ) { + $job_id = $upload_info->data->name; update_post_meta( $attachment_id, '_rt_transcoding_job_id', $job_id ); } } @@ -350,7 +361,7 @@ public function bypass_video_audio( $flag, $file ) { * @return boolean $status If true then key is valid else key is not valid. */ public function is_valid_key( $key ) { - $validate_url = trailingslashit( $this->store_url ) . 'rt-eddsl-api/?rt-eddsl-license-key=' . $key; + $validate_url = trailingslashit( $this->store_url ) . '/resource/Transcoder License/' . $key; if ( function_exists( 'vip_safe_wp_remote_get' ) ) { $validation_page = vip_safe_wp_remote_get( $validate_url, '', 3, 3 ); } else { @@ -358,8 +369,8 @@ public function is_valid_key( $key ) { } if ( ! is_wp_error( $validation_page ) ) { $validation_info = json_decode( $validation_page['body'] ); - if ( isset( $validation_info->status ) ) { - $status = $validation_info->status; + if ( isset( $validation_info->data->status ) && 'Active' === $validation_info->data->status ) { + $status = true; } } else { $status = false; @@ -378,7 +389,7 @@ public function is_valid_key( $key ) { * @return array $usage_info An array containing usage information. */ public function update_usage( $key ) { - $usage_url = trailingslashit( $this->transcoding_api_url ) . 'usage/' . $key; + $usage_url = trailingslashit( $this->transcoding_api_url ) . 'resource/Transcoder License/' . $key; if ( function_exists( 'vip_safe_wp_remote_get' ) ) { $usage_page = vip_safe_wp_remote_get( $usage_url, '', 3, 3 ); } else { @@ -386,6 +397,7 @@ public function update_usage( $key ) { } if ( ! is_wp_error( $usage_page ) ) { $usage_info = json_decode( $usage_page['body'] ); + $usage_info = $usage_info->data; } else { $usage_info = null; } @@ -463,7 +475,7 @@ public function usage_quota_over() { */ public function save_api_key() { $is_api_key_updated = transcoder_filter_input( INPUT_GET, 'api-key-updated', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); - $is_invalid_license_key = transcoder_filter_input( INPUT_GET, 'invalid-license-key', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); + $is_invalid_license_key = false; $is_localhost = transcoder_filter_input( INPUT_GET, 'need-public-host', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); if ( $is_api_key_updated ) { @@ -514,7 +526,7 @@ public function save_api_key() { $return_page = add_query_arg( array( 'page' => 'rt-transcoder', - 'api-key-updated' => $usage_info->plan->name ? ucfirst( strtolower( $usage_info->plan->name ) ) : 'Free', + 'api-key-updated' => $usage_info->plan ? ucfirst( strtolower( $usage_info->plan ) ) : 'Free', ), admin_url( 'admin.php' ) ); @@ -1111,6 +1123,7 @@ public function get_post_id_by_meta_key_and_value( $key, $value ) { * @since 1.0.0 */ public function handle_callback() { + // TODO: Refactor this function into REST API. require_once ABSPATH . 'wp-admin/includes/image.php'; $job_id = transcoder_filter_input( INPUT_POST, 'job_id', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); @@ -1610,20 +1623,20 @@ class_exists( 'ImagickPixel', false ) && /** * Sanitize transcoder post respopnse array. */ - private function filter_transcoder_response() { + public function filter_transcoder_response() { $post_var = $_POST; // phpcs:ignore WordPress.Security.NonceVerification.Missing $filter_post_args = array( - 'job_id' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'job_type' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'job_for' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'format' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'download_url' => FILTER_SANITIZE_URL, - 'file_name' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'thumb_count' => FILTER_SANITIZE_NUMBER_INT, - 'status' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'error_msg' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, - 'error_code' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'job_id' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'job_type' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'job_for' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'format' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'download_url' => FILTER_SANITIZE_URL, + 'file_name' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'thumbnail_count' => FILTER_SANITIZE_NUMBER_INT, + 'status' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'error_msg' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, + 'error_code' => FILTER_SANITIZE_FULL_SPECIAL_CHARS, ); $post_array = filter_input_array( INPUT_POST, $filter_post_args ); @@ -1643,4 +1656,28 @@ private function filter_transcoder_response() { return $post_array; } + + /** + * Sanitize transcoder post response array for JSON. + * + * @param WP_REST_Request $request Request object. + * + * @return array $post_array Sanitized post array. + */ + public function filter_transcoder_response_json( $request ) { + return array( + 'job_id' => sanitize_text_field( wp_unslash( $request->get_param( 'job_id' ) ) ), + 'job_type' => sanitize_text_field( wp_unslash( $request->get_param( 'job_type' ) ) ), + 'job_for' => sanitize_text_field( wp_unslash( $request->get_param( 'job_for' ) ) ), + 'format' => sanitize_text_field( wp_unslash( $request->get_param( 'format' ) ) ), + 'download_url' => esc_url_raw( $request->get_param( 'download_url' ) ), + 'file_name' => sanitize_text_field( wp_unslash( $request->get_param( 'file_name' ) ) ), + 'thumb_count' => absint( $request->get_param( 'thumbnail_count' ) ), + 'status' => sanitize_text_field( wp_unslash( $request->get_param( 'status' ) ) ), + 'files' => array_map( 'esc_url_raw', (array) $request->get_param( 'files' ) ), + 'file_status' => sanitize_text_field( wp_unslash( $request->get_param( 'file_status' ) ) ), + 'thumbnail' => array_map( 'esc_url_raw', (array) $request->get_param( 'thumbnail' ) ), + 'error_msg' => sanitize_text_field( wp_unslash( $request->get_param( 'error_msg' ) ) ), + ); + } } diff --git a/admin/rt-transcoder-rest-routes.php b/admin/rt-transcoder-rest-routes.php index c3576d2..3264f08 100644 --- a/admin/rt-transcoder-rest-routes.php +++ b/admin/rt-transcoder-rest-routes.php @@ -24,6 +24,29 @@ class Transcoder_Rest_Routes extends WP_REST_Controller { */ public $namespace_prefix = 'transcoder/v'; + /** + * RT Transcoder Handler object. + * + * @var RT_Transcoder_Handler + */ + public $rt_transcoder_handler; + + /** + * Constructor + * + * @since 1.0.0 + * + * @access public + * @return void + */ + public function __construct() { + $this->rt_transcoder_handler = new RT_Transcoder_Handler( true ); + + if ( ! defined( 'RT_TRANSCODER_CALLBACK_URL' ) ) { + define( 'RT_TRANSCODER_CALLBACK_URL', $this->get_callback_url() ); + } + } + /** * Function to register routes. */ @@ -50,6 +73,93 @@ public function register_routes() { 'permission_callback' => '__return_true', ) ); + + // Register `transcoder-callback` route to handle callback request by the FFMPEG transcoding server. + register_rest_route( + $this->namespace_prefix . $this->version, + '/transcoder-callback', + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'handle_callback' ), + 'permission_callback' => '__return_true', + 'args' => array( + 'job_id' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'job_type' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'job_for' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'format' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'download_url' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'esc_url_raw', + ), + 'file_name' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'thumb_count' => array( + 'required' => true, + 'type' => 'integer', + 'sanitize_callback' => 'absint', + ), + 'status' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'files' => array( + 'required' => true, + 'type' => 'array', + 'sanitize_callback' => 'esc_url_raw', + ), + 'file_status' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'thumbnail' => array( + 'required' => true, + 'type' => 'array', + 'sanitize_callback' => 'esc_url_raw', + ), + 'error_msg' => array( + 'required' => true, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + 'job_manager_form' => array( + 'required' => false, + 'type' => 'string', + 'sanitize_callback' => 'sanitize_text_field', + ), + ), + ) + ); + } + + /** + * Return the callback URL for the transcoder. + * + * @return string + */ + public function get_callback_url() { + return rest_url( $this->namespace_prefix . $this->version . '/transcoder-callback' ); } /** @@ -152,4 +262,159 @@ private function get_media_data_by_id( $media_id ) { ); } + /** + * Function to handle the callback request by the FFMPEG transcoding server. + * + * @param WP_REST_Request $request Object of WP_REST_Request. + * + * @return WP_Error|WP_REST_Response REST API response. + */ + public function handle_callback( WP_REST_Request $request ) { + + $job_id = sanitize_text_field( wp_unslash( $request->get_param( 'job_id' ) ) ); + $file_status = sanitize_text_field( wp_unslash( $request->get_param( 'file_status' ) ) ); + $error_msg = sanitize_text_field( wp_unslash( $request->get_param( 'error_msg' ) ) ); + $job_for = sanitize_text_field( wp_unslash( $request->get_param( 'job_for' ) ) ); + $thumbnail = sanitize_text_field( wp_unslash( $request->get_param( 'thumbnail' ) ) ); + $format = sanitize_text_field( wp_unslash( $request->get_param( 'format' ) ) ); + + if ( ! empty( $job_id ) && ! empty( $file_status ) && ( 'error' === $file_status ) ) { + $this->rt_transcoder_handler->nofity_transcoding_failed( $job_id, $error_msg ); + return new WP_Error( 'transcoder_error', 'Something went wrong. Invalid post request.', array( 'status' => 400 ) ); + } + + $mail = defined( 'RT_TRANSCODER_NO_MAIL' ) ? false : true; + + $attachment_id = ''; + + if ( isset( $job_for ) && ( 'wp-media' === $job_for ) ) { + if ( isset( $job_id ) ) { + $has_thumbs = isset( $thumbnail ) ? true : false; + $flag = false; + + $id = $this->rt_transcoder_handler->get_post_id_by_meta_key_and_value( '_rt_transcoding_job_id', $job_id ); + + if ( ! empty( $id ) && is_numeric( $id ) ) { + $attachment_id = $id; + $post_array = $this->rt_transcoder_handler->filter_transcoder_response_json( $request ); + $post_array['post_id'] = $attachment_id; + + if ( $has_thumbs && ! empty( $post_array['thumbnail'] ) ) { + $thumbnail = $this->rt_transcoder_handler->add_media_thumbnails( $post_array ); + } + + if ( isset( $format ) && 'thumbnail' === $format ) { + return new WP_REST_Response( esc_html_e( 'Thumbnail created successfully.', 'transcoder' ), 200 ); + } + + if ( ! empty( $post_array['files'] ) ) { + $this->rt_transcoder_handler->add_transcoded_files( $post_array['files'], $attachment_id, $job_for ); + } + } else { + $flag = 'Something went wrong. The required attachment id does not exists. It must have been deleted.'; + } + + $this->rt_transcoder_handler->update_usage( $this->rt_transcoder_handler->api_key ); + + if ( $flag && $mail ) { + $subject = 'Transcoding: Download Failed'; + $message = '

' . esc_html__( 'Media', 'transcoder' ) . ' ' . esc_html__( ' was successfully encoded but there was an error while downloading:', 'transcoder' ) . '

' . esc_html( $flag ) . '

'; + $users = get_users( array( 'role' => 'administrator' ) ); + if ( $users ) { + $admin_email_ids = array(); + foreach ( $users as $user ) { + $admin_email_ids[] = $user->user_email; + } + add_filter( 'wp_mail_content_type', array( $this->rt_transcoder_handler, 'wp_mail_content_type' ) ); + wp_mail( $admin_email_ids, $subject, $message ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.wp_mail_wp_mail + remove_filter( 'wp_mail_content_type', array( $this->rt_transcoder_handler, 'wp_mail_content_type' ) ); + } + return new WP_Error( 'transcoder_error', $flag, array( 'status' => 500 ) ); + } else { + return new WP_REST_Response( esc_html_e( 'Media transcoded successfully.', 'transcoder' ), 200 ); + } + } + } else { + + // To check if request is sumitted from the WP Job Manager plugin ( https://wordpress.org/plugins/wp-job-manager/ ). + $job_manager_form = sanitize_text_field( wp_unslash( $request->get_param( 'job_manager_form' ) ) ); + + if ( isset( $job_id ) && ! empty( $job_id ) && class_exists( 'RTDBModel' ) && empty( $job_manager_form ) ) { + + $has_thumbs = isset( $thumbnail ) ? true : false; + $flag = false; + $model = new RTDBModel( 'rtm_media_meta', false, 10, true ); + + $meta_details = $model->get( + array( + 'meta_value' => $job_id, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value + 'meta_key' => 'rtmedia-transcoding-job-id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + ) + ); + + if ( ! isset( $meta_details[0] ) ) { + $id = $this->rt_transcoder_handler->get_post_id_by_meta_key_and_value( '_rt_transcoding_job_id', $job_id ); + } else { + $id = $meta_details[0]->media_id; + } + + if ( isset( $id ) && is_numeric( $id ) ) { + $model = new RTMediaModel(); + $media = $model->get_media( array( 'media_id' => $id ), 0, 1 ); + $this->media_author = $media[0]->media_author; + $attachment_id = $media[0]->media_id; + + $post_array = $this->rt_transcoder + ->filter_transcoder_response_json( $request ); + $post_array['post_id'] = $attachment_id; + + if ( $has_thumbs ) { + $this->rt_transcoder_handler->add_media_thumbnails( $post_array ); + } + + if ( isset( $format ) && 'thumbnail' === $format ) { + return new WP_REST_Response( esc_html_e( 'Thumbnail created successfully.', 'transcoder' ), 200 ); + } + + if ( ! empty( $post_array['files'] ) ) { + $this->rt_transcoder_handler->add_transcoded_files( $post_array['files'], $attachment_id, $job_for ); + } + } else { + $flag = 'Something went wrong. The required attachment id does not exists. It must have been deleted.'; + } + + $this->rt_transcoder_handler->update_usage( $this->rt_transcoder_handler->api_key ); + + if ( $flag && $mail ) { + $subject = 'Transcoding: Download Failed'; + $message = '

' . esc_html__( 'Media', 'transcoder' ) . ' ' . esc_html__( ' was successfully transcoded but there was an error while downloading:', 'transcoder' ) . '

' . esc_html( $flag ) . '

'; + $users = get_users( array( 'role' => 'administrator' ) ); + if ( $users ) { + $admin_email_ids = array(); + foreach ( $users as $user ) { + $admin_email_ids[] = $user->user_email; + } + add_filter( 'wp_mail_content_type', array( $this->rt_transcoder_handler, 'wp_mail_content_type' ) ); + wp_mail( $admin_email_ids, $subject, $message ); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.wp_mail_wp_mail + remove_filter( 'wp_mail_content_type', array( $this->rt_transcoder_handler, 'wp_mail_content_type' ) ); + } + return new WP_Error( 'transcoder_error', $flag, array( 'status' => 500 ) ); + + } else { + return new WP_REST_Response( esc_html_e( 'Media transcoded successfully.', 'transcoder' ), 200 ); + } + } + } + + /** + * Allow users/plugins to perform action after response received from the transcoder is + * processed + * + * @since 1.0.9 + * + * @param number $attachment_id Attachment ID for which the callback has sent from the transcoder + * @param number $job_id The transcoding job ID + */ + do_action( 'rtt_handle_callback_finished', $attachment_id, $job_id ); + } }