'GET', 'callback' => __NAMESPACE__ . '\\rest_list', 'permission_callback' => function () { return current_user_can( 'upload_files' ); }, ) ); $can_edit = function ( \WP_REST_Request $req ) { $id = (int) $req['id']; return current_user_can( 'upload_files' ) && current_user_can( 'edit_post', $id ); }; register_rest_route( 'captionwright/v1', '/media/(?P\d+)/tracks', array( 'methods' => 'POST', 'callback' => __NAMESPACE__ . '\\rest_save', 'permission_callback' => $can_edit, 'args' => array( 'lang' => array( 'type' => 'string', 'required' => true, ), 'label' => array( 'type' => 'string' ), 'vtt' => array( 'type' => 'string', 'required' => true, ), ), ) ); register_rest_route( 'captionwright/v1', '/media/(?P\d+)/tracks/(?P[a-z0-9-]+)', array( array( 'methods' => 'GET', 'callback' => __NAMESPACE__ . '\\rest_read', 'permission_callback' => $can_edit, ), array( 'methods' => 'DELETE', 'callback' => __NAMESPACE__ . '\\rest_delete', 'permission_callback' => $can_edit, ), ) ); } /** * Check the attachment is audio or video. * * @param int $id Attachment ID. * @return bool */ function is_media( $id ) { $mime = (string) get_post_mime_type( (int) $id ); $ok = 'attachment' === get_post_type( (int) $id ) && ( 0 === strpos( $mime, 'video/' ) || 0 === strpos( $mime, 'audio/' ) ); /** * Filters whether a post can hold caption tracks. * * @param bool $ok Whether it is an audio/video attachment. * @param int $id Post ID. */ return (bool) apply_filters( 'captionwright_is_captionable', $ok, (int) $id ); } /** * List audio/video attachments (optionally only captioned ones). * * @param \WP_REST_Request $req Request. * @return \WP_REST_Response */ function rest_list( \WP_REST_Request $req ) { $args = array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => array( 'video', 'audio' ), 'posts_per_page' => 100, 'paged' => max( 1, (int) $req->get_param( 'page' ) ), 'orderby' => 'date', 'order' => 'DESC', ); if ( $req->get_param( 'captioned' ) ) { $args['meta_key'] = META; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- small, admin-only list. } $out = array(); foreach ( get_posts( $args ) as $p ) { $out[] = array( 'id' => $p->ID, 'title' => get_the_title( $p ), 'mime' => $p->post_mime_type, 'url' => wp_get_attachment_url( $p->ID ), 'tracks' => get_tracks( $p->ID ), ); } /** * Filters the media list (add-ons can add other captioned sources). * * @param array $out List. * @param \WP_REST_Request $req Request. */ return rest_ensure_response( apply_filters( 'captionwright_media_list', $out, $req ) ); } /** * Save a caption track. * * @param \WP_REST_Request $req Request. * @return \WP_REST_Response|\WP_Error */ function rest_save( \WP_REST_Request $req ) { $id = (int) $req['id']; $lang = strtolower( (string) $req['lang'] ); if ( ! is_media( $id ) ) { return new \WP_Error( 'captionwright_not_media', __( 'That file is not audio or video.', 'captionwright' ), array( 'status' => 404 ) ); } if ( ! valid_lang( $lang ) ) { return new \WP_Error( 'captionwright_lang', __( 'Invalid language code.', 'captionwright' ), array( 'status' => 400 ) ); } $vtt = clean_vtt( (string) $req['vtt'] ); if ( is_wp_error( $vtt ) ) { return $vtt; } $label = sanitize_text_field( (string) $req['label'] ); $saved = save_track( $id, $lang, $vtt, '' !== $label ? $label : $lang ); if ( is_wp_error( $saved ) ) { return $saved; } return rest_ensure_response( array( 'tracks' => get_tracks( $id ) ) ); } /** * Return a track's WebVTT text for editing. * * @param \WP_REST_Request $req Request. * @return \WP_REST_Response|\WP_Error */ function rest_read( \WP_REST_Request $req ) { $vtt = read_track( (int) $req['id'], (string) $req['lang'] ); if ( '' === $vtt ) { return new \WP_Error( 'captionwright_missing', __( 'No captions saved in that language.', 'captionwright' ), array( 'status' => 404 ) ); } return rest_ensure_response( array( 'vtt' => $vtt ) ); } /** * Delete a caption track. * * @param \WP_REST_Request $req Request. * @return \WP_REST_Response */ function rest_delete( \WP_REST_Request $req ) { delete_track( (int) $req['id'], (string) $req['lang'] ); return rest_ensure_response( array( 'tracks' => get_tracks( (int) $req['id'] ) ) ); }