Changeset 2963306
- Timestamp:
- 09/05/2023 10:54:27 PM (2 years ago)
- Location:
- better-video-playlist
- Files:
-
- 8 added
- 3 edited
- 4 copied
-
tags/2.1 (copied) (copied from better-video-playlist/trunk)
-
tags/2.1/README.TXT (copied) (copied from better-video-playlist/trunk/README.TXT) (1 diff)
-
tags/2.1/better-video.php (copied) (copied from better-video-playlist/trunk/better-video.php) (1 diff)
-
tags/2.1/blocks (added)
-
tags/2.1/blocks/block.js (added)
-
tags/2.1/js/admin-better-video.js (added)
-
tags/2.1/js/better-video.js (copied) (copied from better-video-playlist/trunk/js/better-video.js) (1 diff)
-
tags/2.1/uninstall.php (added)
-
trunk/README.TXT (modified) (1 diff)
-
trunk/better-video.php (modified) (1 diff)
-
trunk/blocks (added)
-
trunk/blocks/block.js (added)
-
trunk/js/admin-better-video.js (added)
-
trunk/js/better-video.js (modified) (1 diff)
-
trunk/uninstall.php (added)
Legend:
- Unmodified
- Added
- Removed
-
better-video-playlist/tags/2.1/README.TXT
r2959725 r2963306 5 5 Requires at least: 6.0 6 6 Tested up to: 6.3 7 Stable tag: 2. 0.47 Stable tag: 2.1 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html 11 11 12 Improves video capabilities for wordpress, stores progress and adds video playlist features. 13 12 Improves WordPress Video Experience by adding playlist, resume video and a lot more! 14 13 15 14 == Description == 16 15 17 Super fast video player and playlist player using native HTML5 video player and jQuery. Uses browser local storage for most features. 16 **Elevate Your WordPress Video Experience!** 18 17 19 If user is logged in we store video position in the database. So even if changes browser will save the progress.18 The Better Video & Playlist Plugin is designed to enhance the video capabilities of your WordPress website while adding a sophisticated video playlist feature. This plugin ensures that your site's visitors enjoy a seamless and engaging video-watching experience. 20 19 21 Works in pages, posts, widgets or any place at your site. 20 **Key Features:** 22 21 23 = Features = 22 - **Resume Video Playback**: Never lose progress – our plugin remembers where you left off. 23 - **Video Progress Storage**: Store video progress in the WordPress database and local browser storage. 24 - **Customized Start Time**: Start your videos at specific times using the `?t=SECONDS` parameter (e.g., `?t=120` starts at 2 minutes). 25 - **Video Playlists**: Create and manage video playlists effortlessly using block editor. 26 - **Autoplay Next Video**: Keep viewers engaged with automatic playback of the next video. 27 - **Emoji Customization**: Add a personal touch with custom video emojis. 28 - **Background Color**: Tailor the video player's background color to match your site's aesthetics. 24 29 25 - Resume video from last position. Saves progress in DB and browser storage. 26 - On pause or window close, stores progress 27 - Start playing video at custom time using ?t=SECONDS ex ?t=120 will start at 2 minutes 30 **Why Choose Better Video & Playlist?** 28 31 29 **Playlist Features** 30 - Create playlist video from a HTML5 list or JS array 31 - Resume on last played video 32 - Autoplay next video on video end 33 - Mark video as played 34 - Start playing from video via url parameter using ?start_video=ID_VIDEO 35 - Stored in user browser storage and at WordPress Database 36 32 - **User-Friendly**: Seamlessly integrate advanced video features into your WordPress site. 33 - **Progress Tracking**: Never make viewers start from scratch; they can pick up right where they left off. 34 - **Playlist Management**: Create and organize video playlists with ease. 35 - **Community Support**: Join a community of users benefiting from this plugin's capabilities. 37 36 38 37 == Installation == 39 38 40 Through WordPress admin: 39 **Via WordPress Admin:** 41 40 42 1. Go to Plugins -> Add New43 2. Search for "Better Video "44 3. Install the plugin45 4. Activate it41 1. Go to **Plugins** -> **Add New**. 42 2. Search for "Better Video & Playlist." 43 3. Click **Install Now**. 44 4. Activate the plugin. 46 45 47 Through FTP: 46 **Via FTP:** 48 47 49 1. Download the plugin 50 2. Unzip .zip and upload the folder to the `/wp-content/plugins/` directory 51 3. Activate the plugin through the 'Plugins' menu in WordPress 52 48 1. Download the plugin. 49 2. Unzip the .zip file and upload the folder to `/wp-content/plugins/`. 50 3. Activate the plugin in the **Plugins** menu of WordPress. 53 51 54 52 == Frequently Asked Questions == 55 53 56 = How to use? = 54 **How to Use?** 57 55 58 To enable the video features just add a video from the post editor or add HTML video tag. You can have as many video tags as you want.56 To enable the video features, add a video from the post editor or use the HTML video tag. You can include as many video tags as needed. 59 57 60 = Video Play list = 58 **Creating Video Playlists** 61 59 62 You can create a list on your editor and then in the side panel in advanced, anchor set it to "bvideo_playlist".60 You can create a video playlist within your editor by using the block. 63 61 64 Also you can edit the HTML and create List with id = bvideo_playlist: 62 Or by using the advanced settings panel and setting it to "bvideo_playlist." Alternatively, you can create a list in your HTML with the id "bvideo_playlist." 65 63 66 <ol id="bvideo_playlist"> 67 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/earth_night_rotate_1080.mov">Animation: Rotating Earth at Night</a></li> 68 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/rbsp_launch_1080p.mp4">Radiation Belt Storm Probes Launch</a></li> 69 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/curiosity_lands.mov">Dropping in on Mars in High-Res</a></li> 70 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/GRAIL_launch_1080.mov">GRAIL Launches on Mission to Moon</a></li> 71 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/HLV_Launch_anim.mov">Space Launch System Animation</a></li> 72 </ol> 64 Here's an example HTML playlist: 73 65 66 ```html 67 <ol id="bvideo_playlist"> 68 <li><a href="video1.mp4">Video 1</a></li> 69 <li><a href="video2.mp4">Video 2</a></li> 70 <li><a href="video3.mp4">Video 3</a></li> 71 </ol> 72 ``` 74 73 75 You can also add in your HTML/JS file a playlist array and will create your list magically, the size field it’s optional:74 You can also create a playlist using a JavaScript array: 76 75 77 <script> 78 var video_playlist = [ 79 { 80 "name": "Animation: Rotating Earth at Night", 81 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/earth_night_rotate_1080.mov", 82 "size": 55000000, 83 }, 84 { 85 "name": "Radiation Belt Storm Probes Launch", 86 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/rbsp_launch_1080p.mp4", 87 "size": 475000000, 88 }, 89 { 90 "name": "Dropping in on Mars in High-Res", 91 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/curiosity_lands.mov", 92 "size": 105000000, 93 }, 94 { 95 "name": "GRAIL Launches on Mission to Moon", 96 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/GRAIL_launch_1080.mov", 97 "size": 1113000000, 98 }, 99 { 100 "name": "Space Launch System Animation", 101 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/HLV_Launch_anim.mov", 102 "size": 642570000, 103 }, 104 105 ]; 106 </script> 76 ```javascript 77 <script> 78 var video_playlist = [ 79 { 80 "name": "Video 1", 81 "link": "video1.mp4", 82 "size": 55000000 83 }, 84 { 85 "name": "Video 2", 86 "link": "video2.mp4", 87 "size": 475000000 88 }, 89 { 90 "name": "Video 3", 91 "link": "video3.mp4", 92 "size": 105000000 93 } 94 ]; 95 </script> 96 ``` 107 97 108 To add the JS to your post/page you can use a plugin like [this one](https://wordpress.org/plugins/header-and-footer-scripts/). 109 98 To add the JavaScript to your post/page, consider using a plugin like [this one](https://wordpress.org/plugins/header-and-footer-scripts/). 110 99 111 100 == Screenshots == 112 1. Video player113 2. Play list player114 101 115 == Upgrade Notice == 116 None. 102 1. Video Player 103 2. Playlist Player 117 104 118 == Changelog==105 == Upgrade History == 119 106 107 = Version 2.1 = 108 - Major jQuery and PHP code refactor 109 - Improved method for tracking played videos 110 - New admin panel with customizable settings 120 111 121 = 2.0.4 =122 * Improved description and FAQ's112 = Version 2.0.4 = 113 - Enhanced descriptions and FAQs 123 114 124 = 2.0.3 =125 * WP 6.3 tested 115 = Version 2.0.3 = 116 - Tested for WordPress 6.3 compatibility 126 117 127 = 2.0.2 =128 *smooth scroll to video118 = Version 2.0.2 = 119 - Added smooth scroll to video 129 120 130 = 2.0.1 =131 * ajax stores video time for logged user 121 = Version 2.0.1 = 122 - Implemented AJAX for storing video time for logged-in users 132 123 133 = 1.0 =134 * Initial version 124 = Version 1.0 = 125 - Initial release -
better-video-playlist/tags/2.1/better-video.php
r2959725 r2963306 1 1 <?php 2 2 /** 3 * Plugin Name: Better Video & Playlist 4 * Plugin URI: https://garridodiaz.com/better-video-plugin-for-wordpress/ 5 * Description: Improves video capabilities for wordpress and adds video playlist features. 6 * Version: 2.0.4 7 * Author: Chema 8 * Author URI: https://garridodiaz.com 9 * License: GPL2 10 */ 11 12 add_action( 'wp_enqueue_scripts', 'bbpl_assets'); 13 add_action( 'wp_ajax_bbpl_store_video_time', 'bbpl_store_video_time' ); 14 add_action( 'wp_ajax_bbpl_get_video_time', 'bbpl_get_video_time' ); 15 16 /* enqueue scripts and style from parent theme */ 17 function bbpl_assets() { 18 wp_enqueue_script( 'better-video', plugin_dir_url( __FILE__ ) . 'js/better-video.js', array('jquery'), '2.0.4', true ); 19 20 wp_localize_script( 21 'better-video', 22 'my_ajax_obj', 23 array( 24 'ajax_url' => admin_url( 'admin-ajax.php' ), 25 'nonce' => wp_create_nonce( 'better-video' ), 26 ) 27 ); 3 * Plugin Name: Better Video & Playlist 4 * Plugin URI: https://garridodiaz.com/better-video-plugin-for-wordpress/ 5 * Description: Improves video capabilities for WordPress and adds video playlist features. 6 * Version: 2.1 7 * Author: Chema 8 * Author URI: https://garridodiaz.com 9 * License: GPL2 10 */ 11 12 if (!defined('ABSPATH')) exit; // Exit if accessed directly 13 14 class BetterVideoPlaylistPlugin 15 { 16 const MAIN_FILE = __FILE__; 17 18 public function __construct() 19 { 20 // Initialize the plugin by adding hooks and actions 21 add_action('wp_enqueue_scripts', [$this, 'enqueueAssets']); 22 add_action('wp_ajax_bbpl_store_video_time', [$this, 'storeVideoTime']); 23 add_action('wp_ajax_bbpl_get_video_time', [$this, 'getVideoTime']); 24 add_action('admin_menu', [$this, 'addAdminMenu']); 25 add_action('admin_init', [$this, 'registerSettings']); 26 add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']); 27 add_action('admin_notices', [$this, 'displayDonationMessage']); 28 add_action('admin_head', [$this, 'addDonationMessageJS']); 29 add_filter('plugin_row_meta', [$this, 'addPluginRowMeta'], 10, 2); 30 add_action('admin_init', [$this, 'setupSettingsFields']); 31 } 32 33 /** 34 * Enqueue assets (scripts and styles) for the plugin. 35 */ 36 public function enqueueAssets() 37 { 38 // Enqueue scripts and localize for better-video.js 39 wp_enqueue_script('better-video', plugin_dir_url(__FILE__) . 'js/better-video.js', array('jquery'), '2.1', true); 40 41 wp_localize_script( 42 'better-video', 43 'betterVideo_ajax', 44 array( 45 'ajax_url' => admin_url('admin-ajax.php'), 46 'nonce' => wp_create_nonce('better-video'), 47 ) 48 ); 49 50 $bbpl_settings = array( 51 'playedVideoEmoji' => get_option('bbpl_played_video_emoji', __('✔', 'bbpl-textdomain')), 52 'playingEmoji' => get_option('bbpl_playing_emoji', __('▶️', 'bbpl-textdomain')), 53 'downloadEmoji' => get_option('bbpl_download_emoji', __('💾', 'bbpl-textdomain')), 54 'playingBackgroundColor' => get_option('bbpl_playing_background_color', '#FFFF00'), 55 'autoplay' => get_option('bbpl_autoplay', true), 56 ); 57 wp_localize_script('better-video', 'bbplSettings', $bbpl_settings); 58 } 59 60 /** 61 * Handle AJAX request for storing video time. 62 * 63 * @return bool JSON response indicating success or failure. 64 */ 65 public function storeVideoTime() 66 { 67 // Handle the AJAX request for storing video time 68 check_ajax_referer('better-video'); 69 $return = false; 70 71 if (is_user_logged_in()) { 72 global $current_user; 73 $time = sanitize_text_field($_POST['time']); 74 $video = sanitize_url($_POST['video']); 75 76 if (is_numeric($time) && wp_http_validate_url($video)) { 77 $return = update_user_meta($current_user->ID, 'bvideo-' . md5($video), $time); 78 } 79 } 80 81 wp_send_json($return); 82 } 83 84 /** 85 * Handle AJAX request for getting video time. 86 * 87 * @return mixed JSON response containing the video time or 0. 88 */ 89 public function getVideoTime() 90 { 91 // Handle the AJAX request for getting video time 92 check_ajax_referer('better-video'); 93 $return = 0; 94 95 if (is_user_logged_in()) { 96 global $current_user; 97 $video = sanitize_url($_POST['video']); 98 if (wp_http_validate_url($video)) { 99 $return = get_user_meta($current_user->ID, 'bvideo-' . md5($video)); 100 } 101 } 102 103 wp_send_json($return); 104 } 105 106 /** 107 * Add the admin menu for plugin settings. 108 */ 109 public function addAdminMenu() 110 { 111 // Add the admin menu for settings 112 add_submenu_page( 113 'options-general.php', 114 __('Better Video & Playlist Settings', 'bbpl-textdomain'), 115 __('Video Settings', 'bbpl-textdomain'), 116 'manage_options', 117 'bbpl-settings', 118 [$this, 'renderSettingsPage'] 119 ); 120 } 121 122 /** 123 * Register plugin settings. 124 */ 125 public function registerSettings() 126 { 127 // Register plugin settings 128 register_setting('bbpl_settings_group', 'bbpl_played_video_emoji'); 129 register_setting('bbpl_settings_group', 'bbpl_playing_emoji'); 130 register_setting('bbpl_settings_group', 'bbpl_download_emoji'); 131 register_setting('bbpl_settings_group', 'bbpl_playing_background_color'); 132 register_setting('bbpl_settings_group', 'bbpl_autoplay'); 133 } 134 135 /** 136 * Enqueue scripts for the admin page. 137 * 138 * @param string $hook The current admin page hook. 139 */ 140 public function enqueueAdminScripts($hook) 141 { 142 // Enqueue scripts for the admin page 143 if ($hook === 'settings_page_bbpl-settings') { 144 wp_enqueue_script('bbpl-admin', plugin_dir_url(__FILE__) . 'js/admin-better-video.js', array('jquery', 'wp-color-picker'), '1.0', true); 145 } 146 } 147 148 /** 149 * Display a donation message in the WordPress admin. 150 */ 151 public function displayDonationMessage() 152 { 153 // Display the donation message 154 if ((isset($_GET['page']) && $_GET['page'] === 'bbpl-settings') && !isset($_COOKIE['donation_message_closed'])) { 155 echo '<div id="donation-message" class="notice notice-info is-dismissible" style="background-color: #f5f5f5; border-left: 4px solid #0073aa; padding: 10px;"> 156 <p style="font-size: 16px;">Enjoy using our plugin? Consider <a href="https://paypal.me/chema/10EUR" target="_blank" id="donate-link">making a donation</a> to support our work! THANKS!</p> 157 </div>'; 158 } 159 } 160 161 /** 162 * Add JavaScript for handling the donation message. 163 */ 164 public function addDonationMessageJS() 165 { 166 // Add JavaScript for handling the donation message 167 if (!isset($_COOKIE['donation_message_closed'])) { 168 ?> 169 <script type="text/javascript"> 170 jQuery(document).ready(function ($) { 171 172 $('#donate-link').click(function () { 173 $('#donation-message').remove(); 174 var expirationDate = new Date(); 175 expirationDate.setDate(expirationDate.getDate() + 30); // Expires in 30 days 176 document.cookie = 'donation_message_closed=true; expires=' + expirationDate.toUTCString() + '; path=/'; 177 178 }); 179 }); 180 </script> 181 <?php 182 } 183 } 184 185 /** 186 * Setup settings fields and sections for the plugin. 187 */ 188 public function setupSettingsFields() 189 { 190 // Setup settings fields and sections 191 add_settings_section('bbpl_general_section', __('General Settings', 'bbpl-textdomain'), [$this, 'renderGeneralSection'], 'bbpl-settings'); 192 193 // Define custom sanitize callbacks for each field 194 $sanitize_callbacks = [ 195 'bbpl_played_video_emoji' => 'sanitize_text_field', 196 'bbpl_playing_emoji' => 'sanitize_text_field', 197 'bbpl_download_emoji' => 'sanitize_text_field', 198 'bbpl_playing_background_color' => 'sanitize_hex_color', 199 'bbpl_autoplay' => 'sanitize_checkbox', 200 ]; 201 202 // Sanitize user input for each field 203 add_settings_field('bbpl_played_video_emoji', __('Played Video Emoji', 'bbpl-textdomain'), [$this, 'renderPlayedVideoEmojiField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_played_video_emoji']]); 204 add_settings_field('bbpl_playing_emoji', __('Playing Emoji', 'bbpl-textdomain'), [$this, 'renderPlayingEmojiField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_playing_emoji']]); 205 add_settings_field('bbpl_download_emoji', __('Download Emoji', 'bbpl-textdomain'), [$this, 'renderDownloadEmojiField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_download_emoji']]); 206 add_settings_field('bbpl_playing_background_color', __('Playing Background Color', 'bbpl-textdomain'), [$this, 'renderBackgroundColorField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_playing_background_color']]); 207 add_settings_field('bbpl_autoplay', __('Autoplay', 'bbpl-textdomain'), [$this, 'renderAutoplayField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_autoplay']]); 208 } 209 210 // Custom sanitize function for checkbox input 211 public function sanitize_checkbox($value) 212 { 213 return empty($value) ? false : true; 214 } 215 216 217 /** 218 * Render the plugin's settings page. 219 */ 220 public function renderSettingsPage() 221 { 222 ?> 223 <div class="wrap"> 224 <h2><?php _e('Better Video & Playlist Settings', 'bbpl-textdomain'); ?></h2> 225 <form method="post" action="options.php"> 226 <?php settings_fields('bbpl_settings_group'); ?> 227 <?php do_settings_sections('bbpl-settings'); ?> 228 <input type="submit" class="button-primary" value="<?php _e('Save Settings', 'bbpl-textdomain'); ?>"> 229 </form> 230 </div> 231 <?php 232 } 233 234 /** 235 * Render the general section description. 236 */ 237 public function renderGeneralSection() 238 { 239 echo __('Configure general settings for Better Video & Playlist.', 'bbpl-textdomain'); 240 } 241 242 // Sanitize user input for each field before saving 243 public function renderPlayedVideoEmojiField() 244 { 245 $value = get_option('bbpl_played_video_emoji', __('✔', 'bbpl-textdomain')); 246 $value = sanitize_text_field($value); // Sanitize the input 247 echo "<input type='text' name='bbpl_played_video_emoji' value='$value'>"; 248 } 249 250 public function renderPlayingEmojiField() 251 { 252 $value = get_option('bbpl_playing_emoji', __('▶️', 'bbpl-textdomain')); 253 $value = sanitize_text_field($value); // Sanitize the input 254 echo "<input type='text' name='bbpl_playing_emoji' value='$value'>"; 255 } 256 257 public function renderDownloadEmojiField() 258 { 259 $value = get_option('bbpl_download_emoji', __('💾', 'bbpl-textdomain')); 260 $value = sanitize_text_field($value); // Sanitize the input 261 echo "<input type='text' name='bbpl_download_emoji' value='$value'>"; 262 } 263 264 public function renderBackgroundColorField() 265 { 266 $value = get_option('bbpl_playing_background_color', '#FFFF00'); 267 $value = sanitize_hex_color($value); // Sanitize the color input 268 echo "<input type='text' name='bbpl_playing_background_color' value='$value' class='color-picker'>"; 269 } 270 271 public function renderAutoplayField() 272 { 273 $value = get_option('bbpl_autoplay', true); 274 $value = $value ? '1' : '0'; // Ensure it's either '0' or '1' 275 echo "<input type='hidden' name='bbpl_autoplay' value='0'> 276 <label for='bbpl_autoplay'> 277 <input type='checkbox' id='bbpl_autoplay' name='bbpl_autoplay' value='1' " . checked($value, '1', false) . "> 278 " . __('Enable Autoplay', 'bbpl-textdomain') . " 279 </label>"; 280 } 281 282 283 /** 284 * Add links to settings and sponsorship in plugin row meta. 285 * 286 * @param array $plugin_meta The existing plugin meta. 287 * @param string $plugin_file The plugin file path. 288 * @return array Modified plugin meta with added links. 289 */ 290 public function addPluginRowMeta($plugin_meta, $plugin_file) 291 { 292 if (plugin_basename(self::MAIN_FILE) !== $plugin_file) { 293 return $plugin_meta; 294 } 295 296 $settings_page_url = admin_url('options-general.php?page=bbpl-settings'); 297 298 $plugin_meta[] = sprintf( 299 '<a href="%1$s"><span class="dashicons dashicons-admin-settings" aria-hidden="true" style="font-size:14px;line-height:1.3"></span>%2$s</a>', 300 $settings_page_url, 301 esc_html_x('Settings', 'verb', 'bbpl-textdomain') 302 ); 303 304 $plugin_meta[] = sprintf( 305 '<a href="%1$s"><span class="dashicons dashicons-star-filled" aria-hidden="true" style="font-size:14px;line-height:1.3"></span>%2$s</a>', 306 'https://paypal.me/chema/10EUR', 307 esc_html_x('Sponsor', 'verb', 'better-video') 308 ); 309 310 return $plugin_meta; 311 } 28 312 } 29 313 30 31 /** 32 * Handles AJAX requests. 33 */ 34 function bbpl_store_video_time() { 35 36 // Handle the ajax request here 37 check_ajax_referer( 'better-video' ); 38 $return = FALSE; 39 40 //only store for loged in users 41 if (is_user_logged_in() ){ 42 global $current_user; 43 $time = sanitize_text_field($_POST['time']); 44 $video = sanitize_url($_POST['video']); 45 46 if (is_numeric($time) AND wp_http_validate_url($video)) 47 $return = update_user_meta($current_user->ID,'bvideo-'.md5($video),$time); 48 } 49 50 wp_send_json($return); 314 // Initialize the plugin 315 new BetterVideoPlaylistPlugin(); 316 317 318 319 function enqueueBlockAssets() { 320 wp_enqueue_script( 321 'bbpl-block', 322 plugins_url('blocks/block.js', __FILE__), 323 array('wp-blocks', 'wp-components', 'wp-i18n'), 324 ); 325 51 326 } 52 327 53 54 function bbpl_get_video_time() { 55 // Handle the ajax request here 56 check_ajax_referer( 'better-video' ); 57 $return = 0; 58 59 //only store for loged in users 60 if (is_user_logged_in() ){ 61 global $current_user; 62 $video = sanitize_url($_POST['video']); 63 if (wp_http_validate_url($video)) 64 $return = get_user_meta($current_user->ID,'bvideo-'.md5($video)); 65 } 66 67 wp_send_json($return); 68 } 69 70 71 72 ?> 328 add_action('enqueue_block_editor_assets', 'enqueueBlockAssets'); 329 -
better-video-playlist/tags/2.1/js/better-video.js
r2959725 r2963306 1 1 /** 2 * Better Video and playlist jQuery plugin3 * Version: 2. 0.42 * Better Video and Playlist jQuery Plugin 3 * Version: 2.1 4 4 */ 5 jQuery(document).ready(function( $ ) { 5 6 const config = { 7 playedVideoEmoji: bbplSettings.playedVideoEmoji, 8 playingEmoji: bbplSettings.playingEmoji, 9 downloadEmoji: bbplSettings.downloadEmoji, 10 playingBackgroundColor: bbplSettings.playingBackgroundColor, 11 autoplay: bbplSettings.autoplay, 12 }; 13 14 jQuery(document).ready(function($) { 6 15 7 //when we pause we store the current time 8 $("video").on("pause", function(event) { 9 // Save into local storage,if you change the browser will not work 10 localStorage.setItem('bvideo-'+btoa(this.src), this.currentTime); 11 12 //ajax call 13 $.post(my_ajax_obj.ajax_url, { //POST request 14 _ajax_nonce: my_ajax_obj.nonce, //nonce 15 action: "bbpl_store_video_time", //action 16 time: this.currentTime, //time 17 video: this.src, //video url 18 } 19 ); 20 21 }); 22 23 //if you close the window and video playing store the current time 16 17 //cache for DOM optimization 18 let bvideo = $("video"); 19 20 // If you close the window and a video is playing, store the current time by invoking the pause method 24 21 $(window).on("unload", function(e) { 25 $("video").each(function(index, value) {26 if ( ! this.paused ) {22 bvideo.each(function(index, value) { 23 if (!this.paused) 27 24 this.pause(); 28 }29 25 }); 30 26 }); 31 27 32 // first time the force time happens 33 var first_time = true; 34 35 //play video restores the video from the last point or from the query string using ?t=444 36 $("video").on("play", function(event) { 37 38 //only load the stored time the first time. 39 if (first_time==true) 40 { 41 first_time = false; 42 //using time provided via url only once!! 43 var start_time = new URLSearchParams(window.location.search).get('t'); 44 var start_video = new URLSearchParams(window.location.search).get('start_video'); 45 46 if ( (start_time!==null && $.isNumeric(start_time)) && (start_video!==null && $.isNumeric(start_video)) ){ 47 if (start_time < this.duration) 48 this.currentTime = start_time; 28 // When we pause, we store the current time 29 bvideo.on("pause", function(event) { 30 storeVideoTime(this); 31 }); 32 33 // First time we force the player from the time we have stored. This is used so playlist works. 34 let firstTime = true; 35 36 // Play video restores the video from the last point or from the query string using ?t=444 37 bvideo.on("play", function(event) { 38 39 // Only load the stored time the first time they click play. 40 if (firstTime == true) { 41 firstTime = false; 42 // Using time provided via URL only once!! 43 let startTime = new URLSearchParams(window.location.search).get('t'); 44 45 if (startTime !== null && $.isNumeric(startTime)) { 46 if (startTime < this.duration) 47 this.currentTime = startTime; 48 } else { // Init video at last stored time 49 50 storedTime = getVideoTime(this); 51 // if not at the end or already played 52 if (storedTime >= this.duration || storedTime == -1) { 53 storedTime = 0; 54 } 55 56 this.currentTime = storedTime; 49 57 } 50 else{//init video at last stored time 51 52 //first retrieve from localstorage 53 var storedtime = localStorage.getItem('bvideo-'+btoa(this.src)); 54 55 //only ajax if storedtime is empty, saves queries 56 if (storedtime == null){ 57 var video_obj = this; 58 //ajax call 59 $.post(my_ajax_obj.ajax_url, { //POST request 60 _ajax_nonce: my_ajax_obj.nonce, //nonce 61 action: "bbpl_get_video_time", //action 62 video: this.src, //video url 63 },function(data) { //callback 64 if (data[0] < video_obj.duration) 65 video_obj.currentTime = data[0]; 66 } 67 ); 68 } 69 // Get the time from localStorage and play if not at the end. 70 else if (storedtime < this.duration){ 71 this.currentTime = storedtime; 58 } // End if first time 59 60 this.play(); 61 }); 62 63 // On finished video mark as played 64 bvideo.on('ended', function(e) { 65 markPlayedVideo(this); 66 }); 67 68 /** 69 * Playlist player for 1 video HTML tag 70 */ 71 let bvideo_playlist = $('#bvideo_playlist'); 72 73 if (bvideo_playlist.length) { 74 let currentUrl = btoa(window.location.href.split('?')[0].split('#')[0]); 75 let videoList = getVideoList(); 76 77 // Playlist video player 78 if (typeof videoList !== 'undefined') { 79 // Start video from parameter ID 80 let startVideo = new URLSearchParams(window.location.search).get('start_video'); 81 if (startVideo !== null && $.isNumeric(startVideo)) 82 idCurrent = startVideo - 1; // We start counting from 1 so we do not use 0. 83 else // Init video at last play 84 idCurrent = localStorage.getItem('bvideo-playlist-' + currentUrl); 85 idCurrent = ($.isNumeric(idCurrent)) ? idCurrent : 0; 86 idCurrent = (idCurrent > videoList.length - 1) ? 0 : idCurrent; 87 88 // gets the data from an A tag using the data attribute 89 currentLinkVideo = $('a[data-bvideo_id~="' + idCurrent + '"]'); 90 91 // Current video playing 92 localStorage.setItem('bvideo-playlist-' + currentUrl, idCurrent); 93 94 // Setup player to play current video 95 bvideo.attr({ 96 "id": "bvideo", 97 "src": currentLinkVideo.attr("href"), 98 "data-bvideo_id": idCurrent // Which video are we playing 99 }); 100 101 // Change title for video playing 102 $('#bvideo_title').text(currentLinkVideo.text()); 103 104 listVideoHighlight(currentLinkVideo); 105 106 // On finished video, play next 107 bvideo.on('ended', function(e) { 108 109 // Current ID, using attribute since data gets cached and we are updating it 110 id = parseInt($(this).attr("data-bvideo_id")); 111 112 // Icon marked played 113 if (config.playedVideoEmoji != '') 114 currentLinkVideo.parent().prepend(config.playedVideoEmoji); 115 116 // Remove background color 117 if (config.playingBackgroundColor != '') 118 currentLinkVideo.parent().css("background-color", ""); 119 120 // What to play next 121 idNext = (id == videoList.length - 1) ? 0 : id + 1; 122 123 // Getting the source of the a 124 videoNext = $('a[data-bvideo_id~="' + idNext + '"]'); 125 126 $(this).attr({ 127 "src": videoNext.attr("href"), 128 "data-bvideo_id": idNext // Which video are we playing 129 }); 130 131 if (config.autoplay == 1) 132 $(this).attr("autoplay", "autoplay"); 133 134 // Remember next video 135 localStorage.setItem('bvideo-playlist-' + currentUrl, idNext); 136 137 // Change title for video playing 138 $('#bvideo_title').text(videoNext.text()); 139 140 listVideoHighlight(videoNext); 141 }); 142 143 // Sets the source of the video from an ahref 144 $("#bvideo_playlist a[target!='_blank']").on("click", function(e) { 145 146 // We prevent any default action, so we do not go to the URL 147 e.preventDefault(); 148 149 bvideo.attr({ 150 "src": $(this).attr("href"), 151 "data-bvideo_id": $(this).data("bvideo_id") // Which video are we playing 152 }); 153 154 if (config.autoplay == true) 155 bvideo.attr("autoplay", "autoplay"); 156 157 // Scroll to video 158 if ($('#bvideo_title').length) // Location.href = "#bvideo_title"; 159 document.querySelector('#bvideo_title').scrollIntoView({ 160 behavior: 'smooth' 161 }); 162 else // Location.href = "#bvideo"; 163 document.querySelector('#bvideo').scrollIntoView({ 164 behavior: 'smooth' 165 }); 166 167 // Remember last video 168 localStorage.setItem('bvideo-playlist-' + currentUrl, $(this).data("bvideo_id")); 169 170 // Change title for video playing 171 $('#bvideo_title').text($(this).text()); 172 173 listVideoHighlight($(this)); 174 175 }); 176 177 } 178 } 179 180 181 /** 182 * generates the videoList used for the play list 183 * if uses ARRAY JS generates the inner LI HTML 184 * @return Array videoList 185 */ 186 function getVideoList(){ 187 let videoList = []; 188 189 // 1st way to load the playlist comes from a playlist JS array 190 if (typeof directLinkData !== 'undefined' || typeof video_playlist !== 'undefined') { 191 // In case there's a default playlist array 192 if (typeof video_playlist !== 'undefined') { 193 videoList = video_playlist; 194 } 195 196 // Loading playlist from a pCloud array, in a public folder view page use the directLinkData array embedded in the HTML 197 if (typeof directLinkData !== 'undefined') { 198 // Create the list of links 199 let pCloud = directLinkData.content; 200 let path = 'https://filedn.eu/' + directLinkData.code + directLinkData.dirpath; 201 202 for (i = 0; i < pCloud.length; i++) { 203 let temp = []; 204 temp["name"] = pCloud[i].name.slice(0, -4); 205 temp["link"] = path + pCloud[i].urlencodedname; 206 temp["size"] = pCloud[i].size; 207 videoList.push(temp); 72 208 } 73 209 } 74 }//end if first time 75 76 this.play(); 77 }); 78 79 /** 80 * Playlist player for 1 video HTML tag 81 */ 82 83 if ($('#bvideo_playlist').length ) 84 { 85 var video_list = []; 86 var current_url = btoa(window.location.href.split('?')[0].split('#')[0]); 87 88 // 1st way to load the playlist comes from a plylist JS array 89 if (typeof directLinkData !== 'undefined' || typeof video_playlist !== 'undefined') 90 { 91 //in case there's a default playlist array 92 if (typeof video_playlist !== 'undefined'){ 93 video_list = video_playlist; 210 211 // From array videoList to a table 212 let htmlList = ""; 213 for (i = 0; i < videoList.length; i++) { 214 215 htmlList += '<li>'; 216 217 if (isPlayedVideo(videoList[i].link)) 218 htmlList += config.playedVideoEmoji; 219 220 htmlList += '<a data-bvideo_id="' + i + '" href="' + videoList[i].link + '" title="' + videoList[i].name + '">' + videoList[i].name + '</a>'; 221 222 if (videoList[i].size != undefined) { 223 videoSize = (videoList[i].size != undefined ? fileSize(videoList[i].size) : '-') 224 htmlList += '<span style="float:right;"><a target="_blank" title="' + videoSize + ' Download" download href="' + videoList[i].link + '">' + config.downloadEmoji + '</a></span>'; 225 } 226 227 htmlList += '</li>'; 94 228 } 95 229 96 // loading playlist from a pcloud array, in a public folder view page use the directLinkData array embeded in the HTML 97 if (typeof directLinkData !== 'undefined') 98 { 99 //created the list of links 100 var pcloud = directLinkData.content; 101 var path = 'https://filedn.eu/'+directLinkData.code+directLinkData.dirpath; 102 103 for (i=0; i<pcloud.length; i++) 104 { 105 var temp = []; 106 temp["name"] = pcloud[i].name.slice(0, -4); 107 temp["link"] = path+pcloud[i].urlencodedname; 108 temp["size"] = pcloud[i].size; 109 video_list.push(temp); 110 } 111 112 } 113 114 // from array video_list to a table 115 var html_list = ""; 116 for (i=0; i<video_list.length; i++) { 117 118 html_list+='<li>'; 119 120 if (is_played_video(video_list[i].link)) 121 html_list+='✔ '; 122 123 html_list+='<a data-bvideo_id="'+i+'" href="'+video_list[i].link+'" title="'+video_list[i].name+'">'+video_list[i].name+'</a>'; 124 125 if (video_list[i].size!=undefined) 126 { 127 video_size = (video_list[i].size!=undefined?fileSize(video_list[i].size):'-') 128 html_list+='<span style="float:right;"><a target="_blank" title="'+video_size+' Download" download href="'+video_list[i].link+'">💾</a></span>'; 129 } 130 131 html_list+='</li>'; 132 } 133 134 //print html 135 $("#bvideo_playlist").html(html_list); 136 $("#bvideo_playlist").parent().css( { 137 "height":$("video").height()+120, 138 "overflow-y": "auto" 139 }); 140 141 } 142 143 // 2nd way to get a playlist load video_list array from a list instead than JS array 144 else if($('#bvideo_playlist').is('ol, ul')) 145 { 146 var video_list = []; 147 $("#bvideo_playlist li a").each(function(e) { 230 // Print HTML 231 bvideo_playlist.html(htmlList); 232 bvideo_playlist.parent().css({ 233 "height": bvideo.height() + 120, 234 "overflow-y": "auto" 235 }); 236 237 } 238 239 // 2nd way to get a playlist: load videoList array from a list instead than JS array 240 else if (bvideo_playlist.is('ol, ul')) { 241 videoList = []; 242 $("#bvideo_playlist li a").each(function(e) { 148 243 a = $(this); 149 a.attr('data-bvideo_id',e); 150 var temp = []; 151 temp["name"] = this.text; 152 temp["link"] = this.href; 153 temp["size"] = a.data('size')!==undefined?a.data('size'):0; 154 video_list.push(temp); 155 }); 156 } 157 158 // playlist video player 159 if (typeof video_list !== 'undefined') 160 { 161 //start video from parameeter ID.... 162 var start_video = new URLSearchParams(window.location.search).get('start_video'); 163 if (start_video!==null && $.isNumeric(start_video)) 164 id_current = start_video-1;//we start counting from 1 so we do not use the 0. 165 else//init video at last play 166 id_current = localStorage.getItem('bvideo-'+current_url); 244 a.attr('data-bvideo_id', e); 245 246 // Icon marked played 247 if (config.playedVideoEmoji != '' && isPlayedVideo(this.href) ) 248 a.parent().prepend(config.playedVideoEmoji); 249 250 let temp = {}; 251 temp["name"] = this.text; 252 temp["link"] = this.href; 253 temp["size"] = a.data('size') !== undefined ? a.data('size') : 0; 254 videoList.push(temp); 255 }); 167 256 168 id_current = ($.isNumeric(id_current))?id_current:0; 169 id_current = (id_current > video_list.length-1)?0:id_current; 170 171 current_video = $('a[data-bvideo_id~="'+id_current+'"]'); 172 173 //current video playing 174 localStorage.setItem('bvideo-'+current_url, id_current); 175 176 //setup player to play current video 177 $("video").attr({ 178 "id":"bvideo", 179 "src": current_video.attr("href"), 180 "data-bvideo_id":id_current//which video are we playing 181 }); 182 183 //change title for video playing 184 $('#bvideo_title').text(current_video.text()); 185 186 //highlight 187 current_video.parent().css("background-color","#eeeeee"); 188 189 190 //on finished video play next 191 $("video").on('ended', function(e){ 192 193 //current id,using attribute since data gets cached and we are updating it 194 id = parseInt($(this).attr("data-bvideo_id")); 195 196 //we mark this video as played 197 mark_played_video(id); 198 199 //what to play next 200 id_next = (id == video_list.length-1)?0:id+1; 201 202 //getting the source of the a 203 src = $('a[data-bvideo_id~="'+id_next+'"]'); 204 205 $(this).attr({ 206 "src": src.attr("href"), 207 "autoplay": "autoplay", 208 "data-bvideo_id":id_next //which video are we playing 209 }); 210 211 //remember next video 212 localStorage.setItem('bvideo-'+current_url, id_next); 213 214 //change title for video playing 215 $('#bvideo_title').text(src.text()); 216 217 //highlight whats currently playing 218 //$(this).parent().prepend('▶️ '); 219 $('#bvideo_playlist li').css("background-color",""); 220 src.parent().css("background-color","#eeeeee"); 221 }); 222 223 //sets the source of the video from an ahref 224 $("#bvideo_playlist a[target!='_blank']").on("click", function(e) { 225 226 //we prevent any default action, so we do not go to the url 227 e.preventDefault(); 228 229 $("video").attr({ 230 "src": $(this).attr("href"), 231 "autoplay": "autoplay", 232 "data-bvideo_id":$(this).data("bvideo_id") //which video are we playing 233 }); 234 235 //scroll to video 236 if ($('#bvideo_title').length )//location.href = "#bvideo_title"; 237 document.querySelector('#bvideo_title').scrollIntoView({behavior: 'smooth'}); 238 239 else//location.href = "#bvideo"; 240 document.querySelector('#bvideo').scrollIntoView({behavior: 'smooth'}); 241 242 //remember last video 243 localStorage.setItem('bvideo-'+current_url, $(this).data("bvideo_id")); 244 245 //change title for video playing 246 $('#bvideo_title').text($(this).text()); 247 248 //highlight whats currently playing 249 //$(this).parent().prepend('▶️ '); 250 $('#bvideo_playlist li').css("background-color",""); 251 $(this).parent().css("background-color","#eeeeee"); 252 }); 257 } 258 259 return videoList; 260 } 261 262 263 /** 264 * store video time in local and WP 265 * @param video 266 * @param time we can specify the time we store. For instance -1 means video played. 267 */ 268 function storeVideoTime(video, time = false){ 269 //time not set then using video current 270 if (time==false) 271 time = video.currentTime; 272 273 // Save into local storage; if you change the browser, it will not work 274 localStorage.setItem('bvideo-' + btoa(video.src), time); 275 276 // Ajax call 277 $.post(betterVideo_ajax.ajax_url, { 278 _ajax_nonce: betterVideo_ajax.nonce, // Nonce 279 action: "bbpl_store_video_time", // Action 280 time: time, // Time 281 video: video.src, // Video URL 282 }).fail(handleAjaxError); 283 } 284 285 /** 286 * get the video time from a SRC 287 * @param video 288 * @return integer 289 */ 290 function getVideoTime(video){ 291 storedTime = getVideoTimeSrc(video.src); 292 if (storedTime > video.duration) 293 storedTime = 0; 294 295 return storedTime; 296 } 297 298 299 function getVideoTimeSrc(videoSrc){ 300 // First, retrieve from local storage 301 let storedTime = localStorage.getItem('bvideo-' + btoa(videoSrc)); 302 303 // TODO needed improvement here!! 304 // Only Ajax if stored time is empty, saves queries 305 // but we may have different values if used in different browsers 306 if (storedTime == null) { 307 // Ajax call 308 $.post(betterVideo_ajax.ajax_url, { 309 _ajax_nonce: betterVideo_ajax.nonce, // Nonce 310 action: "bbpl_get_video_time", // Action 311 video: videoSrc, // Video URL 312 }, function(data) { // Callback 313 storedTime = data[0]; 314 }).fail(handleAjaxError); 315 } 253 316 254 } 255 256 /** 257 * we mark a video as played, we use the btoa of the current url and we store the btoa of the video src 258 * @param id_video we get the src from the a 259 */ 260 function mark_played_video(id_video) 261 { 262 //getting the source of the a 263 a = $('a[data-bvideo_id~="'+id_video+'"]'); 264 src = a.attr("href"); 265 266 // if it was not in the array before, then store 267 if(is_played_video(src) == false) 268 { 269 var watched_videos; 270 271 watched_videos = localStorage.getItem('bvideo-played-'+ current_url); 272 273 if (watched_videos == null) 274 watched_videos = []; 275 else 276 watched_videos = JSON.parse(watched_videos); 277 278 watched_videos.push(btoa(src)); 279 localStorage.setItem('bvideo-played-'+ current_url, JSON.stringify(watched_videos)); 280 281 //icon marked played 282 a.parent().prepend('✔ '); 283 //remove backgorund color 284 a.parent().css("background-color",""); 285 } 286 } 287 288 /** 289 * tells us if we have seen that video in this url 290 * @param string btoa src of the video 291 * @return boolean 292 */ 293 function is_played_video(src) 294 { 295 watched_videos = localStorage.getItem('bvideo-played-'+ current_url); 296 297 if (watched_videos == null) 298 return false; 299 300 watched_videos = JSON.parse(watched_videos); 301 302 if( watched_videos.indexOf(btoa(src)) != -1 ) 303 return true; 304 else 305 return false; 306 } 307 308 } 317 return storedTime; 318 } 319 320 /** 321 * video is marked as played using -1 322 * @param video 323 */ 324 function markPlayedVideo(video){ 325 326 if (isPlayedVideo(video.src) == false) 327 storeVideoTime(video,-1); 328 } 329 330 /** 331 * Tells us if we have seen that video in this URL 332 * @param string btoa src of the video 333 * @return boolean 334 */ 335 function isPlayedVideo(videoSrc) { 336 return getVideoTimeSrc(videoSrc) == -1; 337 } 338 339 /** 340 * Highlights the item on the playlist to know what is been playing 341 * @return none 342 */ 343 function listVideoHighlight(linkList) { 344 // Highlight what's currently playing 345 if (config.playingEmoji != '') { 346 $("#bvideoCurrentVideoEmoji").remove(); 347 linkList.parent().prepend('<span id="bvideoCurrentVideoEmoji">' + config.playingEmoji + ' </span>'); 348 } 349 if (config.playingBackgroundColor != '') { 350 $(".bvideoCurrentVideoColor").css("background-color", ""); 351 linkList.parent().addClass('bvideoCurrentVideoColor'); 352 linkList.parent().css("background-color", config.playingBackgroundColor); 353 } 354 } 355 356 // AJAX error handling function 357 function handleAjaxError(xhr, textStatus, errorThrown) { 358 console.error("AJAX Error: " + textStatus); 359 console.error("Error Details: " + errorThrown); 360 } 361 309 362 310 363 }) 311 364 312 //from https://stackoverflow.com/a/20463021 313 function fileSize(a,b,c,d,e) 314 { 315 return (b=Math,c=b.log,d=1e3,e=c(a)/c(d)|0,a/b.pow(d,e)).toFixed(e?2:0)+' '+(e?'kMGTPEZY'[--e]+'B':'Bytes') 365 // From https://stackoverflow.com/a/20463021 366 function fileSize(a, b, c, d, e) { 367 return (b = Math, c = b.log, d = 1e3, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(e ? 2 : 0) + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes') 316 368 } -
better-video-playlist/trunk/README.TXT
r2959725 r2963306 5 5 Requires at least: 6.0 6 6 Tested up to: 6.3 7 Stable tag: 2. 0.47 Stable tag: 2.1 8 8 Requires PHP: 7.4 9 9 License: GPLv2 or later 10 10 License URI: http://www.gnu.org/licenses/gpl-2.0.html 11 11 12 Improves video capabilities for wordpress, stores progress and adds video playlist features. 13 12 Improves WordPress Video Experience by adding playlist, resume video and a lot more! 14 13 15 14 == Description == 16 15 17 Super fast video player and playlist player using native HTML5 video player and jQuery. Uses browser local storage for most features. 16 **Elevate Your WordPress Video Experience!** 18 17 19 If user is logged in we store video position in the database. So even if changes browser will save the progress.18 The Better Video & Playlist Plugin is designed to enhance the video capabilities of your WordPress website while adding a sophisticated video playlist feature. This plugin ensures that your site's visitors enjoy a seamless and engaging video-watching experience. 20 19 21 Works in pages, posts, widgets or any place at your site. 20 **Key Features:** 22 21 23 = Features = 22 - **Resume Video Playback**: Never lose progress – our plugin remembers where you left off. 23 - **Video Progress Storage**: Store video progress in the WordPress database and local browser storage. 24 - **Customized Start Time**: Start your videos at specific times using the `?t=SECONDS` parameter (e.g., `?t=120` starts at 2 minutes). 25 - **Video Playlists**: Create and manage video playlists effortlessly using block editor. 26 - **Autoplay Next Video**: Keep viewers engaged with automatic playback of the next video. 27 - **Emoji Customization**: Add a personal touch with custom video emojis. 28 - **Background Color**: Tailor the video player's background color to match your site's aesthetics. 24 29 25 - Resume video from last position. Saves progress in DB and browser storage. 26 - On pause or window close, stores progress 27 - Start playing video at custom time using ?t=SECONDS ex ?t=120 will start at 2 minutes 30 **Why Choose Better Video & Playlist?** 28 31 29 **Playlist Features** 30 - Create playlist video from a HTML5 list or JS array 31 - Resume on last played video 32 - Autoplay next video on video end 33 - Mark video as played 34 - Start playing from video via url parameter using ?start_video=ID_VIDEO 35 - Stored in user browser storage and at WordPress Database 36 32 - **User-Friendly**: Seamlessly integrate advanced video features into your WordPress site. 33 - **Progress Tracking**: Never make viewers start from scratch; they can pick up right where they left off. 34 - **Playlist Management**: Create and organize video playlists with ease. 35 - **Community Support**: Join a community of users benefiting from this plugin's capabilities. 37 36 38 37 == Installation == 39 38 40 Through WordPress admin: 39 **Via WordPress Admin:** 41 40 42 1. Go to Plugins -> Add New43 2. Search for "Better Video "44 3. Install the plugin45 4. Activate it41 1. Go to **Plugins** -> **Add New**. 42 2. Search for "Better Video & Playlist." 43 3. Click **Install Now**. 44 4. Activate the plugin. 46 45 47 Through FTP: 46 **Via FTP:** 48 47 49 1. Download the plugin 50 2. Unzip .zip and upload the folder to the `/wp-content/plugins/` directory 51 3. Activate the plugin through the 'Plugins' menu in WordPress 52 48 1. Download the plugin. 49 2. Unzip the .zip file and upload the folder to `/wp-content/plugins/`. 50 3. Activate the plugin in the **Plugins** menu of WordPress. 53 51 54 52 == Frequently Asked Questions == 55 53 56 = How to use? = 54 **How to Use?** 57 55 58 To enable the video features just add a video from the post editor or add HTML video tag. You can have as many video tags as you want.56 To enable the video features, add a video from the post editor or use the HTML video tag. You can include as many video tags as needed. 59 57 60 = Video Play list = 58 **Creating Video Playlists** 61 59 62 You can create a list on your editor and then in the side panel in advanced, anchor set it to "bvideo_playlist".60 You can create a video playlist within your editor by using the block. 63 61 64 Also you can edit the HTML and create List with id = bvideo_playlist: 62 Or by using the advanced settings panel and setting it to "bvideo_playlist." Alternatively, you can create a list in your HTML with the id "bvideo_playlist." 65 63 66 <ol id="bvideo_playlist"> 67 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/earth_night_rotate_1080.mov">Animation: Rotating Earth at Night</a></li> 68 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/rbsp_launch_1080p.mp4">Radiation Belt Storm Probes Launch</a></li> 69 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/curiosity_lands.mov">Dropping in on Mars in High-Res</a></li> 70 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/GRAIL_launch_1080.mov">GRAIL Launches on Mission to Moon</a></li> 71 <li><a href="http://s3.amazonaws.com/akamai.netstorage/HD_downloads/HLV_Launch_anim.mov">Space Launch System Animation</a></li> 72 </ol> 64 Here's an example HTML playlist: 73 65 66 ```html 67 <ol id="bvideo_playlist"> 68 <li><a href="video1.mp4">Video 1</a></li> 69 <li><a href="video2.mp4">Video 2</a></li> 70 <li><a href="video3.mp4">Video 3</a></li> 71 </ol> 72 ``` 74 73 75 You can also add in your HTML/JS file a playlist array and will create your list magically, the size field it’s optional:74 You can also create a playlist using a JavaScript array: 76 75 77 <script> 78 var video_playlist = [ 79 { 80 "name": "Animation: Rotating Earth at Night", 81 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/earth_night_rotate_1080.mov", 82 "size": 55000000, 83 }, 84 { 85 "name": "Radiation Belt Storm Probes Launch", 86 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/rbsp_launch_1080p.mp4", 87 "size": 475000000, 88 }, 89 { 90 "name": "Dropping in on Mars in High-Res", 91 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/curiosity_lands.mov", 92 "size": 105000000, 93 }, 94 { 95 "name": "GRAIL Launches on Mission to Moon", 96 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/GRAIL_launch_1080.mov", 97 "size": 1113000000, 98 }, 99 { 100 "name": "Space Launch System Animation", 101 "link": "http://s3.amazonaws.com/akamai.netstorage/HD_downloads/HLV_Launch_anim.mov", 102 "size": 642570000, 103 }, 104 105 ]; 106 </script> 76 ```javascript 77 <script> 78 var video_playlist = [ 79 { 80 "name": "Video 1", 81 "link": "video1.mp4", 82 "size": 55000000 83 }, 84 { 85 "name": "Video 2", 86 "link": "video2.mp4", 87 "size": 475000000 88 }, 89 { 90 "name": "Video 3", 91 "link": "video3.mp4", 92 "size": 105000000 93 } 94 ]; 95 </script> 96 ``` 107 97 108 To add the JS to your post/page you can use a plugin like [this one](https://wordpress.org/plugins/header-and-footer-scripts/). 109 98 To add the JavaScript to your post/page, consider using a plugin like [this one](https://wordpress.org/plugins/header-and-footer-scripts/). 110 99 111 100 == Screenshots == 112 1. Video player113 2. Play list player114 101 115 == Upgrade Notice == 116 None. 102 1. Video Player 103 2. Playlist Player 117 104 118 == Changelog==105 == Upgrade History == 119 106 107 = Version 2.1 = 108 - Major jQuery and PHP code refactor 109 - Improved method for tracking played videos 110 - New admin panel with customizable settings 120 111 121 = 2.0.4 =122 * Improved description and FAQ's112 = Version 2.0.4 = 113 - Enhanced descriptions and FAQs 123 114 124 = 2.0.3 =125 * WP 6.3 tested 115 = Version 2.0.3 = 116 - Tested for WordPress 6.3 compatibility 126 117 127 = 2.0.2 =128 *smooth scroll to video118 = Version 2.0.2 = 119 - Added smooth scroll to video 129 120 130 = 2.0.1 =131 * ajax stores video time for logged user 121 = Version 2.0.1 = 122 - Implemented AJAX for storing video time for logged-in users 132 123 133 = 1.0 =134 * Initial version 124 = Version 1.0 = 125 - Initial release -
better-video-playlist/trunk/better-video.php
r2959725 r2963306 1 1 <?php 2 2 /** 3 * Plugin Name: Better Video & Playlist 4 * Plugin URI: https://garridodiaz.com/better-video-plugin-for-wordpress/ 5 * Description: Improves video capabilities for wordpress and adds video playlist features. 6 * Version: 2.0.4 7 * Author: Chema 8 * Author URI: https://garridodiaz.com 9 * License: GPL2 10 */ 11 12 add_action( 'wp_enqueue_scripts', 'bbpl_assets'); 13 add_action( 'wp_ajax_bbpl_store_video_time', 'bbpl_store_video_time' ); 14 add_action( 'wp_ajax_bbpl_get_video_time', 'bbpl_get_video_time' ); 15 16 /* enqueue scripts and style from parent theme */ 17 function bbpl_assets() { 18 wp_enqueue_script( 'better-video', plugin_dir_url( __FILE__ ) . 'js/better-video.js', array('jquery'), '2.0.4', true ); 19 20 wp_localize_script( 21 'better-video', 22 'my_ajax_obj', 23 array( 24 'ajax_url' => admin_url( 'admin-ajax.php' ), 25 'nonce' => wp_create_nonce( 'better-video' ), 26 ) 27 ); 3 * Plugin Name: Better Video & Playlist 4 * Plugin URI: https://garridodiaz.com/better-video-plugin-for-wordpress/ 5 * Description: Improves video capabilities for WordPress and adds video playlist features. 6 * Version: 2.1 7 * Author: Chema 8 * Author URI: https://garridodiaz.com 9 * License: GPL2 10 */ 11 12 if (!defined('ABSPATH')) exit; // Exit if accessed directly 13 14 class BetterVideoPlaylistPlugin 15 { 16 const MAIN_FILE = __FILE__; 17 18 public function __construct() 19 { 20 // Initialize the plugin by adding hooks and actions 21 add_action('wp_enqueue_scripts', [$this, 'enqueueAssets']); 22 add_action('wp_ajax_bbpl_store_video_time', [$this, 'storeVideoTime']); 23 add_action('wp_ajax_bbpl_get_video_time', [$this, 'getVideoTime']); 24 add_action('admin_menu', [$this, 'addAdminMenu']); 25 add_action('admin_init', [$this, 'registerSettings']); 26 add_action('admin_enqueue_scripts', [$this, 'enqueueAdminScripts']); 27 add_action('admin_notices', [$this, 'displayDonationMessage']); 28 add_action('admin_head', [$this, 'addDonationMessageJS']); 29 add_filter('plugin_row_meta', [$this, 'addPluginRowMeta'], 10, 2); 30 add_action('admin_init', [$this, 'setupSettingsFields']); 31 } 32 33 /** 34 * Enqueue assets (scripts and styles) for the plugin. 35 */ 36 public function enqueueAssets() 37 { 38 // Enqueue scripts and localize for better-video.js 39 wp_enqueue_script('better-video', plugin_dir_url(__FILE__) . 'js/better-video.js', array('jquery'), '2.1', true); 40 41 wp_localize_script( 42 'better-video', 43 'betterVideo_ajax', 44 array( 45 'ajax_url' => admin_url('admin-ajax.php'), 46 'nonce' => wp_create_nonce('better-video'), 47 ) 48 ); 49 50 $bbpl_settings = array( 51 'playedVideoEmoji' => get_option('bbpl_played_video_emoji', __('✔', 'bbpl-textdomain')), 52 'playingEmoji' => get_option('bbpl_playing_emoji', __('▶️', 'bbpl-textdomain')), 53 'downloadEmoji' => get_option('bbpl_download_emoji', __('💾', 'bbpl-textdomain')), 54 'playingBackgroundColor' => get_option('bbpl_playing_background_color', '#FFFF00'), 55 'autoplay' => get_option('bbpl_autoplay', true), 56 ); 57 wp_localize_script('better-video', 'bbplSettings', $bbpl_settings); 58 } 59 60 /** 61 * Handle AJAX request for storing video time. 62 * 63 * @return bool JSON response indicating success or failure. 64 */ 65 public function storeVideoTime() 66 { 67 // Handle the AJAX request for storing video time 68 check_ajax_referer('better-video'); 69 $return = false; 70 71 if (is_user_logged_in()) { 72 global $current_user; 73 $time = sanitize_text_field($_POST['time']); 74 $video = sanitize_url($_POST['video']); 75 76 if (is_numeric($time) && wp_http_validate_url($video)) { 77 $return = update_user_meta($current_user->ID, 'bvideo-' . md5($video), $time); 78 } 79 } 80 81 wp_send_json($return); 82 } 83 84 /** 85 * Handle AJAX request for getting video time. 86 * 87 * @return mixed JSON response containing the video time or 0. 88 */ 89 public function getVideoTime() 90 { 91 // Handle the AJAX request for getting video time 92 check_ajax_referer('better-video'); 93 $return = 0; 94 95 if (is_user_logged_in()) { 96 global $current_user; 97 $video = sanitize_url($_POST['video']); 98 if (wp_http_validate_url($video)) { 99 $return = get_user_meta($current_user->ID, 'bvideo-' . md5($video)); 100 } 101 } 102 103 wp_send_json($return); 104 } 105 106 /** 107 * Add the admin menu for plugin settings. 108 */ 109 public function addAdminMenu() 110 { 111 // Add the admin menu for settings 112 add_submenu_page( 113 'options-general.php', 114 __('Better Video & Playlist Settings', 'bbpl-textdomain'), 115 __('Video Settings', 'bbpl-textdomain'), 116 'manage_options', 117 'bbpl-settings', 118 [$this, 'renderSettingsPage'] 119 ); 120 } 121 122 /** 123 * Register plugin settings. 124 */ 125 public function registerSettings() 126 { 127 // Register plugin settings 128 register_setting('bbpl_settings_group', 'bbpl_played_video_emoji'); 129 register_setting('bbpl_settings_group', 'bbpl_playing_emoji'); 130 register_setting('bbpl_settings_group', 'bbpl_download_emoji'); 131 register_setting('bbpl_settings_group', 'bbpl_playing_background_color'); 132 register_setting('bbpl_settings_group', 'bbpl_autoplay'); 133 } 134 135 /** 136 * Enqueue scripts for the admin page. 137 * 138 * @param string $hook The current admin page hook. 139 */ 140 public function enqueueAdminScripts($hook) 141 { 142 // Enqueue scripts for the admin page 143 if ($hook === 'settings_page_bbpl-settings') { 144 wp_enqueue_script('bbpl-admin', plugin_dir_url(__FILE__) . 'js/admin-better-video.js', array('jquery', 'wp-color-picker'), '1.0', true); 145 } 146 } 147 148 /** 149 * Display a donation message in the WordPress admin. 150 */ 151 public function displayDonationMessage() 152 { 153 // Display the donation message 154 if ((isset($_GET['page']) && $_GET['page'] === 'bbpl-settings') && !isset($_COOKIE['donation_message_closed'])) { 155 echo '<div id="donation-message" class="notice notice-info is-dismissible" style="background-color: #f5f5f5; border-left: 4px solid #0073aa; padding: 10px;"> 156 <p style="font-size: 16px;">Enjoy using our plugin? Consider <a href="https://paypal.me/chema/10EUR" target="_blank" id="donate-link">making a donation</a> to support our work! THANKS!</p> 157 </div>'; 158 } 159 } 160 161 /** 162 * Add JavaScript for handling the donation message. 163 */ 164 public function addDonationMessageJS() 165 { 166 // Add JavaScript for handling the donation message 167 if (!isset($_COOKIE['donation_message_closed'])) { 168 ?> 169 <script type="text/javascript"> 170 jQuery(document).ready(function ($) { 171 172 $('#donate-link').click(function () { 173 $('#donation-message').remove(); 174 var expirationDate = new Date(); 175 expirationDate.setDate(expirationDate.getDate() + 30); // Expires in 30 days 176 document.cookie = 'donation_message_closed=true; expires=' + expirationDate.toUTCString() + '; path=/'; 177 178 }); 179 }); 180 </script> 181 <?php 182 } 183 } 184 185 /** 186 * Setup settings fields and sections for the plugin. 187 */ 188 public function setupSettingsFields() 189 { 190 // Setup settings fields and sections 191 add_settings_section('bbpl_general_section', __('General Settings', 'bbpl-textdomain'), [$this, 'renderGeneralSection'], 'bbpl-settings'); 192 193 // Define custom sanitize callbacks for each field 194 $sanitize_callbacks = [ 195 'bbpl_played_video_emoji' => 'sanitize_text_field', 196 'bbpl_playing_emoji' => 'sanitize_text_field', 197 'bbpl_download_emoji' => 'sanitize_text_field', 198 'bbpl_playing_background_color' => 'sanitize_hex_color', 199 'bbpl_autoplay' => 'sanitize_checkbox', 200 ]; 201 202 // Sanitize user input for each field 203 add_settings_field('bbpl_played_video_emoji', __('Played Video Emoji', 'bbpl-textdomain'), [$this, 'renderPlayedVideoEmojiField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_played_video_emoji']]); 204 add_settings_field('bbpl_playing_emoji', __('Playing Emoji', 'bbpl-textdomain'), [$this, 'renderPlayingEmojiField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_playing_emoji']]); 205 add_settings_field('bbpl_download_emoji', __('Download Emoji', 'bbpl-textdomain'), [$this, 'renderDownloadEmojiField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_download_emoji']]); 206 add_settings_field('bbpl_playing_background_color', __('Playing Background Color', 'bbpl-textdomain'), [$this, 'renderBackgroundColorField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_playing_background_color']]); 207 add_settings_field('bbpl_autoplay', __('Autoplay', 'bbpl-textdomain'), [$this, 'renderAutoplayField'], 'bbpl-settings', 'bbpl_general_section', ['sanitize_callback' => $sanitize_callbacks['bbpl_autoplay']]); 208 } 209 210 // Custom sanitize function for checkbox input 211 public function sanitize_checkbox($value) 212 { 213 return empty($value) ? false : true; 214 } 215 216 217 /** 218 * Render the plugin's settings page. 219 */ 220 public function renderSettingsPage() 221 { 222 ?> 223 <div class="wrap"> 224 <h2><?php _e('Better Video & Playlist Settings', 'bbpl-textdomain'); ?></h2> 225 <form method="post" action="options.php"> 226 <?php settings_fields('bbpl_settings_group'); ?> 227 <?php do_settings_sections('bbpl-settings'); ?> 228 <input type="submit" class="button-primary" value="<?php _e('Save Settings', 'bbpl-textdomain'); ?>"> 229 </form> 230 </div> 231 <?php 232 } 233 234 /** 235 * Render the general section description. 236 */ 237 public function renderGeneralSection() 238 { 239 echo __('Configure general settings for Better Video & Playlist.', 'bbpl-textdomain'); 240 } 241 242 // Sanitize user input for each field before saving 243 public function renderPlayedVideoEmojiField() 244 { 245 $value = get_option('bbpl_played_video_emoji', __('✔', 'bbpl-textdomain')); 246 $value = sanitize_text_field($value); // Sanitize the input 247 echo "<input type='text' name='bbpl_played_video_emoji' value='$value'>"; 248 } 249 250 public function renderPlayingEmojiField() 251 { 252 $value = get_option('bbpl_playing_emoji', __('▶️', 'bbpl-textdomain')); 253 $value = sanitize_text_field($value); // Sanitize the input 254 echo "<input type='text' name='bbpl_playing_emoji' value='$value'>"; 255 } 256 257 public function renderDownloadEmojiField() 258 { 259 $value = get_option('bbpl_download_emoji', __('💾', 'bbpl-textdomain')); 260 $value = sanitize_text_field($value); // Sanitize the input 261 echo "<input type='text' name='bbpl_download_emoji' value='$value'>"; 262 } 263 264 public function renderBackgroundColorField() 265 { 266 $value = get_option('bbpl_playing_background_color', '#FFFF00'); 267 $value = sanitize_hex_color($value); // Sanitize the color input 268 echo "<input type='text' name='bbpl_playing_background_color' value='$value' class='color-picker'>"; 269 } 270 271 public function renderAutoplayField() 272 { 273 $value = get_option('bbpl_autoplay', true); 274 $value = $value ? '1' : '0'; // Ensure it's either '0' or '1' 275 echo "<input type='hidden' name='bbpl_autoplay' value='0'> 276 <label for='bbpl_autoplay'> 277 <input type='checkbox' id='bbpl_autoplay' name='bbpl_autoplay' value='1' " . checked($value, '1', false) . "> 278 " . __('Enable Autoplay', 'bbpl-textdomain') . " 279 </label>"; 280 } 281 282 283 /** 284 * Add links to settings and sponsorship in plugin row meta. 285 * 286 * @param array $plugin_meta The existing plugin meta. 287 * @param string $plugin_file The plugin file path. 288 * @return array Modified plugin meta with added links. 289 */ 290 public function addPluginRowMeta($plugin_meta, $plugin_file) 291 { 292 if (plugin_basename(self::MAIN_FILE) !== $plugin_file) { 293 return $plugin_meta; 294 } 295 296 $settings_page_url = admin_url('options-general.php?page=bbpl-settings'); 297 298 $plugin_meta[] = sprintf( 299 '<a href="%1$s"><span class="dashicons dashicons-admin-settings" aria-hidden="true" style="font-size:14px;line-height:1.3"></span>%2$s</a>', 300 $settings_page_url, 301 esc_html_x('Settings', 'verb', 'bbpl-textdomain') 302 ); 303 304 $plugin_meta[] = sprintf( 305 '<a href="%1$s"><span class="dashicons dashicons-star-filled" aria-hidden="true" style="font-size:14px;line-height:1.3"></span>%2$s</a>', 306 'https://paypal.me/chema/10EUR', 307 esc_html_x('Sponsor', 'verb', 'better-video') 308 ); 309 310 return $plugin_meta; 311 } 28 312 } 29 313 30 31 /** 32 * Handles AJAX requests. 33 */ 34 function bbpl_store_video_time() { 35 36 // Handle the ajax request here 37 check_ajax_referer( 'better-video' ); 38 $return = FALSE; 39 40 //only store for loged in users 41 if (is_user_logged_in() ){ 42 global $current_user; 43 $time = sanitize_text_field($_POST['time']); 44 $video = sanitize_url($_POST['video']); 45 46 if (is_numeric($time) AND wp_http_validate_url($video)) 47 $return = update_user_meta($current_user->ID,'bvideo-'.md5($video),$time); 48 } 49 50 wp_send_json($return); 314 // Initialize the plugin 315 new BetterVideoPlaylistPlugin(); 316 317 318 319 function enqueueBlockAssets() { 320 wp_enqueue_script( 321 'bbpl-block', 322 plugins_url('blocks/block.js', __FILE__), 323 array('wp-blocks', 'wp-components', 'wp-i18n'), 324 ); 325 51 326 } 52 327 53 54 function bbpl_get_video_time() { 55 // Handle the ajax request here 56 check_ajax_referer( 'better-video' ); 57 $return = 0; 58 59 //only store for loged in users 60 if (is_user_logged_in() ){ 61 global $current_user; 62 $video = sanitize_url($_POST['video']); 63 if (wp_http_validate_url($video)) 64 $return = get_user_meta($current_user->ID,'bvideo-'.md5($video)); 65 } 66 67 wp_send_json($return); 68 } 69 70 71 72 ?> 328 add_action('enqueue_block_editor_assets', 'enqueueBlockAssets'); 329 -
better-video-playlist/trunk/js/better-video.js
r2959725 r2963306 1 1 /** 2 * Better Video and playlist jQuery plugin3 * Version: 2. 0.42 * Better Video and Playlist jQuery Plugin 3 * Version: 2.1 4 4 */ 5 jQuery(document).ready(function( $ ) { 5 6 const config = { 7 playedVideoEmoji: bbplSettings.playedVideoEmoji, 8 playingEmoji: bbplSettings.playingEmoji, 9 downloadEmoji: bbplSettings.downloadEmoji, 10 playingBackgroundColor: bbplSettings.playingBackgroundColor, 11 autoplay: bbplSettings.autoplay, 12 }; 13 14 jQuery(document).ready(function($) { 6 15 7 //when we pause we store the current time 8 $("video").on("pause", function(event) { 9 // Save into local storage,if you change the browser will not work 10 localStorage.setItem('bvideo-'+btoa(this.src), this.currentTime); 11 12 //ajax call 13 $.post(my_ajax_obj.ajax_url, { //POST request 14 _ajax_nonce: my_ajax_obj.nonce, //nonce 15 action: "bbpl_store_video_time", //action 16 time: this.currentTime, //time 17 video: this.src, //video url 18 } 19 ); 20 21 }); 22 23 //if you close the window and video playing store the current time 16 17 //cache for DOM optimization 18 let bvideo = $("video"); 19 20 // If you close the window and a video is playing, store the current time by invoking the pause method 24 21 $(window).on("unload", function(e) { 25 $("video").each(function(index, value) {26 if ( ! this.paused ) {22 bvideo.each(function(index, value) { 23 if (!this.paused) 27 24 this.pause(); 28 }29 25 }); 30 26 }); 31 27 32 // first time the force time happens 33 var first_time = true; 34 35 //play video restores the video from the last point or from the query string using ?t=444 36 $("video").on("play", function(event) { 37 38 //only load the stored time the first time. 39 if (first_time==true) 40 { 41 first_time = false; 42 //using time provided via url only once!! 43 var start_time = new URLSearchParams(window.location.search).get('t'); 44 var start_video = new URLSearchParams(window.location.search).get('start_video'); 45 46 if ( (start_time!==null && $.isNumeric(start_time)) && (start_video!==null && $.isNumeric(start_video)) ){ 47 if (start_time < this.duration) 48 this.currentTime = start_time; 28 // When we pause, we store the current time 29 bvideo.on("pause", function(event) { 30 storeVideoTime(this); 31 }); 32 33 // First time we force the player from the time we have stored. This is used so playlist works. 34 let firstTime = true; 35 36 // Play video restores the video from the last point or from the query string using ?t=444 37 bvideo.on("play", function(event) { 38 39 // Only load the stored time the first time they click play. 40 if (firstTime == true) { 41 firstTime = false; 42 // Using time provided via URL only once!! 43 let startTime = new URLSearchParams(window.location.search).get('t'); 44 45 if (startTime !== null && $.isNumeric(startTime)) { 46 if (startTime < this.duration) 47 this.currentTime = startTime; 48 } else { // Init video at last stored time 49 50 storedTime = getVideoTime(this); 51 // if not at the end or already played 52 if (storedTime >= this.duration || storedTime == -1) { 53 storedTime = 0; 54 } 55 56 this.currentTime = storedTime; 49 57 } 50 else{//init video at last stored time 51 52 //first retrieve from localstorage 53 var storedtime = localStorage.getItem('bvideo-'+btoa(this.src)); 54 55 //only ajax if storedtime is empty, saves queries 56 if (storedtime == null){ 57 var video_obj = this; 58 //ajax call 59 $.post(my_ajax_obj.ajax_url, { //POST request 60 _ajax_nonce: my_ajax_obj.nonce, //nonce 61 action: "bbpl_get_video_time", //action 62 video: this.src, //video url 63 },function(data) { //callback 64 if (data[0] < video_obj.duration) 65 video_obj.currentTime = data[0]; 66 } 67 ); 68 } 69 // Get the time from localStorage and play if not at the end. 70 else if (storedtime < this.duration){ 71 this.currentTime = storedtime; 58 } // End if first time 59 60 this.play(); 61 }); 62 63 // On finished video mark as played 64 bvideo.on('ended', function(e) { 65 markPlayedVideo(this); 66 }); 67 68 /** 69 * Playlist player for 1 video HTML tag 70 */ 71 let bvideo_playlist = $('#bvideo_playlist'); 72 73 if (bvideo_playlist.length) { 74 let currentUrl = btoa(window.location.href.split('?')[0].split('#')[0]); 75 let videoList = getVideoList(); 76 77 // Playlist video player 78 if (typeof videoList !== 'undefined') { 79 // Start video from parameter ID 80 let startVideo = new URLSearchParams(window.location.search).get('start_video'); 81 if (startVideo !== null && $.isNumeric(startVideo)) 82 idCurrent = startVideo - 1; // We start counting from 1 so we do not use 0. 83 else // Init video at last play 84 idCurrent = localStorage.getItem('bvideo-playlist-' + currentUrl); 85 idCurrent = ($.isNumeric(idCurrent)) ? idCurrent : 0; 86 idCurrent = (idCurrent > videoList.length - 1) ? 0 : idCurrent; 87 88 // gets the data from an A tag using the data attribute 89 currentLinkVideo = $('a[data-bvideo_id~="' + idCurrent + '"]'); 90 91 // Current video playing 92 localStorage.setItem('bvideo-playlist-' + currentUrl, idCurrent); 93 94 // Setup player to play current video 95 bvideo.attr({ 96 "id": "bvideo", 97 "src": currentLinkVideo.attr("href"), 98 "data-bvideo_id": idCurrent // Which video are we playing 99 }); 100 101 // Change title for video playing 102 $('#bvideo_title').text(currentLinkVideo.text()); 103 104 listVideoHighlight(currentLinkVideo); 105 106 // On finished video, play next 107 bvideo.on('ended', function(e) { 108 109 // Current ID, using attribute since data gets cached and we are updating it 110 id = parseInt($(this).attr("data-bvideo_id")); 111 112 // Icon marked played 113 if (config.playedVideoEmoji != '') 114 currentLinkVideo.parent().prepend(config.playedVideoEmoji); 115 116 // Remove background color 117 if (config.playingBackgroundColor != '') 118 currentLinkVideo.parent().css("background-color", ""); 119 120 // What to play next 121 idNext = (id == videoList.length - 1) ? 0 : id + 1; 122 123 // Getting the source of the a 124 videoNext = $('a[data-bvideo_id~="' + idNext + '"]'); 125 126 $(this).attr({ 127 "src": videoNext.attr("href"), 128 "data-bvideo_id": idNext // Which video are we playing 129 }); 130 131 if (config.autoplay == 1) 132 $(this).attr("autoplay", "autoplay"); 133 134 // Remember next video 135 localStorage.setItem('bvideo-playlist-' + currentUrl, idNext); 136 137 // Change title for video playing 138 $('#bvideo_title').text(videoNext.text()); 139 140 listVideoHighlight(videoNext); 141 }); 142 143 // Sets the source of the video from an ahref 144 $("#bvideo_playlist a[target!='_blank']").on("click", function(e) { 145 146 // We prevent any default action, so we do not go to the URL 147 e.preventDefault(); 148 149 bvideo.attr({ 150 "src": $(this).attr("href"), 151 "data-bvideo_id": $(this).data("bvideo_id") // Which video are we playing 152 }); 153 154 if (config.autoplay == true) 155 bvideo.attr("autoplay", "autoplay"); 156 157 // Scroll to video 158 if ($('#bvideo_title').length) // Location.href = "#bvideo_title"; 159 document.querySelector('#bvideo_title').scrollIntoView({ 160 behavior: 'smooth' 161 }); 162 else // Location.href = "#bvideo"; 163 document.querySelector('#bvideo').scrollIntoView({ 164 behavior: 'smooth' 165 }); 166 167 // Remember last video 168 localStorage.setItem('bvideo-playlist-' + currentUrl, $(this).data("bvideo_id")); 169 170 // Change title for video playing 171 $('#bvideo_title').text($(this).text()); 172 173 listVideoHighlight($(this)); 174 175 }); 176 177 } 178 } 179 180 181 /** 182 * generates the videoList used for the play list 183 * if uses ARRAY JS generates the inner LI HTML 184 * @return Array videoList 185 */ 186 function getVideoList(){ 187 let videoList = []; 188 189 // 1st way to load the playlist comes from a playlist JS array 190 if (typeof directLinkData !== 'undefined' || typeof video_playlist !== 'undefined') { 191 // In case there's a default playlist array 192 if (typeof video_playlist !== 'undefined') { 193 videoList = video_playlist; 194 } 195 196 // Loading playlist from a pCloud array, in a public folder view page use the directLinkData array embedded in the HTML 197 if (typeof directLinkData !== 'undefined') { 198 // Create the list of links 199 let pCloud = directLinkData.content; 200 let path = 'https://filedn.eu/' + directLinkData.code + directLinkData.dirpath; 201 202 for (i = 0; i < pCloud.length; i++) { 203 let temp = []; 204 temp["name"] = pCloud[i].name.slice(0, -4); 205 temp["link"] = path + pCloud[i].urlencodedname; 206 temp["size"] = pCloud[i].size; 207 videoList.push(temp); 72 208 } 73 209 } 74 }//end if first time 75 76 this.play(); 77 }); 78 79 /** 80 * Playlist player for 1 video HTML tag 81 */ 82 83 if ($('#bvideo_playlist').length ) 84 { 85 var video_list = []; 86 var current_url = btoa(window.location.href.split('?')[0].split('#')[0]); 87 88 // 1st way to load the playlist comes from a plylist JS array 89 if (typeof directLinkData !== 'undefined' || typeof video_playlist !== 'undefined') 90 { 91 //in case there's a default playlist array 92 if (typeof video_playlist !== 'undefined'){ 93 video_list = video_playlist; 210 211 // From array videoList to a table 212 let htmlList = ""; 213 for (i = 0; i < videoList.length; i++) { 214 215 htmlList += '<li>'; 216 217 if (isPlayedVideo(videoList[i].link)) 218 htmlList += config.playedVideoEmoji; 219 220 htmlList += '<a data-bvideo_id="' + i + '" href="' + videoList[i].link + '" title="' + videoList[i].name + '">' + videoList[i].name + '</a>'; 221 222 if (videoList[i].size != undefined) { 223 videoSize = (videoList[i].size != undefined ? fileSize(videoList[i].size) : '-') 224 htmlList += '<span style="float:right;"><a target="_blank" title="' + videoSize + ' Download" download href="' + videoList[i].link + '">' + config.downloadEmoji + '</a></span>'; 225 } 226 227 htmlList += '</li>'; 94 228 } 95 229 96 // loading playlist from a pcloud array, in a public folder view page use the directLinkData array embeded in the HTML 97 if (typeof directLinkData !== 'undefined') 98 { 99 //created the list of links 100 var pcloud = directLinkData.content; 101 var path = 'https://filedn.eu/'+directLinkData.code+directLinkData.dirpath; 102 103 for (i=0; i<pcloud.length; i++) 104 { 105 var temp = []; 106 temp["name"] = pcloud[i].name.slice(0, -4); 107 temp["link"] = path+pcloud[i].urlencodedname; 108 temp["size"] = pcloud[i].size; 109 video_list.push(temp); 110 } 111 112 } 113 114 // from array video_list to a table 115 var html_list = ""; 116 for (i=0; i<video_list.length; i++) { 117 118 html_list+='<li>'; 119 120 if (is_played_video(video_list[i].link)) 121 html_list+='✔ '; 122 123 html_list+='<a data-bvideo_id="'+i+'" href="'+video_list[i].link+'" title="'+video_list[i].name+'">'+video_list[i].name+'</a>'; 124 125 if (video_list[i].size!=undefined) 126 { 127 video_size = (video_list[i].size!=undefined?fileSize(video_list[i].size):'-') 128 html_list+='<span style="float:right;"><a target="_blank" title="'+video_size+' Download" download href="'+video_list[i].link+'">💾</a></span>'; 129 } 130 131 html_list+='</li>'; 132 } 133 134 //print html 135 $("#bvideo_playlist").html(html_list); 136 $("#bvideo_playlist").parent().css( { 137 "height":$("video").height()+120, 138 "overflow-y": "auto" 139 }); 140 141 } 142 143 // 2nd way to get a playlist load video_list array from a list instead than JS array 144 else if($('#bvideo_playlist').is('ol, ul')) 145 { 146 var video_list = []; 147 $("#bvideo_playlist li a").each(function(e) { 230 // Print HTML 231 bvideo_playlist.html(htmlList); 232 bvideo_playlist.parent().css({ 233 "height": bvideo.height() + 120, 234 "overflow-y": "auto" 235 }); 236 237 } 238 239 // 2nd way to get a playlist: load videoList array from a list instead than JS array 240 else if (bvideo_playlist.is('ol, ul')) { 241 videoList = []; 242 $("#bvideo_playlist li a").each(function(e) { 148 243 a = $(this); 149 a.attr('data-bvideo_id',e); 150 var temp = []; 151 temp["name"] = this.text; 152 temp["link"] = this.href; 153 temp["size"] = a.data('size')!==undefined?a.data('size'):0; 154 video_list.push(temp); 155 }); 156 } 157 158 // playlist video player 159 if (typeof video_list !== 'undefined') 160 { 161 //start video from parameeter ID.... 162 var start_video = new URLSearchParams(window.location.search).get('start_video'); 163 if (start_video!==null && $.isNumeric(start_video)) 164 id_current = start_video-1;//we start counting from 1 so we do not use the 0. 165 else//init video at last play 166 id_current = localStorage.getItem('bvideo-'+current_url); 244 a.attr('data-bvideo_id', e); 245 246 // Icon marked played 247 if (config.playedVideoEmoji != '' && isPlayedVideo(this.href) ) 248 a.parent().prepend(config.playedVideoEmoji); 249 250 let temp = {}; 251 temp["name"] = this.text; 252 temp["link"] = this.href; 253 temp["size"] = a.data('size') !== undefined ? a.data('size') : 0; 254 videoList.push(temp); 255 }); 167 256 168 id_current = ($.isNumeric(id_current))?id_current:0; 169 id_current = (id_current > video_list.length-1)?0:id_current; 170 171 current_video = $('a[data-bvideo_id~="'+id_current+'"]'); 172 173 //current video playing 174 localStorage.setItem('bvideo-'+current_url, id_current); 175 176 //setup player to play current video 177 $("video").attr({ 178 "id":"bvideo", 179 "src": current_video.attr("href"), 180 "data-bvideo_id":id_current//which video are we playing 181 }); 182 183 //change title for video playing 184 $('#bvideo_title').text(current_video.text()); 185 186 //highlight 187 current_video.parent().css("background-color","#eeeeee"); 188 189 190 //on finished video play next 191 $("video").on('ended', function(e){ 192 193 //current id,using attribute since data gets cached and we are updating it 194 id = parseInt($(this).attr("data-bvideo_id")); 195 196 //we mark this video as played 197 mark_played_video(id); 198 199 //what to play next 200 id_next = (id == video_list.length-1)?0:id+1; 201 202 //getting the source of the a 203 src = $('a[data-bvideo_id~="'+id_next+'"]'); 204 205 $(this).attr({ 206 "src": src.attr("href"), 207 "autoplay": "autoplay", 208 "data-bvideo_id":id_next //which video are we playing 209 }); 210 211 //remember next video 212 localStorage.setItem('bvideo-'+current_url, id_next); 213 214 //change title for video playing 215 $('#bvideo_title').text(src.text()); 216 217 //highlight whats currently playing 218 //$(this).parent().prepend('▶️ '); 219 $('#bvideo_playlist li').css("background-color",""); 220 src.parent().css("background-color","#eeeeee"); 221 }); 222 223 //sets the source of the video from an ahref 224 $("#bvideo_playlist a[target!='_blank']").on("click", function(e) { 225 226 //we prevent any default action, so we do not go to the url 227 e.preventDefault(); 228 229 $("video").attr({ 230 "src": $(this).attr("href"), 231 "autoplay": "autoplay", 232 "data-bvideo_id":$(this).data("bvideo_id") //which video are we playing 233 }); 234 235 //scroll to video 236 if ($('#bvideo_title').length )//location.href = "#bvideo_title"; 237 document.querySelector('#bvideo_title').scrollIntoView({behavior: 'smooth'}); 238 239 else//location.href = "#bvideo"; 240 document.querySelector('#bvideo').scrollIntoView({behavior: 'smooth'}); 241 242 //remember last video 243 localStorage.setItem('bvideo-'+current_url, $(this).data("bvideo_id")); 244 245 //change title for video playing 246 $('#bvideo_title').text($(this).text()); 247 248 //highlight whats currently playing 249 //$(this).parent().prepend('▶️ '); 250 $('#bvideo_playlist li').css("background-color",""); 251 $(this).parent().css("background-color","#eeeeee"); 252 }); 257 } 258 259 return videoList; 260 } 261 262 263 /** 264 * store video time in local and WP 265 * @param video 266 * @param time we can specify the time we store. For instance -1 means video played. 267 */ 268 function storeVideoTime(video, time = false){ 269 //time not set then using video current 270 if (time==false) 271 time = video.currentTime; 272 273 // Save into local storage; if you change the browser, it will not work 274 localStorage.setItem('bvideo-' + btoa(video.src), time); 275 276 // Ajax call 277 $.post(betterVideo_ajax.ajax_url, { 278 _ajax_nonce: betterVideo_ajax.nonce, // Nonce 279 action: "bbpl_store_video_time", // Action 280 time: time, // Time 281 video: video.src, // Video URL 282 }).fail(handleAjaxError); 283 } 284 285 /** 286 * get the video time from a SRC 287 * @param video 288 * @return integer 289 */ 290 function getVideoTime(video){ 291 storedTime = getVideoTimeSrc(video.src); 292 if (storedTime > video.duration) 293 storedTime = 0; 294 295 return storedTime; 296 } 297 298 299 function getVideoTimeSrc(videoSrc){ 300 // First, retrieve from local storage 301 let storedTime = localStorage.getItem('bvideo-' + btoa(videoSrc)); 302 303 // TODO needed improvement here!! 304 // Only Ajax if stored time is empty, saves queries 305 // but we may have different values if used in different browsers 306 if (storedTime == null) { 307 // Ajax call 308 $.post(betterVideo_ajax.ajax_url, { 309 _ajax_nonce: betterVideo_ajax.nonce, // Nonce 310 action: "bbpl_get_video_time", // Action 311 video: videoSrc, // Video URL 312 }, function(data) { // Callback 313 storedTime = data[0]; 314 }).fail(handleAjaxError); 315 } 253 316 254 } 255 256 /** 257 * we mark a video as played, we use the btoa of the current url and we store the btoa of the video src 258 * @param id_video we get the src from the a 259 */ 260 function mark_played_video(id_video) 261 { 262 //getting the source of the a 263 a = $('a[data-bvideo_id~="'+id_video+'"]'); 264 src = a.attr("href"); 265 266 // if it was not in the array before, then store 267 if(is_played_video(src) == false) 268 { 269 var watched_videos; 270 271 watched_videos = localStorage.getItem('bvideo-played-'+ current_url); 272 273 if (watched_videos == null) 274 watched_videos = []; 275 else 276 watched_videos = JSON.parse(watched_videos); 277 278 watched_videos.push(btoa(src)); 279 localStorage.setItem('bvideo-played-'+ current_url, JSON.stringify(watched_videos)); 280 281 //icon marked played 282 a.parent().prepend('✔ '); 283 //remove backgorund color 284 a.parent().css("background-color",""); 285 } 286 } 287 288 /** 289 * tells us if we have seen that video in this url 290 * @param string btoa src of the video 291 * @return boolean 292 */ 293 function is_played_video(src) 294 { 295 watched_videos = localStorage.getItem('bvideo-played-'+ current_url); 296 297 if (watched_videos == null) 298 return false; 299 300 watched_videos = JSON.parse(watched_videos); 301 302 if( watched_videos.indexOf(btoa(src)) != -1 ) 303 return true; 304 else 305 return false; 306 } 307 308 } 317 return storedTime; 318 } 319 320 /** 321 * video is marked as played using -1 322 * @param video 323 */ 324 function markPlayedVideo(video){ 325 326 if (isPlayedVideo(video.src) == false) 327 storeVideoTime(video,-1); 328 } 329 330 /** 331 * Tells us if we have seen that video in this URL 332 * @param string btoa src of the video 333 * @return boolean 334 */ 335 function isPlayedVideo(videoSrc) { 336 return getVideoTimeSrc(videoSrc) == -1; 337 } 338 339 /** 340 * Highlights the item on the playlist to know what is been playing 341 * @return none 342 */ 343 function listVideoHighlight(linkList) { 344 // Highlight what's currently playing 345 if (config.playingEmoji != '') { 346 $("#bvideoCurrentVideoEmoji").remove(); 347 linkList.parent().prepend('<span id="bvideoCurrentVideoEmoji">' + config.playingEmoji + ' </span>'); 348 } 349 if (config.playingBackgroundColor != '') { 350 $(".bvideoCurrentVideoColor").css("background-color", ""); 351 linkList.parent().addClass('bvideoCurrentVideoColor'); 352 linkList.parent().css("background-color", config.playingBackgroundColor); 353 } 354 } 355 356 // AJAX error handling function 357 function handleAjaxError(xhr, textStatus, errorThrown) { 358 console.error("AJAX Error: " + textStatus); 359 console.error("Error Details: " + errorThrown); 360 } 361 309 362 310 363 }) 311 364 312 //from https://stackoverflow.com/a/20463021 313 function fileSize(a,b,c,d,e) 314 { 315 return (b=Math,c=b.log,d=1e3,e=c(a)/c(d)|0,a/b.pow(d,e)).toFixed(e?2:0)+' '+(e?'kMGTPEZY'[--e]+'B':'Bytes') 365 // From https://stackoverflow.com/a/20463021 366 function fileSize(a, b, c, d, e) { 367 return (b = Math, c = b.log, d = 1e3, e = c(a) / c(d) | 0, a / b.pow(d, e)).toFixed(e ? 2 : 0) + ' ' + (e ? 'kMGTPEZY'[--e] + 'B' : 'Bytes') 316 368 }
Note: See TracChangeset
for help on using the changeset viewer.