Completed
Push — update/node-version ( 857559...c25464 )
by Jeremy
313:10 queued 285:45
created

Jetpack_Podcast_Helper::get_player_data()   D

Complexity

Conditions 15
Paths 160

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
nc 160
nop 1
dl 0
loc 76
rs 4.8569
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Helper to massage Podcast data to be used in the Podcast block.
4
 *
5
 * @package automattic/jetpack
6
 */
7
8
/**
9
 * Class Jetpack_Podcast_Helper
10
 */
11
class Jetpack_Podcast_Helper {
12
	/**
13
	 * The RSS feed of the podcast.
14
	 *
15
	 * @var string
16
	 */
17
	protected $feed = null;
18
19
	/**
20
	 * Initialize class.
21
	 *
22
	 * @param string $feed The RSS feed of the podcast.
23
	 */
24
	public function __construct( $feed ) {
25
		$this->feed = esc_url_raw( $feed );
26
	}
27
28
	/**
29
	 * Gets podcast data formatted to be used by the Podcast Player block in both server-side
30
	 * block rendering and in API `WPCOM_REST_API_V2_Endpoint_Podcast_Player`.
31
	 *
32
	 * The result is cached for one hour.
33
	 *
34
	 * @param array $args {
35
	 *    Optional array of arguments.
36
	 *    @type string|int $guid  The ID of a specific episode to return rather than a list.
37
	 * }
38
	 *
39
	 * @return array|WP_Error  The player data or a error object.
40
	 */
41
	public function get_player_data( $args = array() ) {
42
		$guids           = isset( $args['guids'] ) && $args['guids'] ? $args['guids'] : array();
43
		$episode_options = isset( $args['episode-options'] ) && $args['episode-options'];
44
45
		// Try loading data from the cache.
46
		$transient_key = 'jetpack_podcast_' . md5( $this->feed . implode( ',', $guids ) . "-$episode_options" );
47
		$player_data   = get_transient( $transient_key );
48
49
		// Fetch data if we don't have any cached.
50
		if ( false === $player_data || ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) {
51
			// Load feed.
52
			$rss = $this->load_feed();
53
54
			if ( is_wp_error( $rss ) ) {
55
				return $rss;
56
			}
57
58
			// Get a list of episodes by guid or all tracks in feed.
59
			if ( count( $guids ) ) {
60
				$tracks = array_map( array( $this, 'get_track_data' ), $guids );
61
				$tracks = array_filter(
62
					$tracks,
63
					function ( $track ) {
64
						return ! is_wp_error( $track );
65
					}
66
				);
67
			} else {
68
				$tracks = $this->get_track_list();
69
			}
70
71
			if ( empty( $tracks ) ) {
72
				return new WP_Error( 'no_tracks', __( 'Your Podcast couldn\'t be embedded as it doesn\'t contain any tracks. Please double check your URL.', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'no_tracks'.

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...
73
			}
74
75
			// Get podcast meta.
76
			$title = $rss->get_title();
77
			$title = $this->get_plain_text( $title );
78
79
			$description = $rss->get_description();
80
			$description = $this->get_plain_text( $description );
81
82
			$cover = $rss->get_image_url();
83
			$cover = ! empty( $cover ) ? esc_url( $cover ) : null;
84
85
			$link = $rss->get_link();
86
			$link = ! empty( $link ) ? esc_url( $link ) : null;
87
88
			$player_data = array(
89
				'title'       => $title,
90
				'description' => $description,
91
				'link'        => $link,
92
				'cover'       => $cover,
93
				'tracks'      => $tracks,
94
			);
95
96
			if ( $episode_options ) {
97
				$player_data['options'] = array();
98
				foreach ( $rss->get_items() as $episode ) {
0 ignored issues
show
Bug introduced by
The method get_items does only exist in SimplePie, but not in WP_Error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
99
					$enclosure = $this->get_audio_enclosure( $episode );
100
					// If the episode doesn't have playable audio, then don't include it.
101
					if ( is_wp_error( $enclosure ) ) {
102
						continue;
103
					}
104
					$player_data['options'][] = array(
105
						'label' => $this->get_plain_text( $episode->get_title() ),
106
						'value' => $episode->get_id(),
107
					);
108
				}
109
			}
110
111
			// Cache for 1 hour.
112
			set_transient( $transient_key, $player_data, HOUR_IN_SECONDS );
113
		}
114
115
		return $player_data;
116
	}
117
118
	/**
119
	 * Gets a specific track from the supplied feed URL.
120
	 *
121
	 * @param string  $guid          The GUID of the track.
122
	 * @param boolean $force_refresh Clear the feed cache.
123
	 * @return array|WP_Error The track object or an error object.
124
	 */
125
	public function get_track_data( $guid, $force_refresh = false ) {
126
		// Get the cache key.
127
		$transient_key = 'jetpack_podcast_' . md5( "$this->feed::$guid" );
128
129
		// Clear the cache if force_refresh param is true.
130
		if ( true === $force_refresh ) {
131
			delete_transient( $transient_key );
132
		}
133
134
		// Try loading track data from the cache.
135
		$track_data = get_transient( $transient_key );
136
137
		// Fetch data if we don't have any cached.
138
		if ( false === $track_data || ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) {
139
			// Load feed.
140
			$rss = $this->load_feed( $force_refresh );
141
142
			if ( is_wp_error( $rss ) ) {
143
				return $rss;
144
			}
145
146
			// Loop over all tracks to find the one.
147
			foreach ( $rss->get_items() as $track ) {
0 ignored issues
show
Bug introduced by
The method get_items does only exist in SimplePie, but not in WP_Error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
148
				if ( $guid === $track->get_id() ) {
149
					$track_data = $this->setup_tracks_callback( $track );
150
					break;
151
				}
152
			}
153
154
			if ( false === $track_data ) {
155
				return new WP_Error( 'no_track', __( 'The track was not found.', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'no_track'.

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...
156
			}
157
158
			// Cache for 1 hour.
159
			set_transient( $transient_key, $track_data, HOUR_IN_SECONDS );
160
		}
161
162
		return $track_data;
163
	}
164
165
	/**
166
	 * Gets a list of tracks for the supplied RSS feed.
167
	 *
168
	 * @return array|WP_Error The feed's tracks or a error object.
169
	 */
170
	public function get_track_list() {
171
		$rss = $this->load_feed();
172
173
		if ( is_wp_error( $rss ) ) {
174
			return $rss;
175
		}
176
177
		/**
178
		 * Allow requesting a specific number of tracks from SimplePie's `get_items` call.
179
		 * The default number of tracks is ten.
180
		 *
181
		 * @since 9.5.0
182
		 *
183
		 * @param int    $number Number of tracks fetched. Default is 10.
184
		 * @param object $rss    The SimplePie object built from core's `fetch_feed` call.
185
		 */
186
		$tracks_quantity = apply_filters( 'jetpack_podcast_helper_list_quantity', 10, $rss );
0 ignored issues
show
Unused Code introduced by
The call to apply_filters() has too many arguments starting with $rss.

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...
187
188
		// Process the requested number of items from our feed.
189
		$track_list = array_map( array( __CLASS__, 'setup_tracks_callback' ), $rss->get_items( 0, $tracks_quantity ) );
0 ignored issues
show
Unused Code introduced by
The call to SimplePie::get_items() has too many arguments starting with 0.

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...
Bug introduced by
The method get_items does only exist in SimplePie, but not in WP_Error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
190
191
		// Filter out any tracks that are empty.
192
		// Reset the array indicies.
193
		return array_values( array_filter( $track_list ) );
194
	}
195
196
	/**
197
	 * Formats string as pure plaintext, with no HTML tags or entities present.
198
	 * This is ready to be used in React, innerText but needs to be escaped
199
	 * using standard `esc_html` when generating markup on server.
200
	 *
201
	 * @param string $str Input string.
202
	 * @return string Plain text string.
203
	 */
204
	protected function get_plain_text( $str ) {
205
		return $this->sanitize_and_decode_text( $str, true );
206
	}
207
208
	/**
209
	 * Formats strings as safe HTML.
210
	 *
211
	 * @param string $str Input string.
212
	 * @return string HTML text string safe for post_content.
213
	 */
214
	protected function get_html_text( $str ) {
215
		return $this->sanitize_and_decode_text( $str, false );
216
	}
217
218
	/**
219
	 * Strip unallowed html tags and decode entities.
220
	 *
221
	 * @param string  $str Input string.
222
	 * @param boolean $strip_all_tags Strip all tags, otherwise allow post_content safe tags.
223
	 * @return string Sanitized and decoded text.
224
	 */
225
	protected function sanitize_and_decode_text( $str, $strip_all_tags = true ) {
226
		// Trim string and return if empty.
227
		$str = trim( (string) $str );
228
		if ( empty( $str ) ) {
229
			return '';
230
		}
231
232
		if ( $strip_all_tags ) {
233
			// Make sure there are no tags.
234
			$str = wp_strip_all_tags( $str );
235
		} else {
236
			$str = wp_kses_post( $str );
237
		}
238
239
		// Replace all entities with their characters, including all types of quotes.
240
		$str = html_entity_decode( $str, ENT_QUOTES );
241
242
		return $str;
243
	}
244
245
	/**
246
	 * Loads an RSS feed using `fetch_feed`.
247
	 *
248
	 * @param boolean $force_refresh Clear the feed cache.
249
	 * @return SimplePie|WP_Error The RSS object or error.
250
	 */
251
	public function load_feed( $force_refresh = false ) {
252
		// Add action: clear the SimplePie Cache if $force_refresh param is true.
253
		if ( true === $force_refresh ) {
254
			add_action( 'wp_feed_options', array( __CLASS__, 'reset_simplepie_cache' ) );
255
		}
256
		// Add action: detect the podcast feed from the provided feed URL.
257
		add_action( 'wp_feed_options', array( __CLASS__, 'set_podcast_locator' ) );
258
259
		// Fetch the feed.
260
		$rss = fetch_feed( $this->feed );
261
262
		// Remove added actions from wp_feed_options hook.
263
		remove_action( 'wp_feed_options', array( __CLASS__, 'set_podcast_locator' ) );
264
		if ( true === $force_refresh ) {
265
			remove_action( 'wp_feed_options', array( __CLASS__, 'reset_simplepie_cache' ) );
266
		}
267
268
		if ( is_wp_error( $rss ) ) {
269
			return new WP_Error( 'invalid_url', __( 'Your podcast couldn\'t be embedded. Please double check your URL.', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_url'.

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...
270
		}
271
272
		if ( ! $rss->get_item_quantity() ) {
273
			return new WP_Error( 'no_tracks', __( 'Podcast audio RSS feed has no tracks.', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'no_tracks'.

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...
274
		}
275
276
		return $rss;
277
	}
278
279
	/**
280
	 * Action handler to set our podcast specific feed locator class on the SimplePie object.
281
	 *
282
	 * @param SimplePie $feed The SimplePie object, passed by reference.
283
	 */
284
	public static function set_podcast_locator( &$feed ) {
285
		if ( ! class_exists( 'Jetpack_Podcast_Feed_Locator' ) ) {
286
			jetpack_require_lib( 'class-jetpack-podcast-feed-locator' );
287
		}
288
289
		$feed->set_locator_class( 'Jetpack_Podcast_Feed_Locator' );
0 ignored issues
show
Bug introduced by
The method set_locator_class() does not seem to exist on object<SimplePie>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
290
	}
291
292
	/**
293
	 * Action handler to reset the SimplePie cache for the podcast feed.
294
	 *
295
	 * Note this only resets the cache for the specified url. If the feed locator finds the podcast feed
296
	 * within the markup of the that url, that feed itself may still be cached.
297
	 *
298
	 * @param SimplePie $feed The SimplePie object, passed by reference.
299
	 * @return void
300
	 */
301
	public static function reset_simplepie_cache( &$feed ) {
302
		// Retrieve the cache object for a feed url. Based on:
303
		// https://github.com/WordPress/WordPress/blob/fd1c2cb4011845ceb7244a062b09b2506082b1c9/wp-includes/class-simplepie.php#L1412.
304
		$cache = $feed->registry->call( 'Cache', 'get_handler', array( $feed->cache_location, call_user_func( $feed->cache_name_function, $feed->feed_url ), 'spc' ) );
0 ignored issues
show
Bug introduced by
The property cache_location does not seem to exist in SimplePie.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property cache_name_function does not seem to exist in SimplePie.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property feed_url does not seem to exist in SimplePie.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
Bug introduced by
The property registry does not seem to exist in SimplePie.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
305
306
		if ( method_exists( $cache, 'unlink' ) ) {
307
			$cache->unlink();
308
		}
309
	}
310
311
	/**
312
	 * Prepares Episode data to be used by the Podcast Player block.
313
	 *
314
	 * @param SimplePie_Item $episode SimplePie_Item object, representing a podcast episode.
315
	 * @return array
316
	 */
317
	protected function setup_tracks_callback( SimplePie_Item $episode ) {
318
		$enclosure = $this->get_audio_enclosure( $episode );
319
320
		// If the audio enclosure is empty then it is not playable.
321
		// We therefore return an empty array for this track.
322
		// It will be filtered out later.
323
		if ( is_wp_error( $enclosure ) ) {
324
			return array();
325
		}
326
327
		// If there is no link return an empty array. We will filter out later.
328
		if ( empty( $enclosure->link ) ) {
329
			return array();
330
		}
331
332
		$publish_date = $episode->get_gmdate( DATE_ATOM );
0 ignored issues
show
Bug introduced by
The method get_gmdate() does not seem to exist on object<SimplePie_Item>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
333
		// Build track data.
334
		$track = array(
335
			'id'               => wp_unique_id( 'podcast-track-' ),
336
			'link'             => esc_url( $episode->get_link() ),
0 ignored issues
show
Bug introduced by
The method get_link() does not seem to exist on object<SimplePie_Item>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
337
			'src'              => esc_url( $enclosure->link ),
338
			'type'             => esc_attr( $enclosure->type ),
339
			'description'      => $this->get_plain_text( $episode->get_description() ),
0 ignored issues
show
Bug introduced by
The method get_description() does not seem to exist on object<SimplePie_Item>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
340
			'description_html' => $this->get_html_text( $episode->get_description() ),
0 ignored issues
show
Bug introduced by
The method get_description() does not seem to exist on object<SimplePie_Item>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
341
			'title'            => $this->get_plain_text( $episode->get_title() ),
0 ignored issues
show
Bug introduced by
The method get_title() does not seem to exist on object<SimplePie_Item>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
342
			'image'            => esc_url( $this->get_episode_image_url( $episode ) ),
343
			'guid'             => $this->get_plain_text( $episode->get_id() ),
344
			'publish_date'     => $publish_date ? $publish_date : null,
345
		);
346
347
		if ( empty( $track['title'] ) ) {
348
			$track['title'] = esc_html__( '(no title)', 'jetpack' );
349
		}
350
351
		if ( ! empty( $enclosure->duration ) ) {
352
			$track['duration'] = esc_html( $this->format_track_duration( $enclosure->duration ) );
353
		}
354
355
		return $track;
356
	}
357
358
	/**
359
	 * Retrieves an episode's image URL, if it's available.
360
	 *
361
	 * @param SimplePie_Item $episode SimplePie_Item object, representing a podcast episode.
362
	 * @param string         $itunes_ns The itunes namespace, defaulted to the standard 1.0 version.
363
	 * @return string|null The image URL or null if not found.
364
	 */
365
	protected function get_episode_image_url( SimplePie_Item $episode, $itunes_ns = 'http://www.itunes.com/dtds/podcast-1.0.dtd' ) {
366
		$image = $episode->get_item_tags( $itunes_ns, 'image' );
0 ignored issues
show
Bug introduced by
The method get_item_tags() does not seem to exist on object<SimplePie_Item>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
367
		if ( isset( $image[0]['attribs']['']['href'] ) ) {
368
			return $image[0]['attribs']['']['href'];
369
		}
370
		return null;
371
	}
372
373
	/**
374
	 * Retrieves an audio enclosure.
375
	 *
376
	 * @param SimplePie_Item $episode SimplePie_Item object, representing a podcast episode.
377
	 * @return SimplePie_Enclosure|null
378
	 */
379
	protected function get_audio_enclosure( SimplePie_Item $episode ) {
380
		foreach ( (array) $episode->get_enclosures() as $enclosure ) {
381
			if ( 0 === strpos( $enclosure->type, 'audio/' ) ) {
382
				return $enclosure;
383
			}
384
		}
385
386
		return new WP_Error( 'invalid_audio', __( 'Podcast audio is an invalid type.', 'jetpack' ) );
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'invalid_audio'.

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...
387
	}
388
389
	/**
390
	 * Returns the track duration as a formatted string.
391
	 *
392
	 * @param number $duration of the track in seconds.
393
	 * @return string
394
	 */
395
	protected function format_track_duration( $duration ) {
396
		$format = $duration > HOUR_IN_SECONDS ? 'H:i:s' : 'i:s';
397
398
		return date_i18n( $format, $duration );
399
	}
400
401
	/**
402
	 * Gets podcast player data schema.
403
	 *
404
	 * Useful for json schema in REST API endpoints.
405
	 *
406
	 * @return array Player data json schema.
407
	 */
408
	public static function get_player_data_schema() {
409
		return array(
410
			'$schema'    => 'http://json-schema.org/draft-04/schema#',
411
			'title'      => 'jetpack-podcast-player-data',
412
			'type'       => 'object',
413
			'properties' => array(
414
				'title'   => array(
415
					'description' => __( 'The title of the podcast.', 'jetpack' ),
416
					'type'        => 'string',
417
				),
418
				'link'    => array(
419
					'description' => __( 'The URL of the podcast website.', 'jetpack' ),
420
					'type'        => 'string',
421
					'format'      => 'uri',
422
				),
423
				'cover'   => array(
424
					'description' => __( 'The URL of the podcast cover image.', 'jetpack' ),
425
					'type'        => 'string',
426
					'format'      => 'uri',
427
				),
428
				'tracks'  => self::get_tracks_schema(),
429
				'options' => self::get_options_schema(),
430
			),
431
		);
432
	}
433
434
	/**
435
	 * Gets tracks data schema.
436
	 *
437
	 * Useful for json schema in REST API endpoints.
438
	 *
439
	 * @return array Tracks json schema.
440
	 */
441
	public static function get_tracks_schema() {
442
		return array(
443
			'description' => __( 'Latest episodes of the podcast.', 'jetpack' ),
444
			'type'        => 'array',
445
			'items'       => array(
446
				'type'       => 'object',
447
				'properties' => array(
448
					'id'               => array(
449
						'description' => __( 'The episode id. Generated per request, not globally unique.', 'jetpack' ),
450
						'type'        => 'string',
451
					),
452
					'link'             => array(
453
						'description' => __( 'The external link for the episode.', 'jetpack' ),
454
						'type'        => 'string',
455
						'format'      => 'uri',
456
					),
457
					'src'              => array(
458
						'description' => __( 'The audio file URL of the episode.', 'jetpack' ),
459
						'type'        => 'string',
460
						'format'      => 'uri',
461
					),
462
					'type'             => array(
463
						'description' => __( 'The mime type of the episode.', 'jetpack' ),
464
						'type'        => 'string',
465
					),
466
					'description'      => array(
467
						'description' => __( 'The episode description, in plaintext.', 'jetpack' ),
468
						'type'        => 'string',
469
					),
470
					'description_html' => array(
471
						'description' => __( 'The episode description with allowed html tags.', 'jetpack' ),
472
						'type'        => 'string',
473
					),
474
					'title'            => array(
475
						'description' => __( 'The episode title.', 'jetpack' ),
476
						'type'        => 'string',
477
					),
478
					'publish_date'     => array(
479
						'description' => __( 'The UTC publish date and time of the episode', 'jetpack' ),
480
						'type'        => 'string',
481
						'format'      => 'date-time',
482
					),
483
				),
484
			),
485
		);
486
	}
487
488
	/**
489
	 * Gets the episode options schema.
490
	 *
491
	 * Useful for json schema in REST API endpoints.
492
	 *
493
	 * @return array Tracks json schema.
494
	 */
495
	public static function get_options_schema() {
496
		return array(
497
			'description' => __( 'The options that will be displayed in the episode selection UI', 'jetpack' ),
498
			'type'        => 'array',
499
			'items'       => array(
500
				'type'       => 'object',
501
				'properties' => array(
502
					'label' => array(
503
						'description' => __( 'The display label of the option, the episode title.', 'jetpack' ),
504
						'type'        => 'string',
505
					),
506
					'value' => array(
507
						'description' => __( 'The value used for that option, the episode GUID', 'jetpack' ),
508
						'type'        => 'string',
509
					),
510
				),
511
			),
512
		);
513
	}
514
}
515