Completed
Push — add/caching-videopress ( 5c05e3...64918b )
by
unknown
38:37 queued 32:35
created

utility-functions.php ➔ videopress_get_post_id_by_guid()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 3
nop 1
dl 0
loc 35
rs 9.36
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
 * @see videopress_get_post_id_by_guid()
78
 *
79
 * @param string $url
80
 *
81
 * @return int|bool Attachment ID on success, false on failure
82
 */
83
function videopress_get_attachment_id_by_url( $url ) {
84
	_deprecated_function( __FUNCTION__, 'jetpack-8.4' );
85
86
	$wp_upload_dir = wp_upload_dir();
87
	// Strip out protocols, so it doesn't fail because searching for http: in https: dir.
88
	$dir = set_url_scheme( trailingslashit( $wp_upload_dir['baseurl'] ), 'relative' );
89
90
	// Is URL in uploads directory?
91
	if ( false !== strpos( $url, $dir ) ) {
92
93
		$file = basename( $url );
94
95
		$query_args = array(
96
			'post_type'   => 'attachment',
97
			'post_status' => 'inherit',
98
			'fields'      => 'ids',
99
			'meta_query'  => array(
100
				array(
101
					'key'     => '_wp_attachment_metadata',
102
					'compare' => 'LIKE',
103
					'value'   => $file,
104
				),
105
			),
106
		);
107
108
		$query = new WP_Query( $query_args );
109
110
		if ( $query->have_posts() ) {
111
			foreach ( $query->posts as $attachment_id ) {
112
				$meta          = wp_get_attachment_metadata( $attachment_id );
113
				$original_file = basename( $meta['file'] );
114
				$cropped_files = wp_list_pluck( $meta['sizes'], 'file' );
115
116
				if ( $original_file === $file || in_array( $file, $cropped_files ) ) {
117
					return (int) $attachment_id;
118
				}
119
			}
120
		}
121
	}
122
123
	return false;
124
}
125
126
/**
127
 * Similar to `media_sideload_image` -- but returns an ID.
128
 *
129
 * @param $url
130
 * @param $attachment_id
131
 *
132
 * @return int|mixed|object|WP_Error
133
 */
134
function videopress_download_poster_image( $url, $attachment_id ) {
135
	// Set variables for storage, fix file filename for query strings.
136
	preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $url, $matches );
137
	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...
138
		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...
139
	}
140
141
	$file_array             = array();
142
	$file_array['name']     = basename( $matches[0] );
143
	$file_array['tmp_name'] = download_url( $url );
144
145
	// If error storing temporarily, return the error.
146
	if ( is_wp_error( $file_array['tmp_name'] ) ) {
147
		return $file_array['tmp_name'];
148
	}
149
150
	// Do the validation and storage stuff.
151
	$thumbnail_id = media_handle_sideload( $file_array, $attachment_id, null );
152
153
	// Flag it as poster image, so we can exclude it from display.
154
	update_post_meta( $thumbnail_id, 'videopress_poster_image', 1 );
155
156
	return $thumbnail_id;
157
}
158
159
/**
160
 * Creates a local media library item of a remote VideoPress video.
161
 *
162
 * @param $guid
163
 * @param int  $parent_id
164
 *
165
 * @return int|object
166
 */
167
function create_local_media_library_for_videopress_guid( $guid, $parent_id = 0 ) {
168
	$vp_data = videopress_get_video_details( $guid );
169
	if ( ! $vp_data || is_wp_error( $vp_data ) ) {
170
		return $vp_data;
171
	}
172
173
	$args = array(
174
		'post_date'      => $vp_data->upload_date,
175
		'post_title'     => wp_kses( $vp_data->title, array() ),
176
		'post_content'   => wp_kses( $vp_data->description, array() ),
177
		'post_mime_type' => 'video/videopress',
178
		'guid'           => sprintf( 'https://videopress.com/v/%s', $guid ),
179
	);
180
181
	$attachment_id = wp_insert_attachment( $args, null, $parent_id );
182
183
	if ( ! is_wp_error( $attachment_id ) ) {
184
		update_post_meta( $attachment_id, 'videopress_guid', $guid );
185
		wp_update_attachment_metadata(
186
			$attachment_id,
187
			array(
188
				'width'  => $vp_data->width,
189
				'height' => $vp_data->height,
190
			)
191
		);
192
193
		$thumbnail_id = videopress_download_poster_image( $vp_data->poster, $attachment_id );
194
		update_post_meta( $attachment_id, '_thumbnail_id', $thumbnail_id );
195
	}
196
197
	return $attachment_id;
198
}
199
200
/**
201
 * Helper that will look for VideoPress media items that are more than 30 minutes old,
202
 * that have not had anything attached to them by a wpcom upload and deletes the ghost
203
 * attachment.
204
 *
205
 * These happen primarily because of failed upload attempts.
206
 *
207
 * @return int The number of items that were cleaned up.
208
 */
209
function videopress_cleanup_media_library() {
210
211
	// Disable this job for now.
212
	return 0;
213
	$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...
214
		'post_type'      => 'attachment',
215
		'post_status'    => 'inherit',
216
		'post_mime_type' => 'video/videopress',
217
		'meta_query'     => array(
218
			array(
219
				'key'   => 'videopress_status',
220
				'value' => 'new',
221
			),
222
		),
223
	);
224
225
	$query = new WP_Query( $query_args );
226
227
	$cleaned = 0;
228
229
	$now = current_time( 'timestamp' );
230
231
	if ( $query->have_posts() ) {
232
		foreach ( $query->posts as $post ) {
233
			$post_time = strtotime( $post->post_date_gmt );
234
235
			// If the post is older than 30 minutes, it is safe to delete it.
236
			if ( $now - $post_time > MINUTE_IN_SECONDS * 30 ) {
237
				// Force delete the attachment, because we don't want it appearing in the trash.
238
				wp_delete_attachment( $post->ID, true );
239
240
				$cleaned++;
241
			}
242
		}
243
	}
244
245
	return $cleaned;
246
}
247
248
/**
249
 * Return an absolute URI for a given filename and guid on the CDN.
250
 * No check is performed to ensure the guid exists or the file is present. Simple centralized string builder.
251
 *
252
 * @param string $guid     VideoPress identifier
253
 * @param string $filename name of file associated with the guid (video file name or thumbnail file name)
254
 *
255
 * @return string Absolute URL of VideoPress file for the given guid.
256
 */
257
function videopress_cdn_file_url( $guid, $filename ) {
258
	return "https://videos.files.wordpress.com/{$guid}/{$filename}";
259
}
260
261
/**
262
 * Get an array of the transcoding status for the given video post.
263
 *
264
 * @since 4.4
265
 * @param int $post_id
266
 * @return array|bool Returns an array of statuses if this is a VideoPress post, otherwise it returns false.
267
 */
268
function videopress_get_transcoding_status( $post_id ) {
269
	$meta = wp_get_attachment_metadata( $post_id );
270
271
	// If this has not been processed by videopress, we can skip the rest.
272
	if ( ! $meta || ! isset( $meta['file_statuses'] ) ) {
273
		return false;
274
	}
275
276
	$info = (object) $meta['file_statuses'];
277
278
	$status = array(
279
		'std_mp4' => isset( $info->mp4 ) ? $info->mp4 : null,
280
		'std_ogg' => isset( $info->ogg ) ? $info->ogg : null,
281
		'dvd_mp4' => isset( $info->dvd ) ? $info->dvd : null,
282
		'hd_mp4'  => isset( $info->hd ) ? $info->hd : null,
283
	);
284
285
	return $status;
286
}
287
288
/**
289
 * Get the direct url to the video.
290
 *
291
 * @since 4.4
292
 * @param string $guid
293
 * @return string
294
 */
295
function videopress_build_url( $guid ) {
296
297
	// No guid, no videopress url.
298
	if ( ! $guid ) {
299
		return '';
300
	}
301
302
	return 'https://videopress.com/v/' . $guid;
303
}
304
305
/**
306
 * Create an empty videopress media item that will be filled out later by an xmlrpc
307
 * callback from the VideoPress servers.
308
 *
309
 * @since 4.4
310
 * @param string $title
311
 * @return int|WP_Error
312
 */
313
function videopress_create_new_media_item( $title, $guid = null ) {
314
	$post = array(
315
		'post_type'      => 'attachment',
316
		'post_mime_type' => 'video/videopress',
317
		'post_title'     => $title,
318
		'post_content'   => '',
319
		'guid'           => videopress_build_url( $guid ),
320
	);
321
322
	$media_id = wp_insert_post( $post );
323
324
	add_post_meta( $media_id, 'videopress_status', 'initiated' );
325
326
	add_post_meta( $media_id, 'videopress_guid', $guid );
327
328
	return $media_id;
329
}
330
331
332
/**
333
 * @param array $current_status
334
 * @param array $new_meta
335
 * @return array
336
 */
337
function videopress_merge_file_status( $current_status, $new_meta ) {
338
	$new_statuses = array();
339
340 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['hd'] ) ) {
341
		$new_statuses['hd'] = $new_meta['videopress']['files_status']['hd'];
342
	}
343
344 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['dvd'] ) ) {
345
		$new_statuses['dvd'] = $new_meta['videopress']['files_status']['dvd'];
346
	}
347
348 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['std']['mp4'] ) ) {
349
		$new_statuses['mp4'] = $new_meta['videopress']['files_status']['std']['mp4'];
350
	}
351
352 View Code Duplication
	if ( isset( $new_meta['videopress']['files_status']['std']['ogg'] ) ) {
353
		$new_statuses['ogg'] = $new_meta['videopress']['files_status']['std']['ogg'];
354
	}
355
356
	foreach ( $new_statuses as $format => $status ) {
357
		if ( ! isset( $current_status[ $format ] ) ) {
358
			$current_status[ $format ] = $status;
359
			continue;
360
		}
361
362
		if ( $current_status[ $format ] !== 'DONE' ) {
363
			$current_status[ $format ] = $status;
364
		}
365
	}
366
367
	return $current_status;
368
}
369
370
/**
371
 * Check to see if a video has completed processing.
372
 *
373
 * @since 4.4
374
 * @param int $post_id
375
 * @return bool
376
 */
377
function videopress_is_finished_processing( $post_id ) {
378
	$post = get_post( $post_id );
379
380
	if ( is_wp_error( $post ) ) {
381
		return false;
382
	}
383
384
	$meta = wp_get_attachment_metadata( $post->ID );
385
386
	if ( ! isset( $meta['file_statuses'] ) || ! is_array( $meta['file_statuses'] ) ) {
387
		return false;
388
	}
389
390
	$check_statuses = array( 'hd', 'dvd', 'mp4', 'ogg' );
391
392
	foreach ( $check_statuses as $status ) {
393
		if ( ! isset( $meta['file_statuses'][ $status ] ) || $meta['file_statuses'][ $status ] != 'DONE' ) {
394
			return false;
395
		}
396
	}
397
398
	return true;
399
}
400
401
402
/**
403
 * Update the meta information  status for the given video post.
404
 *
405
 * @since 4.4
406
 * @param int $post_id
407
 * @return bool
408
 */
409
function videopress_update_meta_data( $post_id ) {
410
411
	$meta = wp_get_attachment_metadata( $post_id );
412
413
	// If this has not been processed by VideoPress, we can skip the rest.
414
	if ( ! $meta || ! isset( $meta['videopress'] ) ) {
415
		return false;
416
	}
417
418
	$info = (object) $meta['videopress'];
419
420
	$args = array(
421
		// 'sslverify' => false,
422
	);
423
424
	$result = wp_remote_get( videopress_make_video_get_path( $info->guid ), $args );
425
426
	if ( is_wp_error( $result ) ) {
427
		return false;
428
	}
429
430
	$response = json_decode( $result['body'], true );
431
432
	// Update the attachment metadata.
433
	$meta['videopress'] = $response;
434
435
	wp_update_attachment_metadata( $post_id, $meta );
436
437
	return true;
438
}
439
440
/**
441
 * Check to see if this is a VideoPress post that hasn't had a guid set yet.
442
 *
443
 * @param int $post_id
444
 * @return bool
445
 */
446
function videopress_is_attachment_without_guid( $post_id ) {
447
	$post = get_post( $post_id );
448
449
	if ( is_wp_error( $post ) ) {
450
		return false;
451
	}
452
453
	if ( $post->post_mime_type !== 'video/videopress' ) {
454
		return false;
455
	}
456
457
	$videopress_guid = get_post_meta( $post_id, 'videopress_guid', true );
458
459
	if ( $videopress_guid ) {
460
		return false;
461
	}
462
463
	return true;
464
}
465
466
/**
467
 * Check to see if this is a VideoPress attachment.
468
 *
469
 * @param int $post_id
470
 * @return bool
471
 */
472
function is_videopress_attachment( $post_id ) {
473
	$post = get_post( $post_id );
474
475
	if ( is_wp_error( $post ) ) {
476
		return false;
477
	}
478
479
	if ( $post->post_mime_type !== 'video/videopress' ) {
480
		return false;
481
	}
482
483
	return true;
484
}
485
486
/**
487
 * Get the video update path
488
 *
489
 * @since 4.4
490
 * @param string $guid
491
 * @return string
492
 */
493
function videopress_make_video_get_path( $guid ) {
494
	return sprintf(
495
		'%s://%s/rest/v%s/videos/%s',
496
		'https',
497
		JETPACK__WPCOM_JSON_API_HOST,
498
		Client::WPCOM_JSON_API_VERSION,
499
		$guid
500
	);
501
}
502
503
/**
504
 * Get the upload api path.
505
 *
506
 * @since 4.4
507
 * @param int $blog_id The id of the blog we're uploading to.
508
 * @return string
509
 */
510
function videopress_make_media_upload_path( $blog_id ) {
511
	return sprintf(
512
		'https://public-api.wordpress.com/rest/v1.1/sites/%s/media/new',
513
		$blog_id
514
	);
515
}
516
517
/**
518
 * This is a mock of the internal VideoPress method, which is meant to duplicate the functionality
519
 * of the WPCOM API, so that the Jetpack REST API returns the same data with no modifications.
520
 *
521
 * @param int $blog_id Blog ID.
522
 * @param int $post_id Post ID.
523
 * @return bool|stdClass
524
 */
525
function video_get_info_by_blogpostid( $blog_id, $post_id ) {
526
	$post = get_post( $post_id );
527
528
	$video_info                  = new stdClass();
529
	$video_info->post_id         = $post_id;
530
	$video_info->blog_id         = $blog_id;
531
	$video_info->guid            = null;
532
	$video_info->finish_date_gmt = '0000-00-00 00:00:00';
533
534
	if ( is_wp_error( $post ) ) {
535
		return $video_info;
536
	}
537
538
	if ( 'video/videopress' !== $post->post_mime_type ) {
539
		return $video_info;
540
	}
541
542
	// Since this is a VideoPress post, lt's fill out the rest of the object.
543
	$video_info->guid = get_post_meta( $post_id, 'videopress_guid', true );
544
545
	if ( videopress_is_finished_processing( $post_id ) ) {
546
		$video_info->finish_date_gmt = date( 'Y-m-d H:i:s' );
547
	}
548
549
	return $video_info;
550
}
551
552
553
/**
554
 * Check that a VideoPress video format has finished processing.
555
 *
556
 * This uses the info object, because that is what the WPCOM endpoint
557
 * uses, however we don't have a complete info object in the same way
558
 * WPCOM does, so we pull the meta information out of the post
559
 * options instead.
560
 *
561
 * Note: This mimics the WPCOM function of the same name and helps the media
562
 * API endpoint add all needed VideoPress data.
563
 *
564
 * @param stdClass $info
565
 * @param string   $format
566
 * @return bool
567
 */
568
function video_format_done( $info, $format ) {
569
570
	// Avoids notice when a non-videopress item is found.
571
	if ( ! is_object( $info ) ) {
572
		return false;
573
	}
574
575
	$post_id = $info->post_id;
576
577
	if ( get_post_mime_type( $post_id ) !== 'video/videopress' ) {
578
		return false;
579
	}
580
581
	$post = get_post( $post_id );
582
583
	if ( is_wp_error( $post ) ) {
584
		return false;
585
	}
586
587
	$meta = wp_get_attachment_metadata( $post->ID );
588
589
	switch ( $format ) {
590
		case 'fmt_hd':
591
			return isset( $meta['videopress']['files']['hd']['mp4'] );
592
			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...
593
594
		case 'fmt_dvd':
595
			return isset( $meta['videopress']['files']['dvd']['mp4'] );
596
			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...
597
598
		case 'fmt_std':
599
			return isset( $meta['videopress']['files']['std']['mp4'] );
600
			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...
601
602
		case 'fmt_ogg':
603
			return isset( $meta['videopress']['files']['std']['ogg'] );
604
			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...
605
	}
606
607
	return false;
608
}
609
610
/**
611
 * Get the image URL for the given VideoPress GUID
612
 *
613
 * We look up by GUID, because that is what WPCOM does and this needs to be
614
 * parameter compatible with that.
615
 *
616
 * Note: This mimics the WPCOM function of the same name and helps the media
617
 * API endpoint add all needed VideoPress data.
618
 *
619
 * @param string $guid
620
 * @param string $format
621
 * @return string
622
 */
623
function video_image_url_by_guid( $guid, $format ) {
624
625
	$post = video_get_post_by_guid( $guid );
626
627
	if ( is_wp_error( $post ) ) {
628
		return null;
629
	}
630
631
	$meta = wp_get_attachment_metadata( $post->ID );
632
633
	// We add ssl => 1 to make sure that the videos.files.wordpress.com domain is parsed as photon.
634
	$poster = apply_filters( 'jetpack_photon_url', $meta['videopress']['poster'], array( 'ssl' => 1 ), 'https' );
635
636
	return $poster;
637
}
638
639
/**
640
 * Using a GUID, find a post.
641
 *
642
 * @param string $guid
643
 * @return WP_Post|false The post for that guid, or false if none is found.
644
 */
645
function video_get_post_by_guid( $guid ) {
646
	$cache_key   = 'video_get_post_by_guid_' . $guid;
647
	$cache_group = 'videopress';
648
	$cached_post = wp_cache_get( $cache_key, $cache_group );
649
650
	if ( is_object( $cached_post ) && 'WP_Post' === get_class( $cached_post ) ) {
651
		return $cached_post;
652
	}
653
654
	$post_id = videopress_get_post_id_by_guid( $guid );
655
656
	if ( is_int( $post_id ) ) {
657
		$post = get_post( $post_id );
658
		wp_cache_set( $cache_key, $post, $cache_group, HOUR_IN_SECONDS );
659
660
		return $post;
661
	}
662
663
	return false;
664
}
665
666
/**
667
 * Using a GUID, find the associated post ID.
668
 *
669
 * @param string $guid The guid to look for the post ID of.
670
 * @return int|false The post ID for that guid, or false if none is found.
671
 */
672
function videopress_get_post_id_by_guid( $guid ) {
673
	$cache_key = 'videopress_get_post_id_by_guid_' . $guid;
674
	$cached_id = get_transient( $cache_key );
675
676
	if ( is_int( $cached_id ) ) {
677
		return $cached_id;
678
	}
679
680
	$args = array(
681
		'post_type'      => 'attachment',
682
		'post_mime_type' => 'video/videopress',
683
		'post_status'    => 'inherit',
684
		'no_found_rows'  => true,
685
		'fields'         => 'ids',
686
		'meta_query'     => array(
687
			array(
688
				'key'     => 'videopress_guid',
689
				'value'   => $guid,
690
				'compare' => '=',
691
			),
692
		),
693
	);
694
695
	$query = new WP_Query( $args );
696
697
	if ( $query->have_posts() ) {
698
		$post_id = $query->next_post();
699
		// Only store the ID, to prevent filling the database.
700
		set_transient( $cache_key, $post_id, HOUR_IN_SECONDS );
701
702
		return $post_id;
703
	}
704
705
	return false;
706
}
707
708
/**
709
 * From the given VideoPress post_id, return back the appropriate attachment URL.
710
 *
711
 * When the MP4 hasn't been processed yet or this is not a VideoPress video, this will return null.
712
 *
713
 * @param int $post_id Post ID of the attachment.
714
 * @return string|null
715
 */
716
function videopress_get_attachment_url( $post_id ) {
717
718
	// We only handle VideoPress attachments.
719
	if ( get_post_mime_type( $post_id ) !== 'video/videopress' ) {
720
		return null;
721
	}
722
723
	$meta = wp_get_attachment_metadata( $post_id );
724
725
	if ( ! isset( $meta['videopress']['files']['hd']['mp4'] ) ) {
726
		// Use the original file as the url if it isn't transcoded yet.
727
		if ( isset( $meta['original'] ) ) {
728
			$return = $meta['original'];
729
		} else {
730
			// Otherwise, there isn't much we can do.
731
			return null;
732
		}
733
	} else {
734
		$return = $meta['videopress']['file_url_base']['https'] . $meta['videopress']['files']['hd']['mp4'];
735
	}
736
737
	// If the URL is a string, return it. Otherwise, we shouldn't to avoid errors downstream, so null.
738
	return ( is_string( $return ) ) ? $return : null;
739
}
740
741
/**
742
 * Converts VideoPress flash embeds into oEmbed-able URLs.
743
 *
744
 * Older VideoPress embed depended on Flash, which no longer work,
745
 * so let us convert them to an URL that WordPress can oEmbed.
746
 *
747
 * Note that this file is always loaded via modules/module-extras.php and is not dependent on module status.
748
 *
749
 * @param string $content the content.
750
 * @return string filtered content
751
 */
752
function jetpack_videopress_flash_embed_filter( $content ) {
753
	$regex   = '%<embed[^>]*+>(?:\s*</embed>)?%i';
754
	$content = preg_replace_callback(
755
		$regex,
756
		function( $matches, $orig_html = null ) {
757
			$embed_code  = $matches[0];
758
			$url_matches = array();
759
760
			// get video ID from flash URL.
761
			$url_matched = preg_match( '/src="http:\/\/v.wordpress.com\/([^"]+)"/', $embed_code, $url_matches );
762
763
			if ( $url_matched ) {
764
				$video_id = $url_matches[1];
765
				return "https://videopress.com/v/$video_id";
766
			}
767
		},
768
		$content
769
	);
770
	return $content;
771
}
772
773
add_filter( 'the_content', 'jetpack_videopress_flash_embed_filter', 7 ); // Needs to be priority 7 to allow Core to oEmbed.
774