Completed
Push — add/caching-videopress ( 67df90...85b14a )
by
unknown
06:49
created

utility-functions.php ➔ video_get_post_by_guid()   B

Complexity

Conditions 9
Paths 22

Size

Total Lines 49

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
nc 22
nop 1
dl 0
loc 49
rs 7.5571
c 0
b 0
f 0
1
<?php
2
3
use Automattic\Jetpack\Connection\Client;
4
5
/**
6
 * We won't have any videos less than sixty pixels wide. That would be silly.
7
 */
8
defined( 'VIDEOPRESS_MIN_WIDTH' ) or define( 'VIDEOPRESS_MIN_WIDTH', 60 );
9
10
/**
11
 * Validate user-supplied guid values against expected inputs
12
 *
13
 * @since 1.1
14
 * @param string $guid video identifier
15
 * @return bool true if passes validation test
16
 */
17
function videopress_is_valid_guid( $guid ) {
18
	if ( ! empty( $guid ) && is_string( $guid ) && strlen( $guid ) === 8 && ctype_alnum( $guid ) ) {
19
		return true;
20
	}
21
	return false;
22
}
23
24
/**
25
 * Get details about a specific video by GUID:
26
 *
27
 * @param $guid string
28
 * @return object
29
 */
30
function videopress_get_video_details( $guid ) {
31
	if ( ! videopress_is_valid_guid( $guid ) ) {
32
		return new WP_Error( 'bad-guid-format', __( 'Invalid Video GUID!', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'bad-guid-format'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
33
	}
34
35
	$version   = '1.1';
36
	$endpoint  = sprintf( '/videos/%1$s', $guid );
37
	$query_url = sprintf(
38
		'https://public-api.wordpress.com/rest/v%1$s%2$s',
39
		$version,
40
		$endpoint
41
	);
42
43
	// Look for data in our transient. If nothing, let's make a new query.
44
	$data_from_cache = get_transient( 'jetpack_videopress_' . $guid );
45
	if ( false === $data_from_cache ) {
46
		$response = wp_remote_get( esc_url_raw( $query_url ) );
47
		$data     = json_decode( wp_remote_retrieve_body( $response ) );
48
49
		// Cache the response for an hour.
50
		set_transient( 'jetpack_videopress_' . $guid, $data, HOUR_IN_SECONDS );
51
	} else {
52
		$data = $data_from_cache;
53
	}
54
55
	/**
56
	 * Allow functions to modify fetched video details.
57
	 *
58
	 * This filter allows third-party code to modify the return data
59
	 * about a given video.  It may involve swapping some data out or
60
	 * adding new parameters.
61
	 *
62
	 * @since 4.0.0
63
	 *
64
	 * @param object $data The data returned by the WPCOM API. See: https://developer.wordpress.com/docs/api/1.1/get/videos/%24guid/
65
	 * @param string $guid The GUID of the VideoPress video in question.
66
	 */
67
	return apply_filters( 'videopress_get_video_details', $data, $guid );
68
}
69
70
71
/**
72
 * Get an attachment ID given a URL.
73
 *
74
 * Modified from https://wpscholar.com/blog/get-attachment-id-from-wp-image-url/
75
 *
76
 * @deprecated since 8.4.0
77
 *
78
 * @param string $url
79
 *
80
 * @return int|bool Attachment ID on success, false on failure
81
 */
82
function videopress_get_attachment_id_by_url( $url ) {
83
	_deprecated_function( __FUNCTION__, 'jetpack-8.4' );
84
85
	$wp_upload_dir = wp_upload_dir();
86
	// Strip out protocols, so it doesn't fail because searching for http: in https: dir.
87
	$dir = set_url_scheme( trailingslashit( $wp_upload_dir['baseurl'] ), 'relative' );
88
89
	// Is URL in uploads directory?
90
	if ( false !== strpos( $url, $dir ) ) {
91
92
		$file = basename( $url );
93
94
		$query_args = array(
95
			'post_type'   => 'attachment',
96
			'post_status' => 'inherit',
97
			'fields'      => 'ids',
98
			'meta_query'  => array(
99
				array(
100
					'key'     => '_wp_attachment_metadata',
101
					'compare' => 'LIKE',
102
					'value'   => $file,
103
				),
104
			),
105
		);
106
107
		$query = new WP_Query( $query_args );
108
109
		if ( $query->have_posts() ) {
110
			foreach ( $query->posts as $attachment_id ) {
111
				$meta          = wp_get_attachment_metadata( $attachment_id );
112
				$original_file = basename( $meta['file'] );
113
				$cropped_files = wp_list_pluck( $meta['sizes'], 'file' );
114
115
				if ( $original_file === $file || in_array( $file, $cropped_files ) ) {
116
					return (int) $attachment_id;
117
				}
118
			}
119
		}
120
	}
121
122
	return false;
123
}
124
125
/**
126
 * Similar to `media_sideload_image` -- but returns an ID.
127
 *
128
 * @param $url
129
 * @param $attachment_id
130
 *
131
 * @return int|mixed|object|WP_Error
132
 */
133
function videopress_download_poster_image( $url, $attachment_id ) {
134
	// Set variables for storage, fix file filename for query strings.
135
	preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $url, $matches );
136
	if ( ! $matches ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $matches of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
137
		return new WP_Error( 'image_sideload_failed', __( 'Invalid image URL', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'image_sideload_failed'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
138
	}
139
140
	$file_array             = array();
141
	$file_array['name']     = basename( $matches[0] );
142
	$file_array['tmp_name'] = download_url( $url );
143
144
	// If error storing temporarily, return the error.
145
	if ( is_wp_error( $file_array['tmp_name'] ) ) {
146
		return $file_array['tmp_name'];
147
	}
148
149
	// Do the validation and storage stuff.
150
	$thumbnail_id = media_handle_sideload( $file_array, $attachment_id, null );
151
152
	// Flag it as poster image, so we can exclude it from display.
153
	update_post_meta( $thumbnail_id, 'videopress_poster_image', 1 );
154
155
	return $thumbnail_id;
156
}
157
158
/**
159
 * Creates a local media library item of a remote VideoPress video.
160
 *
161
 * @param $guid
162
 * @param int  $parent_id
163
 *
164
 * @return int|object
165
 */
166
function create_local_media_library_for_videopress_guid( $guid, $parent_id = 0 ) {
167
	$vp_data = videopress_get_video_details( $guid );
168
	if ( ! $vp_data || is_wp_error( $vp_data ) ) {
169
		return $vp_data;
170
	}
171
172
	$args = array(
173
		'post_date'      => $vp_data->upload_date,
174
		'post_title'     => wp_kses( $vp_data->title, array() ),
175
		'post_content'   => wp_kses( $vp_data->description, array() ),
176
		'post_mime_type' => 'video/videopress',
177
		'guid'           => sprintf( 'https://videopress.com/v/%s', $guid ),
178
	);
179
180
	$attachment_id = wp_insert_attachment( $args, null, $parent_id );
181
182
	if ( ! is_wp_error( $attachment_id ) ) {
183
		update_post_meta( $attachment_id, 'videopress_guid', $guid );
184
		wp_update_attachment_metadata(
185
			$attachment_id,
186
			array(
187
				'width'  => $vp_data->width,
188
				'height' => $vp_data->height,
189
			)
190
		);
191
192
		$thumbnail_id = videopress_download_poster_image( $vp_data->poster, $attachment_id );
193
		update_post_meta( $attachment_id, '_thumbnail_id', $thumbnail_id );
194
	}
195
196
	return $attachment_id;
197
}
198
199
/**
200
 * Helper that will look for VideoPress media items that are more than 30 minutes old,
201
 * that have not had anything attached to them by a wpcom upload and deletes the ghost
202
 * attachment.
203
 *
204
 * These happen primarily because of failed upload attempts.
205
 *
206
 * @return int The number of items that were cleaned up.
207
 */
208
function videopress_cleanup_media_library() {
209
210
	// Disable this job for now.
211
	return 0;
212
	$query_args = array(
0 ignored issues
show
Unused Code introduced by
$query_args = array('pos...', 'value' => 'new'))); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
213
		'post_type'      => 'attachment',
214
		'post_status'    => 'inherit',
215
		'post_mime_type' => 'video/videopress',
216
		'meta_query'     => array(
217
			array(
218
				'key'   => 'videopress_status',
219
				'value' => 'new',
220
			),
221
		),
222
	);
223
224
	$query = new WP_Query( $query_args );
225
226
	$cleaned = 0;
227
228
	$now = current_time( 'timestamp' );
229
230
	if ( $query->have_posts() ) {
231
		foreach ( $query->posts as $post ) {
232
			$post_time = strtotime( $post->post_date_gmt );
233
234
			// If the post is older than 30 minutes, it is safe to delete it.
235
			if ( $now - $post_time > MINUTE_IN_SECONDS * 30 ) {
236
				// Force delete the attachment, because we don't want it appearing in the trash.
237
				wp_delete_attachment( $post->ID, true );
238
239
				$cleaned++;
240
			}
241
		}
242
	}
243
244
	return $cleaned;
245
}
246
247
/**
248
 * Return an absolute URI for a given filename and guid on the CDN.
249
 * No check is performed to ensure the guid exists or the file is present. Simple centralized string builder.
250
 *
251
 * @param string $guid     VideoPress identifier
252
 * @param string $filename name of file associated with the guid (video file name or thumbnail file name)
253
 *
254
 * @return string Absolute URL of VideoPress file for the given guid.
255
 */
256
function videopress_cdn_file_url( $guid, $filename ) {
257
	return "https://videos.files.wordpress.com/{$guid}/{$filename}";
258
}
259
260
/**
261
 * Get an array of the transcoding status for the given video post.
262
 *
263
 * @since 4.4
264
 * @param int $post_id
265
 * @return array|bool Returns an array of statuses if this is a VideoPress post, otherwise it returns false.
266
 */
267
function videopress_get_transcoding_status( $post_id ) {
268
	$meta = wp_get_attachment_metadata( $post_id );
269
270
	// If this has not been processed by videopress, we can skip the rest.
271
	if ( ! $meta || ! isset( $meta['file_statuses'] ) ) {
272
		return false;
273
	}
274
275
	$info = (object) $meta['file_statuses'];
276
277
	$status = array(
278
		'std_mp4' => isset( $info->mp4 ) ? $info->mp4 : null,
279
		'std_ogg' => isset( $info->ogg ) ? $info->ogg : null,
280
		'dvd_mp4' => isset( $info->dvd ) ? $info->dvd : null,
281
		'hd_mp4'  => isset( $info->hd ) ? $info->hd : null,
282
	);
283
284
	return $status;
285
}
286
287
/**
288
 * Get the direct url to the video.
289
 *
290
 * @since 4.4
291
 * @param string $guid
292
 * @return string
293
 */
294
function videopress_build_url( $guid ) {
295
296
	// No guid, no videopress url.
297
	if ( ! $guid ) {
298
		return '';
299
	}
300
301
	return 'https://videopress.com/v/' . $guid;
302
}
303
304
/**
305
 * Create an empty videopress media item that will be filled out later by an xmlrpc
306
 * callback from the VideoPress servers.
307
 *
308
 * @since 4.4
309
 * @param string $title
310
 * @return int|WP_Error
311
 */
312
function videopress_create_new_media_item( $title, $guid = null ) {
313
	$post = array(
314
		'post_type'      => 'attachment',
315
		'post_mime_type' => 'video/videopress',
316
		'post_title'     => $title,
317
		'post_content'   => '',
318
		'guid'           => videopress_build_url( $guid ),
319
	);
320
321
	$media_id = wp_insert_post( $post );
322
323
	add_post_meta( $media_id, 'videopress_status', 'initiated' );
324
325
	add_post_meta( $media_id, 'videopress_guid', $guid );
326
327
	return $media_id;
328
}
329
330
331
/**
332
 * @param array $current_status
333
 * @param array $new_meta
334
 * @return array
335
 */
336
function videopress_merge_file_status( $current_status, $new_meta ) {
337
	$new_statuses = array();
338
339 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['hd'] ) ) {
340
		$new_statuses['hd'] = $new_meta['videopress']['files_status']['hd'];
341
	}
342
343 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['dvd'] ) ) {
344
		$new_statuses['dvd'] = $new_meta['videopress']['files_status']['dvd'];
345
	}
346
347 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['std']['mp4'] ) ) {
348
		$new_statuses['mp4'] = $new_meta['videopress']['files_status']['std']['mp4'];
349
	}
350
351 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['std']['ogg'] ) ) {
352
		$new_statuses['ogg'] = $new_meta['videopress']['files_status']['std']['ogg'];
353
	}
354
355
	foreach ( $new_statuses as $format => $status ) {
356
		if ( ! isset( $current_status[ $format ] ) ) {
357
			$current_status[ $format ] = $status;
358
			continue;
359
		}
360
361
		if ( $current_status[ $format ] !== 'DONE' ) {
362
			$current_status[ $format ] = $status;
363
		}
364
	}
365
366
	return $current_status;
367
}
368
369
/**
370
 * Check to see if a video has completed processing.
371
 *
372
 * @since 4.4
373
 * @param int $post_id
374
 * @return bool
375
 */
376
function videopress_is_finished_processing( $post_id ) {
377
	$post = get_post( $post_id );
378
379
	if ( is_wp_error( $post ) ) {
380
		return false;
381
	}
382
383
	$meta = wp_get_attachment_metadata( $post->ID );
384
385
	if ( ! isset( $meta['file_statuses'] ) || ! is_array( $meta['file_statuses'] ) ) {
386
		return false;
387
	}
388
389
	$check_statuses = array( 'hd', 'dvd', 'mp4', 'ogg' );
390
391
	foreach ( $check_statuses as $status ) {
392
		if ( ! isset( $meta['file_statuses'][ $status ] ) || $meta['file_statuses'][ $status ] != 'DONE' ) {
393
			return false;
394
		}
395
	}
396
397
	return true;
398
}
399
400
401
/**
402
 * Update the meta information  status for the given video post.
403
 *
404
 * @since 4.4
405
 * @param int $post_id
406
 * @return bool
407
 */
408
function videopress_update_meta_data( $post_id ) {
409
410
	$meta = wp_get_attachment_metadata( $post_id );
411
412
	// If this has not been processed by VideoPress, we can skip the rest.
413
	if ( ! $meta || ! isset( $meta['videopress'] ) ) {
414
		return false;
415
	}
416
417
	$info = (object) $meta['videopress'];
418
419
	$args = array(
420
		// 'sslverify' => false,
421
	);
422
423
	$result = wp_remote_get( videopress_make_video_get_path( $info->guid ), $args );
424
425
	if ( is_wp_error( $result ) ) {
426
		return false;
427
	}
428
429
	$response = json_decode( $result['body'], true );
430
431
	// Update the attachment metadata.
432
	$meta['videopress'] = $response;
433
434
	wp_update_attachment_metadata( $post_id, $meta );
435
436
	return true;
437
}
438
439
/**
440
 * Check to see if this is a VideoPress post that hasn't had a guid set yet.
441
 *
442
 * @param int $post_id
443
 * @return bool
444
 */
445
function videopress_is_attachment_without_guid( $post_id ) {
446
	$post = get_post( $post_id );
447
448
	if ( is_wp_error( $post ) ) {
449
		return false;
450
	}
451
452
	if ( $post->post_mime_type !== 'video/videopress' ) {
453
		return false;
454
	}
455
456
	$videopress_guid = get_post_meta( $post_id, 'videopress_guid', true );
457
458
	if ( $videopress_guid ) {
459
		return false;
460
	}
461
462
	return true;
463
}
464
465
/**
466
 * Check to see if this is a VideoPress attachment.
467
 *
468
 * @param int $post_id
469
 * @return bool
470
 */
471
function is_videopress_attachment( $post_id ) {
472
	$post = get_post( $post_id );
473
474
	if ( is_wp_error( $post ) ) {
475
		return false;
476
	}
477
478
	if ( $post->post_mime_type !== 'video/videopress' ) {
479
		return false;
480
	}
481
482
	return true;
483
}
484
485
/**
486
 * Get the video update path
487
 *
488
 * @since 4.4
489
 * @param string $guid
490
 * @return string
491
 */
492
function videopress_make_video_get_path( $guid ) {
493
	return sprintf(
494
		'%s://%s/rest/v%s/videos/%s',
495
		'https',
496
		JETPACK__WPCOM_JSON_API_HOST,
497
		Client::WPCOM_JSON_API_VERSION,
498
		$guid
499
	);
500
}
501
502
/**
503
 * Get the upload api path.
504
 *
505
 * @since 4.4
506
 * @param int $blog_id The id of the blog we're uploading to.
507
 * @return string
508
 */
509
function videopress_make_media_upload_path( $blog_id ) {
510
	return sprintf(
511
		'https://public-api.wordpress.com/rest/v1.1/sites/%s/media/new',
512
		$blog_id
513
	);
514
}
515
516
/**
517
 * This is a mock of the internal VideoPress method, which is meant to duplicate the functionality
518
 * of the WPCOM API, so that the Jetpack REST API returns the same data with no modifications.
519
 *
520
 * @param int $blog_id Blog ID.
521
 * @param int $post_id Post ID.
522
 * @return bool|stdClass
523
 */
524
function video_get_info_by_blogpostid( $blog_id, $post_id ) {
525
	$post = get_post( $post_id );
526
527
	$video_info                  = new stdClass();
528
	$video_info->post_id         = $post_id;
529
	$video_info->blog_id         = $blog_id;
530
	$video_info->guid            = null;
531
	$video_info->finish_date_gmt = '0000-00-00 00:00:00';
532
533
	if ( is_wp_error( $post ) ) {
534
		return $video_info;
535
	}
536
537
	if ( 'video/videopress' !== $post->post_mime_type ) {
538
		return $video_info;
539
	}
540
541
	// Since this is a VideoPress post, lt's fill out the rest of the object.
542
	$video_info->guid = get_post_meta( $post_id, 'videopress_guid', true );
543
544
	if ( videopress_is_finished_processing( $post_id ) ) {
545
		$video_info->finish_date_gmt = date( 'Y-m-d H:i:s' );
546
	}
547
548
	return $video_info;
549
}
550
551
552
/**
553
 * Check that a VideoPress video format has finished processing.
554
 *
555
 * This uses the info object, because that is what the WPCOM endpoint
556
 * uses, however we don't have a complete info object in the same way
557
 * WPCOM does, so we pull the meta information out of the post
558
 * options instead.
559
 *
560
 * Note: This mimics the WPCOM function of the same name and helps the media
561
 * API endpoint add all needed VideoPress data.
562
 *
563
 * @param stdClass $info
564
 * @param string   $format
565
 * @return bool
566
 */
567
function video_format_done( $info, $format ) {
568
569
	// Avoids notice when a non-videopress item is found.
570
	if ( ! is_object( $info ) ) {
571
		return false;
572
	}
573
574
	$post_id = $info->post_id;
575
576
	if ( get_post_mime_type( $post_id ) !== 'video/videopress' ) {
577
		return false;
578
	}
579
580
	$post = get_post( $post_id );
581
582
	if ( is_wp_error( $post ) ) {
583
		return false;
584
	}
585
586
	$meta = wp_get_attachment_metadata( $post->ID );
587
588
	switch ( $format ) {
589
		case 'fmt_hd':
590
			return isset( $meta['videopress']['files']['hd']['mp4'] );
591
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
592
593
		case 'fmt_dvd':
594
			return isset( $meta['videopress']['files']['dvd']['mp4'] );
595
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
596
597
		case 'fmt_std':
598
			return isset( $meta['videopress']['files']['std']['mp4'] );
599
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
600
601
		case 'fmt_ogg':
602
			return isset( $meta['videopress']['files']['std']['ogg'] );
603
			break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
604
	}
605
606
	return false;
607
}
608
609
/**
610
 * Get the image URL for the given VideoPress GUID
611
 *
612
 * We look up by GUID, because that is what WPCOM does and this needs to be
613
 * parameter compatible with that.
614
 *
615
 * Note: This mimics the WPCOM function of the same name and helps the media
616
 * API endpoint add all needed VideoPress data.
617
 *
618
 * @param string $guid
619
 * @param string $format
620
 * @return string
621
 */
622
function video_image_url_by_guid( $guid, $format ) {
623
624
	$post = video_get_post_by_guid( $guid );
625
626
	if ( is_wp_error( $post ) ) {
627
		return null;
628
	}
629
630
	$meta = wp_get_attachment_metadata( $post->ID );
631
632
	// We add ssl => 1 to make sure that the videos.files.wordpress.com domain is parsed as photon.
633
	$poster = apply_filters( 'jetpack_photon_url', $meta['videopress']['poster'], array( 'ssl' => 1 ), 'https' );
634
635
	return $poster;
636
}
637
638
/**
639
 * Using a GUID, find a post.
640
 *
641
 * @param string $guid
642
 * @return WP_Post|false The post for that guid, or false if none is found.
643
 */
644
function video_get_post_by_guid( $guid ) {
645
	$cache_key          = 'video_get_post_by_guid_' . $guid;
646
	$cache_group        = 'videopress';
647
	$is_using_obj_cache = wp_using_ext_object_cache();
648
	$cached_post        = $is_using_obj_cache ? wp_cache_get( $cache_key, $cache_group ) : get_transient( $cache_key );
649
650
	if ( false !== $cached_post ) {
651
		if ( is_object( $cached_post ) && 'WP_Post' === get_class( $cached_post ) ) {
652
			return $cached_post;
653
		}
654
655
		if ( is_int( $cached_post ) ) {
656
			$post = get_post( $cached_post );
657
			if ( $post ) {
658
				return $post;
659
			}
660
		}
661
	}
662
663
	$args = array(
664
		'post_type'      => 'attachment',
665
		'post_mime_type' => 'video/videopress',
666
		'post_status'    => 'inherit',
667
		'no_found_rows'  => true,
668
		'meta_query'     => array(
669
			array(
670
				'key'     => 'videopress_guid',
671
				'value'   => $guid,
672
				'compare' => '=',
673
			),
674
		),
675
	);
676
677
	$query = new WP_Query( $args );
678
679
	if ( $query->have_posts() ) {
680
		$post = $query->next_post();
681
		if ( $is_using_obj_cache ) {
682
			wp_cache_set( $cache_key, $post, $cache_group, HOUR_IN_SECONDS );
683
		} else {
684
			// Only store the ID, to prevent filling the database.
685
			set_transient( $cache_key, $post->ID );
686
		}
687
688
		return $post;
689
	}
690
691
	return false;
692
}
693
694
/**
695
 * From the given VideoPress post_id, return back the appropriate attachment URL.
696
 *
697
 * When the MP4 hasn't been processed yet or this is not a VideoPress video, this will return null.
698
 *
699
 * @param int $post_id Post ID of the attachment.
700
 * @return string|null
701
 */
702
function videopress_get_attachment_url( $post_id ) {
703
704
	// We only handle VideoPress attachments.
705
	if ( get_post_mime_type( $post_id ) !== 'video/videopress' ) {
706
		return null;
707
	}
708
709
	$meta = wp_get_attachment_metadata( $post_id );
710
711
	if ( ! isset( $meta['videopress']['files']['hd']['mp4'] ) ) {
712
		// Use the original file as the url if it isn't transcoded yet.
713
		if ( isset( $meta['original'] ) ) {
714
			$return = $meta['original'];
715
		} else {
716
			// Otherwise, there isn't much we can do.
717
			return null;
718
		}
719
	} else {
720
		$return = $meta['videopress']['file_url_base']['https'] . $meta['videopress']['files']['hd']['mp4'];
721
	}
722
723
	// If the URL is a string, return it. Otherwise, we shouldn't to avoid errors downstream, so null.
724
	return ( is_string( $return ) ) ? $return : null;
725
}
726
727
/**
728
 * Converts VideoPress flash embeds into oEmbed-able URLs.
729
 *
730
 * Older VideoPress embed depended on Flash, which no longer work,
731
 * so let us convert them to an URL that WordPress can oEmbed.
732
 *
733
 * Note that this file is always loaded via modules/module-extras.php and is not dependent on module status.
734
 *
735
 * @param string $content the content.
736
 * @return string filtered content
737
 */
738
function jetpack_videopress_flash_embed_filter( $content ) {
739
	$regex   = '%<embed[^>]*+>(?:\s*</embed>)?%i';
740
	$content = preg_replace_callback(
741
		$regex,
742
		function( $matches, $orig_html = null ) {
743
			$embed_code  = $matches[0];
744
			$url_matches = array();
745
746
			// get video ID from flash URL.
747
			$url_matched = preg_match( '/src="http:\/\/v.wordpress.com\/([^"]+)"/', $embed_code, $url_matches );
748
749
			if ( $url_matched ) {
750
				$video_id = $url_matches[1];
751
				return "https://videopress.com/v/$video_id";
752
			}
753
		},
754
		$content
755
	);
756
	return $content;
757
}
758
759
add_filter( 'the_content', 'jetpack_videopress_flash_embed_filter', 7 ); // Needs to be priority 7 to allow Core to oEmbed.
760