PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.1
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.1
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
jetpack / jetpack_vendor / automattic / jetpack-videopress / src / class-data.php

class-data.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.1, at jetpack_vendor/automattic/jetpack-videopress/src/class-data.php

479 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The Data class.
4 * This class provides methods for data VideoPress access and manipulation.
5 *
6 * @package automattic/jetpack-videopress
7 */
8
9 namespace Automattic\Jetpack\VideoPress;
10
11 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
12 use Automattic\Jetpack\Status\Host;
13 use WP_REST_Request;
14 /**
15 * The Data class.
16 */
17 class Data {
18
19 /**
20 * Gets the Jetpack blog ID
21 *
22 * @return int The blog ID
23 */
24 public static function get_blog_id() {
25 return VideoPressToken::blog_id();
26 }
27
28 /**
29 * Gets the VideoPress site privacy configuration.
30 *
31 * @return boolean If all the videos are private on the site
32 */
33 public static function get_videopress_videos_private_for_site() {
34 /**
35 * If it's a Simple site, returns the site privacy setting.
36 */
37 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
38 return video_is_private_wpcom_blog( get_current_blog_id() );
39 }
40 /**
41 * If it's a private Atomic site, the default setting is private as well.
42 */
43 if ( ( new Host() )->is_woa_site() ) {
44 if ( ( intval( get_option( 'blog_public', '' ) ) === -1 ) ) {
45 return true;
46 }
47 }
48
49 /* If it's a Jetpack site or a public Atomic site, check the settings */
50 return boolval( get_option( 'videopress_private_enabled_for_site', false ) );
51 }
52
53 /**
54 * Gets whether auto-generated subtitles are disabled for the site.
55 *
56 * Subtitles are generated by default, so this opt-out option defaults to false.
57 *
58 * @return boolean If auto-generated subtitles should be skipped for new videos.
59 */
60 public static function get_videopress_auto_subtitles_disabled() {
61 return boolval( get_option( 'videopress_auto_subtitles_disabled', false ) );
62 }
63
64 /**
65 * Gets whether player preloading is turned off for every embed on the site.
66 *
67 * Preloading is on by default, so this opt-out option defaults to false.
68 *
69 * @return boolean If embeds should wait for playback before fetching video data and player assets.
70 */
71 public static function get_videopress_player_preload_disabled() {
72 return boolval( get_option( 'videopress_player_preload_disabled', false ) );
73 }
74
75 /**
76 * Gets whether embeds render an inline player instead of one iframe per video.
77 *
78 * Iframes are the default, so this opt-in option defaults to false.
79 *
80 * @return boolean If embeds should mount players in the page from one shared player script.
81 */
82 public static function get_videopress_inline_player_enabled() {
83 return boolval( get_option( 'videopress_inline_player_enabled', false ) );
84 }
85
86 /**
87 * Gets the VideoPress Settings.
88 *
89 * @return array The settings as an associative array.
90 */
91 public static function get_videopress_settings() {
92 $site_type = 'jetpack';
93 $site_is_private = false;
94
95 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
96 $site_type = 'simple';
97 $site_is_private = video_is_private_wpcom_blog( get_current_blog_id() );
98 } elseif ( ( new Host() )->is_woa_site() ) {
99 $site_type = 'atomic';
100 $site_is_private = intval( get_option( 'blog_public', '' ) ) === -1;
101 }
102
103 return array(
104 'videopress_videos_private_for_site' => self::get_videopress_videos_private_for_site(),
105 'videopress_auto_subtitles_disabled' => self::get_videopress_auto_subtitles_disabled(),
106 'videopress_player_preload_disabled' => self::get_videopress_player_preload_disabled(),
107 'site_is_private' => $site_is_private,
108 'site_type' => $site_type,
109 );
110 }
111
112 /**
113 * Gets the video data
114 *
115 * @param boolean $is_videopress - True when getting VideoPress data.
116 * @return array
117 */
118 public static function get_video_data( $is_videopress = true ) {
119 $video_data = array(
120 'videos' => array(),
121 'total' => 0,
122 'totalPages' => 0,
123 'query' => array(
124 'order' => 'desc',
125 'orderBy' => 'date',
126 'itemsPerPage' => 6,
127 'page' => 1,
128 ),
129 );
130
131 $args = array(
132 'order' => $video_data['query']['order'],
133 'orderby' => $video_data['query']['orderBy'],
134 'per_page' => $video_data['query']['itemsPerPage'],
135 'page' => $video_data['query']['page'],
136 );
137
138 if ( $is_videopress ) {
139 $args['mime_type'] = 'video/videopress';
140 } else {
141 $args['media_type'] = 'video';
142 $args['no_videopress'] = true;
143 }
144
145 // Do an internal request for the media list
146 $request = new WP_REST_Request( 'GET', '/wp/v2/media' );
147 $request->set_query_params( $args );
148 $response = rest_do_request( $request );
149
150 if ( $response->is_error() ) {
151 // @todo: error handling
152 return $video_data;
153 }
154
155 // load the real values
156 $video_data['videos'] = $response->get_data();
157 $headers = $response->get_headers();
158
159 if ( isset( $headers['X-WP-Total'] ) ) {
160 $video_data['total'] = $headers['X-WP-Total'];
161 }
162
163 if ( isset( $headers['X-WP-TotalPages'] ) ) {
164 $video_data['totalPages'] = $headers['X-WP-TotalPages'];
165 }
166
167 return $video_data;
168 }
169
170 /**
171 * Gets the user data
172 *
173 * @return array
174 */
175 public static function get_user_data() {
176 $user_data = array(
177 'items' => array(),
178 'pagination' => array(
179 'total' => 0,
180 'totalPages' => 1,
181 ),
182 'query' => array(
183 'order' => 'asc',
184 'orderBy' => 'name',
185 ),
186 '_meta' => array(
187 'relyOnInitialState' => true,
188 ),
189 );
190
191 $args = array(
192 'order' => $user_data['query']['order'],
193 'orderby' => $user_data['query']['orderBy'],
194 );
195
196 // Do an internal request for the user list
197 $request = new WP_REST_Request( 'GET', '/wp/v2/users' );
198 $request->set_query_params( $args );
199 $response = rest_do_request( $request );
200
201 if ( $response->is_error() ) {
202 // @todo: error handling
203 return $user_data;
204 }
205
206 // load the real values
207 $user_data['items'] = $response->get_data();
208 $headers = $response->get_headers();
209
210 if ( isset( $headers['X-WP-Total'] ) ) {
211 $user_data['pagination']['total'] = $headers['X-WP-Total'];
212 }
213
214 if ( isset( $headers['X-WP-TotalPages'] ) ) {
215 $user_data['pagination']['totalPages'] = $headers['X-WP-TotalPages'];
216 }
217
218 return $user_data;
219 }
220
221 /**
222 * Gets the VideoPress used storage space in bytes
223 *
224 * @return int the used storage space
225 */
226 public static function get_storage_used() {
227 $site_data = Site::get_site_info();
228 if ( is_wp_error( $site_data ) ) {
229 return 0;
230 }
231
232 if ( isset( $site_data['options'] ) && isset( $site_data['options']['videopress_storage_used'] ) ) {
233 return intval( round( $site_data['options']['videopress_storage_used'] * 1024 * 1024 ) );
234 } else {
235 return 0;
236 }
237 }
238
239 /**
240 * Return all the initial state that depends on a valid site connection
241 *
242 * @return array
243 */
244 public static function get_connected_initial_state() {
245 return array(
246 'videos' => array(
247 'storageUsed' => self::get_storage_used(),
248 ),
249 'purchases' => array(
250 'items' => Site::get_purchases(),
251 'isFetching' => false,
252 ),
253 );
254 }
255
256 /**
257 * Checks if the site has as connected owner
258 */
259 public static function has_connected_owner() {
260 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
261 return true;
262 }
263
264 if ( ( new Connection_Manager() )->has_connected_owner() ) {
265 return true;
266 }
267
268 return false;
269 }
270
271 /**
272 * Checks if the user is able to perform actions that modify data
273 */
274 public static function can_perform_action() {
275 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
276 return true;
277 }
278
279 $connection = new Connection_Manager();
280
281 return (
282 $connection->is_connected() &&
283 self::has_connected_owner() &&
284 $connection->is_user_connected()
285 );
286 }
287
288 /**
289 * Return the initial state of the VideoPress app,
290 * used to render initially the app in the frontend.
291 *
292 * @return array
293 */
294 public static function get_initial_state() {
295 $videopress_data = self::get_video_data();
296 $local_videos_data = self::get_video_data( false );
297
298 // Tweak local videos data.
299 $local_videos = array_map(
300 function ( $video ) {
301 $video = (array) $video;
302 $id = $video['id'];
303 $media_details = $video['media_details'];
304 $jetpack_videopress = $video['jetpack_videopress'];
305 $read_error = null;
306
307 // In malformed files, the media_details or jetpack_videopress properties are not arrays.
308 if ( ! is_array( $media_details ) || ! is_array( $jetpack_videopress ) ) {
309 $media_details = (array) $media_details;
310 $jetpack_videopress = (array) $jetpack_videopress;
311 $read_error = Upload_Exception::ERROR_MALFORMED_FILE;
312 }
313
314 // Check if video is already uploaded to VideoPress or has some error.
315 try {
316 $uploader = new Uploader( $id );
317 $is_uploaded_to_videopress = $uploader->is_uploaded();
318 } catch ( Upload_Exception $e ) {
319 $is_uploaded_to_videopress = false;
320 $read_error = $e->getCode();
321 }
322
323 $upload_date = $video['date'];
324 $url = $video['source_url'];
325
326 $title = $jetpack_videopress['title'];
327 $description = $jetpack_videopress['description'];
328 $caption = $jetpack_videopress['caption'];
329
330 $width = $media_details['width'] ?? null;
331 $height = $media_details['height'] ?? null;
332 $duration = $media_details['length'] ?? null;
333
334 return array(
335 'id' => $id,
336 'title' => $title,
337 'description' => $description,
338 'caption' => $caption,
339 'width' => $width,
340 'height' => $height,
341 'url' => $url,
342 'uploadDate' => $upload_date,
343 'duration' => $duration,
344 'isUploadedToVideoPress' => $is_uploaded_to_videopress,
345 'readError' => $read_error,
346 );
347 },
348 $local_videos_data['videos']
349 );
350
351 // Tweak VideoPress videos data.
352 $videos = array_map(
353 array( __CLASS__, 'prepare_videopress_video_data' ),
354 $videopress_data['videos']
355 );
356
357 $site_settings = self::get_videopress_settings();
358
359 $initial_state = array(
360 'users' => self::get_user_data(),
361 'siteSettings' => array(
362 'videoPressVideosPrivateForSite' => $site_settings['videopress_videos_private_for_site'],
363 'siteIsPrivate' => $site_settings['site_is_private'],
364 'siteType' => $site_settings['site_type'],
365 ),
366 'videos' => array(
367 'uploadedVideoCount' => $videopress_data['total'],
368 'items' => $videos,
369 'isFetching' => false,
370 'isFetchingUploadedVideoCount' => false,
371 'pagination' => array(
372 'totalPages' => $videopress_data['totalPages'],
373 'total' => $videopress_data['total'],
374 ),
375 'query' => $videopress_data['query'],
376 '_meta' => array(
377 'processedAllVideosBeingRemoved' => true,
378 'relyOnInitialState' => true,
379 ),
380 ),
381 'localVideos' => array(
382 'uploadedVideoCount' => $local_videos_data['total'],
383 'items' => $local_videos,
384 'isFetching' => false,
385 'isFetchingUploadedVideoCount' => false,
386 'pagination' => array(
387 'totalPages' => $local_videos_data['totalPages'],
388 'total' => $local_videos_data['total'],
389 ),
390 'query' => $local_videos_data['query'],
391 '_meta' => array(
392 'relyOnInitialState' => true,
393 ),
394 ),
395 );
396
397 if ( self::has_connected_owner() ) {
398 return array_merge_recursive( $initial_state, self::get_connected_initial_state() );
399 }
400
401 return $initial_state;
402 }
403
404 /**
405 * Maps a single VideoPress video, as returned by the media REST endpoint, to
406 * the shape consumed by the VideoPress dashboard app.
407 *
408 * Videos that are still processing (or otherwise have partial metadata) come
409 * back without `videopress`, `width` or `height` in their media_details, so
410 * every nested access is coalesced to avoid undefined-key and offset-on-null
411 * warnings.
412 *
413 * @param array|object $video A single video entry from the media REST endpoint.
414 * @return array The video data formatted for the dashboard app.
415 */
416 private static function prepare_videopress_video_data( $video ) {
417 $video = (array) $video;
418 $id = $video['id'];
419 $guid = $video['jetpack_videopress_guid'];
420 $media_details = (array) $video['media_details'];
421 $jetpack_videopress = (array) $video['jetpack_videopress'];
422
423 $videopress_media_details = $media_details['videopress'] ?? array();
424 $width = $media_details['width'] ?? null;
425 $height = $media_details['height'] ?? null;
426
427 $title = $jetpack_videopress['title'];
428 $description = $jetpack_videopress['description'];
429 $caption = $jetpack_videopress['caption'];
430 $rating = $jetpack_videopress['rating'];
431 $allow_download = $jetpack_videopress['allow_download'];
432 $display_embed = $jetpack_videopress['display_embed'];
433 $privacy_setting = $jetpack_videopress['privacy_setting'];
434 $needs_playback_token = $jetpack_videopress['needs_playback_token'];
435 $is_private = $jetpack_videopress['is_private'];
436
437 $original = $videopress_media_details['original'] ?? null;
438 $poster = ( ! $needs_playback_token ) ? ( $videopress_media_details['poster'] ?? null ) : null;
439 $upload_date = $videopress_media_details['upload_date'] ?? null;
440 $duration = $videopress_media_details['duration'] ?? null;
441 $file_url_base = $videopress_media_details['file_url_base'] ?? null;
442 $finished = $videopress_media_details['finished'] ?? null;
443 $files = $videopress_media_details['files'] ?? null;
444 $filename = $original !== null ? basename( $original ) : null;
445
446 if ( isset( $files['dvd']['original_img'] ) && isset( $file_url_base['https'] ) && $privacy_setting !== 1 ) {
447 $thumbnail = $file_url_base['https'] . $files['dvd']['original_img'];
448 } else {
449 $thumbnail = null;
450 }
451
452 return array(
453 'id' => $id,
454 'guid' => $guid,
455 'title' => $title,
456 'description' => $description,
457 'caption' => $caption,
458 'url' => $original,
459 'uploadDate' => $upload_date,
460 'duration' => $duration,
461 'isPrivate' => $is_private,
462 'posterImage' => $poster,
463 'allowDownload' => $allow_download,
464 'displayEmbed' => $display_embed,
465 'rating' => $rating,
466 'privacySetting' => $privacy_setting,
467 'needsPlaybackToken' => $needs_playback_token,
468 'width' => $width,
469 'height' => $height,
470 'poster' => array(
471 'src' => $poster,
472 ),
473 'thumbnail' => $thumbnail,
474 'finished' => $finished,
475 'filename' => $filename,
476 );
477 }
478 }
479