diff --git a/projects/packages/stats-admin/changelog/add-stats-admin-media-item-route b/projects/packages/stats-admin/changelog/add-stats-admin-media-item-route new file mode 100644 index 000000000000..cc78746366c1 --- /dev/null +++ b/projects/packages/stats-admin/changelog/add-stats-admin-media-item-route @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Stats: expose a single media item route on the stats-app proxy, so the Odyssey video details page can show the video's title, date, thumbnail, and duration. diff --git a/projects/packages/stats-admin/src/class-rest-controller.php b/projects/packages/stats-admin/src/class-rest-controller.php index baabac483201..d70fd529b32d 100644 --- a/projects/packages/stats-admin/src/class-rest-controller.php +++ b/projects/packages/stats-admin/src/class-rest-controller.php @@ -111,6 +111,17 @@ public function register_rest_routes() { ) ); + // Single media item info (e.g. the video shown on the video details page). + register_rest_route( + static::$namespace, + sprintf( '/sites/%d/media/(?P[\d]+)', Jetpack_Options::get_option( 'id' ) ), + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_single_media_item' ), + 'permission_callback' => array( $this, 'can_user_view_general_stats_callback' ), + ) + ); + // General stats for the site. register_rest_route( static::$namespace, @@ -658,6 +669,57 @@ public function get_single_post( $req ) { ); } + /** + * Get brief information for a single media item. + * + * @param WP_REST_Request $req The request object. + * @return array|WP_Error + */ + public function get_single_media_item( $req ) { + $media_id = intval( $req->get_param( 'resource_id' ) ); + $post = get_post( $media_id, OBJECT, 'display' ); + if ( empty( $post ) || 'attachment' !== $post->post_type ) { + return new WP_Error( + 'unknown_media', + 'Unknown media', + array( 'status' => 404 ) + ); + } + + // The response should be as compatible as possible with `/sites/$site_id/media/$media_id`. + // Like `get_single_post`, the request is not forwarded to WordPress.com because that + // might require user tokens, which is not possible for users without a WordPress.com account. + $metadata = wp_get_attachment_metadata( $media_id ); + $length = null; + $thumbnails = array(); + + if ( ! empty( $metadata['length'] ) ) { + $length = intval( $metadata['length'] ); + } elseif ( ! empty( $metadata['videopress']['duration'] ) ) { + // VideoPress stores the duration in milliseconds. + $length = intval( round( $metadata['videopress']['duration'] / 1000 ) ); + } + + if ( ! empty( $metadata['videopress']['poster'] ) ) { + // VideoPress format thumbnails (fmt_*) are only generated on WordPress.com; + // map the poster to the largest format so consumers find a thumbnail where expected. + $thumbnails['fmt_hd'] = $metadata['videopress']['poster']; + } elseif ( get_the_post_thumbnail_url( $post->ID ) ) { + $thumbnails['fmt_std'] = get_the_post_thumbnail_url( $post->ID ); + } + + return array( + 'ID' => $post->ID, + 'site_ID' => Jetpack_Options::get_option( 'id' ), + 'title' => $post->post_title, + 'date' => $post->post_date, + 'URL' => wp_get_attachment_url( $post->ID ), + 'mime_type' => $post->post_mime_type, + 'length' => $length, + 'thumbnails' => (object) $thumbnails, + ); + } + /** * Get site stats. * diff --git a/projects/packages/stats-admin/tests/php/REST_Controller_Test.php b/projects/packages/stats-admin/tests/php/REST_Controller_Test.php index b2a7efbaf796..99991b1b8878 100644 --- a/projects/packages/stats-admin/tests/php/REST_Controller_Test.php +++ b/projects/packages/stats-admin/tests/php/REST_Controller_Test.php @@ -163,6 +163,41 @@ public function assert_route_not_supported( $route ) { $this->assertNotEquals( 200, $response->get_status() ); } + /** + * Test '/jetpack/v4/stats-app/sites/999/media/{media_id}' + */ + public function test_get_single_media_item() { + wp_set_current_user( $this->admin_id ); + + $attachment_id = wp_insert_attachment( + array( + 'post_title' => 'Test video', + 'post_mime_type' => 'video/mp4', + 'post_status' => 'inherit', + ) + ); + wp_update_attachment_metadata( $attachment_id, array( 'length' => 95 ) ); + + $request = new WP_REST_Request( + 'GET', + sprintf( '/jetpack/v4/stats-app/sites/999/media/%d', $attachment_id ) + ); + $request->set_header( 'content-type', 'application/json' ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 200, $response->get_status() ); + $data = $response->get_data(); + $this->assertEquals( 'Test video', $data['title'] ); + $this->assertEquals( 95, $data['length'] ); + + // Unknown media items return 404. + $request = new WP_REST_Request( 'GET', '/jetpack/v4/stats-app/sites/999/media/987654' ); + $request->set_header( 'content-type', 'application/json' ); + $response = $this->server->dispatch( $request ); + + $this->assertEquals( 404, $response->get_status() ); + } + /** * Test '/jetpack/v4/stats-app/sites/999/site-has-never-published-post' */