Video Thumbnails - Version 2.0

Version Description

  • Completely rewritten for better performance, more organized code, and easier maintenance
  • Added support for Funny or Die
  • Added support for MPORA
  • Added support for Wistia
  • Added support for Facebook videos
  • Added support for CollegeHumor
  • Added support for Youku
  • Added support for HD YouTube thumbnails
  • Added support for higher resolution Vimeo thumbnails
  • Added support for private Vimeo videos (API credentials required)
  • Added support for Vimeo channel URLs
  • Added support for Automatic Youtube Video Posts Plugin
  • Added filters to make plugin extensible
  • Removed cURL requirement (still requires ability to make external requests)
  • Better checks for blank thumbnails before added to media library
  • Adds 'video_thumbnail' field to video thumbnails saved in the media library
  • Option to clear all video thumbnails (clears custom field from posts and deletes video thumbnails added after 2.0 from library)
  • Better file names
  • Added provider tests on debugging page to help troubleshoot
  • Added a markup detection on debugging page
  • Added "Installation Information" section to debugging page with helpful troubleshooting info
  • Settings improvements
  • Bug fixes
Download this release

Release Info

Developer sutherlandboswell
Plugin Icon 128x128 Video Thumbnails
Version 2.0
Comparing to
See all releases

Code changes from version 1.8.2 to 2.0

default.jpg CHANGED
Binary file
js/clear.js ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function clear_all_video_thumbnails( nonce ) {
2
+ var confimation_result = confirm("Are you sure you want to clear all video thumbnails? This cannot be undone.");
3
+ if (confimation_result){
4
+ var data = {
5
+ action: 'clear_all_video_thumbnails',
6
+ nonce: nonce
7
+ };
8
+ document.getElementById( 'clear-all-video-thumbnails-result' ).innerHTML = '<p>Working...</p>';
9
+ jQuery.post(ajaxurl, data, function(response){
10
+ document.getElementById( 'clear-all-video-thumbnails-result' ).innerHTML = response;
11
+ });
12
+ }
13
+ else{
14
+ //
15
+ }
16
+ };
js/test.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function test_video_thumbnail( test_type ) {
2
+ var data = {
3
+ action: 'video_thumbnail_' + test_type + '_test'
4
+ };
5
+ document.getElementById( test_type + '-test' ).innerHTML = 'Working...';
6
+ jQuery.post(ajaxurl, data, function(response){
7
+ document.getElementById( test_type + '-test' ).innerHTML = response;
8
+ });
9
+ };
10
+
11
+ function test_video_thumbnail_markup_detection() {
12
+ var data = {
13
+ action: 'video_thumbnail_markup_detection_test',
14
+ markup: jQuery('#markup-input').val()
15
+ };
16
+ document.getElementById( 'markup-test-result' ).innerHTML = '<p>Working...</p>';
17
+ jQuery.post(ajaxurl, data, function(response){
18
+ document.getElementById( 'markup-test-result' ).innerHTML = response;
19
+ });
20
+ }
php/class-video-thumbnails-settings.php ADDED
@@ -0,0 +1,631 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ class Video_Thumbnails_Settings {
20
+
21
+ public $options;
22
+
23
+ var $default_options = array(
24
+ 'save_media' => 1,
25
+ 'set_featured' => 1,
26
+ 'post_types' => array( 'post' ),
27
+ 'custom_field' => ''
28
+ );
29
+
30
+ function __construct() {
31
+ // Activation and deactivation hooks
32
+ register_activation_hook( VIDEO_THUMBNAILS_PATH . '/video-thumbnails.php', array( &$this, 'plugin_activation' ) );
33
+ register_deactivation_hook( VIDEO_THUMBNAILS_PATH . '/video-thumbnails.php', array( &$this, 'plugin_deactivation' ) );
34
+ // Set current options
35
+ add_action( 'plugins_loaded', array( &$this, 'set_options' ) );
36
+ // Add options page to menu
37
+ add_action( 'admin_menu', array( &$this, 'admin_menu' ) );
38
+ // Initialize options
39
+ add_action( 'admin_init', array( &$this, 'initialize_options' ) );
40
+ // Ajax past search callback
41
+ add_action( 'wp_ajax_past_video_thumbnail', array( &$this, 'ajax_past_callback' ) );
42
+ // Ajax past search callback
43
+ add_action( 'wp_ajax_clear_all_video_thumbnails', array( &$this, 'ajax_clear_all_callback' ) );
44
+ // Ajax test callbacks
45
+ add_action( 'wp_ajax_video_thumbnail_provider_test', array( &$this, 'provider_test_callback' ) ); // Provider test
46
+ add_action( 'wp_ajax_video_thumbnail_saving_media_test', array( &$this, 'saving_media_test_callback' ) ); // Saving media test
47
+ add_action( 'wp_ajax_video_thumbnail_markup_detection_test', array( &$this, 'markup_detection_test_callback' ) ); // Markup input test
48
+ // Settings page actions
49
+ if ( isset ( $_GET['page'] ) && ( $_GET['page'] == 'video_thumbnails' ) ) {
50
+ // Admin scripts
51
+ add_action( 'admin_enqueue_scripts', array( &$this, 'admin_scripts' ) );
52
+ // Ajax past posts script
53
+ add_action( 'admin_head', array( &$this, 'ajax_past_script' ) );
54
+ }
55
+ }
56
+
57
+ // Activation hook
58
+ function plugin_activation() {
59
+ add_option( 'video_thumbnails', $this->default_options );
60
+ }
61
+
62
+ // Deactivation hook
63
+ function plugin_deactivation() {
64
+ delete_option( 'video_thumbnails' );
65
+ }
66
+
67
+ // Set options & possibly upgrade
68
+ function set_options() {
69
+ // Get the current options from the database
70
+ $options = get_option( 'video_thumbnails' );
71
+ // If there aren't any options, load the defaults
72
+ if ( ! $options ) $options = $this->default_options;
73
+ // Check if our options need upgrading
74
+ $options = $this->upgrade_options( $options );
75
+ // Set the options class variable
76
+ $this->options = $options;
77
+ }
78
+
79
+ function upgrade_options( $options ) {
80
+
81
+ // Boolean for if options need updating
82
+ $options_need_updating = false;
83
+
84
+ // If there isn't a settings version we need to check for pre 2.0 settings
85
+ if ( ! isset( $options['version'] ) ) {
86
+
87
+ // Check for post type setting
88
+ $post_types = get_option( 'video_thumbnails_post_types' );
89
+
90
+ // If there is a a post type option we know there should be others
91
+ if ( $post_types !== false ) {
92
+
93
+ $options['post_types'] = $post_types;
94
+ delete_option( 'video_thumbnails_post_types' );
95
+
96
+ $options['save_media'] = get_option( 'video_thumbnails_save_media' );
97
+ delete_option( 'video_thumbnails_save_media' );
98
+
99
+ $options['set_featured'] = get_option( 'video_thumbnails_set_featured' );
100
+ delete_option( 'video_thumbnails_set_featured' );
101
+
102
+ $options['custom_field'] = get_option( 'video_thumbnails_custom_field' );
103
+ delete_option( 'video_thumbnails_custom_field' );
104
+
105
+ }
106
+
107
+ // Updates the options version to 2.0
108
+ $options['version'] = '2.0';
109
+ $options_need_updating = true;
110
+
111
+ }
112
+
113
+ // Save options to database if they've been updated
114
+ if ( $options_need_updating ) {
115
+ update_option( 'video_thumbnails', $options );
116
+ }
117
+
118
+ return $options;
119
+
120
+ }
121
+
122
+ function admin_menu() {
123
+ add_options_page(
124
+ 'Video Thumbnail Options',
125
+ 'Video Thumbnails',
126
+ 'manage_options',
127
+ 'video_thumbnails',
128
+ array( &$this, 'options_page' )
129
+ );
130
+ }
131
+
132
+ function admin_scripts() {
133
+ wp_enqueue_script( 'video_thumbnails_test', plugins_url( 'js/test.js' , VIDEO_THUMBNAILS_PATH . '/video-thumbnails.php' ) );
134
+ wp_enqueue_script( 'video_thumbnails_clear', plugins_url( 'js/clear.js' , VIDEO_THUMBNAILS_PATH . '/video-thumbnails.php' ) );
135
+ }
136
+
137
+ function ajax_past_script() {
138
+
139
+ ?><!-- Video Thumbnails Past Post Ajax -->
140
+ <script type="text/javascript">
141
+ function video_thumbnails_past(id) {
142
+
143
+ var data = {
144
+ action: 'past_video_thumbnail',
145
+ post_id: id
146
+ };
147
+
148
+ // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
149
+ jQuery.post(ajaxurl, data, function(response){
150
+
151
+ document.getElementById(id+'_result').innerHTML = response;
152
+
153
+ });
154
+
155
+ };
156
+ <?php
157
+ $posts = get_posts( array(
158
+ 'showposts' => -1,
159
+ 'post_type' => $this->options['post_types']
160
+ ) );
161
+
162
+ if ( $posts ) {
163
+ foreach ( $posts as $post ) {
164
+ $post_ids[] = $post->ID;
165
+ }
166
+ $ids = implode( ', ', $post_ids );
167
+ }
168
+ ?>
169
+
170
+ var scanComplete = false;
171
+
172
+ function scan_video_thumbnails(){
173
+
174
+ if(scanComplete==false){
175
+ scanComplete = true;
176
+ var ids = new Array(<?php echo $ids; ?>);
177
+ for (var i = 0; i < ids.length; i++){
178
+ var container = document.getElementById('video-thumbnails-past');
179
+ var new_element = document.createElement('li');
180
+ new_element.setAttribute('id',ids[i]+'_result');
181
+ new_element.innerHTML = 'Waiting...';
182
+ container.insertBefore(new_element, container.firstChild);
183
+ }
184
+ for (var i = 0; i < ids.length; i++){
185
+ document.getElementById(ids[i]+'_result').innerHTML = '<span style="color:yellow">&#8226;</span> Working...';
186
+ video_thumbnails_past(ids[i]);
187
+ }
188
+ } else {
189
+ alert('Scan has already been run, please reload the page before trying again.')
190
+ }
191
+
192
+ }
193
+ </script><?php
194
+
195
+ }
196
+
197
+ function ajax_past_callback() {
198
+ global $wpdb; // this is how you get access to the database
199
+
200
+ $post_id = $_POST['post_id'];
201
+
202
+ echo get_the_title( $post_id ) . ' - ';
203
+
204
+ $video_thumbnail = get_video_thumbnail( $post_id );
205
+
206
+ if ( is_wp_error( $video_thumbnail ) ) {
207
+ echo $video_thumbnail->get_error_message();
208
+ } else if ( $video_thumbnail != null ) {
209
+ echo '<span style="color:green">&#10004;</span> Success!';
210
+ } else {
211
+ echo '<span style="color:red">&#10006;</span> Couldn\'t find a video thumbnail for this post.';
212
+ }
213
+
214
+ die();
215
+ }
216
+
217
+ function ajax_clear_all_callback() {
218
+ if ( wp_verify_nonce( $_POST['nonce'], 'clear_all_video_thumbnails' ) ) {
219
+ global $wpdb;
220
+ // Clear images from media library
221
+ $media_library_items = get_posts( array(
222
+ 'showposts' => -1,
223
+ 'post_type' => 'attachment',
224
+ 'meta_key' => 'video_thumbnail',
225
+ 'meta_value' => '1',
226
+ 'fields' => 'ids'
227
+ ) );
228
+ foreach ( $media_library_items as $item ) {
229
+ wp_delete_attachment( $item, true );
230
+ }
231
+ echo '<p><span style="color:green">&#10004;</span> ' . sprintf( _n( '1 attachment deleted', '%s attachments deleted', count( $media_library_items ), 'video-thumbnails' ), count( $media_library_items ) ) . '</p>';
232
+ // Clear custom fields
233
+ $custom_fields_cleared = $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key='_video_thumbnail'" );
234
+ echo '<p><span style="color:green">&#10004;</span> ' . sprintf( _n( '1 custom field cleared', '%s custom fields cleared', $custom_fields_cleared, 'video-thumbnails' ), $custom_fields_cleared ) . '</p>';
235
+ } else {
236
+ echo '<p><span style="color:red">&#10006;</span> <strong>Error</strong>: Could not verify nonce.</p>';
237
+ }
238
+
239
+ die();
240
+ }
241
+
242
+ function provider_test_callback() {
243
+
244
+ global $video_thumbnails;
245
+
246
+ ?>
247
+ <table class="widefat">
248
+ <thead>
249
+ <tr>
250
+ <th>Name</th>
251
+ <th>Pass/Fail</th>
252
+ <th>Result</th>
253
+ </tr>
254
+ </thead>
255
+ <tbody>
256
+ <?php
257
+ $passed = 0;
258
+ $failed = 0;
259
+ foreach ( $video_thumbnails->providers as $provider ) {
260
+ foreach ( $provider->test_cases as $test_case ) {
261
+ $result = $provider->scan_for_thumbnail( $test_case['markup'] );
262
+ $result = explode( '?', $result );
263
+ $result = $result[0];
264
+ echo '<tr>';
265
+ echo '<td><strong>' . $provider->service_name . '</strong> - ' . $test_case['name'] . '</td>';
266
+ if ( $result == $test_case['expected'] ) {
267
+ echo '<td style="color:green;">&#10004; Passed</td>';
268
+ $passed++;
269
+ } else {
270
+ echo '<td style="color:red;">&#10007; Failed</td>';
271
+ $failed++;
272
+ if ( is_wp_error( $result ) ) echo $result->get_error_message();
273
+ }
274
+ echo '<td>' . $result . '</td>';
275
+ echo '</tr>';
276
+ }
277
+ } ?>
278
+ <tbody>
279
+ <tfoot>
280
+ <tr>
281
+ <th></th>
282
+ <th><span style="color:green;">&#10004; <?php echo $passed; ?></span> / <span style="color:red;">&#10007; <?php echo $failed; ?></span></th>
283
+ <th></th>
284
+ </tr>
285
+ </tfoot>
286
+ </table>
287
+ <?php die();
288
+ } // End provider test callback
289
+
290
+ function saving_media_test_callback() {
291
+
292
+ // Try saving 'http://img.youtube.com/vi/dMH0bHeiRNg/0.jpg' to media library
293
+ $attachment_id = Video_Thumbnails::save_to_media_library( 'http://img.youtube.com/vi/dMH0bHeiRNg/0.jpg', 1 );
294
+ if ( is_wp_error( $attachment_id ) ) {
295
+ echo '<p><span style="color:red;">&#10006;</span> ' . $attachment_id->get_error_message() . '</p>';
296
+ } else {
297
+ echo '<p><span style="color:green;">&#10004;</span>Attachment created with an ID of ' . $attachment_id . '</p>';
298
+ wp_delete_attachment( $attachment_id, true );
299
+ echo '<p><span style="color:green;">&#10004;</span>Attachment with an ID of ' . $attachment_id . ' deleted</p>';
300
+ }
301
+
302
+ die();
303
+ } // End saving media test callback
304
+
305
+ function markup_detection_test_callback() {
306
+
307
+ $new_thumbnail = null;
308
+
309
+ global $video_thumbnails;
310
+
311
+ foreach ( $video_thumbnails->providers as $provider ) {
312
+ $new_thumbnail = $provider->scan_for_thumbnail( stripslashes( $_POST['markup'] ) );
313
+ if ( $new_thumbnail != null ) break;
314
+ }
315
+
316
+ if ( $new_thumbnail == null ) {
317
+ echo '<p><span style="color:red;">&#10006;</span> No thumbnail found</p>';
318
+ } elseif ( is_wp_error( $new_thumbnail ) ) {
319
+ echo '<p><span style="color:red;">&#10006;</span> Error: ' . $new_thumbnail->get_error_message() . '</p>';
320
+ } else {
321
+ echo '<p><span style="color:green;">&#10004;</span> Thumbnail found! <a href="' . $new_thumbnail . '" target="_blank">View full size</a></p>';
322
+ echo '<p><img src="' . $new_thumbnail . '" style="max-width: 500px;"></p>';
323
+ }
324
+
325
+ die();
326
+ } // End markup detection test callback
327
+
328
+ function initialize_options() {
329
+ add_settings_section(
330
+ 'general_settings_section',
331
+ 'General Settings',
332
+ array( &$this, 'general_settings_callback' ),
333
+ 'video_thumbnails'
334
+ );
335
+ $this->add_checkbox_setting(
336
+ 'save_media',
337
+ 'Save Thumbnails to Media Library',
338
+ 'Checking this option will download video thumbnails to your server'
339
+ );
340
+ $this->add_checkbox_setting(
341
+ 'set_featured',
342
+ 'Automatically Set Featured Image',
343
+ 'Check this option to automatically set video thumbnails as the featured image (requires saving to media library)'
344
+ );
345
+ // Get post types
346
+ $post_types = get_post_types( null, 'names' );
347
+ // Remove certain post types from array
348
+ $post_types = array_diff( $post_types, array( 'attachment', 'revision', 'nav_menu_item' ) );
349
+ $this->add_multicheckbox_setting(
350
+ 'post_types',
351
+ 'Post Types',
352
+ $post_types
353
+ );
354
+ $this->add_text_setting(
355
+ 'custom_field',
356
+ 'Custom Field (optional)',
357
+ 'Enter the name of the custom field where your embed code or video URL is stored.'
358
+ );
359
+ register_setting( 'video_thumbnails', 'video_thumbnails', array( &$this, 'sanitize_callback' ) );
360
+ }
361
+
362
+ function sanitize_callback( $input ) {
363
+ $current_settings = get_option( 'video_thumbnails' );
364
+ $output = array();
365
+ // General settings
366
+ if ( !isset( $input['provider_options'] ) ) {
367
+ foreach( $current_settings as $key => $value ) {
368
+ if ( $key == 'version' OR $key == 'providers' ) {
369
+ $output[$key] = $current_settings[$key];
370
+ } elseif ( isset( $input[$key] ) ) {
371
+ $output[$key] = $input[$key];
372
+ } else {
373
+ $output[$key] = '';
374
+ }
375
+ }
376
+ }
377
+ // Provider settings
378
+ else {
379
+ $output = $current_settings;
380
+ unset( $output['providers'] );
381
+ $output['providers'] = $input['providers'];
382
+ }
383
+ return $output;
384
+ }
385
+
386
+ function general_settings_callback() {
387
+ echo '<p>These options configure where the plugin will search for videos and what to do with thumbnails once found.</p>';
388
+ }
389
+
390
+ function add_checkbox_setting( $slug, $name, $description ) {
391
+ add_settings_field(
392
+ $slug,
393
+ $name,
394
+ array( &$this, 'checkbox_callback' ),
395
+ 'video_thumbnails',
396
+ 'general_settings_section',
397
+ array(
398
+ 'slug' => $slug,
399
+ 'description' => $description
400
+ )
401
+ );
402
+ }
403
+
404
+ function checkbox_callback( $args ) {
405
+ $html = '<label for="' . $args['slug'] . '"><input type="checkbox" id="' . $args['slug'] . '" name="video_thumbnails[' . $args['slug'] . ']" value="1" ' . checked( 1, $this->options[$args['slug']], false ) . '/> ' . $args['description'] . '</label>';
406
+ echo $html;
407
+ }
408
+
409
+ function add_multicheckbox_setting( $slug, $name, $options ) {
410
+ add_settings_field(
411
+ $slug,
412
+ $name,
413
+ array( &$this, 'multicheckbox_callback' ),
414
+ 'video_thumbnails',
415
+ 'general_settings_section',
416
+ array(
417
+ 'slug' => $slug,
418
+ 'options' => $options
419
+ )
420
+ );
421
+ }
422
+
423
+ function multicheckbox_callback( $args ) {
424
+ if ( is_array( $this->options[$args['slug']] ) ) {
425
+ $selected_types = $this->options[$args['slug']];
426
+ } else {
427
+ $selected_types = array();
428
+ }
429
+ $html = '';
430
+ foreach ( $args['options'] as $option ) {
431
+ $checked = ( in_array( $option, $selected_types ) ? 'checked="checked"' : '' );
432
+ $html .= '<label for="' . $args['slug'] . '_' . $option . '"><input type="checkbox" id="' . $args['slug'] . '_' . $option . '" name="video_thumbnails[' . $args['slug'] . '][]" value="' . $option . '" ' . $checked . '/> ' . $option . '</label><br>';
433
+ }
434
+ echo $html;
435
+ }
436
+
437
+ function add_text_setting( $slug, $name, $description ) {
438
+ add_settings_field(
439
+ $slug,
440
+ $name,
441
+ array( &$this, 'text_field_callback' ),
442
+ 'video_thumbnails',
443
+ 'general_settings_section',
444
+ array(
445
+ 'slug' => $slug,
446
+ 'description' => $description
447
+ )
448
+ );
449
+ }
450
+
451
+ function text_field_callback( $args ) {
452
+ $html = '<input type="text" id="' . $args['slug'] . '" name="video_thumbnails[' . $args['slug'] . ']" value="' . $this->options[$args['slug']] . '"/>';
453
+ $html .= '<label for="' . $args['slug'] . '"> ' . $args['description'] . '</label>';
454
+ echo $html;
455
+ }
456
+
457
+ function options_page() {
458
+
459
+ if ( ! current_user_can( 'manage_options' ) ) {
460
+ wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
461
+ }
462
+
463
+ ?><div class="wrap">
464
+
465
+ <div id="icon-options-general" class="icon32"></div><h2>Video Thumbnails Options</h2>
466
+
467
+ <?php $active_tab = isset( $_GET[ 'tab' ] ) ? $_GET[ 'tab' ] : 'general_settings'; ?>
468
+ <h2 class="nav-tab-wrapper">
469
+ <a href="?page=video_thumbnails&tab=general_settings" class="nav-tab <?php echo $active_tab == 'general_settings' ? 'nav-tab-active' : ''; ?>">General</a>
470
+ <a href="?page=video_thumbnails&tab=provider_settings" class="nav-tab <?php echo $active_tab == 'provider_settings' ? 'nav-tab-active' : ''; ?>">Providers</a>
471
+ <a href="?page=video_thumbnails&tab=mass_actions" class="nav-tab <?php echo $active_tab == 'mass_actions' ? 'nav-tab-active' : ''; ?>">Mass Actions</a>
472
+ <a href="?page=video_thumbnails&tab=debugging" class="nav-tab <?php echo $active_tab == 'debugging' ? 'nav-tab-active' : ''; ?>">Debugging</a>
473
+ </h2>
474
+
475
+ <?php
476
+ // Main settings
477
+ if ( $active_tab == 'general_settings' ) {
478
+ ?>
479
+ <h3>Getting started</h3>
480
+
481
+ <p>If your theme supports post thumbnails, just leave "Save Thumbnails to Media Library" and "Automatically Set Featured Image" enabled, then select what post types you'd like scanned for videos.</p>
482
+
483
+ <p>For more detailed instructions, check out the page for <a href="http://wordpress.org/extend/plugins/video-thumbnails/">Video Thumbnails on the official plugin directory</a>.</p>
484
+
485
+ <form method="post" action="options.php">
486
+ <?php settings_fields( 'video_thumbnails' ); ?>
487
+ <?php do_settings_sections( 'video_thumbnails' ); ?>
488
+ <?php submit_button(); ?>
489
+ </form>
490
+
491
+ <?php
492
+ // End main settings
493
+ }
494
+ // Provider Settings
495
+ if ( $active_tab == 'provider_settings' ) {
496
+ ?>
497
+
498
+ <form method="post" action="options.php">
499
+ <input type="hidden" name="video_thumbnails[provider_options]" value="1" />
500
+ <?php settings_fields( 'video_thumbnails' ); ?>
501
+ <?php do_settings_sections( 'video_thumbnails_providers' ); ?>
502
+ <?php submit_button(); ?>
503
+ </form>
504
+
505
+ <?php
506
+ // End provider settings
507
+ }
508
+ // Scan all posts
509
+ if ( $active_tab == 'mass_actions' ) {
510
+ ?>
511
+ <h3>Scan All Posts</h3>
512
+
513
+ <p>Scan all of your past posts for video thumbnails. Be sure to save any settings before running the scan.</p>
514
+
515
+ <p><input type="submit" class="button-primary" onclick="scan_video_thumbnails();" value="Scan Past Posts" /></p>
516
+
517
+ <ol id="video-thumbnails-past">
518
+ </ol>
519
+
520
+ <h3>Clear all Video Thumbnails</h3>
521
+
522
+ <p>This will clear the video thumbnail field for all posts and delete any video thumbnail attachments. Note: This only works for attachments added using version 2.0 or later.</p>
523
+
524
+ <p><input type="submit" class="button-primary" onclick="clear_all_video_thumbnails('<?php echo wp_create_nonce( 'clear_all_video_thumbnails' ); ?>');" value="Clear Video Thumbnails" /></p>
525
+
526
+ <div id="clear-all-video-thumbnails-result"></div>
527
+
528
+ <?php
529
+ // End scan all posts
530
+ }
531
+ // Debugging
532
+ if ( $active_tab == 'debugging' ) {
533
+ ?>
534
+
535
+ <p>Use these tests to help diagnose any problems. Please include results when requesting support.</p>
536
+
537
+ <h3>Test Thumbnail Providers</h3>
538
+
539
+ <p>This test automatically searches a sample for every type of video supported and compares it to the expected value. Sometimes tests may fail due to API rate limits.</p>
540
+
541
+ <div id="provider-test">
542
+ <p><input type="submit" class="button-primary" onclick="test_video_thumbnail('provider');" value="Test Providers" /></p>
543
+ </div>
544
+
545
+ <h3>Test Markup for Video</h3>
546
+
547
+ <p>Copy and paste an embed code below to see if a video is detected.</p>
548
+
549
+ <textarea id="markup-input" cols="50" rows="5"></textarea>
550
+
551
+ <p><input type="submit" class="button-primary" onclick="test_video_thumbnail_markup_detection();" value="Scan For Thumbnail" /></p>
552
+
553
+ <div id="markup-test-result"></div>
554
+
555
+ <h3>Test Saving to Media Library</h3>
556
+
557
+ <p>This test checks for issues with the process of saving a remote thumbnail to your local media library.</p>
558
+
559
+ <div id="saving_media-test">
560
+ <p><input type="submit" class="button-primary" onclick="test_video_thumbnail('saving_media');" value="Test Image Downloading" /></p>
561
+ </div>
562
+
563
+ <h3>Installation Information</h3>
564
+ <table class="widefat">
565
+ <thead>
566
+ <tr>
567
+ <th></th>
568
+ <th></th>
569
+ <th></th>
570
+ </tr>
571
+ </thead>
572
+ <tbody>
573
+ <tr>
574
+ <td><strong>WordPress Version</strong></td>
575
+ <td><?php echo get_bloginfo( 'version' ); ?></td>
576
+ <td></td>
577
+ </tr>
578
+ <tr>
579
+ <td><strong>Video Thumbnails Version</strong></td>
580
+ <td><?php echo VIDEO_THUMBNAILS_VERSION; ?></td>
581
+ <td></td>
582
+ </tr>
583
+ <tr>
584
+ <td><strong>Video Thumbnails Settings Version</strong></td>
585
+ <td><?php echo $this->options['version']; ?></td>
586
+ <td></td>
587
+ </tr>
588
+ <tr>
589
+ <td><strong>PHP Version</strong></td>
590
+ <td><?php echo PHP_VERSION; ?></td>
591
+ <td></td>
592
+ </tr>
593
+ <tr>
594
+ <td><strong>Post Thumbnails</strong></td>
595
+ <td><?php if ( current_theme_supports( 'post-thumbnails' ) ) : ?><span style="color:green">&#10004;</span> Your theme supports post thumbnails.<?php else: ?><span style="color:red">&#10006;</span> Your theme doesn't support post thumbnails, you'll need to make modifications or switch to a different theme. <a href="http://codex.wordpress.org/Post_Thumbnails">More info</a><?php endif; ?></td>
596
+ <td></td>
597
+ </tr>
598
+ <tr>
599
+ <td><strong>Active Providers</strong></td>
600
+ <td>
601
+ <?php global $video_thumbnails; ?>
602
+ <?php $provider_names = array(); foreach ( $video_thumbnails->providers as $provider ) { $provider_names[] = $provider->service_name; }; ?>
603
+ <strong><?php echo count( $video_thumbnails->providers ); ?></strong>: <?php echo implode( ', ', $provider_names ); ?>
604
+ </td>
605
+ <td></td>
606
+ </tr>
607
+ </tbody>
608
+ <tfoot>
609
+ <tr>
610
+ <th></th>
611
+ <th></th>
612
+ <th></th>
613
+ </tr>
614
+ </tfoot>
615
+ </table>
616
+
617
+ <?php
618
+ // End debugging
619
+ }
620
+ ?>
621
+
622
+ <div style="width: 250px; margin: 20px 0; padding: 0 20px; background: #f5f5f5; border: 1px solid #dfdfdf; text-align: center; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px;">
623
+ <p>All donations are appreciated!<form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_s-xclick"><input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYB1rPWk/Rr89ydxDsoXWyYIlAwIORRiWzcLHSBBVBMY69PHCO6WVTK2lXYmjZbDrvrHmN/jrM5r3Q008oX19NujzZ4d1VV+dWZxPU+vROuLToOFkk3ivjcvlT825HfdZRoiY/eTwWfBH93YQ+3kAAdc2s3FRxVyC4cUdrtbkBmYpDELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIkO3IVfkE9PGAgaA9fgOdXrQSpdGgo8ZgjiOxDGlEHoRL51gvB6AZdhNCubfLbqolJjYfTPEMg6Z0dfrq3hVSF2+nLV7BRcmXAtxY5NkH7vu1Kv0Bsb5kDOWb8h4AfnwElD1xyaykvYAr7CRNqHcizYRXZHKE7elWY0w6xRV/bfE7w6E4ZjKvFowHFp9E7/3mcZDrqxbZVU5hqs5gsV2YJj8fNBzG1bbdTucXoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTExMDA3MDUzMjM1WjAjBgkqhkiG9w0BCQQxFgQUHXhTYmeIfU7OyslesSVlGviqHbIwDQYJKoZIhvcNAQEBBQAEgYDAU3s+ej0si2FdN0uZeXhR+GGCDOMSYbkRswu7K3TRDXoD9D9c67VjQ+GfqP95cA9s40aT73goH+AxPbiQhG64OaHZZGJeSmwiGiCo4rBoVPxNUDONMPWaYfp6vm3Mt41gbxUswUEDNnzps4waBsFRJvuFjbbeQVYg7wbVfQC99Q==-----END PKCS7-----"><input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"><img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1"></form></p>
624
+ </div>
625
+
626
+ </div><?php
627
+ }
628
+
629
+ }
630
+
631
+ ?>
php/extensions/class-ayvp-thumbnails.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail extension class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/extensions/class-video-thumbnails-extension.php' );
21
+
22
+ // Require YouTube provider class
23
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-youtube-thumbnails.php' );
24
+
25
+ class AYVP_Thumbnails extends Video_Thumbnails_Extension {
26
+
27
+ public static function new_thumbnail( $new_thumbnail, $post_id ) {
28
+ if ( $new_thumbnail == null ) {
29
+ $youtube_id = get_post_meta( $post_id, '_tern_wp_youtube_video', true );
30
+ if ( $youtube_id != '' ) {
31
+ $new_thumbnail = YouTube_Thumbnails::get_thumbnail_url( $youtube_id );
32
+ }
33
+ }
34
+ return $new_thumbnail;
35
+ }
36
+
37
+ }
38
+
39
+ // Make sure we can use is_plugin_active()
40
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
41
+
42
+ // If AYVP is active, add filter
43
+ if ( is_plugin_active( 'automatic-youtube-video-posts/tern_wp_youtube.php' ) ) {
44
+ add_filter( 'new_video_thumbnail_url', array( 'AYVP_Thumbnails', 'new_thumbnail' ), 10, 2 );
45
+ remove_filter( 'post_thumbnail_html', 'WP_ayvpp_thumbnail' );
46
+ remove_filter( 'post_thumbnail_size', 'WP_ayvpp_thumbnail_size' );
47
+ }
48
+
49
+ ?>
php/extensions/class-simple-video-embedder-thumbnails.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail extension class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/extensions/class-video-thumbnails-extension.php' );
21
+
22
+ class Simple_Video_Embedder_Thumbnails extends Video_Thumbnails_Extension {
23
+
24
+ public static function markup( $markup, $post_id ) {
25
+ if ( function_exists( 'p75HasVideo' ) ) {
26
+ if ( p75HasVideo( $post_id ) ) {
27
+ $markup .= ' ' . p75GetVideo( $post_id );
28
+ }
29
+ }
30
+ return $markup;
31
+ }
32
+
33
+ }
34
+
35
+ // Add filter to modify markup
36
+ add_filter( 'video_thumbnail_markup', array( 'Simple_Video_Embedder_Thumbnails', 'markup' ), 10, 2 );
37
+
38
+ ?>
php/extensions/class-video-thumbnails-extension.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ class Video_Thumbnails_Extension {
20
+
21
+ function __construct() {
22
+ if ( method_exists( $this, 'settings_section') ) add_action( 'video_thumbnails_provider_options', array( &$this, 'settings_section' ) );
23
+ }
24
+
25
+ }
26
+
27
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/extensions/class-simple-video-embedder-thumbnails.php' );
28
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/extensions/class-ayvp-thumbnails.php' );
29
+
30
+ ?>
php/providers/class-blip-thumbnails.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Blip_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Blip';
26
+ const service_name = 'Blip';
27
+ // Slug for the video provider
28
+ public $service_slug = 'blip';
29
+ const service_slug = 'blip';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#http://blip\.tv/play/([^.]+)\.#' // Embed URL
39
+ );
40
+
41
+ // Thumbnail URL
42
+ public function get_thumbnail_url( $id ) {
43
+ $request = "http://blip.tv/players/episode/$id?skin=rss";
44
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
45
+ if( is_wp_error( $response ) ) {
46
+ $result = new WP_Error( 'blip_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
47
+ } else {
48
+ $xml = new SimpleXMLElement( $response['body'] );
49
+ $result = $xml->xpath( "/rss/channel/item/media:thumbnail/@url" );
50
+ $result = (string) $result[0]['url'];
51
+ }
52
+ return $result;
53
+ }
54
+
55
+ // Test cases
56
+ public $test_cases = array(
57
+ array(
58
+ 'markup' => '<iframe src="http://blip.tv/play/AYL1uFkC.html?p=1" width="780" height="438" frameborder="0" allowfullscreen></iframe><embed type="application/x-shockwave-flash" src="http://a.blip.tv/api.swf#AYL1uFkC" style="display:none"></embed>',
59
+ 'expected' => 'http://a.images.blip.tv/ReelScience-TheScientificMethodOfOz139.jpg',
60
+ 'name' => 'iFrame player'
61
+ ),
62
+ array(
63
+ 'markup' => '<iframe src="http://blip.tv/play/AYLz%2BEsC.html?p=1" width="780" height="438" frameborder="0" allowfullscreen></iframe><embed type="application/x-shockwave-flash" src="http://a.blip.tv/api.swf#AYLz+EsC" style="display:none"></embed>',
64
+ 'expected' => 'http://a.images.blip.tv/GeekCrashCourse-TheAvengersMarvelMovieCatchUpGeekCrashCourse331.png',
65
+ 'name' => 'iFrame player (special characters in ID)'
66
+ ),
67
+ );
68
+
69
+ }
70
+
71
+ // Add to provider array
72
+ add_filter( 'video_thumbnail_providers', array( 'Blip_Thumbnails', 'register_provider' ) );
73
+
74
+ ?>
php/providers/class-collegehumor-thumbnails.php ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class CollegeHumor_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'CollegeHumor';
26
+ const service_name = 'CollegeHumor';
27
+ // Slug for the video provider
28
+ public $service_slug = 'collegehumor';
29
+ const service_slug = 'collegehumor';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#https?://(?:www\.)?collegehumor\.com/(?:video|e)/([0-9]+)#' // URL
39
+ );
40
+
41
+ // Thumbnail URL
42
+ public function get_thumbnail_url( $id ) {
43
+ $request = "http://www.collegehumor.com/oembed.json?url=http%3A%2F%2Fwww.collegehumor.com%2Fvideo%2F$id";
44
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
45
+ if( is_wp_error( $response ) ) {
46
+ $result = new WP_Error( 'collegehumor_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
47
+ } else {
48
+ $result = json_decode( $response['body'] );
49
+ $result = $result->thumbnail_url;
50
+ }
51
+ return $result;
52
+ }
53
+
54
+ // Test cases
55
+ public $test_cases = array(
56
+ array(
57
+ 'markup' => '<iframe src="http://www.collegehumor.com/e/6830834" width="600" height="338" frameborder="0" webkitAllowFullScreen allowFullScreen></iframe><div style="padding:5px 0; text-align:center; width:600px;"><p><a href="http://www.collegehumor.com/videos/most-viewed/this-year">CollegeHumor\'s Favorite Funny Videos</a></p></div>',
58
+ 'expected' => 'http://2.media.collegehumor.cvcdn.com/62/99/20502ca0d5b2172421002b52f437dcf8-mitt-romney-style-gangnam-style-parody.jpg',
59
+ 'name' => 'Embed'
60
+ ),
61
+ array(
62
+ 'markup' => 'http://www.collegehumor.com/video/6830834/mitt-romney-style-gangnam-style-parody',
63
+ 'expected' => 'http://2.media.collegehumor.cvcdn.com/62/99/20502ca0d5b2172421002b52f437dcf8-mitt-romney-style-gangnam-style-parody.jpg',
64
+ 'name' => 'URL'
65
+ ),
66
+ );
67
+
68
+ }
69
+
70
+ // Add to provider array
71
+ add_filter( 'video_thumbnail_providers', array( 'CollegeHumor_Thumbnails', 'register_provider' ) );
72
+
73
+ ?>
php/providers/class-dailymotion-thumbnails.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Dailymotion_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Dailymotion';
26
+ const service_name = 'Dailymotion';
27
+ // Slug for the video provider
28
+ public $service_slug = 'dailymotion';
29
+ const service_slug = 'dailymotion';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#<object[^>]+>.+?http://www\.dailymotion\.com/swf/video/([A-Za-z0-9]+).+?</object>#s', // Dailymotion flash
39
+ '#https?://www\.dailymotion\.com/embed/video/([A-Za-z0-9]+)#', // Dailymotion iframe
40
+ '#(?:https?://)?(?:www\.)?dailymotion\.com/video/([A-Za-z0-9]+)#' // Dailymotion URL
41
+ );
42
+
43
+ // Thumbnail URL
44
+ public function get_thumbnail_url( $id ) {
45
+ $request = "https://api.dailymotion.com/video/$id?fields=thumbnail_url";
46
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
47
+ if( is_wp_error( $response ) ) {
48
+ $result = new WP_Error( 'dailymotion_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
49
+ } else {
50
+ $result = json_decode( $response['body'] );
51
+ $result = $result->thumbnail_url;
52
+ }
53
+ return $result;
54
+ }
55
+
56
+ // Test cases
57
+ public $test_cases = array(
58
+ array(
59
+ 'markup' => '<iframe frameborder="0" width="480" height="270" src="http://www.dailymotion.com/embed/video/xqlhts"></iframe><br /><a href="http://www.dailymotion.com/video/xqlhts_adam-yauch-of-the-beastie-boys-dies-at-47_people" target="_blank">Adam Yauch of the Beastie Boys Dies at 47</a> <i>by <a href="http://www.dailymotion.com/associatedpress" target="_blank">associatedpress</a></i>',
60
+ 'expected' => 'http://s1.dmcdn.net/AMjdy.jpg',
61
+ 'name' => 'iFrame player'
62
+ ),
63
+ array(
64
+ 'markup' => '<object width="480" height="270"><param name="movie" value="http://www.dailymotion.com/swf/video/xqlhts"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><param name="wmode" value="transparent"></param><embed type="application/x-shockwave-flash" src="http://www.dailymotion.com/swf/video/xqlhts" width="480" height="270" wmode="transparent" allowfullscreen="true" allowscriptaccess="always"></embed></object><br /><a href="http://www.dailymotion.com/video/xqlhts_adam-yauch-of-the-beastie-boys-dies-at-47_people" target="_blank">Adam Yauch of the Beastie Boys Dies at 47</a> <i>by <a href="http://www.dailymotion.com/associatedpress" target="_blank">associatedpress</a></i>',
65
+ 'expected' => 'http://s1.dmcdn.net/AMjdy.jpg',
66
+ 'name' => 'Flash player'
67
+ ),
68
+ );
69
+
70
+ }
71
+
72
+ // Add to provider array
73
+ add_filter( 'video_thumbnail_providers', array( 'Dailymotion_Thumbnails', 'register_provider' ) );
74
+
75
+ ?>
php/providers/class-facebook-thumbnails.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Facebook_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Facebook';
26
+ const service_name = 'Facebook';
27
+ // Slug for the video provider
28
+ public $service_slug = 'facebook';
29
+ const service_slug = 'facebook';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#"http://www.facebook.com/v/([0-9]+)"#' // Facebook Embed
39
+ );
40
+
41
+ // Thumbnail URL
42
+ public function get_thumbnail_url( $id ) {
43
+ return 'https://graph.facebook.com/' . $id . '/picture';
44
+ }
45
+
46
+ // Test cases
47
+ public $test_cases = array(
48
+ array(
49
+ 'markup' => '<object width=420 height=180><param name=allowfullscreen value=true></param><param name=allowscriptaccess value=always></param><param name=movie value="http://www.facebook.com/v/2560032632599"></param><embed src="http://www.facebook.com/v/2560032632599" type="application/x-shockwave-flash" allowscriptaccess=always allowfullscreen=true width=420 height=180></embed></object>',
50
+ 'expected' => 'https://graph.facebook.com/2560032632599/picture',
51
+ 'name' => 'Embed'
52
+ ),
53
+ );
54
+
55
+ }
56
+
57
+ // Add to provider array
58
+ add_filter( 'video_thumbnail_providers', array( 'Facebook_Thumbnails', 'register_provider' ) );
59
+
60
+ ?>
php/providers/class-funnyordie-thumbnails.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Funnyordie_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Funny or Die';
26
+ const service_name = 'Funny or Die';
27
+ // Slug for the video provider
28
+ public $service_slug = 'funnyordie';
29
+ const service_slug = 'funnyordie';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#http://www\.funnyordie\.com/embed/([A-Za-z0-9]+)#', // Iframe src
39
+ '#id="ordie_player_([A-Za-z0-9]+)"#' // Flash object
40
+ );
41
+
42
+ // Thumbnail URL
43
+ public function get_thumbnail_url( $id ) {
44
+ return 'http://assets0.ordienetworks.com/tmbs/' . $id . '/large_11.jpg';
45
+ }
46
+
47
+ // Test cases
48
+ public $test_cases = array(
49
+ array(
50
+ 'markup' => '<iframe src="http://www.funnyordie.com/embed/5325b03b52" width="640" height="400" frameborder="0"></iframe>',
51
+ 'expected' => 'http://assets0.ordienetworks.com/tmbs/5325b03b52/large_11.jpg',
52
+ 'name' => 'iFrame player'
53
+ ),
54
+ array(
55
+ 'markup' => '<object width="640" height="400" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" id="ordie_player_5325b03b52"><param name="movie" value="http://player.ordienetworks.com/flash/fodplayer.swf" /><param name="flashvars" value="key=5325b03b52" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always"><embed width="640" height="400" flashvars="key=5325b03b52" allowfullscreen="true" allowscriptaccess="always" quality="high" src="http://player.ordienetworks.com/flash/fodplayer.swf" name="ordie_player_5325b03b52" type="application/x-shockwave-flash"></embed></object>',
56
+ 'expected' => 'http://assets0.ordienetworks.com/tmbs/5325b03b52/large_11.jpg',
57
+ 'name' => 'Flash player'
58
+ ),
59
+ );
60
+
61
+ }
62
+
63
+ // Add to provider array
64
+ add_filter( 'video_thumbnail_providers', array( 'Funnyordie_Thumbnails', 'register_provider' ) );
65
+
66
+ ?>
php/providers/class-justintv-thumbnails.php ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Justintv_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Justin.tv';
26
+ const service_name = 'Justin.tv';
27
+ // Slug for the video provider
28
+ public $service_slug = 'justintv';
29
+ const service_slug = 'justintv';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#archive_id=([0-9]+)#' // Archive ID
39
+ );
40
+
41
+ // Thumbnail URL
42
+ public function get_thumbnail_url( $id ) {
43
+ $request = "http://api.justin.tv/api/clip/show/$id.xml";
44
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
45
+ if( is_wp_error( $response ) ) {
46
+ $result = new WP_Error( 'justintv_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
47
+ } else {
48
+ $xml = new SimpleXMLElement( $response['body'] );
49
+ $result = (string) $xml->object->image_url_large;
50
+ }
51
+ return $result;
52
+ }
53
+
54
+ // Test cases
55
+ public $test_cases = array(
56
+ array(
57
+ 'markup' => '<object type="application/x-shockwave-flash" height="300" width="400" id="clip_embed_player_flash" data="http://www-cdn.justin.tv/widgets/archive_embed_player.swf" bgcolor="#000000"><param name="movie" value="http://www-cdn.justin.tv/widgets/archive_embed_player.swf" /><param name="allowScriptAccess" value="always" /><param name="allowNetworking" value="all" /><param name="allowFullScreen" value="true" /><param name="flashvars" value="auto_play=false&start_volume=25&title=Title&channel=scamschoolbrian&archive_id=392481524" /></object>',
58
+ 'expected' => 'http://static-cdn.jtvnw.net/jtv.thumbs/archive-392481524-320x240.jpg',
59
+ 'name' => 'Embed'
60
+ ),
61
+ );
62
+
63
+ }
64
+
65
+ // Add to provider array
66
+ add_filter( 'video_thumbnail_providers', array( 'Justintv_Thumbnails', 'register_provider' ) );
67
+
68
+ ?>
php/providers/class-kaltura-thumbnails.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Kaltura_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Kaltura';
26
+ const service_name = 'Kaltura';
27
+ // Slug for the video provider
28
+ public $service_slug = 'kaltura';
29
+ const service_slug = 'kaltura';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#http://cdnapi\.kaltura\.com/p/[0-9]+/sp/[0-9]+/embedIframeJs/uiconf_id/[0-9]+/partner_id/[0-9]+\?entry_id=([a-z0-9_]+)#' // Hosted
39
+ );
40
+
41
+ // Thumbnail URL
42
+ public function get_thumbnail_url( $id ) {
43
+ $request = "http://www.kaltura.com/api_v3/?service=thumbAsset&action=getbyentryid&entryId=$id";
44
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
45
+ if( is_wp_error( $response ) ) {
46
+ $result = new WP_Error( 'kaltura_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
47
+ } else {
48
+ $xml = new SimpleXMLElement( $response['body'] );
49
+ $result = (string) $xml->result->item->id;
50
+ $request = "http://www.kaltura.com/api_v3/?service=thumbAsset&action=geturl&id=$result";
51
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
52
+ if( is_wp_error( $response ) ) {
53
+ $result = new WP_Error( 'kaltura_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
54
+ } else {
55
+ $xml = new SimpleXMLElement( $response['body'] );
56
+ $result = (string) $xml->result;
57
+ }
58
+ }
59
+ return $result;
60
+ }
61
+
62
+ // Test cases
63
+ public $test_cases = array(
64
+ array(
65
+ 'markup' => '<script type="text/javascript" src="http://cdnapi.kaltura.com/p/1374841/sp/137484100/embedIframeJs/uiconf_id/12680902/partner_id/1374841?entry_id=1_y7xzqsxw&playerId=kaltura_player_1363589321&cache_st=1363589321&autoembed=true&width=400&height=333&"></script>',
66
+ 'expected' => 'http://example.com/thumbnail.jpg',
67
+ 'name' => 'Auto embed'
68
+ ),
69
+ );
70
+
71
+ }
72
+
73
+ // Add to provider array
74
+ add_filter( 'video_thumbnail_providers', array( 'Kaltura_Thumbnails', 'register_provider' ) );
75
+
76
+ ?>
php/providers/class-metacafe-thumbnails.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Metacafe_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Metacafe';
26
+ const service_name = 'Metacafe';
27
+ // Slug for the video provider
28
+ public $service_slug = 'metacafe';
29
+ const service_slug = 'metacafe';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#http://www\.metacafe\.com/fplayer/([A-Za-z0-9\-_]+)/#' // Metacafe embed
39
+ );
40
+
41
+ // Thumbnail URL
42
+ public function get_thumbnail_url( $id ) {
43
+ $request = "http://www.metacafe.com/api/item/$id/";
44
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
45
+ if( is_wp_error( $response ) ) {
46
+ $result = new WP_Error( 'metacafe_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
47
+ } else {
48
+ $xml = new SimpleXMLElement( $response['body'] );
49
+ $result = $xml->xpath( "/rss/channel/item/media:thumbnail/@url" );
50
+ $result = (string) $result[0]['url'];
51
+ }
52
+ return $result;
53
+ }
54
+
55
+ // Test cases
56
+ public $test_cases = array(
57
+ array(
58
+ 'markup' => '<embed flashVars="playerVars=autoPlay=no" src="http://www.metacafe.com/fplayer/8456223/men_in_black_3_trailer_2.swf" width="440" height="248" wmode="transparent" allowFullScreen="true" allowScriptAccess="always" name="Metacafe_8456223" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"></embed>',
59
+ 'expected' => 'http://s4.mcstatic.com/thumb/8456223/22479418/4/catalog_item5/0/1/men_in_black_3_trailer_2.jpg',
60
+ 'name' => 'Embed'
61
+ ),
62
+ );
63
+
64
+ }
65
+
66
+ // Add to provider array
67
+ add_filter( 'video_thumbnail_providers', array( 'Metacafe_Thumbnails', 'register_provider' ) );
68
+
69
+ ?>
php/providers/class-mpora-thumbnails.php ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Mpora_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'MPORA';
26
+ const service_name = 'MPORA';
27
+ // Slug for the video provider
28
+ public $service_slug = 'mpora';
29
+ const service_slug = 'mpora';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#http://(?:video\.|www\.)?mpora\.com/(?:ep|videos)/([A-Za-z0-9]+)#', // Flash or iFrame src
39
+ '#mporaplayer_([A-Za-z0-9]+)_#' // Object ID
40
+ );
41
+
42
+ // Thumbnail URL
43
+ public function get_thumbnail_url( $id ) {
44
+ return 'http://ugc4.mporatrons.com/thumbs/' . $id . '_640x360_0000.jpg';
45
+ }
46
+
47
+ // Test cases
48
+ public $test_cases = array(
49
+ array(
50
+ 'markup' => '<object width="480" height="270" id="mporaplayer_wEr2CBooV_N" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" type="application/x-shockwave-flash" ><param name="movie" value="http://video.mpora.com/ep/wEr2CBooV/"></param><param name="wmode" value="transparent"></param><param name="allowScriptAccess" value="always"></param><param name="allowFullScreen" value="true"></param><embed src="http://video.mpora.com/ep/wEr2CBooV/" width="480" height="270" wmode="transparent" allowfullscreen="true" allowscriptaccess="always" type="application/x-shockwave-flash"></embed></object>',
51
+ 'expected' => 'http://ugc4.mporatrons.com/thumbs/wEr2CBooV_640x360_0000.jpg',
52
+ 'name' => 'Flash player'
53
+ ),
54
+ array(
55
+ 'markup' => '<iframe width="640" height="360" src="http://mpora.com/videos/AAdfegovdop0/embed" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>',
56
+ 'expected' => 'http://ugc4.mporatrons.com/thumbs/AAdfegovdop0_640x360_0000.jpg',
57
+ 'name' => 'iFrame player'
58
+ ),
59
+ );
60
+ }
61
+
62
+ // Add to provider array
63
+ add_filter( 'video_thumbnail_providers', array( 'Mpora_Thumbnails', 'register_provider' ) );
64
+
65
+ ?>
php/providers/class-video-thumbnails-providers.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ class Video_Thumbnails_Providers {
20
+
21
+ public $options = array();
22
+
23
+ function __construct() {
24
+ // If options are defined add the settings section
25
+ if ( isset( $this->options_section ) ) add_action( 'admin_init', array( &$this, 'initialize_options' ) );
26
+ // Get current settings for this provider
27
+ $options = get_option( 'video_thumbnails' );
28
+ if ( isset( $options['providers'][$this->service_slug] ) ) {
29
+ $this->options = $options['providers'][$this->service_slug];
30
+ }
31
+ }
32
+
33
+ function initialize_options() {
34
+ add_settings_section(
35
+ $this->service_slug . '_provider_settings_section',
36
+ $this->service_name . ' Settings',
37
+ array( &$this, 'settings_section_callback' ),
38
+ 'video_thumbnails_providers'
39
+ );
40
+ foreach ( $this->options_section['fields'] as $key => $value ) {
41
+ add_settings_field(
42
+ $key,
43
+ $value['name'],
44
+ array( &$this, $value['type'] . '_setting_callback' ),
45
+ 'video_thumbnails_providers',
46
+ $this->service_slug . '_provider_settings_section',
47
+ array(
48
+ 'slug' => $key,
49
+ 'description' => $value['description']
50
+ )
51
+ );
52
+ }
53
+ }
54
+
55
+ function settings_section_callback() {
56
+ echo $this->options_section['description'];
57
+ }
58
+
59
+ function text_setting_callback( $args ) {
60
+ $html = '<input type="text" id="' . $args['slug'] . '" name="video_thumbnails[providers][' . $this->service_slug . '][' . $args['slug'] . ']" value="' . $this->options[$args['slug']] . '"/>';
61
+ $html .= '<label for="' . $args['slug'] . '"> ' . $args['description'] . '</label>';
62
+ echo $html;
63
+ }
64
+
65
+ public function scan_for_thumbnail( $markup ) {
66
+ foreach ( $this->regexes as $regex ) {
67
+ if ( preg_match( $regex, $markup, $matches ) ) {
68
+ return $this->get_thumbnail_url( $matches[1] );
69
+ }
70
+ }
71
+ }
72
+
73
+ // // Requires PHP 5.3.0+
74
+ // public static function register_provider( $providers ) {
75
+ // $providers[] = new static;
76
+ // return $providers;
77
+ // }
78
+
79
+ }
80
+
81
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-youtube-thumbnails.php' );
82
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-vimeo-thumbnails.php' );
83
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-facebook-thumbnails.php' );
84
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-blip-thumbnails.php' );
85
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-justintv-thumbnails.php' );
86
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-dailymotion-thumbnails.php' );
87
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-metacafe-thumbnails.php' );
88
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-funnyordie-thumbnails.php' );
89
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-mpora-thumbnails.php' );
90
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-wistia-thumbnails.php' );
91
+ // require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-kaltura-thumbnails.php' );
92
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-youku-thumbnails.php' );
93
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-collegehumor-thumbnails.php' );
94
+
95
+ ?>
php/providers/class-vimeo-thumbnails.php ADDED
@@ -0,0 +1,666 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Vimeo_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Vimeo';
26
+ const service_name = 'Vimeo';
27
+ // Slug for the video provider
28
+ public $service_slug = 'vimeo';
29
+ const service_slug = 'vimeo';
30
+
31
+ public $options_section = array(
32
+ 'description' => '<p><strong>Optional</strong>: Only required for accessing private videos. <a href="https://developer.vimeo.com/apps">Register an app with Vimeo</a> then fill in the appropriate keys below. Requires cURL to authenticate.</p>',
33
+ 'fields' => array(
34
+ 'client_id' => array(
35
+ 'name' => 'Client ID',
36
+ 'type' => 'text',
37
+ 'description' => ''
38
+ ),
39
+ 'client_secret' => array(
40
+ 'name' => 'Client Secret',
41
+ 'type' => 'text',
42
+ 'description' => ''
43
+ ),
44
+ 'access_token' => array(
45
+ 'name' => 'Access token',
46
+ 'type' => 'text',
47
+ 'description' => ''
48
+ ),
49
+ 'access_token_secret' => array(
50
+ 'name' => 'Access token secret',
51
+ 'type' => 'text',
52
+ 'description' => ''
53
+ )
54
+ )
55
+ );
56
+
57
+ public static function register_provider( $providers ) {
58
+ $providers[self::service_slug] = new self;
59
+ return $providers;
60
+ }
61
+
62
+ // Regex strings
63
+ public $regexes = array(
64
+ '#<object[^>]+>.+?http://vimeo\.com/moogaloop.swf\?clip_id=([A-Za-z0-9\-_]+)&.+?</object>#s', // Standard Vimeo embed code
65
+ '#http://player\.vimeo\.com/video/([0-9]+)#', // Vimeo iframe player
66
+ '#\[vimeo id=([A-Za-z0-9\-_]+)]#', // JR_embed shortcode
67
+ '#\[vimeo clip_id="([A-Za-z0-9\-_]+)"[^>]*]#', // Another shortcode
68
+ '#\[vimeo video_id="([A-Za-z0-9\-_]+)"[^>]*]#', // Yet another shortcode
69
+ '#(?:https?://)?(?:www\.)?vimeo\.com/([0-9]+)#', // Vimeo URL
70
+ '#(?:https?://)?(?:www\.)?vimeo\.com/channels/(?:[A-Za-z0-9]+)/([0-9]+)#' // Channel URL
71
+ );
72
+
73
+ // Thumbnail URL
74
+ public function get_thumbnail_url( $id ) {
75
+ // If API credentials are entered, use the API
76
+ if ( $this->options['client_id'] && $this->options['client_secret'] && $this->options['access_token'] && $this->options['access_token_secret'] ) {
77
+ $vimeo = new phpVimeo( $this->options['client_id'], $this->options['client_secret'] );
78
+ $vimeo->setToken( $this->options['access_token'], $this->options['access_token_secret'] );
79
+ $response = $vimeo->call('vimeo.videos.getThumbnailUrls', array('video_id'=>$id));
80
+ $result = $response->thumbnails->thumbnail[count($response->thumbnails->thumbnail)-1]->_content;
81
+ } else {
82
+ $request = "http://vimeo.com/api/oembed.xml?url=http%3A//vimeo.com/$id";
83
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
84
+ if( is_wp_error( $response ) ) {
85
+ $result = new WP_Error( 'vimeo_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
86
+ } elseif ( $response['response']['code'] == 404 ) {
87
+ $result = new WP_Error( 'vimeo_info_retrieval', __( 'The Vimeo endpoint located at <a href="' . $request . '">' . $request . '</a> returned a 404 error.<br />Details: ' . $response['response']['message'] ) );
88
+ } else {
89
+ $xml = new SimpleXMLElement( $response['body'] );
90
+ $result = (string) $xml->thumbnail_url;
91
+ }
92
+ }
93
+ return $result;
94
+ }
95
+
96
+ // Test cases
97
+ public $test_cases = array(
98
+ array(
99
+ 'markup' => '<iframe src="http://player.vimeo.com/video/41504360" width="500" height="281" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe>',
100
+ 'expected' => 'http://b.vimeocdn.com/ts/287/850/287850781_1280.jpg',
101
+ 'name' => 'iFrame'
102
+ ),
103
+ array(
104
+ 'markup' => '<object width="500" height="281"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=41504360&amp;force_embed=1&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=41504360&amp;force_embed=1&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=1&amp;show_portrait=1&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="500" height="281"></embed></object>',
105
+ 'expected' => 'http://b.vimeocdn.com/ts/287/850/287850781_1280.jpg',
106
+ 'name' => 'Old embed'
107
+ ),
108
+ array(
109
+ 'markup' => 'https://vimeo.com/channels/soundworkscollection/44520894',
110
+ 'expected' => 'http://b.vimeocdn.com/ts/313/130/313130530_640.jpg',
111
+ 'name' => 'Channel URL'
112
+ ),
113
+ );
114
+
115
+ }
116
+
117
+ // Add to provider array
118
+ add_filter( 'video_thumbnail_providers', array( 'Vimeo_Thumbnails', 'register_provider' ) );
119
+
120
+ // Vimeo API class
121
+ if( !class_exists( 'phpVimeo' ) ) :
122
+ class phpVimeo
123
+ {
124
+ const API_REST_URL = 'http://vimeo.com/api/rest/v2';
125
+ const API_AUTH_URL = 'http://vimeo.com/oauth/authorize';
126
+ const API_ACCESS_TOKEN_URL = 'http://vimeo.com/oauth/access_token';
127
+ const API_REQUEST_TOKEN_URL = 'http://vimeo.com/oauth/request_token';
128
+
129
+ const CACHE_FILE = 'file';
130
+
131
+ private $_consumer_key = false;
132
+ private $_consumer_secret = false;
133
+ private $_cache_enabled = false;
134
+ private $_cache_dir = false;
135
+ private $_token = false;
136
+ private $_token_secret = false;
137
+ private $_upload_md5s = array();
138
+
139
+ public function __construct($consumer_key, $consumer_secret, $token = null, $token_secret = null)
140
+ {
141
+ $this->_consumer_key = $consumer_key;
142
+ $this->_consumer_secret = $consumer_secret;
143
+
144
+ if ($token && $token_secret) {
145
+ $this->setToken($token, $token_secret);
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Cache a response.
151
+ *
152
+ * @param array $params The parameters for the response.
153
+ * @param string $response The serialized response data.
154
+ */
155
+ private function _cache($params, $response)
156
+ {
157
+ // Remove some unique things
158
+ unset($params['oauth_nonce']);
159
+ unset($params['oauth_signature']);
160
+ unset($params['oauth_timestamp']);
161
+
162
+ $hash = md5(serialize($params));
163
+
164
+ if ($this->_cache_enabled == self::CACHE_FILE) {
165
+ $file = $this->_cache_dir.'/'.$hash.'.cache';
166
+ if (file_exists($file)) {
167
+ unlink($file);
168
+ }
169
+ return file_put_contents($file, $response);
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Create the authorization header for a set of params.
175
+ *
176
+ * @param array $oauth_params The OAuth parameters for the call.
177
+ * @return string The OAuth Authorization header.
178
+ */
179
+ private function _generateAuthHeader($oauth_params)
180
+ {
181
+ $auth_header = 'Authorization: OAuth realm=""';
182
+
183
+ foreach ($oauth_params as $k => $v) {
184
+ $auth_header .= ','.self::url_encode_rfc3986($k).'="'.self::url_encode_rfc3986($v).'"';
185
+ }
186
+
187
+ return $auth_header;
188
+ }
189
+
190
+ /**
191
+ * Generate a nonce for the call.
192
+ *
193
+ * @return string The nonce
194
+ */
195
+ private function _generateNonce()
196
+ {
197
+ return md5(uniqid(microtime()));
198
+ }
199
+
200
+ /**
201
+ * Generate the OAuth signature.
202
+ *
203
+ * @param array $args The full list of args to generate the signature for.
204
+ * @param string $request_method The request method, either POST or GET.
205
+ * @param string $url The base URL to use.
206
+ * @return string The OAuth signature.
207
+ */
208
+ private function _generateSignature($params, $request_method = 'GET', $url = self::API_REST_URL)
209
+ {
210
+ uksort($params, 'strcmp');
211
+ $params = self::url_encode_rfc3986($params);
212
+
213
+ // Make the base string
214
+ $base_parts = array(
215
+ strtoupper($request_method),
216
+ $url,
217
+ urldecode(http_build_query($params, '', '&'))
218
+ );
219
+ $base_parts = self::url_encode_rfc3986($base_parts);
220
+ $base_string = implode('&', $base_parts);
221
+
222
+ // Make the key
223
+ $key_parts = array(
224
+ $this->_consumer_secret,
225
+ ($this->_token_secret) ? $this->_token_secret : ''
226
+ );
227
+ $key_parts = self::url_encode_rfc3986($key_parts);
228
+ $key = implode('&', $key_parts);
229
+
230
+ // Generate signature
231
+ return base64_encode(hash_hmac('sha1', $base_string, $key, true));
232
+ }
233
+
234
+ /**
235
+ * Get the unserialized contents of the cached request.
236
+ *
237
+ * @param array $params The full list of api parameters for the request.
238
+ */
239
+ private function _getCached($params)
240
+ {
241
+ // Remove some unique things
242
+ unset($params['oauth_nonce']);
243
+ unset($params['oauth_signature']);
244
+ unset($params['oauth_timestamp']);
245
+
246
+ $hash = md5(serialize($params));
247
+
248
+ if ($this->_cache_enabled == self::CACHE_FILE) {
249
+ $file = $this->_cache_dir.'/'.$hash.'.cache';
250
+ if (file_exists($file)) {
251
+ return unserialize(file_get_contents($file));
252
+ }
253
+ }
254
+ }
255
+
256
+ /**
257
+ * Call an API method.
258
+ *
259
+ * @param string $method The method to call.
260
+ * @param array $call_params The parameters to pass to the method.
261
+ * @param string $request_method The HTTP request method to use.
262
+ * @param string $url The base URL to use.
263
+ * @param boolean $cache Whether or not to cache the response.
264
+ * @param boolean $use_auth_header Use the OAuth Authorization header to pass the OAuth params.
265
+ * @return string The response from the method call.
266
+ */
267
+ private function _request($method, $call_params = array(), $request_method = 'GET', $url = self::API_REST_URL, $cache = true, $use_auth_header = true)
268
+ {
269
+ // Prepare oauth arguments
270
+ $oauth_params = array(
271
+ 'oauth_consumer_key' => $this->_consumer_key,
272
+ 'oauth_version' => '1.0',
273
+ 'oauth_signature_method' => 'HMAC-SHA1',
274
+ 'oauth_timestamp' => time(),
275
+ 'oauth_nonce' => $this->_generateNonce()
276
+ );
277
+
278
+ // If we have a token, include it
279
+ if ($this->_token) {
280
+ $oauth_params['oauth_token'] = $this->_token;
281
+ }
282
+
283
+ // Regular args
284
+ $api_params = array('format' => 'php');
285
+ if (!empty($method)) {
286
+ $api_params['method'] = $method;
287
+ }
288
+
289
+ // Merge args
290
+ foreach ($call_params as $k => $v) {
291
+ if (strpos($k, 'oauth_') === 0) {
292
+ $oauth_params[$k] = $v;
293
+ }
294
+ else if ($call_params[$k] !== null) {
295
+ $api_params[$k] = $v;
296
+ }
297
+ }
298
+
299
+ // Generate the signature
300
+ $oauth_params['oauth_signature'] = $this->_generateSignature(array_merge($oauth_params, $api_params), $request_method, $url);
301
+
302
+ // Merge all args
303
+ $all_params = array_merge($oauth_params, $api_params);
304
+
305
+ // Returned cached value
306
+ if ($this->_cache_enabled && ($cache && $response = $this->_getCached($all_params))) {
307
+ return $response;
308
+ }
309
+
310
+ // Curl options
311
+ if ($use_auth_header) {
312
+ $params = $api_params;
313
+ }
314
+ else {
315
+ $params = $all_params;
316
+ }
317
+
318
+ if (strtoupper($request_method) == 'GET') {
319
+ $curl_url = $url.'?'.http_build_query($params, '', '&');
320
+ $curl_opts = array(
321
+ CURLOPT_RETURNTRANSFER => true,
322
+ CURLOPT_TIMEOUT => 30
323
+ );
324
+ }
325
+ else if (strtoupper($request_method) == 'POST') {
326
+ $curl_url = $url;
327
+ $curl_opts = array(
328
+ CURLOPT_RETURNTRANSFER => true,
329
+ CURLOPT_TIMEOUT => 30,
330
+ CURLOPT_POST => true,
331
+ CURLOPT_POSTFIELDS => http_build_query($params, '', '&')
332
+ );
333
+ }
334
+
335
+ // Authorization header
336
+ if ($use_auth_header) {
337
+ $curl_opts[CURLOPT_HTTPHEADER] = array($this->_generateAuthHeader($oauth_params));
338
+ }
339
+
340
+ // Call the API
341
+ $curl = curl_init($curl_url);
342
+ curl_setopt_array($curl, $curl_opts);
343
+ $response = curl_exec($curl);
344
+ $curl_info = curl_getinfo($curl);
345
+ curl_close($curl);
346
+
347
+ // Cache the response
348
+ if ($this->_cache_enabled && $cache) {
349
+ $this->_cache($all_params, $response);
350
+ }
351
+
352
+ // Return
353
+ if (!empty($method)) {
354
+ $response = unserialize($response);
355
+ if ($response->stat == 'ok') {
356
+ return $response;
357
+ }
358
+ else if ($response->err) {
359
+ throw new VimeoAPIException($response->err->msg, $response->err->code);
360
+ }
361
+
362
+ return false;
363
+ }
364
+
365
+ return $response;
366
+ }
367
+
368
+ /**
369
+ * Send the user to Vimeo to authorize your app.
370
+ * http://www.vimeo.com/api/docs/oauth
371
+ *
372
+ * @param string $perms The level of permissions to request: read, write, or delete.
373
+ */
374
+ public function auth($permission = 'read', $callback_url = 'oob')
375
+ {
376
+ $t = $this->getRequestToken($callback_url);
377
+ $this->setToken($t['oauth_token'], $t['oauth_token_secret'], 'request', true);
378
+ $url = $this->getAuthorizeUrl($this->_token, $permission);
379
+ header("Location: {$url}");
380
+ }
381
+
382
+ /**
383
+ * Call a method.
384
+ *
385
+ * @param string $method The name of the method to call.
386
+ * @param array $params The parameters to pass to the method.
387
+ * @param string $request_method The HTTP request method to use.
388
+ * @param string $url The base URL to use.
389
+ * @param boolean $cache Whether or not to cache the response.
390
+ * @return array The response from the API method
391
+ */
392
+ public function call($method, $params = array(), $request_method = 'GET', $url = self::API_REST_URL, $cache = true)
393
+ {
394
+ $method = (substr($method, 0, 6) != 'vimeo.') ? "vimeo.{$method}" : $method;
395
+ return $this->_request($method, $params, $request_method, $url, $cache);
396
+ }
397
+
398
+ /**
399
+ * Enable the cache.
400
+ *
401
+ * @param string $type The type of cache to use (phpVimeo::CACHE_FILE is built in)
402
+ * @param string $path The path to the cache (the directory for CACHE_FILE)
403
+ * @param int $expire The amount of time to cache responses (default 10 minutes)
404
+ */
405
+ public function enableCache($type, $path, $expire = 600)
406
+ {
407
+ $this->_cache_enabled = $type;
408
+ if ($this->_cache_enabled == self::CACHE_FILE) {
409
+ $this->_cache_dir = $path;
410
+ $files = scandir($this->_cache_dir);
411
+ foreach ($files as $file) {
412
+ $last_modified = filemtime($this->_cache_dir.'/'.$file);
413
+ if (substr($file, -6) == '.cache' && ($last_modified + $expire) < time()) {
414
+ unlink($this->_cache_dir.'/'.$file);
415
+ }
416
+ }
417
+ }
418
+ return false;
419
+ }
420
+
421
+ /**
422
+ * Get an access token. Make sure to call setToken() with the
423
+ * request token before calling this function.
424
+ *
425
+ * @param string $verifier The OAuth verifier returned from the authorization page or the user.
426
+ */
427
+ public function getAccessToken($verifier)
428
+ {
429
+ $access_token = $this->_request(null, array('oauth_verifier' => $verifier), 'GET', self::API_ACCESS_TOKEN_URL, false, true);
430
+ parse_str($access_token, $parsed);
431
+ return $parsed;
432
+ }
433
+
434
+ /**
435
+ * Get the URL of the authorization page.
436
+ *
437
+ * @param string $token The request token.
438
+ * @param string $permission The level of permissions to request: read, write, or delete.
439
+ * @param string $callback_url The URL to redirect the user back to, or oob for the default.
440
+ * @return string The Authorization URL.
441
+ */
442
+ public function getAuthorizeUrl($token, $permission = 'read')
443
+ {
444
+ return self::API_AUTH_URL."?oauth_token={$token}&permission={$permission}";
445
+ }
446
+
447
+ /**
448
+ * Get a request token.
449
+ */
450
+ public function getRequestToken($callback_url = 'oob')
451
+ {
452
+ $request_token = $this->_request(
453
+ null,
454
+ array('oauth_callback' => $callback_url),
455
+ 'GET',
456
+ self::API_REQUEST_TOKEN_URL,
457
+ false,
458
+ false
459
+ );
460
+
461
+ parse_str($request_token, $parsed);
462
+ return $parsed;
463
+ }
464
+
465
+ /**
466
+ * Get the stored auth token.
467
+ *
468
+ * @return array An array with the token and token secret.
469
+ */
470
+ public function getToken()
471
+ {
472
+ return array($this->_token, $this->_token_secret);
473
+ }
474
+
475
+ /**
476
+ * Set the OAuth token.
477
+ *
478
+ * @param string $token The OAuth token
479
+ * @param string $token_secret The OAuth token secret
480
+ * @param string $type The type of token, either request or access
481
+ * @param boolean $session_store Store the token in a session variable
482
+ * @return boolean true
483
+ */
484
+ public function setToken($token, $token_secret, $type = 'access', $session_store = false)
485
+ {
486
+ $this->_token = $token;
487
+ $this->_token_secret = $token_secret;
488
+
489
+ if ($session_store) {
490
+ $_SESSION["{$type}_token"] = $token;
491
+ $_SESSION["{$type}_token_secret"] = $token_secret;
492
+ }
493
+
494
+ return true;
495
+ }
496
+
497
+ /**
498
+ * Upload a video in one piece.
499
+ *
500
+ * @param string $file_path The full path to the file
501
+ * @param boolean $use_multiple_chunks Whether or not to split the file up into smaller chunks
502
+ * @param string $chunk_temp_dir The directory to store the chunks in
503
+ * @param int $size The size of each chunk in bytes (defaults to 2MB)
504
+ * @return int The video ID
505
+ */
506
+ public function upload($file_path, $use_multiple_chunks = false, $chunk_temp_dir = '.', $size = 2097152, $replace_id = null)
507
+ {
508
+ if (!file_exists($file_path)) {
509
+ return false;
510
+ }
511
+
512
+ // Figure out the filename and full size
513
+ $path_parts = pathinfo($file_path);
514
+ $file_name = $path_parts['basename'];
515
+ $file_size = filesize($file_path);
516
+
517
+ // Make sure we have enough room left in the user's quota
518
+ $quota = $this->call('vimeo.videos.upload.getQuota');
519
+ if ($quota->user->upload_space->free < $file_size) {
520
+ throw new VimeoAPIException('The file is larger than the user\'s remaining quota.', 707);
521
+ }
522
+
523
+ // Get an upload ticket
524
+ $params = array();
525
+
526
+ if ($replace_id) {
527
+ $params['video_id'] = $replace_id;
528
+ }
529
+
530
+ $rsp = $this->call('vimeo.videos.upload.getTicket', $params, 'GET', self::API_REST_URL, false);
531
+ $ticket = $rsp->ticket->id;
532
+ $endpoint = $rsp->ticket->endpoint;
533
+
534
+ // Make sure we're allowed to upload this size file
535
+ if ($file_size > $rsp->ticket->max_file_size) {
536
+ throw new VimeoAPIException('File exceeds maximum allowed size.', 710);
537
+ }
538
+
539
+ // Split up the file if using multiple pieces
540
+ $chunks = array();
541
+ if ($use_multiple_chunks) {
542
+ if (!is_writeable($chunk_temp_dir)) {
543
+ throw new Exception('Could not write chunks. Make sure the specified folder has write access.');
544
+ }
545
+
546
+ // Create pieces
547
+ $number_of_chunks = ceil(filesize($file_path) / $size);
548
+ for ($i = 0; $i < $number_of_chunks; $i++) {
549
+ $chunk_file_name = "{$chunk_temp_dir}/{$file_name}.{$i}";
550
+
551
+ // Break it up
552
+ $chunk = file_get_contents($file_path, FILE_BINARY, null, $i * $size, $size);
553
+ $file = file_put_contents($chunk_file_name, $chunk);
554
+
555
+ $chunks[] = array(
556
+ 'file' => realpath($chunk_file_name),
557
+ 'size' => filesize($chunk_file_name)
558
+ );
559
+ }
560
+ }
561
+ else {
562
+ $chunks[] = array(
563
+ 'file' => realpath($file_path),
564
+ 'size' => filesize($file_path)
565
+ );
566
+ }
567
+
568
+ // Upload each piece
569
+ foreach ($chunks as $i => $chunk) {
570
+ $params = array(
571
+ 'oauth_consumer_key' => $this->_consumer_key,
572
+ 'oauth_token' => $this->_token,
573
+ 'oauth_signature_method' => 'HMAC-SHA1',
574
+ 'oauth_timestamp' => time(),
575
+ 'oauth_nonce' => $this->_generateNonce(),
576
+ 'oauth_version' => '1.0',
577
+ 'ticket_id' => $ticket,
578
+ 'chunk_id' => $i
579
+ );
580
+
581
+ // Generate the OAuth signature
582
+ $params = array_merge($params, array(
583
+ 'oauth_signature' => $this->_generateSignature($params, 'POST', self::API_REST_URL),
584
+ 'file_data' => '@'.$chunk['file'] // don't include the file in the signature
585
+ ));
586
+
587
+ // Post the file
588
+ $curl = curl_init($endpoint);
589
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
590
+ curl_setopt($curl, CURLOPT_POST, 1);
591
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
592
+ $rsp = curl_exec($curl);
593
+ curl_close($curl);
594
+ }
595
+
596
+ // Verify
597
+ $verify = $this->call('vimeo.videos.upload.verifyChunks', array('ticket_id' => $ticket));
598
+
599
+ // Make sure our file sizes match up
600
+ foreach ($verify->ticket->chunks as $chunk_check) {
601
+ $chunk = $chunks[$chunk_check->id];
602
+
603
+ if ($chunk['size'] != $chunk_check->size) {
604
+ // size incorrect, uh oh
605
+ echo "Chunk {$chunk_check->id} is actually {$chunk['size']} but uploaded as {$chunk_check->size}<br>";
606
+ }
607
+ }
608
+
609
+ // Complete the upload
610
+ $complete = $this->call('vimeo.videos.upload.complete', array(
611
+ 'filename' => $file_name,
612
+ 'ticket_id' => $ticket
613
+ ));
614
+
615
+ // Clean up
616
+ if (count($chunks) > 1) {
617
+ foreach ($chunks as $chunk) {
618
+ unlink($chunk['file']);
619
+ }
620
+ }
621
+
622
+ // Confirmation successful, return video id
623
+ if ($complete->stat == 'ok') {
624
+ return $complete->ticket->video_id;
625
+ }
626
+ else if ($complete->err) {
627
+ throw new VimeoAPIException($complete->err->msg, $complete->err->code);
628
+ }
629
+ }
630
+
631
+ /**
632
+ * Upload a video in multiple pieces.
633
+ *
634
+ * @deprecated
635
+ */
636
+ public function uploadMulti($file_name, $size = 1048576)
637
+ {
638
+ // for compatibility with old library
639
+ return $this->upload($file_name, true, '.', $size);
640
+ }
641
+
642
+ /**
643
+ * URL encode a parameter or array of parameters.
644
+ *
645
+ * @param array/string $input A parameter or set of parameters to encode.
646
+ */
647
+ public static function url_encode_rfc3986($input)
648
+ {
649
+ if (is_array($input)) {
650
+ return array_map(array('phpVimeo', 'url_encode_rfc3986'), $input);
651
+ }
652
+ else if (is_scalar($input)) {
653
+ return str_replace(array('+', '%7E'), array(' ', '~'), rawurlencode($input));
654
+ }
655
+ else {
656
+ return '';
657
+ }
658
+ }
659
+
660
+ }
661
+
662
+ class VimeoAPIException extends Exception {}
663
+
664
+ endif;
665
+
666
+ ?>
php/providers/class-wistia-thumbnails.php ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Wistia_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Wistia';
26
+ const service_name = 'Wistia';
27
+ // Slug for the video provider
28
+ public $service_slug = 'wistia';
29
+ const service_slug = 'wistia';
30
+
31
+ // public $options_section = array(
32
+ // 'description' => '<p><strong>Optional</strong>: Only required if you have a CNAME record set up to use a custom domain.</p>',
33
+ // 'fields' => array(
34
+ // 'domain' => array(
35
+ // 'name' => 'Custom Wistia Domain',
36
+ // 'type' => 'text',
37
+ // 'description' => 'Enter the domain corresponding to your CNAME record for Wistia. Ex: videos.example.com'
38
+ // )
39
+ // )
40
+ // );
41
+
42
+ public static function register_provider( $providers ) {
43
+ $providers[self::service_slug] = new self;
44
+ return $providers;
45
+ }
46
+
47
+ public function scan_for_thumbnail( $markup ) {
48
+ // Find thumbnail URL if embedded in player
49
+ $thumb_regex = '#https://wistia\.sslcs\.cdngc\.net/deliveries/[0-9a-zA-Z]+\.jpg#';
50
+ if ( preg_match( $thumb_regex, urldecode( $markup ), $matches ) ) {
51
+ return $matches[0];
52
+ }
53
+ $oembed_regex = '#https?://(.+)?(wistia\.com|wistia\.net|wi\.st)/(medias|embed)/(?:[\+~%\/\.\w\-]*)#';
54
+ if ( preg_match( $oembed_regex, urldecode( $markup ), $matches ) ) {
55
+ return $this->get_thumbnail_url( $matches[0] );
56
+ }
57
+ // Run regex for oEmbed API
58
+ foreach ( $this->regexes as $regex ) {
59
+ if ( preg_match( $regex, $markup, $matches ) ) {
60
+ return $this->get_thumbnail_url( 'http://fast.wistia.net/embed/iframe/' . $matches[1] );
61
+ }
62
+ }
63
+ }
64
+
65
+ // Regex strings
66
+ public $regexes = array(
67
+ '#Wistia\.embed\("([0-9a-zA-Z]+)"#', // JavaScript API embedding
68
+ );
69
+
70
+ // Thumbnail URL
71
+ public function get_thumbnail_url( $url ) {
72
+ $url = urlencode( $url );
73
+ $request = "http://fast.wistia.com/oembed?url=$url";
74
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
75
+ if( is_wp_error( $response ) ) {
76
+ $result = new WP_Error( 'wistia_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
77
+ } else {
78
+ $result = json_decode( $response['body'] );
79
+ $result = $result->thumbnail_url;
80
+ }
81
+ return $result;
82
+ }
83
+
84
+ // Test cases
85
+ public $test_cases = array(
86
+ array(
87
+ 'markup' => '<iframe src="http://fast.wistia.net/embed/iframe/po4utu3zde?controlsVisibleOnLoad=true&version=v1&videoHeight=360&videoWidth=640&volumeControl=true" allowtransparency="true" frameborder="0" scrolling="no" class="wistia_embed" name="wistia_embed" width="640" height="360"></iframe>',
88
+ 'expected' => 'http://embed-0.wistia.com/deliveries/6928fcba8355e38de4d95863a659e1de23cb2071.jpg',
89
+ 'name' => 'Inline player'
90
+ ),
91
+ array(
92
+ 'markup' => '<div class=\'wistia_embed\' data-video-height=\'312\' data-video-width=\'499\' id=\'wistia_j1qd2lvys1\'></div> <script charset=\'ISO-8859-1\' src=\'http://fast.wistia.com/static/concat/E-v1.js\'></script> <script> var platform = ( Modernizr.touch ) ? "html5" : "flash"; wistiaEmbed = Wistia.embed("j1qd2lvys1", { version: "v1", videoWidth: 499, videoHeight: 312, playButton: Modernizr.touch, smallPlayButton: Modernizr.touch, playbar: Modernizr.touch, platformPreference: platform, chromeless: Modernizr.touch ? false : true, fullscreenButton: false, autoPlay: !Modernizr.touch, videoFoam: true }); </script>',
93
+ 'expected' => 'http://embed.wistia.com/deliveries/a086707fe096e7f3fbefef1d1dcba1488d23a3e9.jpg',
94
+ 'name' => 'JavaScript API embedding'
95
+ ),
96
+ );
97
+
98
+ }
99
+
100
+ // Add to provider array
101
+ add_filter( 'video_thumbnail_providers', array( 'Wistia_Thumbnails', 'register_provider' ) );
102
+
103
+ ?>
php/providers/class-youku-thumbnails.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class Youku_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'Youku';
26
+ const service_name = 'Youku';
27
+ // Slug for the video provider
28
+ public $service_slug = 'youku';
29
+ const service_slug = 'youku';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#http://player\.youku\.com/player\.php/sid/([A-Za-z0-9]+)/v\.swf#', // Flash
39
+ '#http://v\.youku\.com/v_show/id_([A-Za-z0-9]+)\.html#' // Link
40
+ );
41
+
42
+ // Thumbnail URL
43
+ public function get_thumbnail_url( $id ) {
44
+ $request = "http://v.youku.com/player/getPlayList/VideoIDS/$id/";
45
+ $response = wp_remote_get( $request, array( 'sslverify' => false ) );
46
+ if( is_wp_error( $response ) ) {
47
+ $result = new WP_Error( 'youku_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $request . '">' . $request . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
48
+ } else {
49
+ $result = json_decode( $response['body'] );
50
+ $result = $result->data[0]->logo;
51
+ }
52
+ return $result;
53
+ }
54
+
55
+ // Test cases
56
+ public $test_cases = array(
57
+ array(
58
+ 'markup' => '<embed src="http://player.youku.com/player.php/sid/XMzQyMzk5MzQ4/v.swf" quality="high" width="480" height="400" align="middle" allowScriptAccess="sameDomain" allowFullscreen="true" type="application/x-shockwave-flash"></embed>',
59
+ 'expected' => 'http://g1.ykimg.com/1100641F464F0FB57407E2053DFCBC802FBBC4-E4C5-7A58-0394-26C366F10493',
60
+ 'name' => 'Flash embed'
61
+ ),
62
+ array(
63
+ 'markup' => 'http://v.youku.com/v_show/id_XMzQyMzk5MzQ4.html',
64
+ 'expected' => 'http://g1.ykimg.com/1100641F464F0FB57407E2053DFCBC802FBBC4-E4C5-7A58-0394-26C366F10493',
65
+ 'name' => 'Link'
66
+ ),
67
+ );
68
+
69
+ }
70
+
71
+ // Add to provider array
72
+ add_filter( 'video_thumbnail_providers', array( 'Youku_Thumbnails', 'register_provider' ) );
73
+
74
+ ?>
php/providers/class-youtube-thumbnails.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
4
+
5
+ This program is free software; you can redistribute it and/or modify
6
+ it under the terms of the GNU General Public License, version 2, as
7
+ published by the Free Software Foundation.
8
+
9
+ This program is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ GNU General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with this program; if not, write to the Free Software
16
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
+ */
18
+
19
+ // Require thumbnail provider class
20
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
21
+
22
+ class YouTube_Thumbnails extends Video_Thumbnails_Providers {
23
+
24
+ // Human-readable name of the video provider
25
+ public $service_name = 'YouTube';
26
+ const service_name = 'YouTube';
27
+ // Slug for the video provider
28
+ public $service_slug = 'youtube';
29
+ const service_slug = 'youtube';
30
+
31
+ public static function register_provider( $providers ) {
32
+ $providers[self::service_slug] = new self;
33
+ return $providers;
34
+ }
35
+
36
+ // Regex strings
37
+ public $regexes = array(
38
+ '#<object[^>]+>.+?https?://www\.youtube(?:\-nocookie)?\.com/[ve]/([A-Za-z0-9\-_]+).+?</object>#s', // Old standard YouTube embed
39
+ '#https?://www\.youtube(?:\-nocookie)?\.com/[ve]/([A-Za-z0-9\-_]+)#', // More comprehensive search for old YouTube embed (probably can be removed)
40
+ '#https?://www\.youtube(?:\-nocookie)?\.com/embed/([A-Za-z0-9\-_]+)#', // YouTube iframe, the new standard since at least 2011
41
+ '#(?:https?(?:a|vh?)?://)?(?:www\.)?youtube(?:\-nocookie)?\.com/watch\?.*v=([A-Za-z0-9\-_]+)#', // Any YouTube URL. After http(s) support a or v for Youtube Lyte and v or vh for Smart Youtube plugin
42
+ '#(?:https?(?:a|vh?)?://)?youtu\.be/([A-Za-z0-9\-_]+)#', // Any shortened youtu.be URL. After http(s) a or v for Youtube Lyte and v or vh for Smart Youtube plugin
43
+ '#<div class="lyte" id="([A-Za-z0-9\-_]+)"#' // YouTube Lyte
44
+ );
45
+
46
+ // Thumbnail URL
47
+ public function get_thumbnail_url( $id ) {
48
+ $maxres = 'http://img.youtube.com/vi/' . $id . '/maxresdefault.jpg';
49
+ $response = wp_remote_head( $maxres );
50
+ if ( $response['response']['code'] == '200' ) {
51
+ $result = $maxres;
52
+ } else {
53
+ $result = 'http://img.youtube.com/vi/' . $id . '/0.jpg';
54
+ }
55
+ return $result;
56
+ }
57
+
58
+ // Test cases
59
+ public $test_cases = array(
60
+ array(
61
+ 'markup' => '<iframe width="560" height="315" src="http://www.youtube.com/embed/Fp0U2Vglkjw" frameborder="0" allowfullscreen></iframe>',
62
+ 'expected' => 'http://img.youtube.com/vi/Fp0U2Vglkjw/maxresdefault.jpg',
63
+ 'name' => 'iFrame HD'
64
+ ),
65
+ array(
66
+ 'markup' => '<object width="560" height="315"><param name="movie" value="http://www.youtube.com/v/Fp0U2Vglkjw?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/Fp0U2Vglkjw?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="560" height="315" allowscriptaccess="always" allowfullscreen="true"></embed></object>',
67
+ 'expected' => 'http://img.youtube.com/vi/Fp0U2Vglkjw/maxresdefault.jpg',
68
+ 'name' => 'Old embed HD'
69
+ ),
70
+ array(
71
+ 'markup' => '<iframe width="560" height="315" src="http://www.youtube.com/embed/vv_AitYPjtc" frameborder="0" allowfullscreen></iframe>',
72
+ 'expected' => 'http://img.youtube.com/vi/vv_AitYPjtc/0.jpg',
73
+ 'name' => 'iFrame SD'
74
+ ),
75
+ array(
76
+ 'markup' => '<object width="560" height="315"><param name="movie" value="http://www.youtube.com/v/vv_AitYPjtc?version=3&amp;hl=en_US"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/vv_AitYPjtc?version=3&amp;hl=en_US" type="application/x-shockwave-flash" width="560" height="315" allowscriptaccess="always" allowfullscreen="true"></embed></object>',
77
+ 'expected' => 'http://img.youtube.com/vi/vv_AitYPjtc/0.jpg',
78
+ 'name' => 'Old embed SD'
79
+ ),
80
+ );
81
+
82
+ }
83
+
84
+ // Add to provider array
85
+ add_filter( 'video_thumbnail_providers', array( 'YouTube_Thumbnails', 'register_provider' ) );
86
+
87
+ ?>
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === Video Thumbnails ===
2
  Contributors: sutherlandboswell
3
  Donate link: http://wie.ly/u/donate
4
- Tags: Video, Thumbnails, YouTube, Vimeo, Blip.tv, Justin.tv, Dailymotion, Metacafe, Image, Featured Image, Post Thumbnail
5
- Requires at least: 3.0
6
- Tested up to: 3.4.2
7
- Stable tag: 1.8.2
8
 
9
  Video Thumbnails simplifies the process of automatically displaying video thumbnails in your WordPress template.
10
 
@@ -16,13 +16,20 @@ Video Thumbnails currently supports these video services:
16
 
17
  * YouTube
18
  * Vimeo
 
 
19
  * Justin.tv
20
- * Blip.tv
21
  * Dailymotion
22
  * Metacafe
 
 
 
 
 
23
 
24
  Video Thumbnails even works with most video embedding plugins, including:
25
 
 
26
  * [Viper's Video Quicktags](http://wordpress.org/extend/plugins/vipers-video-quicktags/)
27
  * [Simple Video Embedder](http://wordpress.org/extend/plugins/simple-video-embedder/)
28
  * [Vimeo Shortcode](http://blog.esimplestudios.com/2010/08/embedding-vimeo-videos-in-wordpress/)
@@ -68,7 +75,7 @@ The settings page includes a checklist of all your post types so you can pick an
68
 
69
  The best solution is to use the Featured Image setting and [the_post_thumbnail](http://codex.wordpress.org/Function_Reference/the_post_thumbnail) template tag.
70
 
71
- As an alternative you could assign a class to the element and style it with CSS, or even use a library like [TimThumb](http://code.google.com/p/timthumb/) to resize your images.
72
 
73
  = I edited my theme and now I'm seeing the thumbnail and the video, how do I only display the thumbnail? =
74
 
@@ -76,7 +83,7 @@ Every theme is different, so this can be tricky if you aren't familiar with Word
76
 
77
  = Why are there black bars on some YouTube thumbnails? =
78
 
79
- This is an unfortunate side effect of widescreen videos on YouTube. The thumbnail YouTube provides is always the same ratio, which creates black bars when a video is widescreen. Some themes will crop featured images and it may not be visible, but if you are comfortable editing your theme, I recommend using [TimThumb](http://code.google.com/p/timthumb/) to resize and crop your images.
80
 
81
  = Why did it stop finding thumbnails for Vimeo? =
82
 
@@ -85,9 +92,35 @@ The Vimeo API has a rate limit, so in rare cases you may exceed this limit. Try
85
  == Screenshots ==
86
 
87
  1. The Video Thumbnail meta box on the Edit Post page
 
88
 
89
  == Changelog ==
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  = 1.8.2 =
92
  * Fixes issue where some servers were unable to download thumbnails from YouTube
93
  * Fixes possible issue setting new thumbnail as featured image
@@ -228,6 +261,9 @@ The Vimeo API has a rate limit, so in rare cases you may exceed this limit. Try
228
 
229
  == Upgrade Notice ==
230
 
 
 
 
231
  = 1.0 =
232
  This is the single biggest update to Video Thumbnails so far, so be sure to check out the new settings page and documentation.
233
 
@@ -240,4 +276,4 @@ This version adds the thumbnail URL to the post's meta data, meaning any outside
240
 
241
  == Roadmap ==
242
 
243
- Version 2.0 is in the works and will mainly include code reorganization and optimizations, but suggestions for new features are always welcome.
1
  === Video Thumbnails ===
2
  Contributors: sutherlandboswell
3
  Donate link: http://wie.ly/u/donate
4
+ Tags: Video, Thumbnails, YouTube, Vimeo, Blip, Justin.tv, Dailymotion, Metacafe, Image, Featured Image, Post Thumbnail
5
+ Requires at least: 3.1
6
+ Tested up to: 3.5.1
7
+ Stable tag: 2.0
8
 
9
  Video Thumbnails simplifies the process of automatically displaying video thumbnails in your WordPress template.
10
 
16
 
17
  * YouTube
18
  * Vimeo
19
+ * Facebook
20
+ * Blip
21
  * Justin.tv
 
22
  * Dailymotion
23
  * Metacafe
24
+ * Funny or Die
25
+ * MPORA
26
+ * Wistia
27
+ * Youku
28
+ * CollegeHumor
29
 
30
  Video Thumbnails even works with most video embedding plugins, including:
31
 
32
+ * [Automatic Youtube Video Posts Plugin](http://wordpress.org/extend/plugins/automatic-youtube-video-posts/)
33
  * [Viper's Video Quicktags](http://wordpress.org/extend/plugins/vipers-video-quicktags/)
34
  * [Simple Video Embedder](http://wordpress.org/extend/plugins/simple-video-embedder/)
35
  * [Vimeo Shortcode](http://blog.esimplestudios.com/2010/08/embedding-vimeo-videos-in-wordpress/)
75
 
76
  The best solution is to use the Featured Image setting and [the_post_thumbnail](http://codex.wordpress.org/Function_Reference/the_post_thumbnail) template tag.
77
 
78
+ As an alternative you could assign a class to the element and style it with CSS.
79
 
80
  = I edited my theme and now I'm seeing the thumbnail and the video, how do I only display the thumbnail? =
81
 
83
 
84
  = Why are there black bars on some YouTube thumbnails? =
85
 
86
+ This is an unfortunate side effect of some old YouTube videos not having widescreen thumbnails. As of version 2.0, the plugin checks for HD thumbnails so this issue should be less common.
87
 
88
  = Why did it stop finding thumbnails for Vimeo? =
89
 
92
  == Screenshots ==
93
 
94
  1. The Video Thumbnail meta box on the Edit Post page
95
+ 1. Settings page
96
 
97
  == Changelog ==
98
 
99
+ = 2.0 =
100
+ * Completely rewritten for better performance, more organized code, and easier maintenance
101
+ * Added support for Funny or Die
102
+ * Added support for MPORA
103
+ * Added support for Wistia
104
+ * Added support for Facebook videos
105
+ * Added support for CollegeHumor
106
+ * Added support for Youku
107
+ * Added support for HD YouTube thumbnails
108
+ * Added support for higher resolution Vimeo thumbnails
109
+ * Added support for private Vimeo videos (API credentials required)
110
+ * Added support for Vimeo channel URLs
111
+ * Added support for [Automatic Youtube Video Posts Plugin](http://wordpress.org/extend/plugins/automatic-youtube-video-posts/)
112
+ * Added filters to make plugin extensible
113
+ * Removed cURL requirement (still requires ability to make external requests)
114
+ * Better checks for blank thumbnails before added to media library
115
+ * Adds 'video_thumbnail' field to video thumbnails saved in the media library
116
+ * Option to clear all video thumbnails (clears custom field from posts and deletes video thumbnails added after 2.0 from library)
117
+ * Better file names
118
+ * Added provider tests on debugging page to help troubleshoot
119
+ * Added a markup detection on debugging page
120
+ * Added "Installation Information" section to debugging page with helpful troubleshooting info
121
+ * Settings improvements
122
+ * Bug fixes
123
+
124
  = 1.8.2 =
125
  * Fixes issue where some servers were unable to download thumbnails from YouTube
126
  * Fixes possible issue setting new thumbnail as featured image
261
 
262
  == Upgrade Notice ==
263
 
264
+ = 2.0 =
265
+ Despite being a major upgrade, your settings should remain intact. Please report any problems so they can be fixed quickly!
266
+
267
  = 1.0 =
268
  This is the single biggest update to Video Thumbnails so far, so be sure to check out the new settings page and documentation.
269
 
276
 
277
  == Roadmap ==
278
 
279
+ With the release of 2.0, focus will be put on ensuring more widespread support and providing tools for other developers.
screenshot-2.gif ADDED
Binary file
video-thumbnails.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
  /*
3
  Plugin Name: Video Thumbnails
4
- Plugin URI: http://sutherlandboswell.com/projects/wordpress-video-thumbnails/
5
- Description: Automatically retrieve video thumbnails for your posts and display them in your theme. Currently supports YouTube, Vimeo, Blip.tv, Justin.tv, Dailymotion and Metacafe.
6
  Author: Sutherland Boswell
7
  Author URI: http://sutherlandboswell.com
8
- Version: 1.8.2
9
  License: GPL2
10
  */
11
- /* Copyright 2010 Sutherland Boswell (email : sutherland.boswell@gmail.com)
12
 
13
  This program is free software; you can redistribute it and/or modify
14
  it under the terms of the GNU General Public License, version 2, as
@@ -24,303 +24,208 @@ License: GPL2
24
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
  */
26
 
27
- // Get Vimeo Thumbnail
28
- function getVimeoInfo( $id, $info = 'thumbnail_large' ) {
29
- if ( ! function_exists( 'curl_init' ) ) {
30
- return null;
31
- } else {
32
- $ch = curl_init();
33
- $videoinfo_url = "http://vimeo.com/api/v2/video/$id.php";
34
- curl_setopt( $ch, CURLOPT_URL, $videoinfo_url );
35
- curl_setopt( $ch, CURLOPT_HEADER, 0 );
36
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
37
- curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
38
- curl_setopt( $ch, CURLOPT_FAILONERROR, true ); // Return an error for curl_error() processing if HTTP response code >= 400
39
- $output = unserialize( curl_exec( $ch ) );
40
- $output = $output[0][$info];
41
- if ( curl_error( $ch ) != null ) {
42
- $output = new WP_Error( 'vimeo_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $videoinfo_url . '">' . $videoinfo_url . '</a>.<br /><a href="http://curl.haxx.se/libcurl/c/libcurl-errors.html">Libcurl error</a> ' . curl_errno( $ch ) . ': <code>' . curl_error( $ch ) . '</code>. If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.' ) );
43
- }
44
- curl_close( $ch );
45
- return $output;
46
- }
47
- };
48
-
49
- // Blip.tv Functions
50
- function getBliptvInfo( $id ) {
51
- $videoinfo_url = "http://blip.tv/players/episode/$id?skin=rss";
52
- $xml = simplexml_load_file( $videoinfo_url );
53
- if ( $xml == false ) {
54
- return new WP_Error( 'bliptv_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $videoinfo_url . '">' . $videoinfo_url . '</a>. If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.' ) );
55
- } else {
56
- $result = $xml->xpath( "/rss/channel/item/media:thumbnail/@url" );
57
- $thumbnail = (string) $result[0]['url'];
58
- return $thumbnail;
59
- }
60
- }
61
 
62
- // Justin.tv Functions
63
- function getJustintvInfo( $id ) {
64
- $xml = simplexml_load_file( "http://api.justin.tv/api/clip/show/$id.xml" );
65
- return (string) $xml->clip->image_url_large;
66
- }
67
 
68
- // Get DailyMotion Thumbnail
69
- function getDailyMotionThumbnail( $id ) {
70
- if ( ! function_exists( 'curl_init' ) ) {
71
- return null;
72
- } else {
73
- $ch = curl_init();
74
- $videoinfo_url = "https://api.dailymotion.com/video/$id?fields=thumbnail_url";
75
- curl_setopt( $ch, CURLOPT_URL, $videoinfo_url );
76
- curl_setopt( $ch, CURLOPT_HEADER, 0 );
77
- curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
78
- curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false );
79
- curl_setopt( $ch, CURLOPT_TIMEOUT, 10 );
80
- curl_setopt( $ch, CURLOPT_FAILONERROR, true ); // Return an error for curl_error() processing if HTTP response code >= 400
81
- $output = curl_exec( $ch );
82
- $output = json_decode( $output );
83
- $output = $output->thumbnail_url;
84
- if ( curl_error( $ch ) != null ) {
85
- $output = new WP_Error( 'dailymotion_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $videoinfo_url . '">' . $videoinfo_url . '</a>.<br /><a href="http://curl.haxx.se/libcurl/c/libcurl-errors.html">Libcurl error</a> ' . curl_errno( $ch ) . ': <code>' . curl_error( $ch ) . '</code>. If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.' ) );
86
- }
87
- curl_close( $ch ); // Moved here to allow curl_error() operation above. Was previously below curl_exec() call.
88
- return $output;
89
- }
90
- };
91
-
92
- // Metacafe
93
- function getMetacafeThumbnail( $id ) {
94
- $videoinfo_url = "http://www.metacafe.com/api/item/$id/";
95
- $xml = simplexml_load_file( $videoinfo_url );
96
- if ( $xml == false ) {
97
- return new WP_Error( 'metacafe_info_retrieval', __( 'Error retrieving video information from the URL <a href="' . $videoinfo_url . '">' . $videoinfo_url . '</a>.<br /><a href="http://curl.haxx.se/libcurl/c/libcurl-errors.html">Libcurl error</a> ' . curl_errno( $ch ) . ': <code>' . curl_error( $ch ) . '</code>. If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.' ) );
98
- } else {
99
- $result = $xml->xpath( "/rss/channel/item/media:thumbnail/@url" );
100
- $thumbnail = (string) $result[0]['url'];
101
- return $thumbnail;
102
- }
103
- };
104
 
105
- //
106
- // The Main Event
107
- //
108
- function get_video_thumbnail( $post_id = null ) {
109
 
110
- // Get the post ID if none is provided
111
- if ( $post_id == null OR $post_id == '' ) $post_id = get_the_ID();
112
 
113
- // Check to see if thumbnail has already been found
114
- if( ( $thumbnail_meta = get_post_meta( $post_id, '_video_thumbnail', true ) ) != '' ) {
115
- return $thumbnail_meta;
116
- }
117
- // If the thumbnail isn't stored in custom meta, fetch a thumbnail
118
- else {
119
 
120
- // Get the post or custom field to search
121
- if ( $video_key = get_option( 'video_thumbnails_custom_field' ) ) {
122
- $markup = get_post_meta( $post_id, $video_key, true );
123
- } else {
124
- $post_array = get_post( $post_id );
125
- $markup = $post_array->post_content;
126
- $markup = apply_filters( 'the_content', $markup );
127
- }
128
- $new_thumbnail = null;
129
 
130
- // Simple Video Embedder Compatibility
131
- if ( function_exists( 'p75HasVideo' ) ) {
132
- if ( p75HasVideo( $post_id ) ) {
133
- $markup = p75GetVideo( $post_id );
134
- }
135
- }
136
 
137
- // Checks for the old standard YouTube embed
138
- preg_match( '#<object[^>]+>.+?https?://www\.youtube(?:\-nocookie)?\.com/[ve]/([A-Za-z0-9\-_]+).+?</object>#s', $markup, $matches );
139
 
140
- // More comprehensive search for YouTube embed, redundant but necessary until more testing is completed
141
- if ( !isset( $matches[1] ) ) {
142
- preg_match( '#https?://www\.youtube(?:\-nocookie)?\.com/[ve]/([A-Za-z0-9\-_]+)#', $markup, $matches );
143
- }
144
 
145
- // Checks for YouTube iframe, the new standard since at least 2011
146
- if ( !isset( $matches[1] ) ) {
147
- preg_match( '#https?://www\.youtube(?:\-nocookie)?\.com/embed/([A-Za-z0-9\-_]+)#', $markup, $matches );
148
- }
149
 
150
- // Checks for any YouTube URL. After http(s) support a or v for Youtube Lyte and v or vh for Smart Youtube plugin
151
- if ( !isset( $matches[1] ) ) {
152
- preg_match( '#(?:https?(?:a|vh?)?://)?(?:www\.)?youtube(?:\-nocookie)?\.com/watch\?.*v=([A-Za-z0-9\-_]+)#', $markup, $matches );
153
- }
154
 
155
- // Checks for any shortened youtu.be URL. After http(s) a or v for Youtube Lyte and v or vh for Smart Youtube plugin
156
- if ( !isset( $matches[1] ) ) {
157
- preg_match( '#(?:https?(?:a|vh?)?://)?youtu\.be/([A-Za-z0-9\-_]+)#', $markup, $matches );
158
- }
 
 
 
159
 
160
- // Checks for YouTube Lyte
161
- if ( !isset( $matches[1] ) && function_exists( 'lyte_parse' ) ) {
162
- preg_match( '#<div class="lyte" id="([A-Za-z0-9\-_]+)"#', $markup, $matches );
163
- }
164
-
165
- // If we've found a YouTube video ID, create the thumbnail URL
166
- if ( isset( $matches[1] ) ) {
167
- $youtube_thumbnail = 'http://img.youtube.com/vi/' . $matches[1] . '/0.jpg';
168
 
169
- // Check to make sure it's an actual thumbnail
170
- if ( ! function_exists( 'curl_init' ) ) {
171
- $new_thumbnail = $youtube_thumbnail;
172
- } else {
173
- $ch = curl_init( $youtube_thumbnail );
174
- curl_setopt( $ch, CURLOPT_NOBODY, true );
175
- curl_exec( $ch );
176
- $retcode = curl_getinfo( $ch, CURLINFO_HTTP_CODE );
177
- // $retcode > 400 -> not found, $retcode = 200, found.
178
- curl_close( $ch );
179
- if ( $retcode == 200 ) {
180
- $new_thumbnail = $youtube_thumbnail;
181
- }
182
- }
183
  }
184
 
185
- // Vimeo
186
- if ( $new_thumbnail == null ) {
187
 
188
- // Standard embed code
189
- preg_match( '#<object[^>]+>.+?http://vimeo\.com/moogaloop.swf\?clip_id=([A-Za-z0-9\-_]+)&.+?</object>#s', $markup, $matches );
190
 
191
- // Find Vimeo embedded with iframe code
192
- if ( !isset( $matches[1] ) ) {
193
- preg_match( '#http://player\.vimeo\.com/video/([0-9]+)#', $markup, $matches );
 
 
194
  }
 
 
195
 
196
- // If we still haven't found anything, check for Vimeo embedded with JR_embed
197
- if ( !isset( $matches[1] ) ) {
198
- preg_match( '#\[vimeo id=([A-Za-z0-9\-_]+)]#', $markup, $matches );
199
- }
 
200
 
201
- // If we still haven't found anything, check for Vimeo URL
202
- if ( !isset( $matches[1] ) ) {
203
- preg_match( '#(?:http://)?(?:www\.)?vimeo\.com/([A-Za-z0-9\-_]+)#', $markup, $matches );
204
- }
205
 
206
- // If we still haven't found anything, check for Vimeo shortcode
207
- if ( !isset( $matches[1] ) ) {
208
- preg_match( '#\[vimeo clip_id="([A-Za-z0-9\-_]+)"[^>]*]#', $markup, $matches );
209
- }
210
- if ( !isset( $matches[1] ) ) {
211
- preg_match( '#\[vimeo video_id="([A-Za-z0-9\-_]+)"[^>]*]#', $markup, $matches );
212
  }
213
-
214
- // Now if we've found a Vimeo ID, let's set the thumbnail URL
215
- if ( isset( $matches[1] ) ) {
216
- $vimeo_thumbnail = getVimeoInfo( $matches[1], $info = 'thumbnail_large' );
217
- if ( is_wp_error( $vimeo_thumbnail ) ) {
218
- return $vimeo_thumbnail;
219
- } else if ( isset( $vimeo_thumbnail ) ) {
220
- $new_thumbnail = $vimeo_thumbnail;
221
- }
222
  }
223
  }
 
224
 
225
- // Blip.tv
226
- if ( $new_thumbnail == null ) {
227
 
228
- // Blip.tv embed URL
229
- preg_match( '#http://blip\.tv/play/([A-Za-z0-9]+)#', $markup, $matches );
230
 
231
- // Now if we've found a Blip.tv embed URL, let's set the thumbnail URL
232
- if ( isset( $matches[1] ) ) {
233
- $blip_thumbnail = getBliptvInfo( $matches[1] );
234
- if ( is_wp_error( $blip_thumbnail ) ) {
235
- return $blip_thumbnail;
236
- } else if ( isset( $blip_thumbnail ) ) {
237
- $new_thumbnail = $blip_thumbnail;
238
- }
239
- }
240
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
- // Justin.tv
243
- if ( $new_thumbnail == null ) {
244
-
245
- // Justin.tv archive ID
246
- preg_match( '#archive_id=([0-9]+)#', $markup, $matches );
247
 
248
- // Now if we've found a Justin.tv archive ID, let's set the thumbnail URL
249
- if ( isset( $matches[1] ) ) {
250
- $justin_thumbnail = getJustintvInfo( $matches[1] );
251
- $new_thumbnail = $justin_thumbnail;
252
  }
253
- }
254
-
255
- // Dailymotion
256
- if ( $new_thumbnail == null ) {
257
 
258
- // Dailymotion flash
259
- preg_match( '#<object[^>]+>.+?http://www\.dailymotion\.com/swf/video/([A-Za-z0-9]+).+?</object>#s', $markup, $matches );
260
 
261
- // Dailymotion url
262
- if ( !isset( $matches[1] ) ) {
263
- preg_match( '#(?:https?://)?(?:www\.)?dailymotion\.com/video/([A-Za-z0-9]+)#', $markup, $matches );
264
- }
 
 
265
 
266
- // Dailymotion iframe
267
- if ( !isset( $matches[1] ) ) {
268
- preg_match( '#https?://www\.dailymotion\.com/embed/video/([A-Za-z0-9]+)#', $markup, $matches );
269
- }
270
 
271
- // Now if we've found a Dailymotion video ID, let's set the thumbnail URL
272
- if ( isset( $matches[1] ) ) {
273
- $dailymotion_thumbnail = getDailyMotionThumbnail( $matches[1] );
274
- if ( is_wp_error( $dailymotion_thumbnail ) ) {
275
- return $dailymotion_thumbnail;
276
- } else if ( isset( $dailymotion_thumbnail ) ) {
277
- $new_thumbnail = strtok( $dailymotion_thumbnail, '?' );
278
  }
279
  }
280
- }
281
-
282
- // Metacafe
283
- if ( $new_thumbnail == null ) {
284
 
285
- // Find ID from Metacafe embed url
286
- preg_match( '#http://www\.metacafe\.com/fplayer/([A-Za-z0-9\-_]+)/#', $markup, $matches );
287
 
288
- // Now if we've found a Metacafe video ID, let's set the thumbnail URL
289
- if ( isset( $matches[1] ) ) {
290
- $metacafe_thumbnail = getMetacafeThumbnail( $matches[1] );
291
- if ( is_wp_error( $metacafe_thumbnail ) ) {
292
- return $metacafe_thumbnail;
293
- } else if ( isset( $metacafe_thumbnail ) ) {
294
- $new_thumbnail = strtok( $metacafe_thumbnail, '?' );
295
- }
 
 
 
296
  }
297
  }
 
298
 
299
- // Return the new thumbnail variable and update meta if one is found
300
- if ( $new_thumbnail != null ) {
301
 
302
- // Save as Attachment if enabled
303
- if ( get_option( 'video_thumbnails_save_media' ) == 1 ) {
 
 
 
 
 
 
304
 
305
- $response = wp_remote_get( $new_thumbnail, array( 'sslverify' => false ) );
 
 
306
 
307
- // Check for error
308
- if( is_wp_error( $response ) ) {
309
- return new WP_Error( 'thumbnail_retrieval', __( 'Error retrieving a thumbnail from the URL <a href="' . $new_thumbnail . '">' . $new_thumbnail . '</a> If opening that URL in your web browser shows an image, the problem may be related to your web server and might be something your server administrator can solve. Error details: "' . $response->get_error_message() . '"' ) );
310
- }
 
 
311
 
312
- $image_contents = wp_remote_retrieve_body( $response );
 
313
 
314
- $upload = wp_upload_bits( basename( $new_thumbnail ), null, $image_contents );
 
 
 
 
315
 
316
- $new_thumbnail = $upload['url'];
317
 
318
  $filename = $upload['file'];
319
 
320
  $wp_filetype = wp_check_filetype( basename( $filename ), null );
321
  $attachment = array(
322
  'post_mime_type' => $wp_filetype['type'],
323
- 'post_title' => get_the_title($post_id),
324
  'post_content' => '',
325
  'post_status' => 'inherit'
326
  );
@@ -330,360 +235,72 @@ function get_video_thumbnail( $post_id = null ) {
330
  require_once( ABSPATH . 'wp-admin/includes/image.php' );
331
  $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
332
  wp_update_attachment_metadata( $attach_id, $attach_data );
333
-
334
- }
335
 
336
- // Add hidden custom field with thumbnail URL
337
- if ( !update_post_meta( $post_id, '_video_thumbnail', $new_thumbnail ) ) add_post_meta( $post_id, '_video_thumbnail', $new_thumbnail, true );
338
 
339
- // Set attachment as featured image if enabled
340
- if ( get_option( 'video_thumbnails_set_featured' ) == 1 && get_option( 'video_thumbnails_save_media' ) == 1 && !has_post_thumbnail( $post_id ) ) {
341
- set_post_thumbnail( $post_id, $attach_id );
342
  }
343
- }
344
- return $new_thumbnail;
345
 
346
- }
347
- };
348
-
349
- // Echo thumbnail
350
- function video_thumbnail( $post_id = null ) {
351
- if ( ( $video_thumbnail = get_video_thumbnail( $post_id ) ) == null ) { echo plugins_url() . '/video-thumbnails/default.jpg'; }
352
- else { echo $video_thumbnail; }
353
- };
354
-
355
- // Create Meta Fields on Edit Page
356
-
357
- add_action( 'admin_init', 'video_thumbnail_admin_init' );
358
-
359
- function video_thumbnail_admin_init() {
360
- $video_thumbnails_post_types = get_option( 'video_thumbnails_post_types' );
361
- if ( is_array( $video_thumbnails_post_types ) ) {
362
- foreach ( $video_thumbnails_post_types as $type ) {
363
- add_meta_box( 'video_thumbnail', 'Video Thumbnail', 'video_thumbnail_admin', $type, 'side', 'low' );
364
  }
365
- }
366
- }
367
 
368
- function video_thumbnail_admin() {
369
- global $post;
370
- $custom = get_post_custom( $post->ID );
371
- $video_thumbnail = $custom["_video_thumbnail"][0];
372
-
373
- if ( isset( $video_thumbnail ) && $video_thumbnail != '' ) {
374
- echo '<p id="video-thumbnails-preview"><img src="' . $video_thumbnail . '" style="max-width:100%;" /></p>'; }
375
-
376
- if ( get_post_status() == 'publish' || get_post_status() == 'private' ) {
377
- if ( isset( $video_thumbnail ) && $video_thumbnail != '' ) {
378
- echo '<p><a href="#" id="video-thumbnails-reset" onclick="video_thumbnails_reset(\'' . $post->ID . '\' );return false;">Reset Video Thumbnail</a></p>';
379
- } else {
380
- echo '<p id="video-thumbnails-preview">We didn\'t find a video thumbnail for this post.</p>';
381
- echo '<p><a href="#" id="video-thumbnails-reset" onclick="video_thumbnails_reset(\'' . $post->ID . '\' );return false;">Search Again</a></p>';
382
- }
383
- } else {
384
- if ( isset( $video_thumbnail ) && $video_thumbnail != '' ) {
385
- echo '<p><a href="#" id="video-thumbnails-reset" onclick="video_thumbnails_reset(\'' . $post->ID . '\' );return false;">Reset Video Thumbnail</a></p>';
386
- } else {
387
- echo '<p>A video thumbnail will be found for this post when it is published.</p>';
388
- }
389
  }
390
- }
391
-
392
- // AJAX Searching
393
 
394
- if ( in_array( basename( $_SERVER['PHP_SELF'] ), apply_filters( 'video_thumbnails_editor_pages', array( 'post-new.php', 'page-new.php', 'post.php', 'page.php' ) ) ) ) {
395
- add_action( 'admin_head', 'video_thumbnails_ajax' );
396
- }
397
 
398
- function video_thumbnails_ajax() {
399
- ?>
400
 
401
- <!-- Video Thumbnails Researching Ajax -->
402
- <script type="text/javascript">
403
- function video_thumbnails_reset(id) {
404
-
405
- var data = {
406
- action: 'video_thumbnails',
407
- post_id: id
408
- };
409
-
410
- document.getElementById('video-thumbnails-preview').innerHTML='Working... <img src="<?php echo home_url( 'wp-admin/images/loading.gif' ); ?>"/>';
411
-
412
- // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
413
- jQuery.post(ajaxurl, data, function(response){
414
- document.getElementById('video-thumbnails-preview').innerHTML=response;
415
- });
416
- };
417
- </script>
418
- <?php
419
- }
420
 
421
- add_action( 'wp_ajax_video_thumbnails', 'video_thumbnails_callback' );
422
 
423
- function video_thumbnails_callback() {
424
- global $wpdb; // this is how you get access to the database
425
-
426
- $post_id = $_POST['post_id'];
427
-
428
- delete_post_meta( $post_id, '_video_thumbnail' );
429
-
430
- $video_thumbnail = get_video_thumbnail( $post_id );
431
-
432
- if ( is_wp_error( $video_thumbnail ) ) {
433
- echo $video_thumbnail->get_error_message();
434
- } else if ( $video_thumbnail != null ) {
435
- echo '<img src="' . $video_thumbnail . '" style="max-width:100%;" />';
436
- } else {
437
- echo 'We didn\'t find a video thumbnail for this post. (be sure you have saved changes first)';
438
- }
439
-
440
- die();
441
- }
442
-
443
- // Find video thumbnail when saving a post, but not on autosave
444
-
445
- add_action( 'new_to_publish', 'save_video_thumbnail', 10, 1 );
446
- add_action( 'draft_to_publish', 'save_video_thumbnail', 10, 1 );
447
- add_action( 'pending_to_publish', 'save_video_thumbnail', 10, 1 );
448
- add_action( 'future_to_publish', 'save_video_thumbnail', 10, 1 );
449
- add_action( 'private_to_publish', 'save_video_thumbnail', 10, 1 );
450
-
451
- // Finds thumbnail when posting from XML-RPC
452
- // (this action passes the post ID as an argument so 'get_video_thumbnail' is used instead)
453
-
454
- add_action( 'xmlrpc_publish_post', 'get_video_thumbnail', 10, 1 );
455
-
456
- function save_video_thumbnail( $post ) {
457
- $post_type = get_post_type( $post->ID );
458
- $video_thumbnails_post_types = get_option( 'video_thumbnails_post_types' );
459
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
460
- return null;
461
- } else {
462
- // Check that Video Thumbnails are enabled for current post type
463
- if ( in_array( $post_type, (array) $video_thumbnails_post_types ) || $post_type == $video_thumbnails_post_types ) {
464
- get_video_thumbnail( $post->ID );
465
  } else {
466
- return null;
467
  }
468
- }
469
- }
470
-
471
- // Set Default Options
472
-
473
- register_activation_hook( __FILE__, 'video_thumbnails_activate' );
474
- register_deactivation_hook( __FILE__, 'video_thumbnails_deactivate' );
475
-
476
- function video_thumbnails_activate() {
477
- add_option( 'video_thumbnails_save_media', '1' );
478
- add_option( 'video_thumbnails_set_featured', '1' );
479
- add_option( 'video_thumbnails_custom_field', '' );
480
- add_option( 'video_thumbnails_post_types', array( 'post' ) );
481
- }
482
-
483
- function video_thumbnails_deactivate() {
484
- delete_option( 'video_thumbnails_save_media' );
485
- delete_option( 'video_thumbnails_set_featured' );
486
- delete_option( 'video_thumbnails_custom_field' );
487
- delete_option( 'video_thumbnails_post_types' );
488
- }
489
-
490
- // Check for cURL
491
-
492
- register_activation_hook( __FILE__, 'video_thumbnails_curl_check' );
493
 
494
- function video_thumbnails_curl_check() {
495
- if ( ! function_exists( 'curl_init' ) ) {
496
- deactivate_plugins( basename( __FILE__ ) ); // Deactivate ourself
497
- wp_die( 'Sorry, but this plugin requires <a href="http://curl.haxx.se/libcurl/">libcurl</a> to be activated on your server.' );
498
  }
499
- }
500
-
501
- // AJAX for Past Posts
502
-
503
- if ( isset ( $_GET['page'] ) && ( $_GET['page'] == 'video-thumbnail-options' ) ) {
504
- add_action( 'admin_head', 'video_thumbnails_past_ajax' );
505
- }
506
-
507
- function video_thumbnails_past_ajax() {
508
- ?>
509
-
510
- <!-- Video Thumbnails Past Post Ajax -->
511
- <script type="text/javascript">
512
- function video_thumbnails_past(id) {
513
-
514
- var data = {
515
- action: 'video_thumbnails_past',
516
- post_id: id
517
- };
518
-
519
- // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
520
- jQuery.post(ajaxurl, data, function(response){
521
-
522
- document.getElementById(id+'_result').innerHTML = response;
523
-
524
- });
525
-
526
- };
527
 
528
- <?php
529
- $video_thumbnails_post_types = get_option( 'video_thumbnails_post_types' );
530
- $posts = get_posts( array(
531
- 'showposts' => -1,
532
- 'post_type' => $video_thumbnails_post_types
533
- ) );
534
-
535
- if ( $posts ) {
536
- foreach ( $posts as $post ) {
537
- $post_ids[] = $post->ID;
538
- }
539
- $ids = implode( ', ', $post_ids );
540
  }
541
- ?>
542
-
543
- var scanComplete = false;
544
 
545
- function scan_video_thumbnails(){
546
 
547
- if(scanComplete==false){
548
- scanComplete = true;
549
- var ids = new Array(<?php echo $ids; ?>);
550
- for (var i = 0; i < ids.length; i++){
551
- var container = document.getElementById('video-thumbnails-past');
552
- var new_element = document.createElement('li');
553
- new_element.setAttribute('id',ids[i]+'_result');
554
- new_element.innerHTML = 'Waiting...';
555
- container.insertBefore(new_element, container.firstChild);
556
- }
557
- for (var i = 0; i < ids.length; i++){
558
- document.getElementById(ids[i]+'_result').innerHTML = '<span style="color:yellow">&#8226;</span> Working...';
559
- video_thumbnails_past(ids[i]);
560
- }
561
- } else {
562
- alert('Scan has already been run, please reload the page before trying again.')
563
- }
564
-
565
- }
566
- </script>
567
-
568
- <?php
569
- }
570
 
571
- add_action( 'wp_ajax_video_thumbnails_past', 'video_thumbnails_past_callback' );
572
-
573
- function video_thumbnails_past_callback() {
574
- global $wpdb; // this is how you get access to the database
575
-
576
- $post_id = $_POST['post_id'];
577
-
578
- echo get_the_title( $post_id ) . ' - ';
579
-
580
- $video_thumbnail = get_video_thumbnail( $post_id );
581
-
582
- if ( is_wp_error( $video_thumbnail ) ) {
583
- echo $video_thumbnail->get_error_message();
584
- } else if ( $video_thumbnail != null ) {
585
- echo '<span style="color:green">&#10004;</span> Success!';
586
- } else {
587
- echo '<span style="color:red">&#10006;</span> Couldn\'t find a video thumbnail for this post.';
588
- }
589
-
590
- die();
591
- }
592
-
593
- // Administration
594
-
595
- add_action( 'admin_menu', 'video_thumbnails_menu' );
596
-
597
- function video_thumbnails_menu() {
598
- add_options_page( 'Video Thumbnail Options', 'Video Thumbnails', 'manage_options', 'video-thumbnail-options', 'video_thumbnail_options' );
599
- }
600
-
601
- function video_thumbnails_checkbox_option( $option_name, $option_description ) { ?>
602
- <fieldset><legend class="screen-reader-text"><span><?php echo $option_description; ?></span></legend>
603
- <label for="<?php echo $option_name; ?>"><input name="<?php echo $option_name; ?>" type="checkbox" id="<?php echo $option_name; ?>" value="1" <?php if ( get_option( $option_name ) == 1 ) echo 'checked="checked"'; ?>/> <?php echo $option_description; ?></label>
604
- </fieldset> <?php
605
  }
606
 
607
- function video_thumbnail_options() {
608
-
609
- if ( ! current_user_can( 'manage_options' ) ) {
610
- wp_die( __( 'You do not have sufficient permissions to access this page.' ) );
611
- }
612
-
613
- ?>
614
-
615
- <div class="wrap">
616
-
617
- <div id="icon-options-general" class="icon32"></div><h2>Video Thumbnails Options</h2>
618
-
619
- <p>Say thanks by donating, any amount is appreciated!<form action="https://www.paypal.com/cgi-bin/webscr" method="post"><input type="hidden" name="cmd" value="_s-xclick"><input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHRwYJKoZIhvcNAQcEoIIHODCCBzQCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYB1rPWk/Rr89ydxDsoXWyYIlAwIORRiWzcLHSBBVBMY69PHCO6WVTK2lXYmjZbDrvrHmN/jrM5r3Q008oX19NujzZ4d1VV+dWZxPU+vROuLToOFkk3ivjcvlT825HfdZRoiY/eTwWfBH93YQ+3kAAdc2s3FRxVyC4cUdrtbkBmYpDELMAkGBSsOAwIaBQAwgcQGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIkO3IVfkE9PGAgaA9fgOdXrQSpdGgo8ZgjiOxDGlEHoRL51gvB6AZdhNCubfLbqolJjYfTPEMg6Z0dfrq3hVSF2+nLV7BRcmXAtxY5NkH7vu1Kv0Bsb5kDOWb8h4AfnwElD1xyaykvYAr7CRNqHcizYRXZHKE7elWY0w6xRV/bfE7w6E4ZjKvFowHFp9E7/3mcZDrqxbZVU5hqs5gsV2YJj8fNBzG1bbdTucXoIIDhzCCA4MwggLsoAMCAQICAQAwDQYJKoZIhvcNAQEFBQAwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMB4XDTA0MDIxMzEwMTMxNVoXDTM1MDIxMzEwMTMxNVowgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBR07d/ETMS1ycjtkpkvjXZe9k+6CieLuLsPumsJ7QC1odNz3sJiCbs2wC0nLE0uLGaEtXynIgRqIddYCHx88pb5HTXv4SZeuv0Rqq4+axW9PLAAATU8w04qqjaSXgbGLP3NmohqM6bV9kZZwZLR/klDaQGo1u9uDb9lr4Yn+rBQIDAQABo4HuMIHrMB0GA1UdDgQWBBSWn3y7xm8XvVk/UtcKG+wQ1mSUazCBuwYDVR0jBIGzMIGwgBSWn3y7xm8XvVk/UtcKG+wQ1mSUa6GBlKSBkTCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb22CAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCBXzpWmoBa5e9fo6ujionW1hUhPkOBakTr3YCDjbYfvJEiv/2P+IobhOGJr85+XHhN0v4gUkEDI8r2/rNk1m0GA8HKddvTjyGw/XqXa+LSTlDYkqI8OwR8GEYj4efEtcRpRYBxV8KxAW93YDWzFGvruKnnLbDAF6VR5w/cCMn5hzGCAZowggGWAgEBMIGUMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbQIBADAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMTExMDA3MDUzMjM1WjAjBgkqhkiG9w0BCQQxFgQUHXhTYmeIfU7OyslesSVlGviqHbIwDQYJKoZIhvcNAQEBBQAEgYDAU3s+ej0si2FdN0uZeXhR+GGCDOMSYbkRswu7K3TRDXoD9D9c67VjQ+GfqP95cA9s40aT73goH+AxPbiQhG64OaHZZGJeSmwiGiCo4rBoVPxNUDONMPWaYfp6vm3Mt41gbxUswUEDNnzps4waBsFRJvuFjbbeQVYg7wbVfQC99Q==-----END PKCS7-----"><input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!"><img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1"></form></p>
620
-
621
- <form method="post" action="options.php">
622
- <?php wp_nonce_field( 'update-options' ); ?>
623
-
624
- <table class="form-table">
625
-
626
- <tr valign="top">
627
- <th scope="row">Save Thumbnail to Media</th>
628
- <td><?php video_thumbnails_checkbox_option( 'video_thumbnails_save_media', 'Save local copies of thumbnails using the media library' ); ?></td>
629
- </tr>
630
-
631
- <tr valign="top">
632
- <th scope="row">Set as Featured Image</th>
633
- <td><?php video_thumbnails_checkbox_option( 'video_thumbnails_set_featured', 'Automatically set thumbnail as featured image ("Save Thumbnail to Media" must be enabled)' ); ?></td>
634
- </tr>
635
-
636
- <tr valign="top">
637
- <th scope="row">Post Types</th>
638
- <td>
639
- <?php $video_thumbnails_post_types = get_option( 'video_thumbnails_post_types' ); ?>
640
- <?php foreach ( get_post_types() as $type ) : if ( $type == 'attachment' OR $type == 'revision' OR $type == 'nav_menu_item' ) continue; ?>
641
- <label for="video_thumbnails_post_types_<?php echo $type; ?>">
642
- <input id="video_thumbnails_post_types_<?php echo $type; ?>" name="video_thumbnails_post_types[]" type="checkbox" value="<?php echo $type; ?>" <?php if ( is_array( $video_thumbnails_post_types ) ) checked( in_array( $type, $video_thumbnails_post_types ) ); ?> />
643
- <?php echo $type; ?>
644
- </label>
645
- <br />
646
- <?php endforeach; ?>
647
- </td>
648
- </tr>
649
-
650
- <tr valign="top">
651
- <th scope="row">Custom Field (Optional: If your video is stored in a custom field, enter the name of that field here. Otherwise, leave this field blank.)</th>
652
- <td><fieldset><legend class="screen-reader-text"><span>Custom Field (Optional: If your video is stored in a custom field, enter the name of that field here. Otherwise, leave this field blank.)</span></legend>
653
- <input name="video_thumbnails_custom_field" type="text" id="video_thumbnails_custom_field" value="<?php echo get_option( 'video_thumbnails_custom_field' ); ?>" />
654
- </fieldset></td>
655
- </tr>
656
-
657
- </table>
658
-
659
- <p class="submit">
660
- <input type="submit" class="button-primary" value="<?php _e( 'Save Changes' ) ?>" />
661
- </p>
662
-
663
- <h3>How to use</h3>
664
-
665
- <p>For themes that use featured images, simply leave the two settings above enabled.</p>
666
-
667
- <p>For more detailed instructions, check out the page for <a href="http://wordpress.org/extend/plugins/video-thumbnails/">Video Thumbnails on the official plugin directory</a>.</p>
668
-
669
- <input type="hidden" name="action" value="update" />
670
- <input type="hidden" name="page_options" value="video_thumbnails_save_media,video_thumbnails_set_featured,video_thumbnails_post_types,video_thumbnails_custom_field" />
671
-
672
- </form>
673
-
674
- <h3>Scan All Posts</h3>
675
-
676
- <p>Scan all of your past posts for video thumbnails. Be sure to save any settings before running the scan.</p>
677
-
678
- <p><input type="submit" class="button-primary" onclick="scan_video_thumbnails();" value="Scan Past Posts" /></p>
679
-
680
- <ol id="video-thumbnails-past">
681
- </ol>
682
-
683
- </div>
684
-
685
- <?php
686
-
687
  }
688
 
689
  ?>
1
  <?php
2
  /*
3
  Plugin Name: Video Thumbnails
4
+ Plugin URI: http://refactored.co/plugins/video-thumbnails
5
+ Description: Automatically retrieve video thumbnails for your posts and display them in your theme. Currently supports YouTube, Vimeo, Facebook, Blip.tv, Justin.tv, Dailymotion, Metacafe, Wistia, Youku, Funny or Die, and MPORA.
6
  Author: Sutherland Boswell
7
  Author URI: http://sutherlandboswell.com
8
+ Version: 2.0
9
  License: GPL2
10
  */
11
+ /* Copyright 2013 Sutherland Boswell (email : sutherland.boswell@gmail.com)
12
 
13
  This program is free software; you can redistribute it and/or modify
14
  it under the terms of the GNU General Public License, version 2, as
24
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
  */
26
 
27
+ // Define
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ define( 'VIDEO_THUMBNAILS_PATH', dirname(__FILE__) );
30
+ define( 'VIDEO_THUMBNAILS_FIELD', '_video_thumbnail' );
31
+ define( 'VIDEO_THUMBNAILS_VERSION', '2.0' );
 
 
32
 
33
+ // Providers
34
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/providers/class-video-thumbnails-providers.php' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ // Extensions
37
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/extensions/class-video-thumbnails-extension.php' );
 
 
38
 
39
+ // Settings
40
+ require_once( VIDEO_THUMBNAILS_PATH . '/php/class-video-thumbnails-settings.php' );
41
 
42
+ // Class
 
 
 
 
 
43
 
44
+ class Video_Thumbnails {
 
 
 
 
 
 
 
 
45
 
46
+ var $providers = array();
47
+ var $settings;
 
 
 
 
48
 
49
+ function __construct() {
 
50
 
51
+ // Create provider array
52
+ $this->providers = apply_filters( 'video_thumbnail_providers', $this->providers );
 
 
53
 
54
+ // Settings
55
+ $this->settings = new Video_Thumbnails_Settings();
 
 
56
 
57
+ // Initialize meta box
58
+ add_action( 'admin_init', array( &$this, 'meta_box_init' ) );
 
 
59
 
60
+ // Add actions to save video thumbnails when saving
61
+ add_action( 'new_to_draft', array( &$this, 'save_video_thumbnail' ), 10, 1 );
62
+ add_action( 'new_to_publish', array( &$this, 'save_video_thumbnail' ), 10, 1 );
63
+ add_action( 'draft_to_publish', array( &$this, 'save_video_thumbnail' ), 10, 1 );
64
+ add_action( 'pending_to_publish', array( &$this, 'save_video_thumbnail' ), 10, 1 );
65
+ add_action( 'future_to_publish', array( &$this, 'save_video_thumbnail' ), 10, 1 );
66
+ add_action( 'private_to_publish', array( &$this, 'save_video_thumbnail' ), 10, 1 );
67
 
68
+ // Add actions to save video thumbnails when posting from XML-RPC (this action passes the post ID as an argument so 'get_video_thumbnail' is used instead)
69
+ add_action( 'xmlrpc_publish_post', 'get_video_thumbnail', 10, 1 );
 
 
 
 
 
 
70
 
71
+ // Add action for Ajax reset script on edit pages
72
+ if ( in_array( basename( $_SERVER['PHP_SELF'] ), apply_filters( 'video_thumbnails_editor_pages', array( 'post-new.php', 'page-new.php', 'post.php', 'page.php' ) ) ) ) {
73
+ add_action( 'admin_head', array( &$this, 'ajax_reset_script' ) );
 
 
 
 
 
 
 
 
 
 
 
74
  }
75
 
76
+ // Add action for Ajax reset callback
77
+ add_action( 'wp_ajax_reset_video_thumbnail', array( &$this, 'ajax_reset_callback' ) );
78
 
79
+ }
 
80
 
81
+ // Initialize meta box on edit page
82
+ function meta_box_init() {
83
+ if ( is_array( $this->settings->options['post_types'] ) ) {
84
+ foreach ( $this->settings->options['post_types'] as $type ) {
85
+ add_meta_box( 'video_thumbnail', 'Video Thumbnail', array( &$this, 'meta_box' ), $type, 'side', 'low' );
86
  }
87
+ }
88
+ }
89
 
90
+ // Construct the meta box
91
+ function meta_box() {
92
+ global $post;
93
+ $custom = get_post_custom( $post->ID );
94
+ if ( isset( $custom[VIDEO_THUMBNAILS_FIELD][0] ) ) $video_thumbnail = $custom[VIDEO_THUMBNAILS_FIELD][0];
95
 
96
+ if ( isset( $video_thumbnail ) && $video_thumbnail != '' ) {
97
+ echo '<p id="video-thumbnails-preview"><img src="' . $video_thumbnail . '" style="max-width:100%;" /></p>'; }
 
 
98
 
99
+ if ( get_post_status() == 'publish' || get_post_status() == 'private' ) {
100
+ if ( isset( $video_thumbnail ) && $video_thumbnail != '' ) {
101
+ echo '<p><a href="#" id="video-thumbnails-reset" onclick="video_thumbnails_reset(\'' . $post->ID . '\' );return false;">Reset Video Thumbnail</a></p>';
102
+ } else {
103
+ echo '<p id="video-thumbnails-preview">We didn\'t find a video thumbnail for this post.</p>';
104
+ echo '<p><a href="#" id="video-thumbnails-reset" onclick="video_thumbnails_reset(\'' . $post->ID . '\' );return false;">Search Again</a></p>';
105
  }
106
+ } else {
107
+ if ( isset( $video_thumbnail ) && $video_thumbnail != '' ) {
108
+ echo '<p><a href="#" id="video-thumbnails-reset" onclick="video_thumbnails_reset(\'' . $post->ID . '\' );return false;">Reset Video Thumbnail</a></p>';
109
+ } else {
110
+ echo '<p>A video thumbnail will be found for this post when it is published.</p>';
 
 
 
 
111
  }
112
  }
113
+ }
114
 
115
+ // The main event
116
+ function get_video_thumbnail( $post_id = null ) {
117
 
118
+ // Get the post ID if none is provided
119
+ if ( $post_id == null OR $post_id == '' ) $post_id = get_the_ID();
120
 
121
+ // Check to see if thumbnail has already been found
122
+ if( ( $thumbnail_meta = get_post_meta( $post_id, VIDEO_THUMBNAILS_FIELD, true ) ) != '' ) {
123
+ return $thumbnail_meta;
 
 
 
 
 
 
124
  }
125
+ // If the thumbnail isn't stored in custom meta, fetch a thumbnail
126
+ else {
127
+
128
+ $new_thumbnail = null;
129
+ // Filter for extensions to set thumbnail
130
+ $new_thumbnail = apply_filters( 'new_video_thumbnail_url', $new_thumbnail, $post_id );
131
+
132
+ if ( $new_thumbnail == null ) {
133
+ // Get the post or custom field to search
134
+ if ( $this->settings->options['custom_field'] ) {
135
+ $markup = get_post_meta( $post_id, $this->settings->options['custom_field'], true );
136
+ } else {
137
+ $post_array = get_post( $post_id );
138
+ $markup = $post_array->post_content;
139
+ $markup = apply_filters( 'the_content', $markup );
140
+ }
141
 
142
+ // Filter for extensions to modify what markup is scanned
143
+ $markup = apply_filters( 'video_thumbnail_markup', $markup, $post_id );
 
 
 
144
 
145
+ foreach ( $this->providers as $key => $provider ) {
146
+ $new_thumbnail = $provider->scan_for_thumbnail( $markup );
147
+ if ( $new_thumbnail != null ) break;
148
+ }
149
  }
 
 
 
 
150
 
151
+ // Return the new thumbnail variable and update meta if one is found
152
+ if ( $new_thumbnail != null ) {
153
 
154
+ // Save as Attachment if enabled
155
+ if ( $this->settings->options['save_media'] == 1 ) {
156
+ $attachment_id = $this->save_to_media_library( $new_thumbnail, $post_id );
157
+ $new_thumbnail = wp_get_attachment_image_src( $attachment_id, 'full' );
158
+ $new_thumbnail = $new_thumbnail[0];
159
+ }
160
 
161
+ // Add hidden custom field with thumbnail URL
162
+ if ( !update_post_meta( $post_id, VIDEO_THUMBNAILS_FIELD, $new_thumbnail ) ) add_post_meta( $post_id, VIDEO_THUMBNAILS_FIELD, $new_thumbnail, true );
 
 
163
 
164
+ // Set attachment as featured image if enabled
165
+ if ( $this->settings->options['set_featured'] == 1 && $this->settings->options['save_media'] == 1 && !get_post_thumbnail_id( $post_id ) ) {
166
+ set_post_thumbnail( $post_id, $attachment_id );
 
 
 
 
167
  }
168
  }
169
+ return $new_thumbnail;
 
 
 
170
 
171
+ }
172
+ }
173
 
174
+ // Runs when post is saved
175
+ function save_video_thumbnail( $post ) {
176
+ $post_type = get_post_type( $post->ID );
177
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
178
+ return null;
179
+ } else {
180
+ // Check that Video Thumbnails are enabled for current post type
181
+ if ( in_array( $post_type, (array) $this->settings->options['post_types'] ) || $post_type == $this->settings->options['post_types'] ) {
182
+ get_video_thumbnail( $post->ID );
183
+ } else {
184
+ return null;
185
  }
186
  }
187
+ }
188
 
189
+ // Saves to media library
190
+ public function save_to_media_library( $image_url, $post_id ) {
191
 
192
+ $error = '';
193
+ $response = wp_remote_get( $image_url, array( 'sslverify' => false ) );
194
+ if( is_wp_error( $response ) ) {
195
+ $error = new WP_Error( 'thumbnail_retrieval', __( 'Error retrieving a thumbnail from the URL <a href="' . $image_url . '">' . $image_url . '</a> using <code>wp_remote_get()</code><br />If opening that URL in your web browser returns anything else than an error page, the problem may be related to your web server and might be something your host administrator can solve.<br />Details: ' . $response->get_error_message() ) );
196
+ } else {
197
+ $image_contents = $response['body'];
198
+ $image_type = wp_remote_retrieve_header( $response, 'content-type' );
199
+ }
200
 
201
+ if ( $error != '' ) {
202
+ return $error;
203
+ } else {
204
 
205
+ // Translate MIME type into an extension
206
+ if ( $image_type == 'image/jpeg' ) $image_extension = '.jpg';
207
+ elseif ( $image_extension == 'image/png' ) $image_extension = '.png';
208
+
209
+ // Construct a file name using post slug and extension
210
+ $new_filename = basename( get_permalink( $post_id ) ) . $image_extension;
211
 
212
+ // Save the image bits using the new filename
213
+ $upload = wp_upload_bits( $new_filename, null, $image_contents );
214
 
215
+ // Stop for any errors while saving the data or else continue adding the image to the media library
216
+ if ( $upload['error'] ) {
217
+ $error = new WP_Error( 'thumbnail_upload', __( 'Error uploading image data:' ) . ' ' . $upload['error'] );
218
+ return $error;
219
+ } else {
220
 
221
+ $image_url = $upload['url'];
222
 
223
  $filename = $upload['file'];
224
 
225
  $wp_filetype = wp_check_filetype( basename( $filename ), null );
226
  $attachment = array(
227
  'post_mime_type' => $wp_filetype['type'],
228
+ 'post_title' => get_the_title( $post_id ),
229
  'post_content' => '',
230
  'post_status' => 'inherit'
231
  );
235
  require_once( ABSPATH . 'wp-admin/includes/image.php' );
236
  $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
237
  wp_update_attachment_metadata( $attach_id, $attach_data );
 
 
238
 
239
+ // Add field to mark image as a video thumbnail
240
+ update_post_meta( $attach_id, 'video_thumbnail', '1' );
241
 
 
 
 
242
  }
 
 
243
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  }
 
 
245
 
246
+ return $attach_id;
247
+
248
+ } // End of save to media library function
249
+
250
+ // Post editor Ajax reset script
251
+ function ajax_reset_script() {
252
+ echo '<!-- Video Thumbnails Ajax Search -->' . PHP_EOL;
253
+ echo '<script type="text/javascript">' . PHP_EOL;
254
+ echo 'function video_thumbnails_reset(id) {' . PHP_EOL;
255
+ echo ' var data = {' . PHP_EOL;
256
+ echo ' action: "reset_video_thumbnail",' . PHP_EOL;
257
+ echo ' post_id: id' . PHP_EOL;
258
+ echo ' };' . PHP_EOL;
259
+ echo ' document.getElementById(\'video-thumbnails-preview\').innerHTML=\'Working... <img src="' . home_url( 'wp-admin/images/loading.gif' ) . '"/>\';' . PHP_EOL;
260
+ echo ' jQuery.post(ajaxurl, data, function(response){' . PHP_EOL;
261
+ echo ' document.getElementById(\'video-thumbnails-preview\').innerHTML=response;' . PHP_EOL;
262
+ echo ' });' . PHP_EOL;
263
+ echo '};' . PHP_EOL;
264
+ echo '</script>' . PHP_EOL;
 
 
265
  }
 
 
 
266
 
267
+ // Ajax reset callback
268
+ function ajax_reset_callback() {
269
+ global $wpdb; // this is how you get access to the database
270
 
271
+ $post_id = $_POST['post_id'];
 
272
 
273
+ delete_post_meta( $post_id, VIDEO_THUMBNAILS_FIELD );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
 
275
+ $video_thumbnail = get_video_thumbnail( $post_id );
276
 
277
+ if ( is_wp_error( $video_thumbnail ) ) {
278
+ echo $video_thumbnail->get_error_message();
279
+ } else if ( $video_thumbnail != null ) {
280
+ echo '<img src="' . $video_thumbnail . '" style="max-width:100%;" />';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  } else {
282
+ echo 'We didn\'t find a video thumbnail for this post. (be sure you have saved changes first)';
283
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
+ die();
 
 
 
286
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  }
 
 
 
289
 
290
+ $video_thumbnails = new Video_Thumbnails();
291
 
292
+ // End class
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
+ // Get video thumbnail function
295
+ function get_video_thumbnail( $post_id = null ) {
296
+ global $video_thumbnails;
297
+ return $video_thumbnails->get_video_thumbnail( $post_id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  }
299
 
300
+ // Echo thumbnail
301
+ function video_thumbnail( $post_id = null ) {
302
+ if ( ( $video_thumbnail = get_video_thumbnail( $post_id ) ) == null ) { echo plugins_url() . '/video-thumbnails/default.jpg'; }
303
+ else { echo $video_thumbnail; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  }
305
 
306
  ?>