rtMedia for WordPress, BuddyPress and bbPress - Version 2.0

Version Description

  • Integration into BuddyPress Activities
  • HTML5 Audio Tag Support (with fallback)
  • HTML5 Video Tag Support (with fallback)
Download this release

Release Info

Developer rtcamp
Plugin Icon 128x128 rtMedia for WordPress, BuddyPress and bbPress
Version 2.0
Comparing to
See all releases

Version 2.0

Files changed (52) hide show
  1. includes/bp-media-actions.php +186 -0
  2. includes/bp-media-admin.php +187 -0
  3. includes/bp-media-class-wordpress.php +365 -0
  4. includes/bp-media-filters.php +76 -0
  5. includes/bp-media-functions.php +118 -0
  6. includes/bp-media-loader.php +353 -0
  7. includes/bp-media-screens.php +337 -0
  8. includes/bp-media-shortcodes.php +38 -0
  9. includes/bp-media-template-functions.php +102 -0
  10. includes/css/bp-media-admin.css +39 -0
  11. includes/css/bp-media-style.css +65 -0
  12. includes/img/audio_thumb.png +0 -0
  13. includes/img/bp_media_social.png +0 -0
  14. includes/img/image_thumb.png +0 -0
  15. includes/img/logo_medibp_32.png +0 -0
  16. includes/img/video_thumb.png +0 -0
  17. includes/js/bp-media.js +15 -0
  18. includes/lib/MP4Info.php +257 -0
  19. includes/lib/MP4Info/Box.php +446 -0
  20. includes/lib/MP4Info/Box/Container.php +99 -0
  21. includes/lib/MP4Info/Box/ftyp.php +231 -0
  22. includes/lib/MP4Info/Box/hdlr.php +140 -0
  23. includes/lib/MP4Info/Box/ilst.php +122 -0
  24. includes/lib/MP4Info/Box/ilst_sub.php +148 -0
  25. includes/lib/MP4Info/Box/mdhd.php +146 -0
  26. includes/lib/MP4Info/Box/meta.php +69 -0
  27. includes/lib/MP4Info/Box/mvhd.php +233 -0
  28. includes/lib/MP4Info/Box/stsd.php +139 -0
  29. includes/lib/MP4Info/Box/tkhd.php +215 -0
  30. includes/lib/MP4Info/Box/uuid.php +117 -0
  31. includes/lib/MP4Info/Exception.php +61 -0
  32. includes/lib/MP4Info/Helper.php +72 -0
  33. includes/media-element/background.png +0 -0
  34. includes/media-element/bigplay.png +0 -0
  35. includes/media-element/controls-ted.png +0 -0
  36. includes/media-element/controls-wmp-bg.png +0 -0
  37. includes/media-element/controls-wmp.png +0 -0
  38. includes/media-element/controls.png +0 -0
  39. includes/media-element/flashmediaelement.swf +0 -0
  40. includes/media-element/loading.gif +0 -0
  41. includes/media-element/mediaelement-and-player.js +4262 -0
  42. includes/media-element/mediaelement-and-player.min.js +149 -0
  43. includes/media-element/mediaelement.js +1517 -0
  44. includes/media-element/mediaelement.min.js +59 -0
  45. includes/media-element/mediaelementplayer.css +801 -0
  46. includes/media-element/mediaelementplayer.js +2743 -0
  47. includes/media-element/mediaelementplayer.min.css +1 -0
  48. includes/media-element/mediaelementplayer.min.js +88 -0
  49. includes/media-element/mejs-skins.css +283 -0
  50. includes/media-element/silverlightmediaelement.xap +0 -0
  51. loader.php +56 -0
  52. readme.txt +40 -0
includes/bp-media-actions.php ADDED
@@ -0,0 +1,186 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Handles the uploads and creates respective posts for the upload
4
+ *
5
+ * @since BP Media 2.0
6
+ */
7
+ function bp_media_handle_uploads() {
8
+ global $bp;
9
+ if (isset($_POST['action']) && $_POST['action'] == 'wp_handle_upload') {
10
+ if (isset($_FILES) && is_array($_FILES) && array_key_exists('bp_media_file', $_FILES) && $_FILES['bp_media_file']['name'] != '') {
11
+ $bp_media_entry = new BP_Media_Host_Wordpress();
12
+ try {
13
+ $title = isset($_POST['bp_media_title']) ? ($_POST['bp_media_title'] != "") ? $_POST['bp_media_title'] : pathinfo($_FILES['bp_media_file']['name'], PATHINFO_FILENAME) : pathinfo($_FILES['bp_media_file']['name'], PATHINFO_FILENAME);
14
+ $entry = $bp_media_entry->add_media($title, $_POST['bp_media_description']);
15
+ $bp->{BP_MEDIA_SLUG}->messages['updated'][] = __('Upload Successful', 'bp-media');
16
+ } catch (Exception $e) {
17
+ $bp->{BP_MEDIA_SLUG}->messages['error'][] = $e->getMessage();
18
+ }
19
+ } else {
20
+ $bp->{BP_MEDIA_SLUG}->messages['error'][] = __('You did not specified a file to upload', 'bp-media');
21
+ }
22
+ }
23
+ }
24
+ add_action('bp_init', 'bp_media_handle_uploads');
25
+
26
+ /**
27
+ * Displays the messages that other functions/methods creates according to the BuddyPress' formating
28
+ *
29
+ * @since BP Media 2.0
30
+ */
31
+ function bp_media_show_messages() {
32
+ global $bp;
33
+ if (is_array($bp->{BP_MEDIA_SLUG}->messages)) {
34
+ $types = array('error', 'updated', 'info');
35
+ foreach ($types as $type) {
36
+ if (count($bp->{BP_MEDIA_SLUG}->messages[$type]) > 0) {
37
+ bp_media_show_formatted_error_message($bp->{BP_MEDIA_SLUG}->messages[$type], $type);
38
+ }
39
+ }
40
+ }
41
+ }
42
+ add_action('bp_media_before_content', 'bp_media_show_messages');
43
+
44
+ /**
45
+ * Enqueues all the required scripts and stylesheets for the proper working of BuddyPress Media Component
46
+ *
47
+ * @since BP Media 2.0
48
+ */
49
+ function bp_media_enqueue_scripts_styles() {
50
+ wp_enqueue_script('bp-media-mejs', plugins_url('includes/media-element/mediaelement-and-player.min.js', dirname(__FILE__)));
51
+ wp_enqueue_script('bp-media-default', plugins_url('includes/js/bp-media.js', dirname(__FILE__)));
52
+ wp_enqueue_style('bp-media-mecss', plugins_url('includes/media-element/mediaelementplayer.min.css', dirname(__FILE__)));
53
+ wp_enqueue_style('bp-media-default', plugins_url('includes/css/bp-media-style.css', dirname(__FILE__)));
54
+ }
55
+
56
+ add_action('wp_enqueue_scripts', 'bp_media_enqueue_scripts_styles', 11);
57
+
58
+ /**
59
+ * Deletes associated media entry and its files upon deletion of an activity.
60
+ *
61
+ * @since BP Media 2.0
62
+ */
63
+ function bp_media_delete_activity_handler($activity_id, $user) {
64
+ global $bp_media_count;
65
+ bp_media_init_count(bp_loggedin_user_id());
66
+ $post_id = bp_activity_get_meta($activity_id, 'bp_media_parent_post');
67
+ $type = get_post_meta($post_id, 'bp_media_type', true);
68
+ switch ($type) {
69
+ case 'image':
70
+ $bp_media_count['images'] = intval($bp_media_count['images']) - 1;
71
+ break;
72
+ case 'video':
73
+ $bp_media_count['videos'] = intval($bp_media_count['videos']) - 1;
74
+ break;
75
+ case 'audio':
76
+ $bp_media_count['audio'] = intval($bp_media_count['audio']) - 1;
77
+ break;
78
+ }
79
+ $attachment_id = get_post_meta($post_id, 'bp_media_child_attachment', true);
80
+ wp_delete_attachment($attachment_id, true);
81
+ wp_delete_post($post_id, true);
82
+ bp_update_user_meta(bp_loggedin_user_id(), 'bp_media_count', $bp_media_count);
83
+ }
84
+
85
+ /* Adds bp_media_delete_activity_handler() function to be called on bp_activity_before_action_delete_activity hook */
86
+ add_action('bp_activity_before_action_delete_activity', 'bp_media_delete_activity_handler', 10, 2);
87
+
88
+ /**
89
+ * Called on bp_init by screen functions
90
+ *
91
+ * @uses global $bp, $bp_media_query
92
+ *
93
+ * @since BP Media 2.0
94
+ */
95
+ function bp_media_set_query() {
96
+ global $bp, $bp_media_query;
97
+ switch ($bp->current_action) {
98
+ case BP_MEDIA_IMAGES_SLUG:
99
+ $type = 'image';
100
+ break;
101
+ case BP_MEDIA_AUDIO_SLUG:
102
+ $type = 'audio';
103
+ break;
104
+ case BP_MEDIA_VIDEOS_SLUG:
105
+ $type = 'video';
106
+ break;
107
+ default :
108
+ $type = null;
109
+ }
110
+ if (isset($bp->action_variables) && is_array($bp->action_variables) && isset($bp->action_variables[0]) && $bp->action_variables[0] == 'page' && isset($bp->action_variables[1]) && is_numeric($bp->action_variables[1])) {
111
+ $paged = $bp->action_variables[1];
112
+ } else {
113
+ $paged = 1;
114
+ }
115
+ if ($type) {
116
+ $args = array(
117
+ 'post_type' => 'bp_media',
118
+ 'author' => $bp->displayed_user->id,
119
+ 'meta_key' => 'bp_media_type',
120
+ 'meta_value' => $type,
121
+ 'meta_compare' => 'LIKE',
122
+ 'paged' => $paged
123
+ );
124
+ $bp_media_query = new WP_Query($args);
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Adds a download button on single entry pages of media files.
130
+ *
131
+ * @since BP Media 2.0
132
+ */
133
+ function bp_media_action_download_button() {
134
+ if(!in_array('bp_media_current_entry', $GLOBALS))
135
+ return false;
136
+ global $bp_media_current_entry;
137
+ if($bp_media_current_entry!=NULL)
138
+ echo '<a href="'.$bp_media_current_entry->get_attachment_url().'" class="button item-button bp-secondary-action bp-media-download" title="Download">Download</a>';
139
+ }
140
+ add_action('bp_activity_entry_meta', 'bp_media_action_download_button');
141
+
142
+ /* Should be used with Content Disposition Type for media files set to attachment */
143
+
144
+ /**
145
+ * Shows the media count of a user in the tabs
146
+ *
147
+ * @since BP Media 2.0
148
+ */
149
+ function bp_media_init_count($user = null) {
150
+ global $bp_media_count;
151
+ if (!$user)
152
+ $user = bp_displayed_user_id();
153
+ if ($user < 1) {
154
+ $bp_media_count = null;
155
+ return false;
156
+ }
157
+ $count = bp_get_user_meta($user, 'bp_media_count', true);
158
+ if (!$count) {
159
+ $bp_media_count = array('images' => 0, 'videos' => 0, 'audio' => 0);
160
+ bp_update_user_meta($user, 'bp_media_count', $bp_media_count);
161
+ } else {
162
+ $bp_media_count = $count;
163
+ }
164
+ add_filter('bp_get_displayed_user_nav_' . BP_MEDIA_SLUG, 'bp_media_items_count_filter', 10, 2);
165
+
166
+ if (bp_current_component() == BP_MEDIA_SLUG) {
167
+ add_filter('bp_get_options_nav_' . BP_MEDIA_IMAGES_SLUG, 'bp_media_items_count_filter', 10, 2);
168
+ add_filter('bp_get_options_nav_' . BP_MEDIA_VIDEOS_SLUG, 'bp_media_items_count_filter', 10, 2);
169
+ add_filter('bp_get_options_nav_' . BP_MEDIA_AUDIO_SLUG, 'bp_media_items_count_filter', 10, 2);
170
+ }
171
+ return true;
172
+ }
173
+ add_action('init', 'bp_media_init_count');
174
+
175
+ /**
176
+ * Displays the footer of the BP Media Plugin if enabled through the dashboard options page
177
+ *
178
+ * @since BP Media 2.0
179
+ */
180
+ function bp_media_footer() { ?>
181
+ <div id="bp-media-footer"><p>We &hearts; <a href="http://rtcamp.com/buddypress-media/">MediaBP</a></p></div>
182
+ <?php
183
+ }
184
+ if(get_option('bp_media_remove_linkback')!='1')
185
+ add_action('bp_footer','bp_media_footer');
186
+ ?>
includes/bp-media-admin.php ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Add the BuddyPress Media Component's options menu in the BuddyPress' options subnavigation.
4
+ *
5
+ * @since BP Media 2.0
6
+ */
7
+ function bp_media_add_admin_menu() {
8
+ global $bp;
9
+ if (!is_super_admin())
10
+ return false;
11
+
12
+ $page = add_submenu_page('bp-general-settings', __('BuddyPress Media Component Settings', 'bp-media'), __('MediaBP', 'bp-media'), 'manage_options', 'bp-media-settings', 'bp_media_admin_menu'
13
+ );
14
+ add_action('admin_print_styles-' . $page, 'bp_media_admin_enqueue');
15
+ }
16
+ add_action(bp_core_admin_hook(), 'bp_media_add_admin_menu');
17
+
18
+ /**
19
+ * Displays and updates the options menu of BuddyPress Media Component
20
+ *
21
+ * @since BP Media 2.0
22
+ */
23
+ function bp_media_admin_menu() {
24
+ $bp_media_errors=array();
25
+ $bp_media_messages=array();
26
+
27
+ if(array_key_exists('submit', $_POST)){
28
+ check_admin_referer('bp_media_update_options');
29
+ if(array_key_exists('refresh_media_count', $_POST)){
30
+ if(!bp_media_update_count())
31
+ $bp_media_errors[]="Recounting Failed";
32
+ else
33
+ $bp_media_messages[]="Recounting of media files done successfully";
34
+ }
35
+ if(array_key_exists('remove_linkback', $_POST)&&$_POST['remove_linkback']=='1'){
36
+ update_option('bp_media_remove_linkback', '1');
37
+ }
38
+ else{
39
+ update_option('bp_media_remove_linkback', '0');
40
+ }
41
+ }
42
+ ?>
43
+ <div class="metabox-fixed metabox-holder alignright">
44
+ <?php bp_media_default_admin_sidebar(); ?>
45
+ </div>
46
+ <div class="wrap bp-media-admin">
47
+ <div id="icon-bp-media" class="icon32"><br/></div>
48
+ <h2>BuddyPress Media Component Settings</h2>
49
+ <?php if(count($bp_media_errors)) { ?>
50
+ <div class="error"><p><?php foreach($bp_media_errors as $error) echo $error.'<br/>'; ?></p></div>
51
+ <?php } if(count($bp_media_messages)){?>
52
+ <div class="updated"><p><?php foreach($bp_media_messages as $message) echo $message.'<br/>'; ?></p></div>
53
+ <?php }?>
54
+ <form method="post">
55
+ <?php wp_nonce_field( 'bp_media_update_options' ); ?>
56
+ <table class="form-table ">
57
+ <tbody>
58
+ <tr valign="top">
59
+ <th scope="row"><label for="refresh_media_count">Re-Count Media Entries</label></th>
60
+ <td> <fieldset><legend class="screen-reader-text"><span>Re-Count Media Entries</span></legend><label for="refresh_media_count">
61
+ <input name="refresh_media_count" type="checkbox" id="refresh_media_count" value="1">
62
+ Check for Re-Count</label>
63
+ </fieldset></td>
64
+ </tr>
65
+ <tr valign="top">
66
+ <th scope="row"><label for="remove_linkback">Remove Linkback</label></th>
67
+ <td>
68
+ <fieldset>
69
+ <legend class="screen-reader-text"><span>Remove Linkback</span></legend>
70
+ <label for="remove_linkback"><input name="remove_linkback" type="checkbox" id="remove_linkback" value="1" <?php if(get_option('bp_media_remove_linkback')=='1') echo 'checked="checked"' ?>> Removes the link to MediaBP from footer</label>
71
+ </fieldset>
72
+ </td>
73
+ </tr>
74
+ </tbody>
75
+ </table>
76
+ <p class="submit"><input type="submit" name="submit" id="submit" class="button-primary" value="Save Changes"></p></form>
77
+ </div>
78
+ <?php
79
+ }
80
+
81
+ /**
82
+ * Display feeds from a specified Feed URL
83
+ *
84
+ * @param string $feed_url The Feed URL.
85
+ *
86
+ * @since BP Media 2.0
87
+ */
88
+ function bp_media_get_feeds($feed_url = 'http://rtcamp.com/blog/category/buddypress-media/feed/') {
89
+ // Get RSS Feed(s)
90
+ require_once( ABSPATH . WPINC . '/feed.php' );
91
+ $maxitems = 0;
92
+ // Get a SimplePie feed object from the specified feed source.
93
+ $rss = fetch_feed($feed_url);
94
+ if (!is_wp_error($rss)) { // Checks that the object is created correctly
95
+ // Figure out how many total items there are, but limit it to 5.
96
+ $maxitems = $rss->get_item_quantity(5);
97
+
98
+ // Build an array of all the items, starting with element 0 (first element).
99
+ $rss_items = $rss->get_items(0, $maxitems);
100
+ }
101
+ ?>
102
+ <ul><?php
103
+ if ($maxitems == 0) {
104
+ echo '<li>' . __('No items', 'bp-media') . '.</li>';
105
+ } else {
106
+ // Loop through each feed item and display each item as a hyperlink.
107
+ foreach ($rss_items as $item) {
108
+ ?>
109
+ <li>
110
+ <a href='<?php echo $item->get_permalink(); ?>' title='<?php echo __('Posted ', 'bp-media') . $item->get_date('j F Y | g:i a'); ?>'><?php echo $item->get_title(); ?></a>
111
+ </li><?php
112
+ }
113
+ }
114
+ ?>
115
+ </ul><?php
116
+ }
117
+
118
+ /**
119
+ * Default BuddyPress Media Component admin sidebar with metabox styling
120
+ *
121
+ * @since BP Media 2.0
122
+ */
123
+ function bp_media_default_admin_sidebar() {
124
+ ?>
125
+ <div class="postbox" id="social">
126
+ <div title="<?php _e('Click to toggle', 'bp-media'); ?>" class="handlediv"><br /></div>
127
+ <h3 class="hndle"><span><?php _e('Getting Social is Good', 'bp-media'); ?></span></h3>
128
+ <div class="inside" style="text-align:center;">
129
+ <a href="<?php printf('%s', 'http://www.facebook.com/rtCamp.solutions/'); ?>" target="_blank" title="<?php _e('Become a fan on Facebook', 'bp-media'); ?>" class="bp-media-facebook bp-media-social"><?php _e('Facebook', 'bp-media'); ?></a>
130
+ <a href="<?php printf('%s', 'https://twitter.com/rtcamp/'); ?>" target="_blank" title="<?php _e('Follow us on Twitter', 'bp-media'); ?>" class="bp-media-twitter bp-media-social"><?php _e('Twitter', 'bp-media'); ?></a>
131
+ <a href="<?php printf('%s', 'http://feeds.feedburner.com/rtcamp/'); ?>" target="_blank" title="<?php _e('Subscribe to our feeds', 'bp-media'); ?>" class="bp-media-rss bp-media-social"><?php _e('RSS Feed', 'bp-media'); ?></a>
132
+ </div>
133
+ </div>
134
+
135
+ <div class="postbox" id="donations">
136
+ <div title="<?php _e('Click to toggle', 'bp-media'); ?>" class="handlediv"><br /></div>
137
+ <h3 class="hndle"><span><?php _e('Promote, Donate, Share', 'bp-media'); ?>...</span></h3>
138
+ <div class="inside">
139
+ <p><?php printf(__('Buy coffee/beer for team behind <a href="%s" title="BuddyPress Media Component">BuddyPress Media Component</a>.', 'bp-media'), 'http://rtcamp.com/buddypress-media/'); ?></p>
140
+ <div class="bp-media-paypal" style="text-align:center">
141
+ <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
142
+ <input type="hidden" name="cmd" value="_donations" />
143
+ <input type="hidden" name="business" value="paypal@rtcamp.com" />
144
+ <input type="hidden" name="lc" value="US" />
145
+ <input type="hidden" name="item_name" value="BuddyPress Media Component" />
146
+ <input type="hidden" name="no_note" value="0" />
147
+ <input type="hidden" name="currency_code" value="USD" />
148
+ <input type="hidden" name="bn" value="PP-DonationsBF:btn_donateCC_LG.gif:NonHostedGuest" />
149
+ <input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" name="submit" alt="PayPal - The safer, easier way to pay online!" />
150
+ <img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
151
+ </form>
152
+ </div>
153
+ <div class="rt-social-share" style="text-align:center; width: 135px; margin: 2px auto">
154
+ <div class="rt-facebook" style="float:left; margin-right:5px;">
155
+ <a style=" text-align:center;" name="fb_share" type="box_count" share_url="http://rtcamp.com/buddypress-media/"></a>
156
+ </div>
157
+ <div class="rt-twitter" style="">
158
+ <a href="<?php printf('%s', 'http://twitter.com/share'); ?>" class="twitter-share-button" data-text="I &hearts; #mediabp" data-url="http://rtcamp.com/buddypress-media/" data-count="vertical" data-via="mediabp"><?php _e('Tweet', 'bp-media'); ?></a>
159
+ <script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>
160
+ </div>
161
+ <div class="clear"></div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+
166
+ <div class="postbox" id="support">
167
+ <div title="<?php _e('Click to toggle', 'bp-media'); ?>" class="handlediv"><br /></div>
168
+ <h3 class="hndle"><span><?php _e('Free Support', 'bp-media'); ?></span></h3>
169
+ <div class="inside"><p><?php printf(__(' If you are facing any problems while using BuddyPress Media Component, or have good ideas for improvements, please discuss the same in our <a href="%s" target="_blank" title="Click here for BuddyPress Media Component Free Support">Support forums</a>', 'bp-media'), 'http://rtcamp.com/support/forum/buddypress-media/'); ?>.</p></div>
170
+ </div>
171
+
172
+ <div class="postbox" id="latest_news">
173
+ <div title="<?php _e('Click to toggle', 'bp-media'); ?>" class="handlediv"><br /></div>
174
+ <h3 class="hndle"><span><?php _e('Latest News', 'bp-media'); ?></span></h3>
175
+ <div class="inside"><?php bp_media_get_feeds(); ?></div>
176
+ </div><?php
177
+ }
178
+
179
+ /**
180
+ * Enqueues the scripts and stylesheets needed for the BuddyPress Media Component's options page
181
+ */
182
+ function bp_media_admin_enqueue() {
183
+ wp_enqueue_style('bp-media-admin-style', plugins_url('includes/css/bp-media-admin.css', dirname(__FILE__)));
184
+ wp_enqueue_script('rt-fb-share', ('http://static.ak.fbcdn.net/connect.php/js/FB.Share'), '', '', true);
185
+ }
186
+ add_action('admin_enqueue_scripts', 'bp_media_admin_enqueue');
187
+ ?>
includes/bp-media-class-wordpress.php ADDED
@@ -0,0 +1,365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ class BP_Media_Host_Wordpress {
3
+
4
+ /**
5
+ * Private variables not to be accessible outside this class' member functions
6
+ */
7
+ private $id, //id of the entry
8
+ $name, //Name of the entry
9
+ $description, //Description of the entry
10
+ $url, //URL of the entry
11
+ $type, //Type of the entry (Video, Image or Audio)
12
+ $owner, //Owner of the entry
13
+ $attachment_id; //The attachment ID of the media file
14
+
15
+ /**
16
+ * Constructs a new BP_Media_Host_Wordpress element
17
+ *
18
+ * @param mixed $media_id optional Media ID of the element to be initialized if not defined, returns an empty element.
19
+ *
20
+ * @since BP Media 2.0
21
+ */
22
+ function __construct($media_id = '') {
23
+ if (!$media_id == '') {
24
+ $this->init($media_id);
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Initializes the object with the variables from the post
30
+ *
31
+ * @param mixed $media_id Media ID of the element to be initialized. Can be the ID or the object of the Media
32
+ *
33
+ * @since BP Media 2.0
34
+ */
35
+ function init($media_id = '') {
36
+ if (is_object($media_id)) {
37
+ $media = $media_id;
38
+ } else {
39
+ $media = &get_post($media_id);
40
+ }
41
+ if (empty($media->ID))
42
+ throw new Exception(__('Sorry, the requested entry does not exist.', 'bp-media'));
43
+ $this->id = $media->ID;
44
+ $this->description = $media->post_content;
45
+ $this->name = $media->post_title;
46
+ $this->owner = $media->post_author;
47
+ $this->type = get_post_meta($media->ID, 'bp_media_type', true);
48
+ switch ($this->type) {
49
+ case 'video' :
50
+ $this->url = trailingslashit(bp_core_get_user_domain($this->owner) . BP_MEDIA_VIDEOS_SLUG . '/' . BP_MEDIA_VIDEOS_ENTRY_SLUG . '/' . $this->id);
51
+ break;
52
+ case 'audio' :
53
+ $this->url = trailingslashit(bp_core_get_user_domain($this->owner) . BP_MEDIA_AUDIO_SLUG . '/' . BP_MEDIA_AUDIO_ENTRY_SLUG . '/' . $this->id);
54
+ break;
55
+ case 'image' :
56
+ $this->url = trailingslashit(bp_core_get_user_domain($this->owner) . BP_MEDIA_IMAGES_SLUG . '/' . BP_MEDIA_IMAGES_ENTRY_SLUG . '/' . $this->id);
57
+ break;
58
+ default :
59
+ return false;
60
+ }
61
+ $this->attachment_id = get_post_meta($this->id, 'bp_media_child_attachment', true);
62
+ }
63
+
64
+ /**
65
+ * Handles the uploaded media file and creates attachment post for the file.
66
+ *
67
+ * @since BP Media 2.0
68
+ */
69
+ function add_media($name, $description) {
70
+ global $bp, $wpdb, $bp_media_count;
71
+ include_once(ABSPATH . 'wp-admin/includes/file.php');
72
+ include_once(ABSPATH . 'wp-admin/includes/image.php');
73
+ //media_handle_upload('async-upload', $_REQUEST['post_id']);
74
+ $postarr = array(
75
+ 'post_status' => 'draft',
76
+ 'post_type' => 'bp_media',
77
+ 'post_content' => $description,
78
+ 'post_title' => $name
79
+ );
80
+ $post_id = wp_insert_post($postarr);
81
+ $file = wp_handle_upload($_FILES['bp_media_file']);
82
+ if (isset($file['error']) || $file === null) {
83
+ wp_delete_post($post_id, true);
84
+ throw new Exception(__('Error Uploading File', 'bp-media'));
85
+ }
86
+ $attachment = array();
87
+ $url = $file['url'];
88
+ $type = $file['type'];
89
+ $file = $file['file'];
90
+ $title = $name;
91
+ $content = $description;
92
+ $attachment = array(
93
+ 'post_mime_type' => $type,
94
+ 'guid' => $url,
95
+ 'post_title' => $title,
96
+ 'post_content' => $content,
97
+ 'post_parent' => $post_id,
98
+ );
99
+ bp_media_init_count(bp_loggedin_user_id());
100
+ switch ($type) {
101
+ case 'video/mp4' :
102
+ $type = 'video';
103
+ include_once(trailingslashit(BP_MEDIA_PLUGIN_DIR) . 'includes/lib/MP4Info.php');
104
+ try {
105
+ $vid_info = MP4Info::getInfo($file);
106
+ } catch (MP4Info_Exception $e) {
107
+ wp_delete_post($post_id, true);
108
+ unlink($file);
109
+ $activity_content = false;
110
+ throw new Exception(__('MP4 file you have uploaded is currupt.', 'bp-media'));
111
+ } catch (Exception $e) {
112
+ wp_delete_post($post_id, true);
113
+ unlink($file);
114
+ $activity_content = false;
115
+ throw new Exception(__('MP4 file you have uploaded is currupt.', 'bp-media'));
116
+ }
117
+ if (is_object($vid_info)) {
118
+ if (isset($vid_info->hasVideo) && $vid_info->hasVideo && isset($vid_info->video)) {
119
+ if (!(isset($vid_info->video->codecStr) && $vid_info->video->codecStr == 'H.264')) {
120
+ wp_delete_post($post_id, true);
121
+ unlink($file);
122
+ $activity_content = false;
123
+ throw new Exception(__('The MP4 file you have uploaded is using an unsupported video codec. Supported video codec is H.264.', 'bp-media'));
124
+ }
125
+ } else {
126
+ wp_delete_post($post_id, true);
127
+ unlink($file);
128
+ $activity_content = false;
129
+ throw new Exception(__('The MP4 file you have uploaded contains no video.', 'bp-media'));
130
+ }
131
+ } else {
132
+ wp_delete_post($post_id, true);
133
+ unlink($file);
134
+ $activity_content = false;
135
+ throw new Exception(__('The MP4 file you have uploaded is not a video file.', 'bp-media'));
136
+ }
137
+ $bp_media_count['videos'] = intval($bp_media_count['videos']) + 1;
138
+ break;
139
+ case 'audio/mpeg' :
140
+ $type = 'audio';
141
+ $bp_media_count['audio'] = intval($bp_media_count['audio']) + 1;
142
+ break;
143
+ case 'image/gif' :
144
+ case 'image/jpeg' :
145
+ case 'image/png' :
146
+ $type = 'image';
147
+ $bp_media_count['images'] = intval($bp_media_count['images']) + 1;
148
+ break;
149
+ default : unlink($file);
150
+ wp_delete_post($post_id, true);
151
+ unlink($file);
152
+ $activity_content = false;
153
+ throw new Exception(__('Media File you have tried to upload is not supported. Supported media files are .jpg, .png, .gif, .mp3 and .mp4.', 'bp-media'));
154
+ }
155
+ $attachment_id = wp_insert_attachment($attachment, $file, $post_id);
156
+ if (!is_wp_error($attachment_id)) {
157
+ wp_update_attachment_metadata($attachment_id, wp_generate_attachment_metadata($attachment_id, $file));
158
+ } else {
159
+ wp_delete_post($post_id, true);
160
+ unlink($file);
161
+ throw new Exception(__('Error creating activity for the media file, please try again', 'bp-media'));
162
+ }
163
+ $postarr['ID'] = $post_id;
164
+ $postarr['post_mime_type'] = $type;
165
+ $postarr['post_status'] = 'publish';
166
+ wp_insert_post($postarr);
167
+ $activity_content = '[bp_media_content id="' . $post_id . '"]';
168
+ $activity_id = bp_media_record_activity(array(
169
+ 'action' => '[bp_media_action id="' . $post_id . '"]',
170
+ 'content' => $activity_content,
171
+ 'primary_link' => '[bp_media_url id="' . $post_id . '"]',
172
+ 'type' => 'media_upload'
173
+ ));
174
+ bp_activity_update_meta($activity_id, 'bp_media_parent_post', $post_id);
175
+ update_post_meta($post_id, 'bp_media_child_activity', $activity_id);
176
+ update_post_meta($post_id, 'bp_media_child_attachment', $attachment_id);
177
+ update_post_meta($post_id, 'bp_media_type', $type);
178
+ update_post_meta($post_id, 'bp_media_hosting', 'wordpress');
179
+ $this->id = $post_id;
180
+ $this->name = $name;
181
+ $this->description = $description;
182
+ $this->owner = bp_loggedin_user_id();
183
+ $this->type = $type;
184
+ $this->url = $url;
185
+ bp_update_user_meta(bp_loggedin_user_id(), 'bp_media_count', $bp_media_count);
186
+ }
187
+
188
+ function get_media_activity_content() {
189
+ if (!bp_is_activity_component()) {
190
+ return false;
191
+ }
192
+ global $bp_media_counter, $bp_media_default_excerpts;
193
+ $attachment_id = get_post_meta($this->id, 'bp_media_child_attachment', true);
194
+ $activity_content = '<div class="bp_media_title"><a href="' . $this->url . '" title="' . $this->description . '">' . wp_html_excerpt($this->name, $bp_media_default_excerpts['activity_entry_title']) . '</a></div>';
195
+ $activity_content .='<div class="bp_media_content">';
196
+ switch ($this->type) {
197
+ case 'video' :
198
+ $activity_content.='<video src="' . wp_get_attachment_url($attachment_id) . '" width="320" height="240" type="video/mp4" id="bp_media_video_' . $this->id . '_' . $bp_media_counter . '" controls="controls" preload="none"></video></span><script>bp_media_create_element("bp_media_video_' . $this->id . '_' . $bp_media_counter . '");</script>';
199
+ break;
200
+ case 'audio' :
201
+ $activity_content.='<audio src="' . wp_get_attachment_url($attachment_id) . '" width="320" type="audio/mp3" id="bp_media_audio_' . $this->id . '_' . $bp_media_counter . '" controls="controls" preload="none" ></audio></span><script>bp_media_create_element("bp_media_audio_' . $this->id . '_' . $bp_media_counter . '");</script>';
202
+ $type = 'audio';
203
+ break;
204
+ case 'image' :
205
+ $image_array = image_downsize($attachment_id, 'bp_media_activity_image');
206
+ $activity_content.='<a href="' . $this->url . '" title="' . $this->name . '"><img src="' . $image_array[0] . '" id="bp_media_image_' . $this->id . '_' . $bp_media_counter++ . '" alt="' . $this->name . '" /></a>';
207
+ $type = 'image';
208
+ break;
209
+ default :
210
+ return false;
211
+ }
212
+ $activity_content .= '</div>';
213
+ $activity_content .= '<div class="bp_media_description">' . wp_html_excerpt($this->description, $bp_media_default_excerpts['activity_entry_description']) . '</div>';
214
+ return $activity_content;
215
+ }
216
+
217
+ function get_media_activity_url() {
218
+ if (!bp_is_activity_component())
219
+ return false;
220
+ $activity_url = $this->url;
221
+ return $activity_url;
222
+ }
223
+
224
+ function get_media_activity_action() {
225
+ if (!bp_is_activity_component())
226
+ return false;
227
+ $activity_action = sprintf(__("%s uploaded a media."), bp_core_get_userlink($this->owner));
228
+ return $activity_action;
229
+ }
230
+
231
+ function get_media_single_content() {
232
+ global $bp_media_default_sizes, $bp_media_default_excerpts;
233
+
234
+ $content = '<div class="bp_media_title">' . wp_html_excerpt($this->name, $bp_media_default_excerpts['single_entry_title']) . '</div><div class="bp_media_content">';
235
+ switch ($this->type) {
236
+ case 'video' :
237
+ $content.='<video src="' . wp_get_attachment_url($this->attachment_id) . '" width="' . $bp_media_default_sizes['single_video']['width'] . '" height="' . ($bp_media_default_sizes['single_video']['height'] == 0 ? 'auto' : $bp_media_default_sizes['single_video']['height']) . '" type="video/mp4" id="bp_media_video_' . $this->id . '" controls="controls" preload="none"></video><script>bp_media_create_element("bp_media_video_' . $this->id . '");</script>';
238
+ break;
239
+ case 'audio' :
240
+ $content.='<audio src="' . wp_get_attachment_url($this->attachment_id) . '" width="' . $bp_media_default_sizes['single_audio']['width'] . '" type="audio/mp3" id="bp_media_audio_' . $this->id . '" controls="controls" preload="none" ></audio><script>bp_media_create_element("bp_media_audio_' . $this->id . '");</script>';
241
+ $type = 'audio';
242
+ break;
243
+ case 'image' :
244
+ $image_array = image_downsize($this->attachment_id, 'bp_media_single_image');
245
+ $content.='<img src="' . $image_array[0] . '" id="bp_media_image_' . $this->id . '" />';
246
+ $type = 'image';
247
+ break;
248
+ default :
249
+ return false;
250
+ }
251
+ $content .= '</div>';
252
+ $content .= '<div class="bp_media_description">' . wp_html_excerpt($this->description, $bp_media_default_excerpts['single_entry_description']) . '</div>';
253
+ return $content;
254
+ }
255
+
256
+ function get_media_gallery_content() {
257
+ $attachment = get_post_meta($this->id, 'bp_media_child_attachment', true);
258
+ switch ($this->type) {
259
+ case 'video' :
260
+ ?>
261
+ <li>
262
+ <a href="<?php echo $this->url ?>" title="<?php echo $this->description ?>">
263
+ <img src="<?php echo plugins_url('img/video_thumb.png', __FILE__) ?>" />
264
+ </a>
265
+ <h3 title="<?php echo $this->name ?>"><a href="<?php echo $this->url ?>" title="<?php echo $this->description ?>"><?php echo $this->name ?></a></h3>
266
+ </li>
267
+ <?php
268
+ break;
269
+ case 'audio' :
270
+ ?>
271
+ <li>
272
+ <a href="<?php echo $this->url ?>" title="<?php echo $this->description ?>">
273
+ <img src="<?php echo plugins_url('img/audio_thumb.png', __FILE__) ?>" />
274
+ </a>
275
+ <h3 title="<?php echo $this->name ?>"><a href="<?php echo $this->url ?>" title="<?php echo $this->description ?>"><?php echo $this->name ?></a></h3>
276
+ </li>
277
+ <?php
278
+ break;
279
+ case 'image' :
280
+ $medium_array = image_downsize($attachment, 'thumbnail');
281
+ $medium_path = $medium_array[0];
282
+ ?>
283
+ <li>
284
+ <a href="<?php echo $this->url ?>" title="<?php echo $this->description ?>">
285
+ <img src="<?php echo $medium_path ?>" />
286
+ </a>
287
+ <h3 title="<?php echo $this->name ?>"><a href="<?php echo $this->url ?>" title="<?php echo $this->description ?>"><?php echo $this->name ?></a></h3>
288
+ </li>
289
+ <?php
290
+ break;
291
+ default :
292
+ return false;
293
+ }
294
+ }
295
+
296
+ function show_comment_form() {
297
+ $activity_id = get_post_meta($this->id, 'bp_media_child_activity', true);
298
+ if (bp_has_activities(array(
299
+ 'display_comments' => 'stream',
300
+ 'include' => $activity_id,
301
+ 'max' => 1
302
+ ))) :
303
+ while (bp_activities()) : bp_the_activity();
304
+ do_action('bp_before_activity_entry');
305
+ ?>
306
+ <div class="activity">
307
+ <ul id="activity-stream" class="activity-list item-list">
308
+ <li class="activity activity_update" id="activity-<?php echo $activity_id; ?>">
309
+ <div class="activity-content">
310
+ <?php do_action('bp_activity_entry_content'); ?>
311
+ <?php if (is_user_logged_in()) : ?>
312
+ <div class="activity-meta no-ajax">
313
+ <?php if (bp_activity_can_comment()) : ?>
314
+ <a href="<?php bp_get_activity_comment_link(); ?>" class="button acomment-reply bp-primary-action" id="acomment-comment-<?php bp_activity_id(); ?>"><?php printf(__('Comment <span>%s</span>', 'buddypress'), bp_activity_get_comment_count()); ?></a>
315
+ <?php endif; ?>
316
+ <?php if (bp_activity_can_favorite()) : ?>
317
+ <?php if (!bp_get_activity_is_favorite()) : ?>
318
+ <a href="<?php bp_activity_favorite_link(); ?>" class="button fav bp-secondary-action" title="<?php esc_attr_e('Mark as Favorite', 'buddypress'); ?>"><?php _e('Favorite', 'buddypress') ?></a>
319
+ <?php else : ?>
320
+ <a href="<?php bp_activity_unfavorite_link(); ?>" class="button unfav bp-secondary-action" title="<?php esc_attr_e('Remove Favorite', 'buddypress'); ?>"><?php _e('Remove Favorite', 'buddypress') ?></a>
321
+ <?php endif; ?>
322
+ <?php endif; ?>
323
+ <?php if (bp_activity_user_can_delete()) bp_activity_delete_link(); ?>
324
+ <?php do_action('bp_activity_entry_meta'); ?>
325
+ </div>
326
+ <?php endif; ?>
327
+ </div>
328
+ <?php do_action('bp_before_activity_entry_comments'); ?>
329
+ <?php if (( is_user_logged_in() && bp_activity_can_comment() ) || bp_activity_get_comment_count()) : ?>
330
+ <div class="activity-comments">
331
+ <?php bp_activity_comments(); ?>
332
+ <?php if (is_user_logged_in()) : ?>
333
+ <form action="<?php bp_activity_comment_form_action(); ?>" method="post" id="ac-form-<?php bp_activity_id(); ?>" class="ac-form"<?php bp_activity_comment_form_nojs_display(); ?>>
334
+ <div class="ac-reply-avatar"><?php bp_loggedin_user_avatar('width=' . BP_AVATAR_THUMB_WIDTH . '&height=' . BP_AVATAR_THUMB_HEIGHT); ?></div>
335
+ <div class="ac-reply-content">
336
+ <div class="ac-textarea">
337
+ <textarea id="ac-input-<?php bp_activity_id(); ?>" class="ac-input" name="ac_input_<?php bp_activity_id(); ?>"></textarea>
338
+ </div>
339
+ <input type="submit" name="ac_form_submit" value="<?php _e('Post', 'buddypress'); ?>" /> &nbsp; <?php _e('or press esc to cancel.', 'buddypress'); ?>
340
+ <input type="hidden" name="comment_form_id" value="<?php bp_activity_id(); ?>" />
341
+ </div>
342
+ <?php do_action('bp_activity_entry_comments'); ?>
343
+ <?php wp_nonce_field('new_activity_comment', '_wpnonce_new_activity_comment'); ?>
344
+ </form>
345
+ <?php endif; ?>
346
+ </div>
347
+ <?php endif; ?>
348
+ <?php do_action('bp_after_activity_entry_comments'); ?>
349
+ </li>
350
+ </ul>
351
+ </div>
352
+ <?php
353
+ endwhile;
354
+ endif;
355
+ }
356
+
357
+ function get_url() {
358
+ return $this->url;
359
+ }
360
+
361
+ function get_attachment_url(){
362
+ return wp_get_attachment_url($this->attachment_id);
363
+ }
364
+ }
365
+ ?>
includes/bp-media-filters.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function bp_media_activity_permalink_filter($link, $activity_obj) {
3
+ if ('media_upload' == $activity_obj->type) {
4
+ add_shortcode('bp_media_url', 'bp_media_shortcode_url');
5
+ $link = do_shortcode($activity_obj->primary_link);
6
+ remove_shortcode('bp_media_url');
7
+ }
8
+ if ('activity_comment' == $activity_obj->type) {
9
+ $parent = bp_activity_get_meta($activity_obj->item_id, 'bp_media_parent_post');
10
+ if ($parent) {
11
+ $parent = new BP_Media_Host_Wordpress($parent);
12
+ $link = $parent->get_url();
13
+ }
14
+ }
15
+ return $link;
16
+ }
17
+ add_filter('bp_activity_get_permalink', 'bp_media_activity_permalink_filter', 10, 2);
18
+
19
+ function bp_media_activity_action_filter($activity_action, $activity_obj) {
20
+ if ('media_upload' == $activity_obj->type) {
21
+ add_shortcode('bp_media_action', 'bp_media_shortcode_action');
22
+ $activity_action = do_shortcode($activity_action);
23
+ remove_shortcode('bp_media_action');
24
+ }
25
+ return $activity_action;
26
+ }
27
+ add_filter('bp_get_activity_action', 'bp_media_activity_action_filter', 10, 2);
28
+
29
+ function bp_media_activity_content_filter($activity_content, $activity_obj) {
30
+ if ('media_upload' == $activity_obj->type) {
31
+ add_shortcode('bp_media_content', 'bp_media_shortcode_content');
32
+ $activity_content = do_shortcode($activity_content);
33
+ remove_shortcode('bp_media_content');
34
+ }
35
+ return $activity_content;
36
+ }
37
+ add_filter('bp_get_activity_content_body', 'bp_media_activity_content_filter', 10, 2);
38
+
39
+ function bp_media_activity_parent_content_filter($content) {
40
+ add_shortcode('bp_media_action', 'bp_media_shortcode_action');
41
+ add_shortcode('bp_media_content', 'bp_media_shortcode_content');
42
+ $content=do_shortcode($content);
43
+ remove_shortcode('bp_media_action');
44
+ remove_shortcode('bp_media_content');
45
+ return $content;
46
+ }
47
+
48
+ add_filter('bp_get_activity_parent_content', 'bp_media_activity_parent_content_filter');
49
+
50
+ function bp_media_delete_button_handler($link) {
51
+ if(bp_current_component()=='media')
52
+ $link=str_replace('class="button', 'class="button delete-activity-single"', $link);
53
+ return $link;
54
+ }
55
+ add_filter('bp_get_activity_delete_link','bp_media_delete_button_handler');
56
+
57
+ function bp_media_items_count_filter ($title,$nav_item) {
58
+ global $bp_media_count;
59
+ switch($nav_item['slug']){
60
+ case BP_MEDIA_SLUG :
61
+ $count= intval($bp_media_count['images'])+intval($bp_media_count['videos'])+intval($bp_media_count['audio']);
62
+ break;
63
+ case BP_MEDIA_IMAGES_SLUG:
64
+ $count= intval($bp_media_count['images']);
65
+ break;
66
+ case BP_MEDIA_VIDEOS_SLUG:
67
+ $count= intval($bp_media_count['videos']);
68
+ break;
69
+ case BP_MEDIA_AUDIO_SLUG:
70
+ $count= intval($bp_media_count['audio']);
71
+ break;
72
+ }
73
+ $count_html=' <span>'. $count.'</span>';
74
+ return str_replace('</a>', $count_html.'</a>', $title);
75
+ }
76
+ ?>
includes/bp-media-functions.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function bp_media_record_activity($args = '') {
3
+ global $bp;
4
+ if (!function_exists('bp_activity_add'))
5
+ return false;
6
+ $defaults = array(
7
+ 'id' => false, // Pass an existing activity ID to update an existing entry.
8
+ 'action' => '', // The activity action - e.g. "Jon Doe posted an update"
9
+ 'content' => '', // Optional: The content of the activity item e.g. "BuddyPress is awesome guys!"
10
+ 'component' => BP_MEDIA_SLUG, // The name/ID of the component e.g. groups, profile, mycomponent
11
+ 'type' => false, // The activity type e.g. activity_update, profile_updated
12
+ 'primary_link' => '', // Optional: The primary URL for this item in RSS feeds (defaults to activity permalink)
13
+ 'user_id' => $bp->loggedin_user->id, // Optional: The user to record the activity for, can be false if this activity is not for a user.
14
+ 'item_id' => false, // Optional: The ID of the specific item being recorded, e.g. a blog_id
15
+ 'secondary_item_id' => false, // Optional: A second ID used to further filter e.g. a comment_id
16
+ 'recorded_time' => bp_core_current_time(), // The GMT time that this activity was recorded
17
+ 'hide_sitewide' => false // Should this be hidden on the sitewide activity stream?
18
+ );
19
+ add_filter('bp_activity_allowed_tags', 'bp_media_override_allowed_tags');
20
+ $r = wp_parse_args($args, $defaults);
21
+ extract($r);
22
+ $activity_id = bp_activity_add(array('id' => $id, 'user_id' => $user_id, 'action' => $action, 'content' => $content, 'primary_link' => $primary_link, 'component' => $component, 'type' => $type, 'item_id' => $item_id, 'secondary_item_id' => $secondary_item_id, 'recorded_time' => $recorded_time, 'hide_sitewide' => $hide_sitewide));
23
+ return $activity_id;
24
+ }
25
+
26
+ function bp_media_override_allowed_tags($activity_allowedtags) {
27
+ $activity_allowedtags['video'] = array();
28
+ $activity_allowedtags['video']['id'] = array();
29
+ $activity_allowedtags['video']['class'] = array();
30
+ $activity_allowedtags['video']['src'] = array();
31
+ $activity_allowedtags['video']['height'] = array();
32
+ $activity_allowedtags['video']['width'] = array();
33
+ $activity_allowedtags['video']['controls'] = array();
34
+ $activity_allowedtags['video']['preload'] = array();
35
+ $activity_allowedtags['video']['alt'] = array();
36
+ $activity_allowedtags['video']['title'] = array();
37
+ $activity_allowedtags['audio'] = array();
38
+ $activity_allowedtags['audio']['id'] = array();
39
+ $activity_allowedtags['audio']['class'] = array();
40
+ $activity_allowedtags['audio']['src'] = array();
41
+ $activity_allowedtags['audio']['controls'] = array();
42
+ $activity_allowedtags['audio']['preload'] = array();
43
+ $activity_allowedtags['audio']['alt'] = array();
44
+ $activity_allowedtags['audio']['title'] = array();
45
+ $activity_allowedtags['script'] = array();
46
+ $activity_allowedtags['script']['type'] = array();
47
+ $activity_allowedtags['div'] = array();
48
+ $activity_allowedtags['div']['id'] = array();
49
+ $activity_allowedtags['div']['class'] = array();
50
+ $activity_allowedtags['a'] = array();
51
+ $activity_allowedtags['a']['title'] = array();
52
+ $activity_allowedtags['a']['href'] = array();
53
+ return $activity_allowedtags;
54
+ }
55
+
56
+ function bp_media_show_formatted_error_message($messages, $type) {
57
+ echo '<div id="message" class="' . $type . '">';
58
+ if (is_array($messages)) {
59
+ foreach ($messages as $key => $message) {
60
+ if (is_string($message)) {
61
+ echo '<p>' . $message . '</p>';
62
+ }
63
+ }
64
+ } else {
65
+ if (is_string($messages)) {
66
+ echo '<p>' . $messages . '</p>';
67
+ }
68
+ }
69
+ echo '</div>';
70
+ }
71
+
72
+ function bp_media_conditional_override_allowed_tags($content, $activity) {
73
+ if ($activity->type == 'media_upload') {
74
+ add_filter('bp_activity_allowed_tags', 'bp_media_override_allowed_tags', 1);
75
+ }
76
+ return bp_activity_filter_kses($content);
77
+ }
78
+
79
+ function bp_media_swap_filters() {
80
+ add_filter('bp_get_activity_content_body', 'bp_media_conditional_override_allowed_tags', 1, 2);
81
+ remove_filter('bp_get_activity_content_body', 'bp_activity_filter_kses', 1);
82
+ }
83
+ add_action('bp_init', 'bp_media_swap_filters');
84
+
85
+ /**
86
+ * Updates the media count of all users.
87
+ */
88
+ function bp_media_update_count() {
89
+ global $wpdb;
90
+ $query = "SELECT COUNT(*) AS total,b.meta_value AS type,a.post_author
91
+ FROM $wpdb->posts AS a,$wpdb->postmeta AS b
92
+ WHERE (a.id = b.post_id) AND a.post_type='bp_media' AND b.meta_key='bp_media_type'
93
+ GROUP BY b.meta_value,a.post_author";
94
+ $result = $wpdb->get_results($query);
95
+ $users_count = array();
96
+ foreach ($result as $obj) {
97
+ $users_count[$obj->post_author][$obj->type] = $obj->total;
98
+ }
99
+ $users = get_users();
100
+ foreach ($users as $user) {
101
+ if (array_key_exists($user->ID, $users_count)) {
102
+ $count = array(
103
+ 'images' => isset($users_count[$user->ID]['image']) ? intval($users_count[$user->ID]['image']) : 0,
104
+ 'videos' => isset($users_count[$user->ID]['video']) ? intval($users_count[$user->ID]['video']) : 0,
105
+ 'audio' => isset($users_count[$user->ID]['audio']) ? intval($users_count[$user->ID]['audio']) : 0,
106
+ );
107
+ } else {
108
+ $count = array(
109
+ 'images' => 0,
110
+ 'videos' => 0,
111
+ 'audio' => 0
112
+ );
113
+ }
114
+ bp_update_user_meta($user->ID, 'bp_media_count', $count);
115
+ }
116
+ return true;
117
+ }
118
+ ?>
includes/bp-media-loader.php ADDED
@@ -0,0 +1,353 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The Main loader file of BuddyPress Media Component Plugin
4
+ */
5
+ /* Exit if accessed directlly. */
6
+ if (!defined('ABSPATH'))
7
+ exit;
8
+
9
+ /* Slug Constants */
10
+ define('BP_MEDIA_SLUG', 'media');
11
+ define('BP_MEDIA_UPLOAD_SLUG', 'upload');
12
+
13
+ define('BP_MEDIA_IMAGES_SLUG', 'images');
14
+ define('BP_MEDIA_IMAGES_ENTRY_SLUG', 'view');
15
+ define('BP_MEDIA_IMAGES_EDIT_SLUG', 'edit');
16
+
17
+ define('BP_MEDIA_VIDEOS_SLUG', 'videos');
18
+ define('BP_MEDIA_VIDEOS_ENTRY_SLUG', 'watch');
19
+ define('BP_MEDIA_VIDEOS_EDIT_SLUG', 'edit');
20
+
21
+ define('BP_MEDIA_AUDIO_SLUG', 'audio');
22
+ define('BP_MEDIA_AUDIO_ENTRY_SLUG', 'listen');
23
+ define('BP_MEDIA_AUDIO_EDIT_SLUG', 'edit');
24
+
25
+ /* Label Constants(need to be translatable) */
26
+ define('BP_MEDIA_LABEL', __('Media', 'bp-media'));
27
+ define('BP_MEDIA_LABEL_SINGULAR', __('Media', 'bp-media'));
28
+ define('BP_MEDIA_IMAGES_LABEL', __('Images', 'bp-media'));
29
+ define('BP_MEDIA_IMAGES_LABEL_SINGULAR', __('Image', 'bp-media'));
30
+ define('BP_MEDIA_VIDEOS_LABEL', __('Videos', 'bp-media'));
31
+ define('BP_MEDIA_VIDEOS_LABEL_SINGULAR', __('Video', 'bp-media'));
32
+ define('BP_MEDIA_AUDIO_LABEL', __('Audio', 'bp-media'));
33
+ define('BP_MEDIA_AUDIO_LABEL_SINGULAR', __('Audio', 'bp-media'));
34
+ define('BP_MEDIA_UPLOAD_LABEL', __('Upload', 'bp-media'));
35
+
36
+ /* Global variable to store the query */
37
+ global $bp_media_query;
38
+
39
+ /* Global variable for making distinct ids for different media objects in activity stream */
40
+ global $bp_media_counter;
41
+ $bp_media_counter = 0;
42
+
43
+ /* Global variable storing the count of the media files displayed user has */
44
+ global $bp_media_count;
45
+ $bp_media_count=null;
46
+
47
+ /* Global variable for various display sizes */
48
+ global $bp_media_default_sizes;
49
+ $bp_media_default_sizes = array(
50
+ 'activity_image' => array(
51
+ 'width' => 320,
52
+ 'height' => 240
53
+ ),
54
+ 'activity_video' => array(
55
+ 'width' => 320,
56
+ 'height' => 240
57
+ ),
58
+ 'activity_audio' => array(
59
+ 'width' => 320,
60
+ ),
61
+ 'single_image' => array(
62
+ 'width' => 800,
63
+ 'height' => 0
64
+ ),
65
+ 'single_video' => array(
66
+ 'width' => 640,
67
+ 'height' => 480
68
+ ),
69
+ 'single_audio' => array(
70
+ 'width' => 640,
71
+ ),
72
+ );
73
+
74
+ /* Global variable to store various excerpt sizes */
75
+ global $bp_media_default_excerpts;
76
+ $bp_media_default_excerpts=array(
77
+ 'single_entry_title' => 100,
78
+ 'single_entry_description' => 500,
79
+ 'activity_entry_title' => 50,
80
+ 'activity_entry_description'=> 500
81
+ );
82
+
83
+ /* To set the language according to the locale selected and availability of the language file. */
84
+ if (file_exists(BP_MEDIA_PLUGIN_DIR . '/languages/' . get_locale() . '.mo'))
85
+ load_textdomain('bp-media', BP_MEDIA_PLUGIN_DIR . '/languages/' . get_locale() . '.mo');
86
+
87
+ /**
88
+ * BP Media Component Class, extends BP_Component
89
+ *
90
+ * @see BP_Component
91
+ *
92
+ * @since BP Media 2.0
93
+ */
94
+ class BP_Media_Component extends BP_Component {
95
+
96
+ /**
97
+ * Hold the messages generated during initialization process and will be shown on the screen functions
98
+ *
99
+ * @since BP Media 2.0
100
+ */
101
+ var $messages = array(
102
+ 'error' => array(),
103
+ 'info' => array(),
104
+ 'updated' => array()
105
+ );
106
+
107
+ /**
108
+ * Constructor for the BuddyPress Media Component
109
+ *
110
+ * @since BP Media 2.0
111
+ */
112
+ function __construct() {
113
+ global $bp;
114
+ parent::start(BP_MEDIA_SLUG, BP_MEDIA_LABEL, BP_MEDIA_PLUGIN_DIR);
115
+ $this->includes();
116
+ $bp->active_components[$this->id] = '1';
117
+ add_action('init', array(&$this, 'register_post_types'));
118
+ }
119
+
120
+ /**
121
+ * Includes the files required for the BuddyPress Media Component and calls the parent class' includes function
122
+ *
123
+ * @since BP Media 2.0
124
+ */
125
+ function includes() {
126
+ $includes = array(
127
+ 'includes/bp-media-screens.php',
128
+ 'includes/bp-media-functions.php',
129
+ 'includes/bp-media-filters.php',
130
+ 'includes/bp-media-template-functions.php',
131
+ 'includes/bp-media-actions.php',
132
+ 'includes/bp-media-interface.php',
133
+ 'includes/bp-media-class-wordpress.php',
134
+ 'includes/bp-media-shortcodes.php'
135
+ );
136
+ if (is_admin() || is_network_admin()) {
137
+ $includes[] = 'includes/bp-media-admin.php';
138
+ }
139
+ parent::includes($includes);
140
+ }
141
+
142
+ /**
143
+ * Initializes the global variables of the BuddyPress Media component and its parent class.
144
+ */
145
+ function setup_globals() {
146
+ global $bp;
147
+ $globals = array(
148
+ 'slug' => BP_MEDIA_SLUG,
149
+ 'root_slug' => isset($bp->pages->{$this->id}->slug) ? $bp->pages->{$this->id}->slug : BP_MEDIA_SLUG,
150
+ /*'has_directory' => true, /* Set to false if not required */
151
+ 'search_string' => __('Search Media...', 'bp-media'),
152
+ );
153
+ parent::setup_globals($globals);
154
+ }
155
+
156
+ function setup_nav() {
157
+ /* Add 'Media' to the main navigation */
158
+ if (bp_is_my_profile()) {
159
+ $main_nav = array(
160
+ 'name' => BP_MEDIA_LABEL,
161
+ 'slug' => BP_MEDIA_SLUG,
162
+ 'position' => 80,
163
+ 'screen_function' => 'bp_media_upload_screen',
164
+ 'default_subnav_slug' => BP_MEDIA_UPLOAD_SLUG
165
+ );
166
+ } else {
167
+ $main_nav = array(
168
+ 'name' => BP_MEDIA_LABEL,
169
+ 'slug' => BP_MEDIA_SLUG,
170
+ 'position' => 80,
171
+ 'screen_function' => 'bp_media_images_screen',
172
+ 'default_subnav_slug' => BP_MEDIA_IMAGES_SLUG
173
+ );
174
+ }
175
+ $sub_nav[] = array(
176
+ 'name' => BP_MEDIA_UPLOAD_LABEL,
177
+ 'slug' => BP_MEDIA_UPLOAD_SLUG,
178
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_SLUG),
179
+ 'parent_slug' => BP_MEDIA_SLUG,
180
+ 'screen_function' => 'bp_media_upload_screen',
181
+ 'position' => 10,
182
+ 'user_has_access' => bp_is_my_profile()
183
+ );
184
+ parent::setup_nav($main_nav, $sub_nav);
185
+
186
+ bp_core_new_nav_item(array(
187
+ 'name' => BP_MEDIA_IMAGES_LABEL,
188
+ 'slug' => BP_MEDIA_IMAGES_SLUG,
189
+ 'screen_function' => 'bp_media_images_screen'
190
+ ));
191
+
192
+ bp_core_new_nav_item(array(
193
+ 'name' => BP_MEDIA_VIDEOS_LABEL,
194
+ 'slug' => BP_MEDIA_VIDEOS_SLUG,
195
+ 'screen_function' => 'bp_media_videos_screen'
196
+ ));
197
+
198
+ bp_core_new_nav_item(array(
199
+ 'name' => BP_MEDIA_AUDIO_LABEL,
200
+ 'slug' => BP_MEDIA_AUDIO_SLUG,
201
+ 'screen_function' => 'bp_media_audio_screen'
202
+ ));
203
+
204
+ bp_core_new_subnav_item(array(
205
+ 'name' => 'Listen', /* Display name for the nav item(It won't be shown anywhere) */
206
+ 'slug' => BP_MEDIA_AUDIO_ENTRY_SLUG, /* URL slug for the nav item */
207
+ 'parent_slug' => BP_MEDIA_AUDIO_SLUG, /* URL slug of the parent nav item */
208
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_AUDIO_SLUG), /* URL of the parent item */
209
+ 'position' => 90, /* Index of where this nav item should be positioned */
210
+ 'screen_function' => 'bp_media_audio_screen', /* The name of the function to run when clicked */
211
+ ));
212
+
213
+ bp_core_new_subnav_item(array(
214
+ 'name' => 'Watch', /* Display name for the nav item(It won't be shown anywhere) */
215
+ 'slug' => BP_MEDIA_VIDEOS_ENTRY_SLUG, /* URL slug for the nav item */
216
+ 'parent_slug' => BP_MEDIA_VIDEOS_SLUG, /* URL slug of the parent nav item */
217
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_VIDEOS_SLUG), /* URL of the parent item */
218
+ 'position' => 90, /* Index of where this nav item should be positioned */
219
+ 'screen_function' => 'bp_media_videos_screen', /* The name of the function to run when clicked */
220
+ ));
221
+
222
+ bp_core_new_subnav_item(array(
223
+ 'name' => 'View', /* Display name for the nav item(It won't be shown anywhere) */
224
+ 'slug' => BP_MEDIA_IMAGES_ENTRY_SLUG, /* URL slug for the nav item */
225
+ 'parent_slug' => BP_MEDIA_IMAGES_SLUG, /* URL slug of the parent nav item */
226
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_IMAGES_SLUG), /* URL of the parent item */
227
+ 'position' => 90, /* Index of where this nav item should be positioned */
228
+ 'screen_function' => 'bp_media_images_screen', /* The name of the function to run when clicked */
229
+ ));
230
+
231
+ bp_core_new_subnav_item(array(
232
+ 'name' => 'Edit', /* Display name for the nav item(It won't be shown anywhere) */
233
+ 'slug' => BP_MEDIA_IMAGES_EDIT_SLUG, /* URL slug for the nav item */
234
+ 'parent_slug' => BP_MEDIA_IMAGES_SLUG, /* URL slug of the parent nav item */
235
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_IMAGES_SLUG), /* URL of the parent item */
236
+ 'position' => 90, /* Index of where this nav item should be positioned */
237
+ 'screen_function' => 'bp_media_images_edit_screen', /* The name of the function to run when clicked */
238
+ ));
239
+
240
+ bp_core_new_subnav_item(array(
241
+ 'name' => 'Edit', /* Display name for the nav item(It won't be shown anywhere) */
242
+ 'slug' => BP_MEDIA_AUDIO_EDIT_SLUG, /* URL slug for the nav item */
243
+ 'parent_slug' => BP_MEDIA_AUDIO_SLUG, /* URL slug of the parent nav item */
244
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_AUDIO_SLUG), /* URL of the parent item */
245
+ 'position' => 90, /* Index of where this nav item should be positioned */
246
+ 'screen_function' => 'bp_media_audio_edit_screen', /* The name of the function to run when clicked */
247
+ ));
248
+
249
+ bp_core_new_subnav_item(array(
250
+ 'name' => 'Edit', /* Display name for the nav item(It won't be shown anywhere) */
251
+ 'slug' => BP_MEDIA_VIDEOS_EDIT_SLUG, /* URL slug for the nav item */
252
+ 'parent_slug' => BP_MEDIA_VIDEOS_SLUG, /* URL slug of the parent nav item */
253
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_VIDEOS_SLUG), /* URL of the parent item */
254
+ 'position' => 90, /* Index of where this nav item should be positioned */
255
+ 'screen_function' => 'bp_media_videos_edit_screen', /* The name of the function to run when clicked */
256
+ ));
257
+
258
+ bp_core_new_subnav_item(array(
259
+ 'name' => 'Page', /* Display name for the nav item(It won't be shown anywhere) */
260
+ 'slug' => 'page', /* URL slug for the nav item */
261
+ 'parent_slug' => BP_MEDIA_IMAGES_SLUG, /* URL slug of the parent nav item */
262
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_IMAGES_SLUG), /* URL of the parent item */
263
+ 'position' => 90, /* Index of where this nav item should be positioned */
264
+ 'screen_function' => 'bp_media_images_screen', /* The name of the function to run when clicked */
265
+ ));
266
+
267
+ bp_core_new_subnav_item(array(
268
+ 'name' => 'Page', /* Display name for the nav item(It won't be shown anywhere) */
269
+ 'slug' => 'page', /* URL slug for the nav item */
270
+ 'parent_slug' => BP_MEDIA_AUDIO_SLUG, /* URL slug of the parent nav item */
271
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_AUDIO_SLUG), /* URL of the parent item */
272
+ 'position' => 90, /* Index of where this nav item should be positioned */
273
+ 'screen_function' => 'bp_media_audio_screen', /* The name of the function to run when clicked */
274
+ ));
275
+
276
+ bp_core_new_subnav_item(array(
277
+ 'name' => 'Page', /* Display name for the nav item(It won't be shown anywhere) */
278
+ 'slug' => 'page', /* URL slug for the nav item */
279
+ 'parent_slug' => BP_MEDIA_VIDEOS_SLUG, /* URL slug of the parent nav item */
280
+ 'parent_url' => trailingslashit(bp_loggedin_user_domain() . BP_MEDIA_VIDEOS_SLUG), /* URL of the parent item */
281
+ 'position' => 90, /* Index of where this nav item should be positioned */
282
+ 'screen_function' => 'bp_media_videos_screen', /* The name of the function to run when clicked */
283
+ ));
284
+ }
285
+
286
+ function register_post_types() {
287
+ /* Set up labels for the post type */
288
+ $labels = array(
289
+ 'name' => __('Media', 'bp-media'),
290
+ 'singular' => __('Media', 'bp-media'),
291
+ 'add_new' => __('Add New Media', 'bp-media')
292
+ );
293
+
294
+ /* Set up the argument array for register_post_type() */
295
+ $args = array(
296
+ 'label' => __('Media', 'bp-media'),
297
+ 'labels' => $labels,
298
+ 'description' => 'BuddyPress Media Component\'s Media Files',
299
+ 'public' => true,
300
+ 'show_ui' => false,
301
+ 'supports' => array('title', 'editor', 'excerpt', 'author', 'thumbnail', 'custom-fields')
302
+ );
303
+ register_post_type('bp_media', $args);
304
+ parent::register_post_types();
305
+ }
306
+ }
307
+
308
+ function bp_media_load_core_component() {
309
+ global $bp;
310
+
311
+ $bp->{BP_MEDIA_SLUG} = new BP_Media_Component();
312
+ }
313
+ add_action('bp_loaded', 'bp_media_load_core_component');
314
+
315
+ /**
316
+ * Function to set the custom navigation system in effect.
317
+ */
318
+ function bp_media_custom_nav() {
319
+ global $bp;
320
+ foreach ($bp->bp_nav as $key => $nav_item) {
321
+ if ($nav_item['slug'] == BP_MEDIA_IMAGES_SLUG || $nav_item['slug'] == BP_MEDIA_VIDEOS_SLUG || $nav_item['slug'] == BP_MEDIA_AUDIO_SLUG) {
322
+ $bp->bp_options_nav[BP_MEDIA_SLUG][] = array(
323
+ 'name' => $nav_item['name'],
324
+ 'link' => (isset($bp->displayed_user->domain) ? $bp->displayed_user->domain : (isset($bp->loggedin_user->domain) ? $bp->loggedin_user->domain : '')) . $nav_item['slug'] . '/',
325
+ 'slug' => $nav_item['slug'],
326
+ 'css_id' => $nav_item['css_id'],
327
+ 'position' => $nav_item['position'],
328
+ 'screen_function' => $nav_item['screen_function'],
329
+ 'user_has_access' => true,
330
+ 'parent_url' => trailingslashit(bp_displayed_user_domain())
331
+ );
332
+ unset($bp->bp_nav[$key]);
333
+ }
334
+ }
335
+ if ($bp->current_component == BP_MEDIA_IMAGES_SLUG || $bp->current_component == BP_MEDIA_VIDEOS_SLUG || $bp->current_component == BP_MEDIA_AUDIO_SLUG) {
336
+ $count = count($bp->action_variables);
337
+ for ($i = $count; $i > 0; $i--) {
338
+ $bp->action_variables[$i] = $bp->action_variables[$i - 1];
339
+ }
340
+ $bp->action_variables[0] = $bp->current_action;
341
+ $bp->current_action = $bp->current_component;
342
+ $bp->current_component = BP_MEDIA_SLUG;
343
+ }
344
+ }
345
+ add_action('bp_setup_nav', 'bp_media_custom_nav', 999);
346
+
347
+ function bp_media_thumbnail() {
348
+ global $bp_media_default_sizes;
349
+ add_image_size('bp_media_activity_image', $bp_media_default_sizes['activity_image']['width'], $bp_media_default_sizes['activity_image']['height'], true);
350
+ add_image_size('bp_media_single_image', $bp_media_default_sizes['single_image']['width'], $bp_media_default_sizes['single_image']['height'], true);
351
+ }
352
+ add_action('after_setup_theme', 'bp_media_thumbnail');
353
+ ?>
includes/bp-media-screens.php ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Screens for all the slugs defined in the BuddyPress Media Component
5
+ */
6
+
7
+ /* Exit if accessed directlly. */
8
+ if (!defined('ABSPATH'))
9
+ exit;
10
+
11
+ /**
12
+ * Screen function for Upload page
13
+ */
14
+ function bp_media_upload_screen() {
15
+ add_action('bp_template_title', 'bp_media_upload_screen_title');
16
+ add_action('bp_template_content', 'bp_media_upload_screen_content');
17
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
18
+ }
19
+
20
+ function bp_media_upload_screen_title() {
21
+ _e('Upload Page');
22
+ }
23
+
24
+ function bp_media_upload_screen_content() {
25
+ do_action('bp_media_before_content');
26
+ bp_media_show_upload_form();
27
+ do_action('bp_media_after_content');
28
+ }
29
+
30
+ /**
31
+ * Screen function for Images listing page (Default)
32
+ */
33
+ function bp_media_images_screen() {
34
+ global $bp;
35
+ if (isset($bp->action_variables[0])) {
36
+ switch ($bp->action_variables[0]) {
37
+ case BP_MEDIA_IMAGES_EDIT_SLUG :
38
+ bp_media_images_edit_screen();
39
+ break;
40
+ case BP_MEDIA_IMAGES_ENTRY_SLUG:
41
+ global $bp_media_current_entry;
42
+ if (!$bp->action_variables[0] == BP_MEDIA_IMAGES_ENTRY_SLUG)
43
+ return false;
44
+ try {
45
+ $bp_media_current_entry = new BP_Media_Host_Wordpress($bp->action_variables[1]);
46
+ } catch (Exception $e) {
47
+ /* Send the values to the cookie for page reload display */
48
+ @setcookie('bp-message', $_COOKIE['bp-message'], time() + 60 * 60 * 24, COOKIEPATH);
49
+ @setcookie('bp-message-type', $_COOKIE['bp-message-type'], time() + 60 * 60 * 24, COOKIEPATH);
50
+ wp_redirect(trailingslashit(bp_displayed_user_domain() . BP_MEDIA_IMAGES_SLUG));
51
+ exit;
52
+ }
53
+ add_action('bp_template_content', 'bp_media_images_entry_screen_content');
54
+ break;
55
+ default:
56
+ bp_media_set_query();
57
+ add_action('bp_template_content', 'bp_media_images_screen_content');
58
+ }
59
+ } else {
60
+ bp_media_set_query();
61
+ add_action('bp_template_content', 'bp_media_images_screen_content');
62
+ }
63
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
64
+ }
65
+
66
+ function bp_media_images_screen_title() {
67
+ _e('Images List Page');
68
+ }
69
+
70
+ function bp_media_images_screen_content() {
71
+ global $bp_media_query;
72
+ if ($bp_media_query && $bp_media_query->have_posts()):
73
+ bp_media_show_pagination();
74
+ do_action('bp_media_before_content');
75
+ echo '<ul id="groups-list" class="bp-media-gallery item-list">';
76
+ while ($bp_media_query->have_posts()) : $bp_media_query->the_post();
77
+ bp_media_the_content();
78
+ endwhile;
79
+ echo '</ul>';
80
+ do_action('bp_media_after_content');
81
+ bp_media_show_pagination('bottom');
82
+ else:
83
+ bp_media_show_formatted_error_message(__('Sorry, no images were found.', 'bp-media'), 'info');
84
+ endif;
85
+ }
86
+
87
+ /**
88
+ * Screen function for Images Edit page
89
+ */
90
+ function bp_media_images_edit_screen() {
91
+ if (bp_loggedin_user_id() != bp_displayed_user_id()) {
92
+ bp_core_no_access(array(
93
+ 'message' => __('You do not have access to this page.', 'buddypress'),
94
+ 'root' => bp_displayed_user_domain(),
95
+ 'redirect' => false
96
+ ));
97
+ exit;
98
+ }
99
+ add_action('bp_template_title', 'bp_media_images_edit_screen_title');
100
+ add_action('bp_template_content', 'bp_media_images_edit_screen_content');
101
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
102
+ }
103
+
104
+ function bp_media_images_edit_screen_title() {
105
+ _e('Images Edit Page');
106
+ }
107
+
108
+ function bp_media_images_edit_screen_content() {
109
+ global $bp;
110
+ _e('Images Edit Page Content');
111
+ }
112
+
113
+ /**
114
+ * Screen function for Images Entry page
115
+ */
116
+ function bp_media_images_entry_screen() {
117
+ add_action('bp_template_title', 'bp_media_images_entry_screen_title');
118
+ add_action('bp_template_content', 'bp_media_images_entry_screen_content');
119
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
120
+ }
121
+
122
+ function bp_media_images_entry_screen_title() {
123
+ _e('Images Entry Page');
124
+ }
125
+
126
+ function bp_media_images_entry_screen_content() {
127
+ global $bp, $bp_media_current_entry;
128
+ if (!$bp->action_variables[0] == BP_MEDIA_IMAGES_ENTRY_SLUG)
129
+ return false;
130
+ do_action('bp_media_before_content');
131
+ echo '<div class="bp-media-single bp-media-image">';
132
+ echo $bp_media_current_entry->get_media_single_content();
133
+ echo $bp_media_current_entry->show_comment_form();
134
+ echo '</div>';
135
+ do_action('bp_media_after_content');
136
+ }
137
+
138
+ /**
139
+ * Screen function for Videos listing page (Default)
140
+ */
141
+ function bp_media_videos_screen() {
142
+ global $bp;
143
+ if (isset($bp->action_variables[0])) {
144
+ switch ($bp->action_variables[0]) {
145
+ case BP_MEDIA_VIDEOS_EDIT_SLUG :
146
+ add_action('bp_template_content', 'bp_media_videos_edit_screen_content');
147
+ break;
148
+ case BP_MEDIA_VIDEOS_ENTRY_SLUG:
149
+ global $bp_media_current_entry;
150
+ if (!$bp->action_variables[0] == BP_MEDIA_IMAGES_ENTRY_SLUG)
151
+ return false;
152
+ try {
153
+ $bp_media_current_entry = new BP_Media_Host_Wordpress($bp->action_variables[1]);
154
+ } catch (Exception $e) {
155
+ /* Send the values to the cookie for page reload display */
156
+ @setcookie('bp-message', $_COOKIE['bp-message'], time() + 60 * 60 * 24, COOKIEPATH);
157
+ @setcookie('bp-message-type', $_COOKIE['bp-message-type'], time() + 60 * 60 * 24, COOKIEPATH);
158
+ wp_redirect(trailingslashit(bp_displayed_user_domain() . BP_MEDIA_VIDEOS_SLUG));
159
+ exit;
160
+ }
161
+ add_action('bp_template_content', 'bp_media_videos_entry_screen_content');
162
+ break;
163
+ default:
164
+ bp_media_set_query();
165
+ add_action('bp_template_content', 'bp_media_videos_screen_content');
166
+ }
167
+ } else {
168
+ bp_media_set_query();
169
+ add_action('bp_template_content', 'bp_media_videos_screen_content');
170
+ }
171
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
172
+ }
173
+
174
+ function bp_media_videos_screen_title() {
175
+ _e('Videos List Page');
176
+ }
177
+
178
+ function bp_media_videos_screen_content() {
179
+ global $bp_media_query;
180
+ if ($bp_media_query && $bp_media_query->have_posts()):
181
+ bp_media_show_pagination();
182
+ do_action('bp_media_before_content');
183
+ echo '<ul class="bp-media-gallery">';
184
+ while ($bp_media_query->have_posts()) : $bp_media_query->the_post();
185
+ bp_media_the_content();
186
+ endwhile;
187
+ echo '</ul>';
188
+ do_action('bp_media_after_content');
189
+ bp_media_show_pagination('bottom');
190
+ else:
191
+ bp_media_show_formatted_error_message(__('Sorry, no videos were found.', 'bp-media'), 'info');
192
+ endif;
193
+ }
194
+
195
+ /**
196
+ * Screen function for Videos Edit page
197
+ */
198
+ function bp_media_videos_edit_screen() {
199
+ add_action('bp_template_title', 'bp_media_videos_edit_screen_title');
200
+ add_action('bp_template_content', 'bp_media_videos_edit_screen_content');
201
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
202
+ }
203
+
204
+ function bp_media_videos_edit_screen_title() {
205
+ _e('Videos Edit Page');
206
+ }
207
+
208
+ function bp_media_videos_edit_screen_content() {
209
+ global $bp;
210
+ _e('Videos Edit Page Content');
211
+ }
212
+
213
+ /**
214
+ * Screen function for Videos Entry page
215
+ */
216
+ function bp_media_videos_entry_screen() {
217
+ add_action('bp_template_title', 'bp_media_videos_entry_screen_title');
218
+ add_action('bp_template_content', 'bp_media_videos_entry_screen_content');
219
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
220
+ }
221
+
222
+ function bp_media_videos_entry_screen_title() {
223
+ _e('Videos Entry Page');
224
+ }
225
+
226
+ function bp_media_videos_entry_screen_content() {
227
+ global $bp, $bp_media_current_entry;
228
+ if (!$bp->action_variables[0] == BP_MEDIA_VIDEOS_ENTRY_SLUG)
229
+ return false;
230
+ do_action('bp_media_before_content');
231
+ echo '<div class="bp-media-single bp-media-video">';
232
+ echo $bp_media_current_entry->get_media_single_content();
233
+ echo $bp_media_current_entry->show_comment_form();
234
+ echo '</div>';
235
+ do_action('bp_media_after_content');
236
+ }
237
+
238
+ /**
239
+ * Screen function for Audio listing page (Default)
240
+ */
241
+ function bp_media_audio_screen() {
242
+ global $bp;
243
+ if (isset($bp->action_variables[0])) {
244
+ switch ($bp->action_variables[0]) {
245
+ case BP_MEDIA_AUDIO_EDIT_SLUG :
246
+ add_action('bp_template_content', 'bp_media_audio_edit_screen_content');
247
+ break;
248
+ case BP_MEDIA_AUDIO_ENTRY_SLUG:
249
+ global $bp_media_current_entry;
250
+ if (!$bp->action_variables[0] == BP_MEDIA_IMAGES_ENTRY_SLUG)
251
+ return false;
252
+ try {
253
+ $bp_media_current_entry = new BP_Media_Host_Wordpress($bp->action_variables[1]);
254
+ } catch (Exception $e) {
255
+ /* Send the values to the cookie for page reload display */
256
+ @setcookie('bp-message', $_COOKIE['bp-message'], time() + 60 * 60 * 24, COOKIEPATH);
257
+ @setcookie('bp-message-type', $_COOKIE['bp-message-type'], time() + 60 * 60 * 24, COOKIEPATH);
258
+ wp_redirect(trailingslashit(bp_displayed_user_domain() . BP_MEDIA_AUDIO_SLUG));
259
+ exit;
260
+ }
261
+ add_action('bp_template_content', 'bp_media_audio_entry_screen_content');
262
+ break;
263
+ default:
264
+ bp_media_set_query();
265
+ add_action('bp_template_content', 'bp_media_audio_screen_content');
266
+ }
267
+ } else {
268
+ bp_media_set_query();
269
+ add_action('bp_template_content', 'bp_media_audio_screen_content');
270
+ }
271
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
272
+ }
273
+
274
+ function bp_media_audio_screen_title() {
275
+ _e('Audio List Page');
276
+ }
277
+
278
+ function bp_media_audio_screen_content() {
279
+ global $bp_media_query;
280
+ if ($bp_media_query && $bp_media_query->have_posts()):
281
+ bp_media_show_pagination();
282
+ do_action('bp_media_before_content');
283
+ echo '<ul class="bp-media-gallery">';
284
+ while ($bp_media_query->have_posts()) : $bp_media_query->the_post();
285
+ bp_media_the_content();
286
+ endwhile;
287
+ echo '</ul>';
288
+ do_action('bp_media_after_content');
289
+ bp_media_show_pagination('bottom');
290
+ else:
291
+ bp_media_show_formatted_error_message(__('Sorry, no audio files were found.', 'bp-media'), 'info');
292
+ endif;
293
+ }
294
+
295
+ /**
296
+ * Screen function for Audio Edit page
297
+ */
298
+ function bp_media_audio_edit_screen() {
299
+ add_action('bp_template_title', 'bp_media_audio_edit_screen_title');
300
+ add_action('bp_template_content', 'bp_media_audio_edit_screen_content');
301
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
302
+ }
303
+
304
+ function bp_media_audio_edit_screen_title() {
305
+ _e('Audio Edit Page');
306
+ }
307
+
308
+ function bp_media_audio_edit_screen_content() {
309
+ global $bp;
310
+ _e('Audio Edit Page Content');
311
+ }
312
+
313
+ /**
314
+ * Screen function for Audio Entry page
315
+ */
316
+ function bp_media_audio_entry_screen() {
317
+ add_action('bp_template_title', 'bp_media_audio_entry_screen_title');
318
+ add_action('bp_template_content', 'bp_media_audio_entry_screen_content');
319
+ bp_core_load_template(apply_filters('bp_core_template_plugin', 'members/single/plugins'));
320
+ }
321
+
322
+ function bp_media_audio_entry_screen_title() {
323
+ _e('Audio Entry Page');
324
+ }
325
+
326
+ function bp_media_audio_entry_screen_content() {
327
+ global $bp, $bp_media_current_entry;
328
+ if (!$bp->action_variables[0] == BP_MEDIA_AUDIO_ENTRY_SLUG)
329
+ return false;
330
+ do_action('bp_media_before_content');
331
+ echo '<div class="bp-media-single bp-media-audio">';
332
+ echo $bp_media_current_entry->get_media_single_content();
333
+ echo $bp_media_current_entry->show_comment_form();
334
+ echo '</div>';
335
+ do_action('bp_media_after_content');
336
+ }
337
+ ?>
includes/bp-media-shortcodes.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Shortcode for generating the action of the activity
5
+ */
6
+ function bp_media_shortcode_action($atts) {
7
+ extract(shortcode_atts(array(
8
+ 'id' => '0'
9
+ ), $atts)
10
+ );
11
+ $media=new BP_Media_Host_Wordpress($id);
12
+ return $media->get_media_activity_action();
13
+ }
14
+ //add_shortcode('bp_media_action', 'bp_media_shortcode_action');
15
+
16
+ /**
17
+ * Shortcode for generationg the content of the activity
18
+ */
19
+ function bp_media_shortcode_content($atts) {
20
+ extract(shortcode_atts(array(
21
+ 'id' => '0'
22
+ ), $atts)
23
+ );
24
+ $media=new BP_Media_Host_Wordpress($id);
25
+ return $media->get_media_activity_content();
26
+ }
27
+ //add_shortcode('bp_media_content', 'bp_media_shortcode_content');
28
+
29
+ function bp_media_shortcode_url($atts) {
30
+ extract(shortcode_atts(array(
31
+ 'id' => '0'
32
+ ), $atts)
33
+ );
34
+ $media=new BP_Media_Host_Wordpress($id);
35
+ return $media->get_media_activity_url();
36
+ }
37
+ //add_shortcode('bp_media_url','bp_media_shortcode_url');
38
+ ?>
includes/bp-media-template-functions.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ function bp_media_show_upload_form() {
3
+ global $bp,$bp_media_default_excerpts;
4
+ ?>
5
+ <form method="post" enctype="multipart/form-data" class="standard-form" id="bp-media-upload-form">
6
+ <label for="bp-media-upload-input-title"><?php _e('Media Title', 'bp-media'); ?></label><input id="bp-media-upload-input-title" type="text" name="bp_media_title" class="settings-input" maxlength="<?php echo max(array($bp_media_default_excerpts['single_entry_title'],$bp_media_default_excerpts['activity_entry_title'])) ?>" />
7
+ <label for="bp-media-upload-input-description"><?php _e('Media Description', 'bp-media'); ?></label><input id="bp-media-upload-input-description" type="text" name="bp_media_description" class="settings-input" maxlength="<?php echo max(array($bp_media_default_excerpts['single_entry_description'],$bp_media_default_excerpts['activity_entry_description'])) ?>" />
8
+ <label for="bp-media-upload-file"><?php _e('Select Media File', 'bp-media') ?> (Max File Size:<?php echo min(array(ini_get('upload_max_filesize'),ini_get('post_max_size'))); ?>)</label><input type="file" name="bp_media_file" id="bp-media-upload-file" />
9
+ <input type="hidden" name="action" value="wp_handle_upload" />
10
+ <div class="submit"><input type="submit" class="auto" value="Upload" /></div>
11
+ </form>
12
+ <?php
13
+ }
14
+
15
+ function bp_media_show_pagination($type = 'top') {
16
+ global $bp, $bp_media_paginated_links, $bp_media_query;
17
+ switch ($bp->current_action) {
18
+ case BP_MEDIA_IMAGES_SLUG :
19
+ $current = $bp_media_query->found_posts > 1 ? BP_MEDIA_IMAGES_LABEL : BP_MEDIA_IMAGES_LABEL_SINGULAR;
20
+ $current_single = BP_MEDIA_IMAGES_LABEL_SINGULAR;
21
+ break;
22
+ case BP_MEDIA_VIDEOS_SLUG :
23
+ $current = $bp_media_query->found_posts > 1 ? BP_MEDIA_VIDEOS_LABEL : BP_MEDIA_VIDEOS_LABEL_SINGULAR;
24
+ $current_single = BP_MEDIA_VIDEOS_LABEL_SINGULAR;
25
+ break;
26
+ case BP_MEDIA_AUDIO_SLUG :
27
+ $current = BP_MEDIA_AUDIO_LABEL;
28
+ $current_single = BP_MEDIA_AUDIO_LABEL_SINGULAR;
29
+ break;
30
+ default :
31
+ $current = BP_MEDIA_LABEL;
32
+ $current_single = BP_MEDIA_LABEL_SINGULAR;
33
+ }
34
+ $args = array(
35
+ 'base' => trailingslashit(bp_displayed_user_domain() . $bp->current_action . '/') . '%_%',
36
+ 'format' => 'page/%#%',
37
+ 'total' => $bp_media_query->max_num_pages,
38
+ 'current' => $bp_media_query->query_vars['paged'],
39
+ 'type' => 'array',
40
+ 'prev_text' => '&larr;',
41
+ 'next_text' => '&rarr;',
42
+ );
43
+ $start_num = intval($bp_media_query->query_vars['posts_per_page'] * ($bp_media_query->query_vars['paged'] - 1)) + 1;
44
+ $from_num = $start_num;
45
+ $to_num = $start_num + $bp_media_query->post_count - 1;
46
+ $total = $bp_media_query->found_posts;
47
+ $bp_media_paginated_links = paginate_links($args);
48
+ ?>
49
+ <div id="pag-<?php echo $type; ?>" class="pagination no-ajax">
50
+ <div class="pag-count">
51
+ Viewing <?php echo $current_single ?> <?php echo $from_num ?> to <?php echo $to_num ?> (of <?php echo $total; ?> <?php echo $current ?>)
52
+ </div>
53
+ <div class="pagination-links">
54
+ <?php if(is_array($bp_media_paginated_links)) : foreach ($bp_media_paginated_links as $link) : ?>
55
+ <?php echo $link; ?>
56
+ <?php endforeach; endif; ?>
57
+ </div>
58
+ </div>
59
+ <?php
60
+ }
61
+
62
+ function bp_media_get_permalink($id = 0) {
63
+ if (is_object($id))
64
+ $media = $id;
65
+ else
66
+ $media = &get_post($id);
67
+ if (empty($media->ID))
68
+ return false;
69
+ if (!$media->post_type == 'bp_media')
70
+ return false;
71
+ switch (get_post_meta($media->ID, 'bp_media_type', true)) {
72
+ case 'video' :
73
+ return trailingslashit(bp_displayed_user_domain() . BP_MEDIA_VIDEOS_SLUG . '/watch/' . $media->ID);
74
+ break;
75
+ case 'audio' :
76
+ return trailingslashit(bp_displayed_user_domain() . BP_MEDIA_AUDIO_SLUG . '/listen/' . $media->ID);
77
+ break;
78
+ case 'image' :
79
+ return trailingslashit(bp_displayed_user_domain() . BP_MEDIA_IMAGES_SLUG . '/view/' . $media->ID);
80
+ break;
81
+ default :
82
+ return false;
83
+ }
84
+ }
85
+
86
+ function bp_media_the_permalink() {
87
+ echo apply_filters('bp_media_the_permalink', bp_media_get_permalink());
88
+ }
89
+
90
+ function bp_media_the_content($id = 0) {
91
+ if (is_object($id))
92
+ $media = $id;
93
+ else
94
+ $media = &get_post($id);
95
+ if (empty($media->ID))
96
+ return false;
97
+ if (!$media->post_type == 'bp_media')
98
+ return false;
99
+ $media = new BP_Media_Host_Wordpress($media->ID);
100
+ echo $media->get_media_gallery_content();
101
+ }
102
+ ?>
includes/css/bp-media-admin.css ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Used on backend */
2
+ #wpbody-content div.metabox-fixed{
3
+ width: 22%;
4
+ margin-right: 10px;
5
+ clear: both;
6
+ }
7
+ #wpbody-content div.wrap.bp-media-admin{
8
+ overflow: hidden;
9
+ width: 76%;
10
+ }
11
+ #icon-bp-media{
12
+ background:url('../img/logo_medibp_32.png') no-repeat scroll 0 0 transparent;
13
+ }.bp-media-social{
14
+ background: url('../img/bp_media_social.png');
15
+ height: 35px;
16
+ width: 35px;
17
+ display: inline-block;
18
+ font-size: 0px;
19
+ margin-right:5px;
20
+ }
21
+ .bp-media-facebook{
22
+ background-position: 0px 0px;
23
+ }
24
+ .bp-media-facebook:hover{
25
+ background-position: 0px 36px;
26
+ }
27
+ .bp-media-twitter{
28
+ background-position: 80px 0px;
29
+ }
30
+ .bp-media-twitter:hover{
31
+ background-position: 80px 36px;
32
+ }
33
+ .bp-media-rss{
34
+ background-position: 35px 0px;
35
+ }
36
+ .bp-media-rss:hover{
37
+ background-position: 35px 36px;
38
+ }
39
+
includes/css/bp-media-style.css ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Default stylesheet for BuddyPress Media Component
3
+ */
4
+ .bp_media_content img{
5
+ max-width:98%;
6
+ }
7
+ .bp_media_title {
8
+ display:block;
9
+ font-size:20px;
10
+ font-weight:bold;
11
+ }
12
+ .bp_media_description {
13
+ display:block;
14
+ }
15
+ ul.bp-media-gallery{
16
+ overflow:hidden;
17
+ }
18
+ ul.bp-media-gallery li{
19
+ float:left;
20
+ margin:1%;
21
+ width:18%;
22
+ border-bottom:none;
23
+ }
24
+ ul.bp-media-gallery li img{
25
+ max-width:150px;
26
+ width:100%;
27
+ height:auto;
28
+ -moz-box-shadow: 1px 1px 10px #a0a0a0;
29
+ -webkit-box-shadow: 1px 1px 10px #a0a0a0;
30
+ box-shadow: 1px 1px 10px #a0a0a0;
31
+ -moz-transition: box-shadow 0.2s linear;
32
+ -webkit-transition: box-shadow 0.2s linear;
33
+ transition: box-shadow 0.2s linear;
34
+ }
35
+ ul.bp-media-gallery li img:hover{
36
+ -moz-box-shadow: 1px 1px 10px #333;
37
+ -webkit-box-shadow: 1px 1px 10px #333;
38
+ box-shadow: 1px 1px 10px #333;
39
+
40
+ }
41
+ ul.bp-media-gallery h3{
42
+ max-width:150px;
43
+ overflow: hidden;
44
+ text-align: center;
45
+ font-size:110%;
46
+ white-space: nowrap;
47
+ height:20px;
48
+ }
49
+ ul.bp-media-gallery a{
50
+ width:150px;
51
+ }
52
+ .bp-media-single .activity-list .activity-content,.bp-media-single div.activity-comments{
53
+ margin-left:0;
54
+ }
55
+ li.media div.activity-content div.activity-inner p{
56
+ display:none;
57
+ }
58
+ div.bp_media_title{
59
+ margin-bottom:5px;
60
+ }
61
+ #bp-media-footer {
62
+ color: #4D4D4D;
63
+ text-align: center;
64
+ text-shadow: #FAFAFA 1px 1px 0;
65
+ }
includes/img/audio_thumb.png ADDED
Binary file
includes/img/bp_media_social.png ADDED
Binary file
includes/img/image_thumb.png ADDED
Binary file
includes/img/logo_medibp_32.png ADDED
Binary file
includes/img/video_thumb.png ADDED
Binary file
includes/js/bp-media.js ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * BuddyPress Media Default JS
3
+ */
4
+
5
+ function bp_media_create_element(id){
6
+ jQuery('#'+id).mediaelementplayer({
7
+ enableKeyboard: false,
8
+ startVolume: 1,
9
+ success: function(mediaElement,domElement){
10
+ var $thisMediaElement = (mediaElement.id) ? jQuery("#"+mediaElement.id) : jQuery(mediaElement);
11
+ $thisMediaElement.parents('.mejs-container').find(".mejs-volume-current").css("top","8px");
12
+ $thisMediaElement.parents('.mejs-container').find(".mejs-volume-handle").css("top","5px");
13
+ }
14
+ });
15
+ }
includes/lib/MP4Info.php ADDED
@@ -0,0 +1,257 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * MP4Info main class
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.1.20090611 $Id: MP4Info.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info {
21
+ // {{{ Audio codec types
22
+ const MP4_AUDIO_CODEC_UNCOMPRESSED = 0x00;
23
+ const MP4_AUDIO_CODEC_MP3 = 0x02;
24
+ const MP4_AUDIO_CODEC_AAC = 0xe0;
25
+ // }}}
26
+
27
+ // {{{ Video codec types
28
+ const MP4_VIDEO_CODEC_H264 = 0xe0;
29
+ // }}}
30
+
31
+
32
+ /**
33
+ * Get information from MP4 file
34
+ *
35
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
36
+ * @param string $file
37
+ * @return array
38
+ * @access public
39
+ * @static
40
+ */
41
+ public static function getInfo($file) {
42
+ // Open file
43
+ $f = fopen($file,'rb');
44
+ if (!$f) {
45
+ throw new Exception('Cannot open file: '.$file);
46
+ }
47
+
48
+ // Get all boxes
49
+ try {
50
+ while (($box = MP4Info_Box::fromStream($f))) {
51
+ $boxes[] = $box;
52
+ }
53
+ } catch (Exception $e) { }
54
+
55
+ // Close
56
+ fclose($f);
57
+
58
+ // Return info
59
+ return self::getInfoFromBoxes($boxes);
60
+ } // getInfo method
61
+
62
+
63
+ /**
64
+ * Get information from MP4 boxes
65
+ *
66
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
67
+ * @param string $file
68
+ * @return array
69
+ * @access public
70
+ * @static
71
+ */
72
+ public static function getInfoFromBoxes($boxes, &$context=null) {
73
+ if ($context === null) {
74
+ $context = new stdClass();
75
+ $context->hasVideo = false;
76
+ $context->hasAudio = false;
77
+ $context->video = new stdClass();
78
+ $context->audio = new stdClass();
79
+ }
80
+
81
+ foreach ($boxes as &$box) {
82
+ // Interpret box
83
+ switch ($box->getBoxTypeStr()) {
84
+ case 'hdlr':
85
+ switch ($box->getHandlerType()) {
86
+ case MP4Info_Box_hdlr::HANDLER_VIDEO:
87
+ $context->hasVideo = true;
88
+ break;
89
+ case MP4Info_Box_hdlr::HANDLER_SOUND:
90
+ $context->hasAudio = true;
91
+ break;
92
+ }
93
+ break;
94
+ case 'mvhd':
95
+ $context->duration = $box->getRealDuration();
96
+ break;
97
+ case 'ilst':
98
+ if ($box->hasValue('©too')) {
99
+ $context->encoder = $box->getValue('©too');
100
+ }
101
+ break;
102
+ case 'uuid':
103
+ $meta = $box->getXMPMetaData();
104
+ if ($meta !== false) {
105
+ // Try to get duration
106
+ if (!isset($context->duration)) {
107
+ if (preg_match('/<(|[a-z]+:)duration[\s\n\r]([^>]*)>/im',$meta,$m)) {
108
+ if (preg_match_all('/xmpDM:([a-z]+)="([^"]+)"/',$m[2],$mm)) {
109
+ $value = $scale = false;
110
+ foreach ($mm[1] as $k=>$v) {
111
+ if (($v == 'value') || ($v == 'scale')) {
112
+ if (preg_match('/^1\/([0-9]+)$/',$mm[2][$k],$mmm)) {
113
+ $mm[2][$k] = 1/$mmm[1];
114
+ }
115
+ $$v = $mm[2][$k];
116
+ }
117
+ }
118
+ if (($value !== false) && ($scale !== false)) {
119
+ $context->duration = $value*$scale;
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ // Try to get size
126
+ if ((!isset($context->width)) || (!isset($context->height))) {
127
+ if (preg_match('/<(|[a-z]+:)videoFrameSize[\s\n\r]([^>]*)>/im',$meta,$m)) {
128
+ if (preg_match_all('/[a-z]:([a-z]+)="([^"]+)"/',$m[2],$mm)) {
129
+ $w = $h = false;
130
+ foreach ($mm[1] as $k=>$v) {
131
+ if (($v == 'w') || ($v == 'h')) {
132
+ $$v = $mm[2][$k];
133
+ }
134
+ }
135
+ if ($w != false) {
136
+ $context->video->width = $w;
137
+ $context->hasVideo = true;
138
+ }
139
+ if ($h != false) {
140
+ $context->video->height = $h;
141
+ $context->hasVideo = true;
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ // Try to get encoder
148
+ if (preg_match('/softwareAgent="([^"]+)"/i',$meta,$m)) {
149
+ $context->encoder = $m[1];
150
+ }
151
+
152
+ // Try to get audio channels
153
+ if (preg_match('/audioChannelType="([^"]+)"/i',$meta,$m)) {
154
+ switch (strtolower($m[1])) {
155
+ case 'stereo':
156
+ case '2':
157
+ $context->audio->channels = 2;
158
+ $context->hasAudio = true;
159
+ break;
160
+ case 'mono':
161
+ case '1':
162
+ $context->audio->channels = 1;
163
+ $context->hasAudio = true;
164
+ break;
165
+ case '5.1':
166
+ case '5':
167
+ $context->audio->channels = 5;
168
+ $context->hasAudio = true;
169
+ break;
170
+ }
171
+ }
172
+
173
+ // Try to get audio frequency
174
+ if (preg_match('/audioSampleRate="([^"]+)"/i',$meta,$m)) {
175
+ $context->audio->frequency = $m[1]/1000;
176
+ $context->hasAudio = true;
177
+ }
178
+
179
+ // Try to get video frame rate
180
+ if (preg_match('/videoFrameRate="([^"]+)"/i',$meta,$m)) {
181
+ $context->video->fps = $m[1];
182
+ $context->hasVideo = true;
183
+ }
184
+
185
+ //print htmlentities($meta);
186
+ }
187
+ break;
188
+ case 'stsd':
189
+ $values = $box->getValues();
190
+ foreach (array_keys($values) as $codec) {
191
+ switch ($codec) {
192
+ case '.mp3':
193
+ $context->audio->codec = self::MP4_AUDIO_CODEC_MP3;
194
+ $context->audio->codecStr = 'MP3';
195
+ $context->hasAudio = true;
196
+ break;
197
+ case 'mp4a':
198
+ case 'mp4s':
199
+ $context->audio->codec = self::MP4_AUDIO_CODEC_AAC;
200
+ $context->audio->codecStr = 'AAC';
201
+ $context->hasAudio = true;
202
+ break;
203
+ case 'avc1':
204
+ case 'h264':
205
+ case 'H264':
206
+ $context->video->codec = self::MP4_VIDEO_CODEC_H264;
207
+ $context->video->codecStr = 'H.264';
208
+ $context->hasVideo = true;
209
+ break;
210
+ }
211
+ }
212
+ break;
213
+ case 'tkhd':
214
+ if ($box->getWidth() > 0) {
215
+ $context->hasVideo = true;
216
+ $context->video->width = $box->getWidth();
217
+ $context->video->height = $box->getHeight();
218
+ $context->hasVideo = true;
219
+ }
220
+ break;
221
+ }
222
+
223
+ // Process children
224
+ if ($box->hasChildren()) {
225
+ self::getInfoFromBoxes($box->children(), $context);
226
+ }
227
+ }
228
+
229
+ return $context;
230
+ } // getInfoFromBoxes method
231
+
232
+
233
+ /**
234
+ * Display boxes for debugging
235
+ *
236
+ * @param MP4Info_Box[] $boxes
237
+ * @param int $level
238
+ * @access public
239
+ * @static
240
+ */
241
+ public static function displayBoxes($boxes,$level=0) {
242
+ foreach ($boxes as $box) {
243
+ print str_repeat('&nbsp;',$level*4) . $box->toString() . '<br>';
244
+ if ($box->hasChildren()) {
245
+ $this->displayBoxes($box->children(), $level+1);
246
+ }
247
+ }
248
+ } // displayBoxes method
249
+ } // MP4Info class
250
+
251
+ // ---
252
+
253
+ // {{{ Dependencies
254
+ include "MP4Info/Helper.php";
255
+ include "MP4Info/Exception.php";
256
+ include "MP4Info/Box.php";
257
+ // }}} Dependencies
includes/lib/MP4Info/Box.php ADDED
@@ -0,0 +1,446 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box.php $
10
+ *
11
+ * Based on:
12
+ * - http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt
13
+ * - http://neuron2.net/library/avc/c041828_ISO_IEC_14496-12_2005(E).pdf
14
+ * - http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v10.pdf
15
+ */
16
+
17
+ // ---
18
+
19
+ /**
20
+ * MP4Info General Box
21
+ *
22
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
23
+ * @version 1.1.20090611 $Id: Box.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
24
+ */
25
+ class MP4Info_Box {
26
+ /**
27
+ * Total box size, including box header (8 bytes)
28
+ *
29
+ * @var int
30
+ */
31
+ protected $totalSize;
32
+
33
+ /**
34
+ * Box type, numeric
35
+ *
36
+ * @var int
37
+ */
38
+ protected $boxType;
39
+
40
+ /**
41
+ * Box type, string
42
+ *
43
+ * @var string
44
+ */
45
+ protected $boxTypeStr;
46
+
47
+ /**
48
+ * Box data
49
+ *
50
+ * @var string(binary)
51
+ */
52
+ protected $data;
53
+
54
+ /**
55
+ * Parent
56
+ *
57
+ * @var MP4Info_Box|false
58
+ */
59
+ protected $parent;
60
+
61
+ /**
62
+ * Children
63
+ *
64
+ * @var MP4Info_Box[]
65
+ */
66
+ protected $children = array();
67
+
68
+ /**
69
+ * Constructor
70
+ *
71
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
72
+ * @param int $totalSize
73
+ * @param int $boxType
74
+ * @param file|string $f
75
+ * @param MP4Info_Box $parent
76
+ * @access public
77
+ */
78
+ public function __construct($totalSize, $boxType, $f, $parent=false) {
79
+ $this->totalSize = $totalSize;
80
+ $this->boxType = $boxType;
81
+ $this->boxTypeStr = pack('N',$boxType);
82
+ $this->data = self::getDataFrom3rd($f,$totalSize);
83
+ $this->parent = $parent;
84
+ if ($parent != false) {
85
+ $parent->addChild($this);
86
+ }
87
+ } // Constructor
88
+
89
+ /**
90
+ * Add a child to this box
91
+ *
92
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
93
+ * @param MP4Info_Box $child
94
+ * @access public
95
+ */
96
+ public function addChild(&$child) {
97
+ if (!$child instanceof MP4Info_Box) {
98
+ throw new Exception('Child is not MP4Info_Box');
99
+ }
100
+ $this->children[] = &$child;
101
+ }
102
+
103
+ /**
104
+ * Check if the box has children
105
+ *
106
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
107
+ * @return bool
108
+ * @access public
109
+ */
110
+ public function hasChildren() {
111
+ return count($this->children) > 0;
112
+ } // hasChildren method
113
+
114
+ /**
115
+ * Get boxes' children
116
+ *
117
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
118
+ * @return MP4Info_Box[]
119
+ * @access public
120
+ */
121
+ public function children() {
122
+ return $this->children;
123
+ } // children method
124
+
125
+
126
+ /**
127
+ * Get data from 3rd argument (file or string)
128
+ *
129
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
130
+ * @param file|string $f
131
+ * @param int $totalSize
132
+ * @return string
133
+ * @access public
134
+ * @static
135
+ */
136
+ public static function getDataFrom3rd($f, $totalSize) {
137
+ // Get data
138
+ if ($f === false) {
139
+ return '';
140
+ } else if (is_string($f)) {
141
+ $data = substr($f,0,$totalSize-8);
142
+ } else {
143
+ $data = fread($f,$totalSize-8);
144
+ }
145
+
146
+ return $data;
147
+ } // getDataFrom3rd method
148
+
149
+
150
+ /**
151
+ * Create an MP4Info_Box object from data
152
+ *
153
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
154
+ * @param int $totalSize
155
+ * @param int $boxType
156
+ * @param file|string $f
157
+ * @param MP4Info_Box|false $parent
158
+ * @return MP4Info_Box
159
+ * @access public
160
+ * @static
161
+ */
162
+ public static function factory($totalSize, $boxType, $f, $parent=false) {
163
+ if (MP4Info_Box_Container::isCompatible($boxType,$parent)) {
164
+ $box = new MP4Info_Box_Container($totalSize, $boxType, $f, $parent);
165
+ } else if (MP4Info_Box_ftyp::isCompatible($boxType,$parent)) {
166
+ $box = new MP4Info_Box_ftyp($totalSize, $boxType, $f, $parent);
167
+ } else if (MP4Info_Box_uuid::isCompatible($boxType,$parent)) {
168
+ $box = new MP4Info_Box_uuid($totalSize, $boxType, $f, $parent);
169
+ } else if (MP4Info_Box_hdlr::isCompatible($boxType,$parent)) {
170
+ $box = new MP4Info_Box_hdlr($totalSize, $boxType, $f, $parent);
171
+ } else if (MP4Info_Box_mvhd::isCompatible($boxType,$parent)) {
172
+ $box = new MP4Info_Box_mvhd($totalSize, $boxType, $f, $parent);
173
+ } else if (MP4Info_Box_tkhd::isCompatible($boxType,$parent)) {
174
+ $box = new MP4Info_Box_tkhd($totalSize, $boxType, $f, $parent);
175
+ } else if (MP4Info_Box_mdhd::isCompatible($boxType,$parent)) {
176
+ $box = new MP4Info_Box_mdhd($totalSize, $boxType, $f, $parent);
177
+ } else if (MP4Info_Box_meta::isCompatible($boxType,$parent)) {
178
+ $box = new MP4Info_Box_meta($totalSize, $boxType, $f, $parent);
179
+ } else if (MP4Info_Box_stsd::isCompatible($boxType,$parent)) {
180
+ $box = new MP4Info_Box_stsd($totalSize, $boxType, $f, $parent);
181
+ } else if (MP4Info_Box_ilst::isCompatible($boxType,$parent)) {
182
+ $box = new MP4Info_Box_ilst($totalSize, $boxType, $f, $parent);
183
+ } else if (MP4Info_Box_ilst_sub::isCompatible($boxType,$parent)) {
184
+ $box = new MP4Info_Box_ilst_sub($totalSize, $boxType, $f, $parent);
185
+ } else {
186
+ throw new Exception('Media type error');
187
+ }
188
+
189
+ // Return box
190
+ return $box;
191
+ } // factory method
192
+
193
+
194
+ /**
195
+ * Create a box from string
196
+ *
197
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
198
+ * @param string $data
199
+ * @param MP4Info_Box|false $parent
200
+ * @return MP4Info_Box
201
+ * @access public
202
+ * @static
203
+ */
204
+ public static function fromString(&$data,$parent=false) {
205
+ if (strlen($data) < 8) {
206
+ throw new Exception('Not enough data, need at least 8 bytes!');
207
+ }
208
+
209
+ $ar = unpack('NtotalSize/NboxType',$data);
210
+ if ($ar['totalSize'] == 1) {
211
+ // Size is bigger than 4GB :-O die
212
+ // Skip ExtendedSize(UI64) and try to decode anyway
213
+ $ar2 = unpack('N2extSize',substr($data,8));
214
+ if ($ar2['extSize1'] > 0) {
215
+ throw new Exception('Extended size not supported');
216
+ } else {
217
+ $ar['totalSize'] = $ar2['extSize2'];
218
+ }
219
+ $skip = 8;
220
+ } else {
221
+ $skip = 0;
222
+ }
223
+
224
+ // Check if we need to skip
225
+ if (self::skipBoxType($ar['boxType'])) {
226
+ //print '+++ Skipping box '.pack('N',$ar['boxType']).'<br>';
227
+ $data = substr($data,$ar['totalSize']);
228
+ return self::fromString($data,$parent);
229
+ }
230
+
231
+ // Check if box is a container, and skip to content if so
232
+ if (self::ignoreBoxType($ar['boxType'])) {
233
+ //print '+++ Ignoring box '.pack('N',$ar['boxType']).'<br>';
234
+ $data = substr($data,8+$skip);
235
+ return self::fromString($data,$parent);
236
+ }
237
+
238
+ // Create box
239
+ $box = self::factory($ar['totalSize'],$ar['boxType'],substr($data,8+$skip),$parent);
240
+ if ($box instanceof MP4Info_Box) {
241
+ $data = substr($data,$box->getTotalSize());
242
+ }
243
+
244
+ return $box;
245
+ } // fromString method
246
+
247
+
248
+ /**
249
+ * Create a box from file stream
250
+ *
251
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
252
+ * @param file $f
253
+ * @param MP4Info_Box|false $parent
254
+ * @return MP4Info_Box
255
+ * @access public
256
+ * @static
257
+ */
258
+ public static function fromStream($f,$parent=false) {
259
+ // Get box header
260
+ $buf = fread($f,8);
261
+ if (strlen($buf) < 8) {
262
+ return false;
263
+ }
264
+ $ar = unpack('NtotalSize/NboxType',$buf);
265
+ if ($ar['totalSize'] == 1) {
266
+ // Size is bigger than 4GB :-O die
267
+ // Skip ExtendedSize(UI64) and try to decode anyway
268
+ $buf = fread($f,8);
269
+ $ar2 = unpack('N2extSize',$buf);
270
+ if ($ar2['extSize1'] > 0) {
271
+ throw new Exception('Extended size not supported');
272
+ } else {
273
+ $ar['totalSize'] = $ar2['extSize2'];
274
+ }
275
+ }
276
+
277
+ // Check if we need to skip
278
+ if (self::skipBoxType($ar['boxType'])) {
279
+ //print '+++ Skipping box '.pack('N',$ar['boxType']).'<br>';
280
+ fseek($f,$ar['totalSize']-8,SEEK_CUR);
281
+ return self::fromStream($f,$parent);
282
+ }
283
+
284
+ // Check if box is a container, and skip it if so
285
+ if (self::ignoreBoxType($ar['boxType'])) {
286
+ //print '+++ Ignoring box '.pack('N',$ar['boxType']).' of size '.$ar['totalSize'].'<br>';
287
+ return self::fromStream($f,$parent);
288
+ }
289
+
290
+ // Get box content
291
+ if ($ar['totalSize'] > 0) {
292
+ if ($ar['totalSize'] < 256*1024) {
293
+ $data = fread($f,$ar['totalSize']-8);
294
+ } else {
295
+ $data = $f;
296
+ }
297
+ } else {
298
+ $data = '';
299
+ }
300
+
301
+ // Create box object
302
+ $box = MP4Info_Box::factory($ar['totalSize'], $ar['boxType'], $data, $parent);
303
+ //print 'Got box from stream of type 0x'.dechex($ar['boxType']).'('.pack('N',$ar['boxType']).') and size '.$ar['totalSize'].' bytes: '.$box->toString().'<br>';
304
+ return $box;
305
+ } // fromStream method
306
+
307
+
308
+ /**
309
+ * Check if we need to ignore that box, based on type
310
+ *
311
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
312
+ * @param int $boxType
313
+ * @return bool
314
+ * @access public
315
+ * @static
316
+ * @todo Cleanup, legacy stuff
317
+ */
318
+ public static function ignoreBoxType($boxType) {
319
+ return false;
320
+ } // ignoreBoxType method
321
+
322
+
323
+ /**
324
+ * Check if we need to skip a box based on type
325
+ *
326
+ * @param int $boxType
327
+ * @return bool
328
+ * @access public
329
+ * @static
330
+ */
331
+ public static function skipBoxType($boxType) {
332
+ switch ($boxType) {
333
+ case 0x696f6473: // iods 5.1 Initial Object Descriptor Box
334
+ case 0x55c40000: // ??? ??
335
+ case 0x6d646174: // mdat ?? Movie Data
336
+ case 0x736d6864: // smhd 8.11.3 Sound Media Header Box
337
+ case 0x766d6864: // vmhd 8.11.2 Video Media Header Box
338
+ case 0x6e6d6864: // nmhd 8.11.5 Null Media Header Box
339
+ case 0x64696e66: // dinf ??
340
+ case 0x73747473: // stts 8.15.2 Decoding Time to Sample Box
341
+ case 0x73747363: // stsc 8.18 Sample To Chunk Box
342
+ case 0x7374737a: // stsz 8.17 Sample Size Boxes
343
+ case 0x7374636f: // stco 8.19 Chunk Offset Box
344
+ case 0x636f3634: // co64 8.19 Chunk Offset Box
345
+ case 0x63747473: // ctts 8.15.3 Composition Time to Sample Box
346
+ case 0x73747373: // stss 8.20 Sync Sample Box
347
+ case 0x74726566: // tref 8.6 Track Reference Box
348
+ return true;
349
+ default:
350
+ return false;
351
+ }
352
+ } // skipBoxType method
353
+
354
+
355
+ /**
356
+ * Total size getter
357
+ *
358
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
359
+ * @return int
360
+ * @access public
361
+ */
362
+ public function getTotalSize() {
363
+ return $this->totalSize;
364
+ } // getTotalSize method
365
+
366
+
367
+ /**
368
+ * Box type getter
369
+ *
370
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
371
+ * @return int
372
+ * @access public
373
+ */
374
+ public function getBoxType() {
375
+ return $this->boxType;
376
+ } // getBoxType method
377
+
378
+
379
+ /**
380
+ * Box type string getter
381
+ *
382
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
383
+ * @return string
384
+ * @access public
385
+ */
386
+ public function getBoxTypeStr() {
387
+ return $this->boxTypeStr;
388
+ } // getBoxTypeStr method
389
+
390
+
391
+ /**
392
+ * Data getter
393
+ *
394
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
395
+ * @return string(binary)
396
+ * @access public
397
+ */
398
+ public function getData() {
399
+ return $this->data;
400
+ } // getData method
401
+
402
+
403
+ /**
404
+ * stdClass converter
405
+ *
406
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
407
+ * @return stdClass
408
+ * @access public
409
+ */
410
+ public function toStdClass() {
411
+ $a = new stdClass();
412
+ foreach ($this as $propName=>$prop) {
413
+ if (($propName != 'children') && ($propName != 'parent') && ($propName != 'boxes')) {
414
+ $a->{$propName} = $prop;
415
+ }
416
+ }
417
+ return $a;
418
+ } // toStdClass method
419
+
420
+
421
+ /**
422
+ * String converter
423
+ *
424
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
425
+ * @return string
426
+ * @access public
427
+ */
428
+ public function toString() {
429
+ return '[MP4Info_Box[0x'.dechex($this->boxType).'('.pack('N',$this->boxType).']]';
430
+ } // toString method
431
+ } // MP4Info_Box class
432
+
433
+
434
+ // {{{ Dependencies
435
+ include "Box/Container.php";
436
+ include "Box/ftyp.php";
437
+ include "Box/uuid.php";
438
+ include "Box/hdlr.php";
439
+ include "Box/tkhd.php";
440
+ include "Box/mvhd.php";
441
+ include "Box/mdhd.php";
442
+ include "Box/meta.php";
443
+ include "Box/stsd.php";
444
+ include "Box/ilst.php";
445
+ include "Box/ilst_sub.php";
446
+ // }}} Dependencies
includes/lib/MP4Info/Box/Container.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/Container.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * Generic container box
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.1.20090611 $Id: Container.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info_Box_Container extends MP4Info_Box {
21
+ /**
22
+ * Constructor
23
+ *
24
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
25
+ * @param int $totalSize
26
+ * @param int $boxType
27
+ * @param file|string $data
28
+ * @param MP4Info_Box $parent
29
+ * @return MP4Info_Box_Container
30
+ * @access public
31
+ * @throws MP4Info_Exception
32
+ */
33
+ public function __construct($totalSize, $boxType, $data, $parent) {
34
+ if (!self::isCompatible($boxType, $parent)) {
35
+ throw new MP4Info_Exception('This box isn\'t a container',MP4Info_Exception::CODE_INCOMPATIBLE,$boxType);
36
+ }
37
+
38
+ // Call ancestor
39
+ parent::__construct($totalSize, $boxType, false, $parent);
40
+
41
+ // Unpack
42
+ if (is_string($data)) {
43
+ while ($data != '') {
44
+ try {
45
+ $box = MP4Info_Box::fromString($data, $this);
46
+ if (!$box instanceof MP4Info_Box) {
47
+ break;
48
+ }
49
+ } catch (Exception $e) {
50
+ break;
51
+ }
52
+ }
53
+ } else {
54
+ do {
55
+ try {
56
+ $box = MP4Info_Box::fromStream($data, $this);
57
+ if (!$box instanceof MP4Info_Box) {
58
+ break;
59
+ }
60
+ } catch (Exception $e) {
61
+ break;
62
+ }
63
+ } while ($box !== false);
64
+ }
65
+ } // Constructor
66
+
67
+
68
+ /**
69
+ * Check if block is compatible with class
70
+ *
71
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
72
+ * @param int $boxType
73
+ * @param MP4Info_Box $parent
74
+ * @return bool
75
+ * @access public
76
+ * @static
77
+ */
78
+ public static function isCompatible($boxType, $parent) {
79
+ return ($boxType == 0x6D6F6F76) || // moov
80
+ ($boxType == 0x7472616B) || // trak
81
+ ($boxType == 0x6d646961) || // mdia
82
+ ($boxType == 0x6D696E66) || // minf
83
+ ($boxType == 0x7374626c) || // stbl
84
+ ($boxType == 0x75647461) || // udta
85
+ false;
86
+ } // isCompatible method
87
+
88
+
89
+ /**
90
+ * String converter
91
+ *
92
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
93
+ * @return string
94
+ * @access public
95
+ */
96
+ public function toString() {
97
+ return '[MP4Info_Box_Container['.$this->boxTypeStr.']:'.count($this->children).']';
98
+ } // toString method
99
+ } // MP4Info_Box_Container method
includes/lib/MP4Info/Box/ftyp.php ADDED
@@ -0,0 +1,231 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/ftyp.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * 4.3 File Type Box (FTYP)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.1.20090611 $Id: ftyp.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info_Box_ftyp extends MP4Info_Box {
21
+ /**
22
+ * Major brand
23
+ *
24
+ * @var int
25
+ */
26
+ protected $majorBrand;
27
+
28
+ /**
29
+ * Minor brand
30
+ *
31
+ * @var int
32
+ */
33
+ protected $minorBrand;
34
+
35
+ /**
36
+ * Compatible brands
37
+ *
38
+ * @var int[]
39
+ */
40
+ protected $compatibleBrands;
41
+
42
+ /**
43
+ * Major Brands' names
44
+ *
45
+ * @var {n:Str,n:Str,...}
46
+ * @static
47
+ */
48
+ protected static $brandNames = array(
49
+ '3g2a' => '3GPP2 Media (.3G2)',
50
+ '3ge6' => '3GPP (.3GP) Release 6 MBMS Extended Presentations',
51
+ '3ge7' => '3GPP (.3GP) Release 7 MBMS Extended Presentations',
52
+ '3gg6' => '3GPP Release 6 General Profile',
53
+ '3gp1' => '3GPP Media (.3GP) Release 1 ? (non-existent)',
54
+ '3gp2' => '3GPP Media (.3GP) Release 2 ? (non-existent)',
55
+ '3gp3' => '3GPP Media (.3GP) Release 3 ? (non-existent)',
56
+ '3gp4' => '3GPP Media (.3GP) Release 4',
57
+ '3gp5' => '3GPP Media (.3GP) Release 5',
58
+ '3gp6' => '3GPP Media (.3GP) Release 6 Basic Profile',
59
+ '3gr6' => '3GPP Media (.3GP) Release 6 Progressive Download',
60
+ '3gs6' => '3GPP Media (.3GP) Release 6 Streaming Servers',
61
+ '3gs7' => '3GPP Media (.3GP) Release 7 Streaming Servers',
62
+ 'avc1' => 'MP4 Base w/ AVC ext [ISO 14496-12:2005]',
63
+ 'caep' => 'Canon Digital Camera',
64
+ 'caqv' => 'Casio Digital Camera',
65
+ 'cdes' => 'Convergent Design',
66
+ 'f4v' => 'Video for Adobe Flash Player 9+ (.F4V)',
67
+ 'f4p' => 'Protected Video for Adobe Flash Player 9+ (.F4P)',
68
+ 'f4a' => 'Audio for Adobe Flash Player 9+ (.F4A)',
69
+ 'f4b' => 'Audio Book for Adobe Flash Player 9+ (.F4B)',
70
+ 'isc2' => 'ISMACryp 2.0 Encrypted File',
71
+ 'iso2' => 'MP4 Base Media v2 [ISO 14496-12:2005]',
72
+ 'isom' => 'MP4  Base Media v1 [IS0 14496-12:2003]',
73
+ 'jp2' => 'JPEG 2000 Image (.JP2) [ISO 15444-1 ?]',
74
+ 'jp20' => 'Unknown, from GPAC samples (prob non-existent)',
75
+ 'jpm' => 'JPEG 2000 Compound Image (.JPM) [ISO 15444-6]',
76
+ 'jpx' => 'JPEG 2000 w/ extensions (.JPX) [ISO 15444-2]',
77
+ 'kddi' => '3GPP2 EZmovie for KDDI 3G Cellphones',
78
+ 'm4a ' => 'Apple iTunes AAC-LC (.M4A) Audio',
79
+ 'm4b ' => 'Apple iTunes AAC-LC (.M4B) Audio Book',
80
+ 'm4p ' => 'Apple iTunes AAC-LC (.M4P) AES Protected Audio',
81
+ 'm4v ' => 'Apple iTunes Video (.M4V) Video',
82
+ 'm4vh' => 'Apple TV (.M4V)',
83
+ 'm4vp' => 'Apple iPhone (.M4V)',
84
+ 'mj2s' => 'Motion JPEG 2000 [ISO 15444-3] Simple Profile',
85
+ 'mjp2' => 'Motion JPEG 2000 [ISO 15444-3] General Profile',
86
+ 'mmp4' => 'MPEG-4/3GPP Mobile Profile (.MP4 / .3GP) (for NTT)',
87
+ 'mp21' => 'MPEG-21 [ISO/IEC 21000-9]',
88
+ 'mp41' => 'MP4 v1 [ISO 14496-1:ch13]',
89
+ 'mp42' => 'MP4 v2 [ISO 14496-14]',
90
+ 'mp71' => 'MP4 w/ MPEG-7 Metadata [per ISO 14496-12]',
91
+ 'mppi' => 'Photo Player, MAF [ISO/IEC 23000-3]',
92
+ 'mqt' => 'Sony / Mobile QuickTime (.MQV)',
93
+ 'msnv' => 'MPEG-4 (.MP4) for SonyPSP',
94
+ 'ndas' => 'MP4 v2 [ISO 14496-14] Nero Digital AAC Audio',
95
+ 'ndsc' => 'MPEG-4 (.MP4) Nero Cinema Profile',
96
+ 'ndsh' => 'MPEG-4 (.MP4) Nero HDTV Profile',
97
+ 'ndsm' => 'MPEG-4 (.MP4) Nero Mobile Profile',
98
+ 'ndsp' => 'MPEG-4 (.MP4) Nero Portable Profile',
99
+ 'ndss' => 'MPEG-4 (.MP4) Nero Standard Profile',
100
+ 'ndxc' => 'H.264/MPEG-4 AVC (.MP4) Nero Cinema Profile',
101
+ 'ndxh' => 'H.264/MPEG-4 AVC (.MP4) Nero HDTV Profile',
102
+ 'ndxm' => 'H.264/MPEG-4 AVC (.MP4) Nero Mobile Profile',
103
+ 'ndxp' => 'H.264/MPEG-4 AVC (.MP4) Nero Portable Profile',
104
+ 'ndxs' => 'H.264/MPEG-4 AVC (.MP4) Nero Standard Profile',
105
+ 'odcf  ' => 'OMA DCF DRM Format 2.0 (OMA-TS-DRM-DCF-V2_0-20060303-A)',
106
+ 'opf2 ' => 'OMA PDCF DRM Format 2.1 (OMA-TS-DRM-DCF-V2_1-20070724-C)',
107
+ 'opx2  ' => 'OMA PDCF DRM + XBS extensions (OMA-TS-DRM_XBS-V1_0-20070529-C)',
108
+ 'qt  ' => 'Apple QuickTime (.MOV/QT)',
109
+ 'sdv' => 'SD Memory Card Video',
110
+ );
111
+
112
+
113
+ /**
114
+ * Constructor
115
+ *
116
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
117
+ * @param int $totalSize
118
+ * @param int $boxType
119
+ * @param file|string $data
120
+ * @param MP4Info_Box $parent
121
+ * @return MP4Info_Box_ftyp
122
+ * @access public
123
+ * @throws MP4Info_Exception
124
+ */
125
+ public function __construct($totalSize, $boxType, $data, $parent) {
126
+ if (!self::isCompatible($boxType, $parent)) {
127
+ throw new MP4Info_Exception('This box isn\'t "ftyp"',MP4Info_Exception::CODE_INCOMPATIBLE,$boxType);
128
+ }
129
+
130
+ // Call ancestor
131
+ parent::__construct($totalSize, $boxType, false, $parent);
132
+
133
+ // Get data
134
+ $data = self::getDataFrom3rd($data, $totalSize);
135
+
136
+ // Unpack
137
+ $ar = unpack('NmajorBrand/NminorVersion/N*compatibleBrands',$data);
138
+ $compatibleBrands = array();
139
+ foreach ($ar as $k=>$v) {
140
+ if (substr($k,0,16) == 'compatibleBrands') {
141
+ $compatibleBrands[] = $v;
142
+ }
143
+ }
144
+
145
+ // Save properties
146
+ $this->majorBrand = $ar['majorBrand'];
147
+ $this->minorVersion = $ar['minorVersion'];
148
+ $this->compatibleBrands = $compatibleBrands;
149
+ } // Constructor
150
+
151
+
152
+ /**
153
+ * Check if block is compatible with class
154
+ *
155
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
156
+ * @param int $boxType
157
+ * @param MP4Info_Box $parent
158
+ * @return bool
159
+ * @access public
160
+ * @static
161
+ */
162
+ static function isCompatible($boxType, $parent) {
163
+ return $boxType == 0x66747970;
164
+ } // isCompatible method
165
+
166
+
167
+ /**
168
+ * Major brand getter
169
+ *
170
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
171
+ * @return int
172
+ * @access public
173
+ */
174
+ public function getMajorBrand() {
175
+ return $this->majorBrand;
176
+ } // getMajorBrand method
177
+
178
+
179
+ /**
180
+ * Minor version getter
181
+ *
182
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
183
+ * @return int
184
+ * @access public
185
+ */
186
+ public function getMinorVersion() {
187
+ return $this->minorVersion;
188
+ } // getMinorVersion method
189
+
190
+
191
+ /**
192
+ * Compatible brands getter
193
+ *
194
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
195
+ * @return int[]
196
+ * @access public
197
+ */
198
+ public function getCompatibleBrands() {
199
+ return $this->compatibleBrands;
200
+ } // getCompatibleBrands method
201
+
202
+
203
+ /**
204
+ * Convert a brand 32bit code to a string
205
+ *
206
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
207
+ * @param int $brand
208
+ * @return string
209
+ * @access public
210
+ * @static
211
+ */
212
+ public static function brandToString($brand) {
213
+ if (isset(self::$$brandNames[$brand])) {
214
+ return self::$$brandNames[$brand];
215
+ } else {
216
+ return $brand;
217
+ }
218
+ } // brandToString method
219
+
220
+
221
+ /**
222
+ * String converter
223
+ *
224
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
225
+ * @return string
226
+ * @access public
227
+ */
228
+ public function toString() {
229
+ return '[MP4Info_Box_ftyp]';
230
+ } // toString method
231
+ } // MP4Info_Box_ftyp method
includes/lib/MP4Info/Box/hdlr.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/hdlr.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * 8.9 Handler Reference Box (HDLR)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: hdlr.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ * @todo Factor this into a fullbox
20
+ */
21
+ class MP4Info_Box_hdlr extends MP4Info_Box {
22
+ // {{{ Constants
23
+ const HANDLER_VIDEO = 'vide';
24
+ const HANDLER_SOUND = 'soun';
25
+ // }}} Constants
26
+
27
+ /**
28
+ * Handler type
29
+ *
30
+ * @var uint32
31
+ */
32
+ protected $handlerType;
33
+
34
+ /**
35
+ * Name
36
+ *
37
+ * @var string
38
+ */
39
+ protected $name;
40
+
41
+ /**
42
+ * Timezone
43
+ *
44
+ * @var int
45
+ * @static
46
+ */
47
+ protected static $timezone = false;
48
+
49
+ /**
50
+ * Constructor
51
+ *
52
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
53
+ * @param int $totalSize
54
+ * @param int $boxType
55
+ * @param file|string $data
56
+ * @param MP4Info_Box $parent
57
+ * @return MP4Info_Box_hdlr
58
+ * @access public
59
+ * @throws MP4Info_Exception
60
+ */
61
+ public function __construct($totalSize, $boxType, $data, $parent) {
62
+ if (!self::isCompatible($boxType, $parent)) {
63
+ throw new Exception('This box isn\'t "ftyp"');
64
+ }
65
+
66
+ // Get timezone
67
+ if (self::$timezone === false) {
68
+ self::$timezone = date('Z');
69
+ }
70
+
71
+ // Call ancestor
72
+ parent::__construct($totalSize,$boxType,'',$parent);
73
+
74
+ // Get data
75
+ $data = self::getDataFrom3rd($data,$totalSize);
76
+
77
+ // Unpack
78
+ $ar = unpack('Cversion/C3flags',$data);
79
+ if ($ar['version'] == 0) {
80
+ // 32 bit
81
+ $ar2 = unpack('Nctime/Nmtime/NtimeScale/Nduration',substr($data,4));
82
+ $len = 6*4;
83
+ } else if ($ar['version'] == 1) {
84
+ // 64 bit
85
+ $ar2 = unpack('N2ctime/N2mtime/NtimeScale/N2duration',substr($data,4));
86
+ $len = 9*4;
87
+ } else {
88
+ throw new Exception('Unhandled version: '.$ar['version']);
89
+ }
90
+
91
+ // Save
92
+ $this->version = $ar['version'];
93
+ $this->flags = $ar['flags1']*65536+$ar['flags1']*256+$ar['flags1']*1;
94
+ $this->ctime = date('r',(isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1'])-2082826800-self::$timezone);
95
+ $this->mtime = date('r',(isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1'])-2082826800-self::$timezone);
96
+ $this->timeScale = $ar2['timeScale'];
97
+ $this->duration = (isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']);
98
+ $this->handlerType = substr($data,$len,4);
99
+ $this->name = substr($data,$len+8,-1);
100
+ } // Constructor
101
+
102
+
103
+ /**
104
+ * Check if block is compatible with class
105
+ *
106
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
107
+ * @param int $boxType
108
+ * @param MP4Info_Box $parent
109
+ * @return bool
110
+ * @access public
111
+ * @static
112
+ */
113
+ static public function isCompatible($boxType, $parent) {
114
+ return $boxType == 0x68646c72;
115
+ } // isCompatible method
116
+
117
+
118
+ /**
119
+ * Handler type getter
120
+ *
121
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
122
+ * @return int
123
+ * @access public
124
+ */
125
+ public function getHandlerType() {
126
+ return $this->handlerType;
127
+ } // getHandlerType method
128
+
129
+
130
+ /**
131
+ * String converter
132
+ *
133
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
134
+ * @return string
135
+ * @access public
136
+ */
137
+ public function toString() {
138
+ return '[MP4Info_Box_hdlr:'.$this->handlerType.']';
139
+ } // toString method
140
+ } // MP4Info_Box_hdlr class
includes/lib/MP4Info/Box/ilst.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/ilst.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x ??? (ILST)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: ilst.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info_Box_ilst extends MP4Info_Box_Container {
21
+ /**
22
+ * Values
23
+ *
24
+ * @var {}
25
+ * @access protected
26
+ */
27
+ protected $values = array();
28
+
29
+
30
+ /**
31
+ * Constructor
32
+ *
33
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
34
+ * @param int $totalSize
35
+ * @param int $boxType
36
+ * @param file|string $data
37
+ * @param MP4Info_Box $parent
38
+ * @return MP4Info_Box_ilst
39
+ * @access public
40
+ * @throws MP4Info_Exception
41
+ */
42
+ public function __construct($totalSize, $boxType, $data, $parent) {
43
+ if (!self::isCompatible($boxType, $parent)) {
44
+ throw new MP4Info_Exception('This box isn\'t "ilst"', MP4Info_Exception::CODE_INCOMPATIBLE, $boxType);
45
+ }
46
+
47
+ // Call ancestor
48
+ parent::__construct($totalSize, $boxType, $data, $parent);
49
+ } // Constructor
50
+
51
+
52
+ /**
53
+ * Check if block is compatible with class
54
+ *
55
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
56
+ * @param int $boxType
57
+ * @param MP4Info_Box $parent
58
+ * @return bool
59
+ * @access public
60
+ * @static
61
+ */
62
+ static public function isCompatible($boxType, $parent) {
63
+ return $boxType == 0x696C7374;
64
+ } // isCompatible method
65
+
66
+
67
+ /**
68
+ * Check if a given key has a value
69
+ *
70
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
71
+ * @param string $k
72
+ * @return bool
73
+ * @access public
74
+ */
75
+ public function hasValue($k) {
76
+ return (isset($this->values[$k])) || (isset($this->values[utf8_decode($k)]));
77
+ } // hasValue method
78
+
79
+
80
+ /**
81
+ * Get the value of a given key
82
+ *
83
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
84
+ * @param string $k
85
+ * @return mixed
86
+ * @access public
87
+ */
88
+ public function getValue($k) {
89
+ if (isset($this->values[$k])) {
90
+ return $this->values[$k];
91
+ } else if (isset($this->values[utf8_decode($k)])) {
92
+ return $this->values[utf8_decode($k)];
93
+ } else {
94
+ return false;
95
+ }
96
+ } // getValue method
97
+
98
+
99
+ /**
100
+ * Set a value for a given key
101
+ *
102
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
103
+ * @param string $k
104
+ * @param mixed $v
105
+ * @access public
106
+ */
107
+ public function setKeyValue($k,$v) {
108
+ $this->values[$k] = $v;
109
+ } // setKeyValue method
110
+
111
+
112
+ /**
113
+ * String converter
114
+ *
115
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
116
+ * @return string
117
+ * @access public
118
+ */
119
+ public function toString() {
120
+ return '[MP4Info_Box_ilst:'.count($this->boxes).']';
121
+ } // toString method
122
+ } // MP4Info_Box_ilst class
includes/lib/MP4Info/Box/ilst_sub.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/ilst_sub.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x ILST sub blocks (numerous)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.1.20090611 $Id: ilst_sub.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info_Box_ilst_sub extends MP4Info_Box {
21
+ /**
22
+ * Constructor
23
+ *
24
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
25
+ * @param int $totalSize
26
+ * @param int $boxType
27
+ * @param file|string $f
28
+ * @param MP4Info_Box $parent
29
+ * @return MP4Info_Box_ilst_sub
30
+ * @access public
31
+ * @throws MP4Info_Exception
32
+ */
33
+ public function __construct($totalSize, $boxType, $data, $parent) {
34
+ if (!$parent instanceof MP4Info_Box_ilst) {
35
+ throw new MP4Info_Exception('This box isn\'t "islt" child', MP4Info_Exception::CODE_INCOMPATIBLE, $boxType);
36
+ }
37
+
38
+ // Call ancestor
39
+ parent::__construct($totalSize,$boxType,$data,$parent);
40
+
41
+ // Get data
42
+ $data = $this->data;
43
+
44
+ // Unpack
45
+ $type = self::getType($this->boxType);
46
+ $ar = unpack('Nlen',$data);
47
+ if (substr($data,4,4) == 'data') {
48
+ $info = substr($data,8,$ar['len']-8);
49
+ switch ($type) {
50
+ case 'uint8':
51
+ $info = reset(unpack('C',$info));
52
+ break;
53
+ case 'uint16':
54
+ $info = reset(unpack('n',$info));
55
+ break;
56
+ case 'uint32':
57
+ $info = reset(unpack('N',$info));
58
+ break;
59
+ case 'text':
60
+ break;
61
+ }
62
+ $this->data = $info;
63
+ $parent->setKeyValue($this->boxTypeStr, $info);
64
+ } else {
65
+ throw new MP4Info_Exception('Didn\'t get the "data" code');
66
+ }
67
+ } // Constructor
68
+
69
+
70
+ /**
71
+ * Check if block is compatible with class
72
+ *
73
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
74
+ * @param int $boxType
75
+ * @param MP4Info_Box $parent
76
+ * @return bool
77
+ * @access public
78
+ * @static
79
+ */
80
+ static public function isCompatible($boxType, $parent) {
81
+ return ($parent instanceof MP4Info_Box_ilst);
82
+ } // isCompatible method
83
+
84
+
85
+ /**
86
+ * Get sub type
87
+ * http://atomicparsley.sourceforge.net/mpeg-4files.html
88
+ *
89
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
90
+ * @param int $boxType
91
+ * @return string
92
+ * @access protected
93
+ * @static
94
+ * @todo The © codes should be chr(...), as utf8 encoding messes things up
95
+ */
96
+ static protected function getType($boxType) {
97
+ switch (pack('N',$boxType)) {
98
+ case '©alb':
99
+ case '©art':
100
+ case 'aART':
101
+ case '©cmt':
102
+ case '©day':
103
+ case '©nam':
104
+ case '©gen':
105
+ case '©wrt':
106
+ case '©too':
107
+ case 'cprt':
108
+ case '©grp':
109
+ case 'catg':
110
+ case 'desc':
111
+ case '©lyr':
112
+ case 'tvnn':
113
+ case 'tvsh':
114
+ case 'tven':
115
+ case 'purd':
116
+ return 'text';
117
+
118
+ case 'gnre':
119
+ case 'trkn':
120
+ case 'disk':
121
+ case 'tmpo':
122
+ case 'cpil':
123
+ case 'rtng':
124
+ case 'stik':
125
+ case 'pcst':
126
+ case 'purl':
127
+ case 'egid':
128
+ case 'tvsn':
129
+ case 'tves':
130
+ case 'pgap':
131
+ return 'uint8';
132
+ default:
133
+ return '';
134
+ }
135
+ } // getType method
136
+
137
+
138
+ /**
139
+ * String converter
140
+ *
141
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
142
+ * @return string
143
+ * @access public
144
+ */
145
+ public function toString() {
146
+ return '[MP4Info_Box_ilst_sub['.$this->boxTypeStr.']:'.$this->getData().']';
147
+ } // toString converter
148
+ } // MP4Info_Box_ilst_sub class
includes/lib/MP4Info/Box/mdhd.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/mdhd.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * 8.8 Media Header Box (MDHD)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090611 $Id: mdhd.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ * @todo Factor this into a fullbox
20
+ */
21
+ class MP4Info_Box_mdhd extends MP4Info_Box {
22
+ /**
23
+ * Version
24
+ *
25
+ * @var int
26
+ */
27
+ protected $version;
28
+
29
+ /**
30
+ * Flags
31
+ *
32
+ * @var int
33
+ */
34
+ protected $flags;
35
+
36
+ /**
37
+ * Creation time
38
+ *
39
+ * @var string
40
+ */
41
+ protected $ctime;
42
+
43
+ /**
44
+ * Modification time
45
+ *
46
+ * @var unknown_type
47
+ */
48
+ protected $mtime;
49
+
50
+ /**
51
+ * Time scale
52
+ *
53
+ * @var int
54
+ */
55
+ protected $timeScale;
56
+
57
+ /**
58
+ * Duration
59
+ *
60
+ * @var int
61
+ */
62
+ protected $duration;
63
+
64
+ /**
65
+ * Time zone
66
+ *
67
+ * @var int
68
+ * @static
69
+ */
70
+ protected static $timezone = false;
71
+
72
+
73
+ /**
74
+ * Constructor
75
+ *
76
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
77
+ * @param int $totalSize
78
+ * @param int $boxType
79
+ * @param file|string $data
80
+ * @param MP4Info_Box $parent
81
+ * @return MP4Info_Box_mdhd
82
+ * @access public
83
+ * @throws MP4Info_Exception
84
+ */
85
+ public function __construct($totalSize, $boxType, $data, $parent) {
86
+ if (!self::isCompatible($boxType, $parent)) {
87
+ throw new Exception('This box isn\'t "mdhd"');
88
+ }
89
+
90
+ // Get timezone
91
+ if (self::$timezone === false) {
92
+ self::$timezone = date('Z');
93
+ }
94
+
95
+ // Call ancestor
96
+ parent::__construct($totalSize, $boxType, '', $parent);
97
+
98
+ // Unpack
99
+ $ar = unpack('Cversion/C3flags',$data);
100
+ if ($ar['version'] == 0) {
101
+ // 32 bit
102
+ $ar2 = unpack('Nctime/Nmtime/NtimeScale/Nduration/nlanguage/ndummy',substr($data,4));
103
+ } else if ($ar['version'] == 1) {
104
+ // 64 bit
105
+ $ar2 = unpack('N2ctime/N2mtime/NtimeScale/N2duration/nlanguage/ndummy',substr($data,4));
106
+ } else {
107
+ throw new Exception('Unhandled version: '.$ar['version']);
108
+ }
109
+
110
+ // Save
111
+ $this->version = $ar['version'];
112
+ $this->flags = $ar['flags1']*65536+$ar['flags1']*256+$ar['flags1']*1;
113
+ $this->ctime = date('r',(isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1'])-2082826800-self::$timezone);
114
+ $this->mtime = date('r',(isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1'])-2082826800-self::$timezone);
115
+ $this->timeScale = $ar2['timeScale'];
116
+ $this->duration = (isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']);
117
+ $this->language = MP4Info_Helper::fromPackedLetters($ar2['language'],1);
118
+ } // Constructor
119
+
120
+
121
+ /**
122
+ * Check if block is compatible with class
123
+ *
124
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
125
+ * @param int $boxType
126
+ * @param MP4Info_Box $parent
127
+ * @return bool
128
+ * @access public
129
+ * @static
130
+ */
131
+ static function isCompatible($boxType, $parent) {
132
+ return $boxType == 0x6d646864;
133
+ } // isCompatible method
134
+
135
+
136
+ /**
137
+ * String converter
138
+ *
139
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
140
+ * @return string
141
+ * @access public
142
+ */
143
+ public function toString() {
144
+ return '[MP4Info_Box_mdhd]';
145
+ } // toString method
146
+ } // MP4Info_Box_mdhd class
includes/lib/MP4Info/Box/meta.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/meta.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x Meta (META)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: meta.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info_Box_meta extends MP4Info_Box_container {
21
+
22
+ /**
23
+ * Constructor
24
+ *
25
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
26
+ * @param int $totalSize
27
+ * @param int $boxType
28
+ * @param file|string $f
29
+ * @param MP4Info_Box_meta $parent
30
+ * @access public
31
+ * @throws MP4Info_Exception
32
+ */
33
+ public function __construct($totalSize, $boxType, $data, $parent=false) {
34
+ if (!self::isCompatible($boxType, $parent)) {
35
+ throw new MP4Info_Exception('This box isn\'t "meta"',MP4Info_Exception::CODE_INCOMPATIBLE,false,$boxType);
36
+ }
37
+
38
+ $ar = unpack('Nlen',$data);
39
+
40
+ parent::__construct($totalSize, $boxType, substr($data,4,$ar['len']), $parent);
41
+ } // Constructor
42
+
43
+
44
+ /**
45
+ * Check if block is compatible with class
46
+ *
47
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
48
+ * @param int $boxType
49
+ * @param MP4Info_Box $parent
50
+ * @return bool
51
+ * @access public
52
+ * @static
53
+ */
54
+ static public function isCompatible($boxType, $parent) {
55
+ return $boxType == 0x6D657461;
56
+ } // isCompatible method
57
+
58
+
59
+ /**
60
+ * String converter
61
+ *
62
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
63
+ * @return string
64
+ * @access public
65
+ */
66
+ public function toString() {
67
+ return '[MP4Info_Box_meta:'.count($this->boxes).']';
68
+ } // toString method
69
+ } // MP4Info_Box_meta class
includes/lib/MP4Info/Box/mvhd.php ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/mvhd.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x Movie Header (MVHD)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: mvhd.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ * @todo Factor this into a fullbox
20
+ */
21
+ class MP4Info_Box_mvhd extends MP4Info_Box {
22
+ /**
23
+ * Version
24
+ *
25
+ * @var int
26
+ */
27
+ protected $version;
28
+
29
+ /**
30
+ * Flags
31
+ *
32
+ * @var int
33
+ */
34
+ protected $flags;
35
+
36
+ /**
37
+ * Creation time
38
+ *
39
+ * @var string
40
+ */
41
+ protected $ctime;
42
+
43
+ /**
44
+ * Modification time
45
+ *
46
+ * @var unknown_type
47
+ */
48
+ protected $mtime;
49
+
50
+ /**
51
+ * Time scale
52
+ *
53
+ * @var int
54
+ */
55
+ protected $timeScale;
56
+
57
+ /**
58
+ * Duration
59
+ *
60
+ * @var int
61
+ */
62
+ protected $duration;
63
+
64
+ /**
65
+ * Rate
66
+ *
67
+ * @var int
68
+ */
69
+ protected $rate;
70
+
71
+ /**
72
+ * Volume
73
+ *
74
+ * @var int
75
+ */
76
+ protected $volume;
77
+
78
+ /**
79
+ * Time zone
80
+ *
81
+ * @var int
82
+ * @static
83
+ */
84
+ protected static $timezone = false;
85
+
86
+
87
+ /**
88
+ * Constructor
89
+ *
90
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
91
+ * @param int $totalSize
92
+ * @param int $boxType
93
+ * @param file|string $data
94
+ * @param MP4Info_Box $parent
95
+ * @return MP4Info_Box_mvhd
96
+ * @access public
97
+ * @throws MP4Info_Exception
98
+ */
99
+ public function __construct($totalSize, $boxType, $data, $parent) {
100
+ if (!self::isCompatible($boxType)) {
101
+ throw new Exception('This box isn\'t "mvhd"');
102
+ }
103
+
104
+ // Get timezone
105
+ if (self::$timezone === false) {
106
+ self::$timezone = date('Z');
107
+ }
108
+
109
+ // Call ancestor's constructor
110
+ parent::__construct($totalSize,$boxType,'',$parent);
111
+
112
+ // Unpack
113
+ $ar = unpack('Cversion/C3flags',$data);
114
+ if ($ar['version'] == 0) {
115
+ // 32 bit
116
+ $ar2 = unpack('Nctime/Nmtime/NtimeScale/Nduration/Nrate/nvolume/ndummy/N2dummy2/N9matrix/N3dummy3/NnextTrack',substr($data,4));
117
+ } else if ($ar['version'] == 1) {
118
+ // 64 bit
119
+ $ar2 = unpack('N2ctime/N2mtime/NtimeScale/N2duration/Nrate/nvolume/ndummy/N2dummy2/N9matrix/N3dummy3/NnextTrack',substr($data,4));
120
+ } else {
121
+ throw new Exception('Unhandled version: '.$ar['version']);
122
+ }
123
+
124
+ // Save
125
+ $this->version = $ar['version'];
126
+ $this->flags = $ar['flags1']*65536+$ar['flags1']*256+$ar['flags1']*1;
127
+ $this->ctime = date('r',(isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1'])-2082826800-self::$timezone);
128
+ $this->mtime = date('r',(isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1'])-2082826800-self::$timezone);
129
+ $this->timeScale = $ar2['timeScale'];
130
+ $this->duration = (isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']);
131
+ $this->rate = MP4Info_Helper::fromFixed16($ar2['rate']);
132
+ $this->volume = MP4Info_Helper::fromFixed8($ar2['volume']);
133
+ } // Constructor
134
+
135
+
136
+ /**
137
+ * Check if block is compatible with class
138
+ *
139
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
140
+ * @param int $boxType
141
+ * @param MP4Info_Box $parent
142
+ * @return bool
143
+ * @access public
144
+ * @static
145
+ */
146
+ static public function isCompatible($boxType) {
147
+ return $boxType == 0x6D766864;
148
+ } // isCompatible method
149
+
150
+
151
+ /**
152
+ * Creation time getter
153
+ *
154
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
155
+ * @return int
156
+ * @access public
157
+ */
158
+ public function getCreationTime() {
159
+ return $this->ctime;
160
+ } // getCreationTime method
161
+
162
+
163
+ /**
164
+ * Time scale getter
165
+ *
166
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
167
+ * @return int
168
+ * @access public
169
+ */
170
+ public function getTimeScale() {
171
+ return $this->timeScale;
172
+ } // getTimeScale method
173
+
174
+
175
+ /**
176
+ * Duration getter
177
+ *
178
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
179
+ * @return int
180
+ * @access public
181
+ */
182
+ public function getDuration() {
183
+ return $this->duration;
184
+ } // getDuration method
185
+
186
+
187
+ /**
188
+ * Real duration getter
189
+ *
190
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
191
+ * @return float
192
+ * @access public
193
+ */
194
+ public function getRealDuration() {
195
+ return $this->duration/$this->timeScale;
196
+ } // getRealDuration method
197
+
198
+
199
+ /**
200
+ * Rate getter
201
+ *
202
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
203
+ * @return int
204
+ * @access public
205
+ */
206
+ public function getRate() {
207
+ return $this->rate();
208
+ } // getRate method
209
+
210
+
211
+ /**
212
+ * Volume getter
213
+ *
214
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
215
+ * @return int
216
+ * @access public
217
+ */
218
+ public function getVolume() {
219
+ return $this->volume();
220
+ } // getVolume method
221
+
222
+
223
+ /**
224
+ * String converter
225
+ *
226
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
227
+ * @return string
228
+ * @access public
229
+ */
230
+ public function toString() {
231
+ return '[MP4Info_Box_mvhd]';
232
+ } // toString method
233
+ }
includes/lib/MP4Info/Box/stsd.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/stsd.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x ??? (STSD)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: stsd.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ * @todo Factor this into a fullbox
20
+ */
21
+ class MP4Info_Box_stsd extends MP4Info_Box {
22
+ /**
23
+ * Version
24
+ *
25
+ * @var int
26
+ */
27
+ protected $version;
28
+
29
+ /**
30
+ * Flags
31
+ *
32
+ * @var int
33
+ */
34
+ protected $flags;
35
+
36
+ /**
37
+ * Count
38
+ *
39
+ * @var int
40
+ */
41
+ protected $count;
42
+
43
+ /**
44
+ * Values
45
+ *
46
+ * @var string{}
47
+ */
48
+ protected $values = array();
49
+
50
+
51
+ /**
52
+ * Constructor
53
+ *
54
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
55
+ * @param int $totalSize
56
+ * @param int $boxType
57
+ * @param file|string $data
58
+ * @param MP4Info_Box $parent
59
+ * @return MP4Info_Box_stsd
60
+ * @access public
61
+ * @throws MP4Info_Exception
62
+ */
63
+ public function __construct($totalSize, $boxType, $data, $parent) {
64
+ if (!self::isCompatible($boxType, $parent)) {
65
+ throw new Exception('This box isn\'t "stsd"');
66
+ }
67
+
68
+ // Call ancestor
69
+ parent::__construct($totalSize,$boxType,'',$parent);
70
+
71
+ // Get data
72
+ $data = self::getDataFrom3rd($data, $totalSize);
73
+
74
+ // Unpack
75
+ $ar = unpack('Cversion/C3flags/Ncount',$data);
76
+ $this->version = $ar['version'];
77
+ $this->flags = $ar['flags1']*65536+$ar['flags1']*256+$ar['flags1']*1;
78
+ $this->count = $ar['count'];
79
+
80
+ // Unpack SAMPLEDESCRIPTION
81
+ $desc = substr($data,8);
82
+ for ($i=0;$i<$this->count;$i++) {
83
+ $ar = unpack('Nlen',$desc);
84
+ $type = substr($desc,4,4);
85
+ $info = substr($desc,8,$ar['len']-8);
86
+ $desc = substr($desc,$ar['len']);
87
+ $this->values[$type] = $info;
88
+ }
89
+ } // Constructor
90
+
91
+
92
+ /**
93
+ * Check if block is compatible with class
94
+ *
95
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
96
+ * @param int $boxType
97
+ * @param MP4Info_Box $parent
98
+ * @return bool
99
+ * @access public
100
+ * @static
101
+ */
102
+ static public function isCompatible($boxType, $parent) {
103
+ return $boxType == 0x73747364;
104
+ } // isCompatible method
105
+
106
+ /**
107
+ * Values getter
108
+ *
109
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
110
+ * @return string{}
111
+ * @access public
112
+ */
113
+ public function getValues() {
114
+ return $this->values;
115
+ } // getValues method
116
+
117
+ /**
118
+ * Value getter
119
+ *
120
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
121
+ * @param string $key
122
+ * @return string
123
+ * @access public
124
+ */
125
+ public function getValue($key) {
126
+ return isset($this->values[$key]) ? $this->values[$key] : false;
127
+ } // getValue method
128
+
129
+ /**
130
+ * String converter
131
+ *
132
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
133
+ * @return string
134
+ * @access public
135
+ */
136
+ public function toString() {
137
+ return '[MP4Info_Box_stsd:'.implode(',',array_keys($this->values)).']';
138
+ } // toString method
139
+ } // MP4Info_Box_stsd class
includes/lib/MP4Info/Box/tkhd.php ADDED
@@ -0,0 +1,215 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/tkhd.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x Track Header (TKHD)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.1.20090611 $Id: tkhd.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ * @todo Factor this into a fullbox
20
+ */
21
+ class MP4Info_Box_tkhd extends MP4Info_Box {
22
+ /**
23
+ * Version
24
+ *
25
+ * @var int
26
+ */
27
+ protected $version;
28
+
29
+ /**
30
+ * Flags
31
+ *
32
+ * @var int
33
+ */
34
+ protected $flags;
35
+
36
+ /**
37
+ * Creation time
38
+ *
39
+ * @var string
40
+ */
41
+ protected $ctime;
42
+
43
+ /**
44
+ * Modification time
45
+ *
46
+ * @var unknown_type
47
+ */
48
+ protected $mtime;
49
+
50
+ /**
51
+ * Time scale
52
+ *
53
+ * @var int
54
+ */
55
+ protected $timeScale;
56
+
57
+ /**
58
+ * Duration
59
+ *
60
+ * @var int
61
+ */
62
+ protected $duration;
63
+
64
+ /**
65
+ * Layer
66
+ *
67
+ * @var int
68
+ */
69
+ protected $layer;
70
+
71
+ /**
72
+ * Volume
73
+ *
74
+ * @var float
75
+ */
76
+ protected $volume;
77
+
78
+ /**
79
+ * Width
80
+ *
81
+ * @var float
82
+ */
83
+ protected $width;
84
+
85
+ /**
86
+ * Height
87
+ *
88
+ * @var float
89
+ */
90
+ protected $height;
91
+
92
+ /**
93
+ * Time zone
94
+ *
95
+ * @var int
96
+ * @static
97
+ */
98
+ protected static $timezone = false;
99
+
100
+ /**
101
+ * Constructor
102
+ *
103
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
104
+ * @param int $totalSize
105
+ * @param int $boxType
106
+ * @param file|string $data
107
+ * @param MP4Info_Box $parent
108
+ * @return MP4Info_Box_tkhd
109
+ * @access public
110
+ * @throws MP4Info_Exception
111
+ */
112
+ public function __construct($totalSize, $boxType, $data, $parent=false) {
113
+ if (!self::isCompatible($boxType,$parent)) {
114
+ throw new Exception('This box isn\'t "tkhd"');
115
+ }
116
+
117
+ // Get timezone
118
+ if (self::$timezone === false) {
119
+ self::$timezone = date('Z');
120
+ }
121
+
122
+ // Call ancestor's constructor
123
+ parent::__construct($totalSize,$boxType,'',$parent);
124
+
125
+ // Get data
126
+ $data = self::getDataFrom3rd($data,$totalSize);
127
+
128
+ // Unpack
129
+ $ar = unpack('Cversion/C3flags',$data);
130
+ if ($ar['version'] == 0) {
131
+ // 32 bit
132
+ $ar2 = unpack('Nctime/Nmtime/NtrackId/Ndummy/Nduration/N2dummy1/nlayer/naltGroup/nvolume/ndummy2/N9matrix/Nwidth/Nheight',substr($data,4));
133
+ } else if ($ar['version'] == 1) {
134
+ // 64 bit
135
+ $ar2 = unpack('N2ctime/N2mtime/NtrackId/Ndummy/N2duration/N2dummy1/nlayer/naltGroup/nvolume/ndummy2/N9matrix/Nwidth/Nheight',substr($data,4));
136
+ } else {
137
+ throw new Exception('Unhandled version: '.$ar['version']);
138
+ }
139
+
140
+ // Save
141
+ $this->version = $ar['version'];
142
+ $this->flags = $ar['flags1']*65536+$ar['flags1']*256+$ar['flags1']*1;
143
+ $this->ctime = date('r',(isset($ar2['ctime']) ? $ar2['ctime'] : $ar2['ctime1'])-2082826800-self::$timezone);
144
+ $this->mtime = date('r',(isset($ar2['mtime']) ? $ar2['mtime'] : $ar2['mtime1'])-2082826800-self::$timezone);
145
+ $this->trackId = $ar2['trackId'];
146
+ $this->duration = (isset($ar2['duration']) ? $ar2['duration'] : $ar2['duration1']);
147
+ $this->layer = ($ar2['layer']>32767 ? $ar2['layer']-65536 : $ar2['layer']);
148
+ $this->volume = MP4Info_Helper::fromFixed8($ar2['volume']);
149
+ $this->width = MP4Info_Helper::fromFixed16($ar2['width']);
150
+ $this->height = MP4Info_Helper::fromFixed16($ar2['height']);
151
+ } // Constructor
152
+
153
+
154
+ /**
155
+ * Check if block is compatible with class
156
+ *
157
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
158
+ * @param int $boxType
159
+ * @param MP4Info_Box $parent
160
+ * @return bool
161
+ * @access public
162
+ * @static
163
+ */
164
+ static public function isCompatible($boxType, $parent) {
165
+ return $boxType == 0x746b6864;
166
+ } // isCompatible method
167
+
168
+
169
+ /**
170
+ * Width getter
171
+ *
172
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
173
+ * @return float
174
+ * @access public
175
+ */
176
+ public function getWidth() {
177
+ return $this->width;
178
+ } // getWidth method
179
+
180
+
181
+ /**
182
+ * Height getter
183
+ *
184
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
185
+ * @return float
186
+ * @access public
187
+ */
188
+ public function getHeight() {
189
+ return $this->height;
190
+ } // getHeight method
191
+
192
+
193
+ /**
194
+ * Duration getter
195
+ *
196
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
197
+ * @return int
198
+ * @access public
199
+ */
200
+ public function getDuration() {
201
+ return $this->duration;
202
+ } // getDuration method
203
+
204
+
205
+ /**
206
+ * String converter
207
+ *
208
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
209
+ * @return string
210
+ * @access public
211
+ */
212
+ public function toString() {
213
+ return '[MP4Info_Box_tkhd]';
214
+ } // toString method
215
+ } // MP4Info_Box_tkhd class
includes/lib/MP4Info/Box/uuid.php ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Box/uuid.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * x.x ??? (UUID)
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: uuid.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ * @todo Limited to XMP meta data... extend
20
+ */
21
+ class MP4Info_Box_uuid extends MP4Info_Box {
22
+ // {{{ Constants
23
+ const UUID_XMP_METADATA = 'BE7ACFCB97A942';
24
+ // }}} Constants
25
+
26
+ /**
27
+ * UUID
28
+ *
29
+ * @var string
30
+ */
31
+ protected $uuid;
32
+
33
+ /**
34
+ * XMP data
35
+ *
36
+ * @var string
37
+ */
38
+ protected $xmp;
39
+
40
+
41
+ /**
42
+ * Constructor
43
+ *
44
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
45
+ * @param int $totalSize
46
+ * @param int $boxType
47
+ * @param file|string $data
48
+ * @param MP4Info_Box $parent
49
+ * @return MP4Info_Box_uuid
50
+ * @access public
51
+ * @throws MP4Info_Exception
52
+ */
53
+ public function __construct($totalSize, $boxType, $data, $parent) {
54
+ if (!self::isCompatible($boxType, $parent)) {
55
+ throw new Exception('This box isn\'t "uuid"');
56
+ }
57
+
58
+ // Call ancestor
59
+ parent::__construct($totalSize,$boxType,'',$parent);
60
+
61
+ // Unpack
62
+ $data = self::getDataFrom3rd($data,$totalSize);
63
+ $this->uuid = bin2hex(substr($data,0,16));
64
+ $this->xmp = substr($data,16);
65
+ } // Constructor
66
+
67
+
68
+ /**
69
+ * Check if block is compatible with class
70
+ *
71
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
72
+ * @param int $boxType
73
+ * @param MP4Info_Box $parent
74
+ * @return bool
75
+ * @access public
76
+ * @static
77
+ */
78
+ static public function isCompatible($boxType, $parent) {
79
+ return $boxType == 0x75756964;
80
+ } // isCompatible method
81
+
82
+
83
+ /**
84
+ * UUID getter
85
+ *
86
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
87
+ * @return string
88
+ * @access public
89
+ */
90
+ public function getUUID() {
91
+ return strtoupper($this->uuid);
92
+ } // getUUID method
93
+
94
+
95
+ /**
96
+ * XMP Meta data getter
97
+ *
98
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
99
+ * @return string
100
+ * @access public
101
+ */
102
+ public function getXMPMetaData() {
103
+ return (substr(strtoupper($this->uuid),0,14) == self::UUID_XMP_METADATA) ? $this->xmp : false;
104
+ } // getXMPMetaData method
105
+
106
+
107
+ /**
108
+ * String converter
109
+ *
110
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
111
+ * @return string
112
+ * @access public
113
+ */
114
+ public function toString() {
115
+ return '[MP4Info_Box_uuid]';
116
+ } // toString method
117
+ } // MP4Info_Box_uuid class
includes/lib/MP4Info/Exception.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Exception.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * MP4Info Exception Class
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.1.20090611 $Id: Exception.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+
21
+ class MP4Info_Exception extends Exception {
22
+ // {{{ Constants
23
+ const CODE_UNKNOWN = 0x00;
24
+ const CODE_INCOMPATIBLE = 0x01;
25
+ // }}} Constants
26
+
27
+ /**
28
+ * Box type
29
+ *
30
+ * @var int
31
+ */
32
+ protected $boxType;
33
+
34
+
35
+ /**
36
+ * Constructor
37
+ *
38
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
39
+ * @param string $message
40
+ * @param int $code
41
+ * @param int $boxType
42
+ * @return MP4Info_Exception
43
+ * @access public
44
+ */
45
+ public function __construct($message, $code = 0, $boxType=false) {
46
+ parent::__construct($message, $code);
47
+ $this->boxType = $boxType;
48
+ } // Constructor
49
+
50
+
51
+ /**
52
+ * Box type getter
53
+ *
54
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
55
+ * @return int
56
+ * @access public
57
+ */
58
+ public function getBoxType() {
59
+ return $this->boxType;
60
+ } // getBoxType method
61
+ } // MP4Info_Exception class
includes/lib/MP4Info/Helper.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * MP4Info
4
+ *
5
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
6
+ * @copyright Copyright (c) 2006-2009 Tommy Lacroix
7
+ * @license LGPL version 3, http://www.gnu.org/licenses/lgpl.html
8
+ * @package php-mp4info
9
+ * @link $HeadURL: https://php-mp4info.googlecode.com/svn/trunk/MP4Info/Helper.php $
10
+ */
11
+
12
+ // ---
13
+
14
+ /**
15
+ * MP4Info helper functions
16
+ *
17
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
18
+ * @version 1.0.20090601 $Id: Helper.php 2 2009-06-11 14:12:31Z lacroix.tommy@gmail.com $
19
+ */
20
+ class MP4Info_Helper {
21
+ /**
22
+ * Convert a short to a float
23
+ *
24
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
25
+ * @param int $n
26
+ * @return float
27
+ * @access public
28
+ * @static
29
+ */
30
+ public static function fromFixed8($n) {
31
+ return $n / 256;
32
+ } // fromFixed8 method
33
+
34
+
35
+ /**
36
+ * Convert a long to a float
37
+ *
38
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
39
+ * @param int $n
40
+ * @return float
41
+ * @access public
42
+ * @static
43
+ */
44
+ public static function fromFixed16($n) {
45
+ return $n / 65536;
46
+ } // fromFixed16 method
47
+
48
+
49
+ /**
50
+ * Convert binary packed (5bit) letters to string
51
+ *
52
+ * @author Tommy Lacroix <lacroix.tommy@gmail.com>
53
+ * @param int $n
54
+ * @param int $pad
55
+ * @return string
56
+ * @access public
57
+ * @static
58
+ */
59
+ public static function fromPackedLetters($n, $pad=1) {
60
+ $s = decbin($n);
61
+ $s .= str_repeat('0',8-(strlen($s)%8));
62
+ $s = substr($s,0,-$pad);
63
+ $out = '';
64
+ while (strlen($s)>=5) {
65
+ $letter = substr($s,0,5);
66
+ $nl = bindec($letter) + 0x60;
67
+ $out .= chr($nl);
68
+ $s = substr($s,5);
69
+ }
70
+ return $out;
71
+ } // fromPackedLetters method
72
+ } // MP4Info_Helper class
includes/media-element/background.png ADDED
Binary file
includes/media-element/bigplay.png ADDED
Binary file
includes/media-element/controls-ted.png ADDED
Binary file
includes/media-element/controls-wmp-bg.png ADDED
Binary file
includes/media-element/controls-wmp.png ADDED
Binary file
includes/media-element/controls.png ADDED
Binary file
includes/media-element/flashmediaelement.swf ADDED
Binary file
includes/media-element/loading.gif ADDED
Binary file
includes/media-element/mediaelement-and-player.js ADDED
@@ -0,0 +1,4262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * MediaElement.js
3
+ * HTML5 <video> and <audio> shim and player
4
+ * http://mediaelementjs.com/
5
+ *
6
+ * Creates a JavaScript object that mimics HTML5 MediaElement API
7
+ * for browsers that don't understand HTML5 or can't play the provided codec
8
+ * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
9
+ *
10
+ * Copyright 2010-2012, John Dyer (http://j.hn)
11
+ * Dual licensed under the MIT or GPL Version 2 licenses.
12
+ *
13
+ */
14
+ // Namespace
15
+ var mejs = mejs || {};
16
+
17
+ // version number
18
+ mejs.version = '2.9.1';
19
+
20
+ // player number (for missing, same id attr)
21
+ mejs.meIndex = 0;
22
+
23
+ // media types accepted by plugins
24
+ mejs.plugins = {
25
+ silverlight: [
26
+ {version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}
27
+ ],
28
+ flash: [
29
+ {version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg', 'video/youtube', 'video/x-youtube']}
30
+ //,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)
31
+ ],
32
+ youtube: [
33
+ {version: null, types: ['video/youtube', 'video/x-youtube']}
34
+ ],
35
+ vimeo: [
36
+ {version: null, types: ['video/vimeo']}
37
+ ]
38
+ };
39
+
40
+ /*
41
+ Utility methods
42
+ */
43
+ mejs.Utility = {
44
+ encodeUrl: function(url) {
45
+ return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
46
+ },
47
+ escapeHTML: function(s) {
48
+ return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
49
+ },
50
+ absolutizeUrl: function(url) {
51
+ var el = document.createElement('div');
52
+ el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
53
+ return el.firstChild.href;
54
+ },
55
+ getScriptPath: function(scriptNames) {
56
+ var
57
+ i = 0,
58
+ j,
59
+ path = '',
60
+ name = '',
61
+ script,
62
+ scripts = document.getElementsByTagName('script'),
63
+ il = scripts.length,
64
+ jl = scriptNames.length;
65
+
66
+ for (; i < il; i++) {
67
+ script = scripts[i].src;
68
+ for (j = 0; j < jl; j++) {
69
+ name = scriptNames[j];
70
+ if (script.indexOf(name) > -1) {
71
+ path = script.substring(0, script.indexOf(name));
72
+ break;
73
+ }
74
+ }
75
+ if (path !== '') {
76
+ break;
77
+ }
78
+ }
79
+ return path;
80
+ },
81
+ secondsToTimeCode: function(time, forceHours, showFrameCount, fps) {
82
+ //add framecount
83
+ if (typeof showFrameCount == 'undefined') {
84
+ showFrameCount=false;
85
+ } else if(typeof fps == 'undefined') {
86
+ fps = 25;
87
+ }
88
+
89
+ var hours = Math.floor(time / 3600) % 24,
90
+ minutes = Math.floor(time / 60) % 60,
91
+ seconds = Math.floor(time % 60),
92
+ frames = Math.floor(((time % 1)*fps).toFixed(3)),
93
+ result =
94
+ ( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '')
95
+ + (minutes < 10 ? '0' + minutes : minutes) + ':'
96
+ + (seconds < 10 ? '0' + seconds : seconds)
97
+ + ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : '');
98
+
99
+ return result;
100
+ },
101
+
102
+ timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){
103
+ if (typeof showFrameCount == 'undefined') {
104
+ showFrameCount=false;
105
+ } else if(typeof fps == 'undefined') {
106
+ fps = 25;
107
+ }
108
+
109
+ var tc_array = hh_mm_ss_ff.split(":"),
110
+ tc_hh = parseInt(tc_array[0], 10),
111
+ tc_mm = parseInt(tc_array[1], 10),
112
+ tc_ss = parseInt(tc_array[2], 10),
113
+ tc_ff = 0,
114
+ tc_in_seconds = 0;
115
+
116
+ if (showFrameCount) {
117
+ tc_ff = parseInt(tc_array[3])/fps;
118
+ }
119
+
120
+ tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;
121
+
122
+ return tc_in_seconds;
123
+ },
124
+
125
+ /* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
126
+ removeSwf: function(id) {
127
+ var obj = document.getElementById(id);
128
+ if (obj && obj.nodeName == "OBJECT") {
129
+ if (mejs.MediaFeatures.isIE) {
130
+ obj.style.display = "none";
131
+ (function(){
132
+ if (obj.readyState == 4) {
133
+ mejs.Utility.removeObjectInIE(id);
134
+ } else {
135
+ setTimeout(arguments.callee, 10);
136
+ }
137
+ })();
138
+ } else {
139
+ obj.parentNode.removeChild(obj);
140
+ }
141
+ }
142
+ },
143
+ removeObjectInIE: function(id) {
144
+ var obj = document.getElementById(id);
145
+ if (obj) {
146
+ for (var i in obj) {
147
+ if (typeof obj[i] == "function") {
148
+ obj[i] = null;
149
+ }
150
+ }
151
+ obj.parentNode.removeChild(obj);
152
+ }
153
+ }
154
+ };
155
+
156
+
157
+ // Core detector, plugins are added below
158
+ mejs.PluginDetector = {
159
+
160
+ // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
161
+ hasPluginVersion: function(plugin, v) {
162
+ var pv = this.plugins[plugin];
163
+ v[1] = v[1] || 0;
164
+ v[2] = v[2] || 0;
165
+ return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
166
+ },
167
+
168
+ // cached values
169
+ nav: window.navigator,
170
+ ua: window.navigator.userAgent.toLowerCase(),
171
+
172
+ // stored version numbers
173
+ plugins: [],
174
+
175
+ // runs detectPlugin() and stores the version number
176
+ addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
177
+ this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
178
+ },
179
+
180
+ // get the version number from the mimetype (all but IE) or ActiveX (IE)
181
+ detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
182
+
183
+ var version = [0,0,0],
184
+ description,
185
+ i,
186
+ ax;
187
+
188
+ // Firefox, Webkit, Opera
189
+ if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
190
+ description = this.nav.plugins[pluginName].description;
191
+ if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
192
+ version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
193
+ for (i=0; i<version.length; i++) {
194
+ version[i] = parseInt(version[i].match(/\d+/), 10);
195
+ }
196
+ }
197
+ // Internet Explorer / ActiveX
198
+ } else if (typeof(window.ActiveXObject) != 'undefined') {
199
+ try {
200
+ ax = new ActiveXObject(activeX);
201
+ if (ax) {
202
+ version = axDetect(ax);
203
+ }
204
+ }
205
+ catch (e) { }
206
+ }
207
+ return version;
208
+ }
209
+ };
210
+
211
+ // Add Flash detection
212
+ mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
213
+ // adapted from SWFObject
214
+ var version = [],
215
+ d = ax.GetVariable("$version");
216
+ if (d) {
217
+ d = d.split(" ")[1].split(",");
218
+ version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
219
+ }
220
+ return version;
221
+ });
222
+
223
+ // Add Silverlight detection
224
+ mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
225
+ // Silverlight cannot report its version number to IE
226
+ // but it does have a isVersionSupported function, so we have to loop through it to get a version number.
227
+ // adapted from http://www.silverlightversion.com/
228
+ var v = [0,0,0,0],
229
+ loopMatch = function(ax, v, i, n) {
230
+ while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
231
+ v[i]+=n;
232
+ }
233
+ v[i] -= n;
234
+ };
235
+ loopMatch(ax, v, 0, 1);
236
+ loopMatch(ax, v, 1, 1);
237
+ loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
238
+ loopMatch(ax, v, 2, 1000);
239
+ loopMatch(ax, v, 2, 100);
240
+ loopMatch(ax, v, 2, 10);
241
+ loopMatch(ax, v, 2, 1);
242
+ loopMatch(ax, v, 3, 1);
243
+
244
+ return v;
245
+ });
246
+ // add adobe acrobat
247
+ /*
248
+ PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
249
+ var version = [],
250
+ d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
251
+
252
+ if (d) {
253
+ version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
254
+ }
255
+ return version;
256
+ });
257
+ */
258
+ // necessary detection (fixes for <IE9)
259
+ mejs.MediaFeatures = {
260
+ init: function() {
261
+ var
262
+ t = this,
263
+ d = document,
264
+ nav = mejs.PluginDetector.nav,
265
+ ua = mejs.PluginDetector.ua.toLowerCase(),
266
+ i,
267
+ v,
268
+ html5Elements = ['source','track','audio','video'];
269
+
270
+ // detect browsers (only the ones that have some kind of quirk we need to work around)
271
+ t.isiPad = (ua.match(/ipad/i) !== null);
272
+ t.isiPhone = (ua.match(/iphone/i) !== null);
273
+ t.isiOS = t.isiPhone || t.isiPad;
274
+ t.isAndroid = (ua.match(/android/i) !== null);
275
+ t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
276
+ t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
277
+ t.isChrome = (ua.match(/chrome/gi) !== null);
278
+ t.isFirefox = (ua.match(/firefox/gi) !== null);
279
+ t.isWebkit = (ua.match(/webkit/gi) !== null);
280
+ t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit;
281
+ t.isOpera = (ua.match(/opera/gi) !== null);
282
+ t.hasTouch = ('ontouchstart' in window);
283
+
284
+ // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
285
+ for (i=0; i<html5Elements.length; i++) {
286
+ v = document.createElement(html5Elements[i]);
287
+ }
288
+
289
+ t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);
290
+
291
+ // detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)
292
+
293
+ // iOS
294
+ t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');
295
+
296
+ // Webkit/firefox
297
+ t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
298
+ t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
299
+
300
+ t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen);
301
+ t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;
302
+ if (t.hasMozNativeFullScreen) {
303
+ t.nativeFullScreenEnabled = v.mozFullScreenEnabled;
304
+ }
305
+
306
+
307
+ if (this.isChrome) {
308
+ t.hasSemiNativeFullScreen = false;
309
+ }
310
+
311
+ if (t.hasTrueNativeFullScreen) {
312
+ t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange';
313
+
314
+
315
+ t.isFullScreen = function() {
316
+ if (v.mozRequestFullScreen) {
317
+ return d.mozFullScreen;
318
+ } else if (v.webkitRequestFullScreen) {
319
+ return d.webkitIsFullScreen;
320
+ }
321
+ }
322
+
323
+ t.requestFullScreen = function(el) {
324
+
325
+ if (t.hasWebkitNativeFullScreen) {
326
+ el.webkitRequestFullScreen();
327
+ } else if (t.hasMozNativeFullScreen) {
328
+ el.mozRequestFullScreen();
329
+ }
330
+ }
331
+
332
+ t.cancelFullScreen = function() {
333
+ if (t.hasWebkitNativeFullScreen) {
334
+ document.webkitCancelFullScreen();
335
+ } else if (t.hasMozNativeFullScreen) {
336
+ document.mozCancelFullScreen();
337
+ }
338
+ }
339
+
340
+ }
341
+
342
+
343
+ // OS X 10.5 can't do this even if it says it can :(
344
+ if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) {
345
+ t.hasNativeFullScreen = false;
346
+ t.hasSemiNativeFullScreen = false;
347
+ }
348
+
349
+ }
350
+ };
351
+ mejs.MediaFeatures.init();
352
+
353
+
354
+ /*
355
+ extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
356
+ */
357
+ mejs.HtmlMediaElement = {
358
+ pluginType: 'native',
359
+ isFullScreen: false,
360
+
361
+ setCurrentTime: function (time) {
362
+ this.currentTime = time;
363
+ },
364
+
365
+ setMuted: function (muted) {
366
+ this.muted = muted;
367
+ },
368
+
369
+ setVolume: function (volume) {
370
+ this.volume = volume;
371
+ },
372
+
373
+ // for parity with the plugin versions
374
+ stop: function () {
375
+ this.pause();
376
+ },
377
+
378
+ // This can be a url string
379
+ // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
380
+ setSrc: function (url) {
381
+
382
+ // Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
383
+ var
384
+ existingSources = this.getElementsByTagName('source');
385
+ while (existingSources.length > 0){
386
+ this.removeChild(existingSources[0]);
387
+ }
388
+
389
+ if (typeof url == 'string') {
390
+ this.src = url;
391
+ } else {
392
+ var i, media;
393
+
394
+ for (i=0; i<url.length; i++) {
395
+ media = url[i];
396
+ if (this.canPlayType(media.type)) {
397
+ this.src = media.src;
398
+ }
399
+ }
400
+ }
401
+ },
402
+
403
+ setVideoSize: function (width, height) {
404
+ this.width = width;
405
+ this.height = height;
406
+ }
407
+ };
408
+
409
+ /*
410
+ Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
411
+ */
412
+ mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
413
+ this.id = pluginid;
414
+ this.pluginType = pluginType;
415
+ this.src = mediaUrl;
416
+ this.events = {};
417
+ };
418
+
419
+ // JavaScript values and ExternalInterface methods that match HTML5 video properties methods
420
+ // http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
421
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
422
+ mejs.PluginMediaElement.prototype = {
423
+
424
+ // special
425
+ pluginElement: null,
426
+ pluginType: '',
427
+ isFullScreen: false,
428
+
429
+ // not implemented :(
430
+ playbackRate: -1,
431
+ defaultPlaybackRate: -1,
432
+ seekable: [],
433
+ played: [],
434
+
435
+ // HTML5 read-only properties
436
+ paused: true,
437
+ ended: false,
438
+ seeking: false,
439
+ duration: 0,
440
+ error: null,
441
+ tagName: '',
442
+
443
+ // HTML5 get/set properties, but only set (updated by event handlers)
444
+ muted: false,
445
+ volume: 1,
446
+ currentTime: 0,
447
+
448
+ // HTML5 methods
449
+ play: function () {
450
+ if (this.pluginApi != null) {
451
+ if (this.pluginType == 'youtube') {
452
+ this.pluginApi.playVideo();
453
+ } else {
454
+ this.pluginApi.playMedia();
455
+ }
456
+ this.paused = false;
457
+ }
458
+ },
459
+ load: function () {
460
+ if (this.pluginApi != null) {
461
+ if (this.pluginType == 'youtube') {
462
+ } else {
463
+ this.pluginApi.loadMedia();
464
+ }
465
+
466
+ this.paused = false;
467
+ }
468
+ },
469
+ pause: function () {
470
+ if (this.pluginApi != null) {
471
+ if (this.pluginType == 'youtube') {
472
+ this.pluginApi.pauseVideo();
473
+ } else {
474
+ this.pluginApi.pauseMedia();
475
+ }
476
+
477
+
478
+ this.paused = true;
479
+ }
480
+ },
481
+ stop: function () {
482
+ if (this.pluginApi != null) {
483
+ if (this.pluginType == 'youtube') {
484
+ this.pluginApi.stopVideo();
485
+ } else {
486
+ this.pluginApi.stopMedia();
487
+ }
488
+ this.paused = true;
489
+ }
490
+ },
491
+ canPlayType: function(type) {
492
+ var i,
493
+ j,
494
+ pluginInfo,
495
+ pluginVersions = mejs.plugins[this.pluginType];
496
+
497
+ for (i=0; i<pluginVersions.length; i++) {
498
+ pluginInfo = pluginVersions[i];
499
+
500
+ // test if user has the correct plugin version
501
+ if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
502
+
503
+ // test for plugin playback types
504
+ for (j=0; j<pluginInfo.types.length; j++) {
505
+ // find plugin that can play the type
506
+ if (type == pluginInfo.types[j]) {
507
+ return true;
508
+ }
509
+ }
510
+ }
511
+ }
512
+
513
+ return false;
514
+ },
515
+
516
+ positionFullscreenButton: function(x,y,visibleAndAbove) {
517
+ if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
518
+ this.pluginApi.positionFullscreenButton(x,y,visibleAndAbove);
519
+ }
520
+ },
521
+
522
+ hideFullscreenButton: function() {
523
+ if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
524
+ this.pluginApi.hideFullscreenButton();
525
+ }
526
+ },
527
+
528
+
529
+ // custom methods since not all JavaScript implementations support get/set
530
+
531
+ // This can be a url string
532
+ // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
533
+ setSrc: function (url) {
534
+ if (typeof url == 'string') {
535
+ this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
536
+ this.src = mejs.Utility.absolutizeUrl(url);
537
+ } else {
538
+ var i, media;
539
+
540
+ for (i=0; i<url.length; i++) {
541
+ media = url[i];
542
+ if (this.canPlayType(media.type)) {
543
+ this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
544
+ this.src = mejs.Utility.absolutizeUrl(url);
545
+ }
546
+ }
547
+ }
548
+
549
+ },
550
+ setCurrentTime: function (time) {
551
+ if (this.pluginApi != null) {
552
+ if (this.pluginType == 'youtube') {
553
+ this.pluginApi.seekTo(time);
554
+ } else {
555
+ this.pluginApi.setCurrentTime(time);
556
+ }
557
+
558
+
559
+
560
+ this.currentTime = time;
561
+ }
562
+ },
563
+ setVolume: function (volume) {
564
+ if (this.pluginApi != null) {
565
+ // same on YouTube and MEjs
566
+ if (this.pluginType == 'youtube') {
567
+ this.pluginApi.setVolume(volume * 100);
568
+ } else {
569
+ this.pluginApi.setVolume(volume);
570
+ }
571
+ this.volume = volume;
572
+ }
573
+ },
574
+ setMuted: function (muted) {
575
+ if (this.pluginApi != null) {
576
+ if (this.pluginType == 'youtube') {
577
+ if (muted) {
578
+ this.pluginApi.mute();
579
+ } else {
580
+ this.pluginApi.unMute();
581
+ }
582
+ this.muted = muted;
583
+ this.dispatchEvent('volumechange');
584
+ } else {
585
+ this.pluginApi.setMuted(muted);
586
+ }
587
+ this.muted = muted;
588
+ }
589
+ },
590
+
591
+ // additional non-HTML5 methods
592
+ setVideoSize: function (width, height) {
593
+
594
+ //if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
595
+ if ( this.pluginElement.style) {
596
+ this.pluginElement.style.width = width + 'px';
597
+ this.pluginElement.style.height = height + 'px';
598
+ }
599
+ if (this.pluginApi != null && this.pluginApi.setVideoSize) {
600
+ this.pluginApi.setVideoSize(width, height);
601
+ }
602
+ //}
603
+ },
604
+
605
+ setFullscreen: function (fullscreen) {
606
+ if (this.pluginApi != null && this.pluginApi.setFullscreen) {
607
+ this.pluginApi.setFullscreen(fullscreen);
608
+ }
609
+ },
610
+
611
+ enterFullScreen: function() {
612
+ if (this.pluginApi != null && this.pluginApi.setFullscreen) {
613
+ this.setFullscreen(true);
614
+ }
615
+
616
+ },
617
+
618
+ exitFullScreen: function() {
619
+ if (this.pluginApi != null && this.pluginApi.setFullscreen) {
620
+ this.setFullscreen(false);
621
+ }
622
+ },
623
+
624
+ // start: fake events
625
+ addEventListener: function (eventName, callback, bubble) {
626
+ this.events[eventName] = this.events[eventName] || [];
627
+ this.events[eventName].push(callback);
628
+ },
629
+ removeEventListener: function (eventName, callback) {
630
+ if (!eventName) { this.events = {}; return true; }
631
+ var callbacks = this.events[eventName];
632
+ if (!callbacks) return true;
633
+ if (!callback) { this.events[eventName] = []; return true; }
634
+ for (i = 0; i < callbacks.length; i++) {
635
+ if (callbacks[i] === callback) {
636
+ this.events[eventName].splice(i, 1);
637
+ return true;
638
+ }
639
+ }
640
+ return false;
641
+ },
642
+ dispatchEvent: function (eventName) {
643
+ var i,
644
+ args,
645
+ callbacks = this.events[eventName];
646
+
647
+ if (callbacks) {
648
+ args = Array.prototype.slice.call(arguments, 1);
649
+ for (i = 0; i < callbacks.length; i++) {
650
+ callbacks[i].apply(null, args);
651
+ }
652
+ }
653
+ },
654
+ // end: fake events
655
+
656
+ // fake DOM attribute methods
657
+ attributes: {},
658
+ hasAttribute: function(name){
659
+ return (name in this.attributes);
660
+ },
661
+ removeAttribute: function(name){
662
+ delete this.attributes[name];
663
+ },
664
+ getAttribute: function(name){
665
+ if (this.hasAttribute(name)) {
666
+ return this.attributes[name];
667
+ }
668
+ return '';
669
+ },
670
+ setAttribute: function(name, value){
671
+ this.attributes[name] = value;
672
+ },
673
+
674
+ remove: function() {
675
+ mejs.Utility.removeSwf(this.pluginElement.id);
676
+ }
677
+ };
678
+
679
+ // Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
680
+ mejs.MediaPluginBridge = {
681
+
682
+ pluginMediaElements:{},
683
+ htmlMediaElements:{},
684
+
685
+ registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
686
+ this.pluginMediaElements[id] = pluginMediaElement;
687
+ this.htmlMediaElements[id] = htmlMediaElement;
688
+ },
689
+
690
+ // when Flash/Silverlight is ready, it calls out to this method
691
+ initPlugin: function (id) {
692
+
693
+ var pluginMediaElement = this.pluginMediaElements[id],
694
+ htmlMediaElement = this.htmlMediaElements[id];
695
+
696
+ if (pluginMediaElement) {
697
+ // find the javascript bridge
698
+ switch (pluginMediaElement.pluginType) {
699
+ case "flash":
700
+ pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
701
+ break;
702
+ case "silverlight":
703
+ pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
704
+ pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
705
+ break;
706
+ }
707
+
708
+ if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
709
+ pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
710
+ }
711
+ }
712
+ },
713
+
714
+ // receives events from Flash/Silverlight and sends them out as HTML5 media events
715
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
716
+ fireEvent: function (id, eventName, values) {
717
+
718
+ var
719
+ e,
720
+ i,
721
+ bufferedTime,
722
+ pluginMediaElement = this.pluginMediaElements[id];
723
+
724
+ pluginMediaElement.ended = false;
725
+ pluginMediaElement.paused = true;
726
+
727
+ // fake event object to mimic real HTML media event.
728
+ e = {
729
+ type: eventName,
730
+ target: pluginMediaElement
731
+ };
732
+
733
+ // attach all values to element and event object
734
+ for (i in values) {
735
+ pluginMediaElement[i] = values[i];
736
+ e[i] = values[i];
737
+ }
738
+
739
+ // fake the newer W3C buffered TimeRange (loaded and total have been removed)
740
+ bufferedTime = values.bufferedTime || 0;
741
+
742
+ e.target.buffered = e.buffered = {
743
+ start: function(index) {
744
+ return 0;
745
+ },
746
+ end: function (index) {
747
+ return bufferedTime;
748
+ },
749
+ length: 1
750
+ };
751
+
752
+ pluginMediaElement.dispatchEvent(e.type, e);
753
+ }
754
+ };
755
+
756
+ /*
757
+ Default options
758
+ */
759
+ mejs.MediaElementDefaults = {
760
+ // allows testing on HTML5, flash, silverlight
761
+ // auto: attempts to detect what the browser can do
762
+ // native: forces HTML5 playback
763
+ // shim: disallows HTML5, will attempt either Flash or Silverlight
764
+ // none: forces fallback view
765
+ mode: 'auto',
766
+ // remove or reorder to change plugin priority and availability
767
+ plugins: ['flash','silverlight','youtube','vimeo'],
768
+ // shows debug errors on screen
769
+ enablePluginDebug: false,
770
+ // overrides the type specified, useful for dynamic instantiation
771
+ type: '',
772
+ // path to Flash and Silverlight plugins
773
+ pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
774
+ // name of flash file
775
+ flashName: 'flashmediaelement.swf',
776
+ // turns on the smoothing filter in Flash
777
+ enablePluginSmoothing: false,
778
+ // name of silverlight file
779
+ silverlightName: 'silverlightmediaelement.xap',
780
+ // default if the <video width> is not specified
781
+ defaultVideoWidth: 480,
782
+ // default if the <video height> is not specified
783
+ defaultVideoHeight: 270,
784
+ // overrides <video width>
785
+ pluginWidth: -1,
786
+ // overrides <video height>
787
+ pluginHeight: -1,
788
+ // additional plugin variables in 'key=value' form
789
+ pluginVars: [],
790
+ // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
791
+ // larger number is less accurate, but less strain on plugin->JavaScript bridge
792
+ timerRate: 250,
793
+ // initial volume for player
794
+ startVolume: 0.8,
795
+ success: function () { },
796
+ error: function () { }
797
+ };
798
+
799
+ /*
800
+ Determines if a browser supports the <video> or <audio> element
801
+ and returns either the native element or a Flash/Silverlight version that
802
+ mimics HTML5 MediaElement
803
+ */
804
+ mejs.MediaElement = function (el, o) {
805
+ return mejs.HtmlMediaElementShim.create(el,o);
806
+ };
807
+
808
+ mejs.HtmlMediaElementShim = {
809
+
810
+ create: function(el, o) {
811
+ var
812
+ options = mejs.MediaElementDefaults,
813
+ htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
814
+ tagName = htmlMediaElement.tagName.toLowerCase(),
815
+ isMediaTag = (tagName === 'audio' || tagName === 'video'),
816
+ src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
817
+ poster = htmlMediaElement.getAttribute('poster'),
818
+ autoplay = htmlMediaElement.getAttribute('autoplay'),
819
+ preload = htmlMediaElement.getAttribute('preload'),
820
+ controls = htmlMediaElement.getAttribute('controls'),
821
+ playback,
822
+ prop;
823
+
824
+ // extend options
825
+ for (prop in o) {
826
+ options[prop] = o[prop];
827
+ }
828
+
829
+ // clean up attributes
830
+ src = (typeof src == 'undefined' || src === null || src == '') ? null : src;
831
+ poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
832
+ preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
833
+ autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
834
+ controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');
835
+
836
+ // test for HTML5 and plugin capabilities
837
+ playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
838
+ playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
839
+
840
+ if (playback.method == 'native') {
841
+ // second fix for android
842
+ if (mejs.MediaFeatures.isBustedAndroid) {
843
+ htmlMediaElement.src = playback.url;
844
+ htmlMediaElement.addEventListener('click', function() {
845
+ htmlMediaElement.play();
846
+ }, false);
847
+ }
848
+
849
+ // add methods to native HTMLMediaElement
850
+ return this.updateNative(playback, options, autoplay, preload);
851
+ } else if (playback.method !== '') {
852
+ // create plugin to mimic HTMLMediaElement
853
+
854
+ return this.createPlugin( playback, options, poster, autoplay, preload, controls);
855
+ } else {
856
+ // boo, no HTML5, no Flash, no Silverlight.
857
+ this.createErrorMessage( playback, options, poster );
858
+
859
+ return this;
860
+ }
861
+ },
862
+
863
+ determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
864
+ var
865
+ mediaFiles = [],
866
+ i,
867
+ j,
868
+ k,
869
+ l,
870
+ n,
871
+ type,
872
+ result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')},
873
+ pluginName,
874
+ pluginVersions,
875
+ pluginInfo,
876
+ dummy;
877
+
878
+ // STEP 1: Get URL and type from <video src> or <source src>
879
+
880
+ // supplied type overrides <video type> and <source type>
881
+ if (typeof options.type != 'undefined' && options.type !== '') {
882
+
883
+ // accept either string or array of types
884
+ if (typeof options.type == 'string') {
885
+ mediaFiles.push({type:options.type, url:src});
886
+ } else {
887
+
888
+ for (i=0; i<options.type.length; i++) {
889
+ mediaFiles.push({type:options.type[i], url:src});
890
+ }
891
+ }
892
+
893
+ // test for src attribute first
894
+ } else if (src !== null) {
895
+ type = this.formatType(src, htmlMediaElement.getAttribute('type'));
896
+ mediaFiles.push({type:type, url:src});
897
+
898
+ // then test for <source> elements
899
+ } else {
900
+ // test <source> types to see if they are usable
901
+ for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
902
+ n = htmlMediaElement.childNodes[i];
903
+ if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
904
+ src = n.getAttribute('src');
905
+ type = this.formatType(src, n.getAttribute('type'));
906
+ mediaFiles.push({type:type, url:src});
907
+ }
908
+ }
909
+ }
910
+
911
+ // in the case of dynamicly created players
912
+ // check for audio types
913
+ if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
914
+ result.isVideo = false;
915
+ }
916
+
917
+
918
+ // STEP 2: Test for playback method
919
+
920
+ // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
921
+ if (mejs.MediaFeatures.isBustedAndroid) {
922
+ htmlMediaElement.canPlayType = function(type) {
923
+ return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
924
+ };
925
+ }
926
+
927
+
928
+ // test for native playback first
929
+ if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'native')) {
930
+
931
+ if (!isMediaTag) {
932
+
933
+ // create a real HTML5 Media Element
934
+ dummy = document.createElement( result.isVideo ? 'video' : 'audio');
935
+ htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
936
+ htmlMediaElement.style.display = 'none';
937
+
938
+ // use this one from now on
939
+ result.htmlMediaElement = htmlMediaElement = dummy;
940
+ }
941
+
942
+ for (i=0; i<mediaFiles.length; i++) {
943
+ // normal check
944
+ if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
945
+ // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
946
+ || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
947
+ result.method = 'native';
948
+ result.url = mediaFiles[i].url;
949
+ break;
950
+ }
951
+ }
952
+
953
+ if (result.method === 'native') {
954
+ if (result.url !== null) {
955
+ htmlMediaElement.src = result.url;
956
+ }
957
+
958
+ return result;
959
+ }
960
+ }
961
+
962
+ // if native playback didn't work, then test plugins
963
+ if (options.mode === 'auto' || options.mode === 'shim') {
964
+ for (i=0; i<mediaFiles.length; i++) {
965
+ type = mediaFiles[i].type;
966
+
967
+ // test all plugins in order of preference [silverlight, flash]
968
+ for (j=0; j<options.plugins.length; j++) {
969
+
970
+ pluginName = options.plugins[j];
971
+
972
+ // test version of plugin (for future features)
973
+ pluginVersions = mejs.plugins[pluginName];
974
+
975
+ for (k=0; k<pluginVersions.length; k++) {
976
+ pluginInfo = pluginVersions[k];
977
+
978
+ // test if user has the correct plugin version
979
+
980
+ // for youtube/vimeo
981
+ if (pluginInfo.version == null ||
982
+
983
+ mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
984
+
985
+ // test for plugin playback types
986
+ for (l=0; l<pluginInfo.types.length; l++) {
987
+ // find plugin that can play the type
988
+ if (type == pluginInfo.types[l]) {
989
+ result.method = pluginName;
990
+ result.url = mediaFiles[i].url;
991
+ return result;
992
+ }
993
+ }
994
+ }
995
+ }
996
+ }
997
+ }
998
+ }
999
+
1000
+ // what if there's nothing to play? just grab the first available
1001
+ if (result.method === '' && mediaFiles.length > 0) {
1002
+ result.url = mediaFiles[0].url;
1003
+ }
1004
+
1005
+ return result;
1006
+ },
1007
+
1008
+ formatType: function(url, type) {
1009
+ var ext;
1010
+
1011
+ // if no type is supplied, fake it with the extension
1012
+ if (url && !type) {
1013
+ return this.getTypeFromFile(url);
1014
+ } else {
1015
+ // only return the mime part of the type in case the attribute contains the codec
1016
+ // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
1017
+ // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
1018
+
1019
+ if (type && ~type.indexOf(';')) {
1020
+ return type.substr(0, type.indexOf(';'));
1021
+ } else {
1022
+ return type;
1023
+ }
1024
+ }
1025
+ },
1026
+
1027
+ getTypeFromFile: function(url) {
1028
+ var ext = url.substring(url.lastIndexOf('.') + 1);
1029
+ return (/(mp4|m4v|ogg|ogv|webm|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + ext;
1030
+ },
1031
+
1032
+ createErrorMessage: function(playback, options, poster) {
1033
+ var
1034
+ htmlMediaElement = playback.htmlMediaElement,
1035
+ errorContainer = document.createElement('div');
1036
+
1037
+ errorContainer.className = 'me-cannotplay';
1038
+
1039
+ try {
1040
+ errorContainer.style.width = htmlMediaElement.width + 'px';
1041
+ errorContainer.style.height = htmlMediaElement.height + 'px';
1042
+ } catch (e) {}
1043
+
1044
+ errorContainer.innerHTML = (poster !== '') ?
1045
+ '<a href="' + playback.url + '"><img src="' + poster + '" width="100%" height="100%" /></a>' :
1046
+ '<a href="' + playback.url + '"><span>Download File</span></a>';
1047
+
1048
+ htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
1049
+ htmlMediaElement.style.display = 'none';
1050
+
1051
+ options.error(htmlMediaElement);
1052
+ },
1053
+
1054
+ createPlugin:function(playback, options, poster, autoplay, preload, controls) {
1055
+ var
1056
+ htmlMediaElement = playback.htmlMediaElement,
1057
+ width = 1,
1058
+ height = 1,
1059
+ pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
1060
+ pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
1061
+ container = document.createElement('div'),
1062
+ specialIEContainer,
1063
+ node,
1064
+ initVars;
1065
+
1066
+ // copy tagName from html media element
1067
+ pluginMediaElement.tagName = htmlMediaElement.tagName
1068
+
1069
+ // copy attributes from html media element to plugin media element
1070
+ for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
1071
+ var attribute = htmlMediaElement.attributes[i];
1072
+ if (attribute.specified == true) {
1073
+ pluginMediaElement.setAttribute(attribute.name, attribute.value);
1074
+ }
1075
+ }
1076
+
1077
+ // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
1078
+ node = htmlMediaElement.parentNode;
1079
+ while (node !== null && node.tagName.toLowerCase() != 'body') {
1080
+ if (node.parentNode.tagName.toLowerCase() == 'p') {
1081
+ node.parentNode.parentNode.insertBefore(node, node.parentNode);
1082
+ break;
1083
+ }
1084
+ node = node.parentNode;
1085
+ }
1086
+
1087
+ if (playback.isVideo) {
1088
+ width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
1089
+ height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
1090
+
1091
+ // in case of '%' make sure it's encoded
1092
+ width = mejs.Utility.encodeUrl(width);
1093
+ height = mejs.Utility.encodeUrl(height);
1094
+
1095
+ } else {
1096
+ if (options.enablePluginDebug) {
1097
+ width = 320;
1098
+ height = 240;
1099
+ }
1100
+ }
1101
+
1102
+ // register plugin
1103
+ pluginMediaElement.success = options.success;
1104
+ mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
1105
+
1106
+ // add container (must be added to DOM before inserting HTML for IE)
1107
+ container.className = 'me-plugin';
1108
+ container.id = pluginid + '_container';
1109
+
1110
+ if (playback.isVideo) {
1111
+ htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
1112
+ } else {
1113
+ document.body.insertBefore(container, document.body.childNodes[0]);
1114
+ }
1115
+
1116
+ // flash/silverlight vars
1117
+ initVars = [
1118
+ 'id=' + pluginid,
1119
+ 'isvideo=' + ((playback.isVideo) ? "true" : "false"),
1120
+ 'autoplay=' + ((autoplay) ? "true" : "false"),
1121
+ 'preload=' + preload,
1122
+ 'width=' + width,
1123
+ 'startvolume=' + options.startVolume,
1124
+ 'timerrate=' + options.timerRate,
1125
+ 'height=' + height];
1126
+
1127
+ if (playback.url !== null) {
1128
+ if (playback.method == 'flash') {
1129
+ initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
1130
+ } else {
1131
+ initVars.push('file=' + playback.url);
1132
+ }
1133
+ }
1134
+ if (options.enablePluginDebug) {
1135
+ initVars.push('debug=true');
1136
+ }
1137
+ if (options.enablePluginSmoothing) {
1138
+ initVars.push('smoothing=true');
1139
+ }
1140
+ if (controls) {
1141
+ initVars.push('controls=true'); // shows controls in the plugin if desired
1142
+ }
1143
+ if (options.pluginVars) {
1144
+ initVars = initVars.concat(options.pluginVars);
1145
+ }
1146
+
1147
+ switch (playback.method) {
1148
+ case 'silverlight':
1149
+ container.innerHTML =
1150
+ '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
1151
+ '<param name="initParams" value="' + initVars.join(',') + '" />' +
1152
+ '<param name="windowless" value="true" />' +
1153
+ '<param name="background" value="black" />' +
1154
+ '<param name="minRuntimeVersion" value="3.0.0.0" />' +
1155
+ '<param name="autoUpgrade" value="true" />' +
1156
+ '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
1157
+ '</object>';
1158
+ break;
1159
+
1160
+ case 'flash':
1161
+
1162
+ if (mejs.MediaFeatures.isIE) {
1163
+ specialIEContainer = document.createElement('div');
1164
+ container.appendChild(specialIEContainer);
1165
+ specialIEContainer.outerHTML =
1166
+ '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
1167
+ 'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
1168
+ '<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
1169
+ '<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
1170
+ '<param name="quality" value="high" />' +
1171
+ '<param name="bgcolor" value="#000000" />' +
1172
+ '<param name="wmode" value="transparent" />' +
1173
+ '<param name="allowScriptAccess" value="always" />' +
1174
+ '<param name="allowFullScreen" value="true" />' +
1175
+ '</object>';
1176
+
1177
+ } else {
1178
+
1179
+ container.innerHTML =
1180
+ '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
1181
+ 'play="true" ' +
1182
+ 'loop="false" ' +
1183
+ 'quality="high" ' +
1184
+ 'bgcolor="#000000" ' +
1185
+ 'wmode="transparent" ' +
1186
+ 'allowScriptAccess="always" ' +
1187
+ 'allowFullScreen="true" ' +
1188
+ 'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
1189
+ 'src="' + options.pluginPath + options.flashName + '" ' +
1190
+ 'flashvars="' + initVars.join('&') + '" ' +
1191
+ 'width="' + width + '" ' +
1192
+ 'height="' + height + '"></embed>';
1193
+ }
1194
+ break;
1195
+
1196
+ case 'youtube':
1197
+
1198
+
1199
+ var
1200
+ videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
1201
+ youtubeSettings = {
1202
+ container: container,
1203
+ containerId: container.id,
1204
+ pluginMediaElement: pluginMediaElement,
1205
+ pluginId: pluginid,
1206
+ videoId: videoId,
1207
+ height: height,
1208
+ width: width
1209
+ };
1210
+
1211
+ if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
1212
+ mejs.YouTubeApi.createFlash(youtubeSettings);
1213
+ } else {
1214
+ mejs.YouTubeApi.enqueueIframe(youtubeSettings);
1215
+ }
1216
+
1217
+ break;
1218
+
1219
+ // DEMO Code. Does NOT work.
1220
+ case 'vimeo':
1221
+ console.log('vimeoid');
1222
+
1223
+ pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
1224
+
1225
+ container.innerHTML =
1226
+ '<object width="' + width + '" height="' + height + '">' +
1227
+ '<param name="allowfullscreen" value="true" />' +
1228
+ '<param name="allowscriptaccess" value="always" />' +
1229
+ '<param name="flashvars" value="api=1" />' +
1230
+ '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" />' +
1231
+ '<embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '"></embed>' +
1232
+ '</object>';
1233
+
1234
+ break;
1235
+ }
1236
+ // hide original element
1237
+ htmlMediaElement.style.display = 'none';
1238
+
1239
+ // FYI: options.success will be fired by the MediaPluginBridge
1240
+
1241
+ return pluginMediaElement;
1242
+ },
1243
+
1244
+ updateNative: function(playback, options, autoplay, preload) {
1245
+
1246
+ var htmlMediaElement = playback.htmlMediaElement,
1247
+ m;
1248
+
1249
+
1250
+ // add methods to video object to bring it into parity with Flash Object
1251
+ for (m in mejs.HtmlMediaElement) {
1252
+ htmlMediaElement[m] = mejs.HtmlMediaElement[m];
1253
+ }
1254
+
1255
+ /*
1256
+ Chrome now supports preload="none"
1257
+ if (mejs.MediaFeatures.isChrome) {
1258
+
1259
+ // special case to enforce preload attribute (Chrome doesn't respect this)
1260
+ if (preload === 'none' && !autoplay) {
1261
+
1262
+ // forces the browser to stop loading (note: fails in IE9)
1263
+ htmlMediaElement.src = '';
1264
+ htmlMediaElement.load();
1265
+ htmlMediaElement.canceledPreload = true;
1266
+
1267
+ htmlMediaElement.addEventListener('play',function() {
1268
+ if (htmlMediaElement.canceledPreload) {
1269
+ htmlMediaElement.src = playback.url;
1270
+ htmlMediaElement.load();
1271
+ htmlMediaElement.play();
1272
+ htmlMediaElement.canceledPreload = false;
1273
+ }
1274
+ }, false);
1275
+ // for some reason Chrome forgets how to autoplay sometimes.
1276
+ } else if (autoplay) {
1277
+ htmlMediaElement.load();
1278
+ htmlMediaElement.play();
1279
+ }
1280
+ }
1281
+ */
1282
+
1283
+ // fire success code
1284
+ options.success(htmlMediaElement, htmlMediaElement);
1285
+
1286
+ return htmlMediaElement;
1287
+ }
1288
+ };
1289
+
1290
+ /*
1291
+ - test on IE (object vs. embed)
1292
+ - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
1293
+ - fullscreen?
1294
+ */
1295
+
1296
+ // YouTube Flash and Iframe API
1297
+ mejs.YouTubeApi = {
1298
+ isIframeStarted: false,
1299
+ isIframeLoaded: false,
1300
+ loadIframeApi: function() {
1301
+ if (!this.isIframeStarted) {
1302
+ var tag = document.createElement('script');
1303
+ tag.src = "http://www.youtube.com/player_api";
1304
+ var firstScriptTag = document.getElementsByTagName('script')[0];
1305
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1306
+ this.isIframeStarted = true;
1307
+ }
1308
+ },
1309
+ iframeQueue: [],
1310
+ enqueueIframe: function(yt) {
1311
+
1312
+ if (this.isLoaded) {
1313
+ this.createIframe(yt);
1314
+ } else {
1315
+ this.loadIframeApi();
1316
+ this.iframeQueue.push(yt);
1317
+ }
1318
+ },
1319
+ createIframe: function(settings) {
1320
+
1321
+ var
1322
+ pluginMediaElement = settings.pluginMediaElement,
1323
+ player = new YT.Player(settings.containerId, {
1324
+ height: settings.height,
1325
+ width: settings.width,
1326
+ videoId: settings.videoId,
1327
+ playerVars: {controls:0},
1328
+ events: {
1329
+ 'onReady': function() {
1330
+
1331
+ // hook up iframe object to MEjs
1332
+ settings.pluginMediaElement.pluginApi = player;
1333
+
1334
+ // init mejs
1335
+ mejs.MediaPluginBridge.initPlugin(settings.pluginId);
1336
+
1337
+ // create timer
1338
+ setInterval(function() {
1339
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
1340
+ }, 250);
1341
+ },
1342
+ 'onStateChange': function(e) {
1343
+
1344
+ mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);
1345
+
1346
+ }
1347
+ }
1348
+ });
1349
+ },
1350
+
1351
+ createEvent: function (player, pluginMediaElement, eventName) {
1352
+ var obj = {
1353
+ type: eventName,
1354
+ target: pluginMediaElement
1355
+ };
1356
+
1357
+ if (player && player.getDuration) {
1358
+
1359
+ // time
1360
+ pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime();
1361
+ pluginMediaElement.duration = obj.duration = player.getDuration();
1362
+
1363
+ // state
1364
+ obj.paused = pluginMediaElement.paused;
1365
+ obj.ended = pluginMediaElement.ended;
1366
+
1367
+ // sound
1368
+ obj.muted = player.isMuted();
1369
+ obj.volume = player.getVolume() / 100;
1370
+
1371
+ // progress
1372
+ obj.bytesTotal = player.getVideoBytesTotal();
1373
+ obj.bufferedBytes = player.getVideoBytesLoaded();
1374
+
1375
+ // fake the W3C buffered TimeRange
1376
+ var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration;
1377
+
1378
+ obj.target.buffered = obj.buffered = {
1379
+ start: function(index) {
1380
+ return 0;
1381
+ },
1382
+ end: function (index) {
1383
+ return bufferedTime;
1384
+ },
1385
+ length: 1
1386
+ };
1387
+
1388
+ }
1389
+
1390
+ // send event up the chain
1391
+ pluginMediaElement.dispatchEvent(obj.type, obj);
1392
+ },
1393
+
1394
+ iFrameReady: function() {
1395
+
1396
+ this.isLoaded = true;
1397
+ this.isIframeLoaded = true;
1398
+
1399
+ while (this.iframeQueue.length > 0) {
1400
+ var settings = this.iframeQueue.pop();
1401
+ this.createIframe(settings);
1402
+ }
1403
+ },
1404
+
1405
+ // FLASH!
1406
+ flashPlayers: {},
1407
+ createFlash: function(settings) {
1408
+
1409
+ this.flashPlayers[settings.pluginId] = settings;
1410
+
1411
+ /*
1412
+ settings.container.innerHTML =
1413
+ '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
1414
+ 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
1415
+ '<param name="allowScriptAccess" value="always">' +
1416
+ '<param name="wmode" value="transparent">' +
1417
+ '</object>';
1418
+ */
1419
+
1420
+ var specialIEContainer,
1421
+ youtubeUrl = 'http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0';
1422
+
1423
+ if (mejs.MediaFeatures.isIE) {
1424
+
1425
+ specialIEContainer = document.createElement('div');
1426
+ settings.container.appendChild(specialIEContainer);
1427
+ specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
1428
+ 'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '">' +
1429
+ '<param name="movie" value="' + youtubeUrl + '" />' +
1430
+ '<param name="wmode" value="transparent" />' +
1431
+ '<param name="allowScriptAccess" value="always" />' +
1432
+ '<param name="allowFullScreen" value="true" />' +
1433
+ '</object>';
1434
+ } else {
1435
+ settings.container.innerHTML =
1436
+ '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
1437
+ 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
1438
+ '<param name="allowScriptAccess" value="always">' +
1439
+ '<param name="wmode" value="transparent">' +
1440
+ '</object>';
1441
+ }
1442
+
1443
+ },
1444
+
1445
+ flashReady: function(id) {
1446
+ var
1447
+ settings = this.flashPlayers[id],
1448
+ player = document.getElementById(id),
1449
+ pluginMediaElement = settings.pluginMediaElement;
1450
+
1451
+ // hook up and return to MediaELementPlayer.success
1452
+ pluginMediaElement.pluginApi =
1453
+ pluginMediaElement.pluginElement = player;
1454
+ mejs.MediaPluginBridge.initPlugin(id);
1455
+
1456
+ // load the youtube video
1457
+ player.cueVideoById(settings.videoId);
1458
+
1459
+ var callbackName = settings.containerId + '_callback'
1460
+
1461
+ window[callbackName] = function(e) {
1462
+ mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
1463
+ }
1464
+
1465
+ player.addEventListener('onStateChange', callbackName);
1466
+
1467
+ setInterval(function() {
1468
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
1469
+ }, 250);
1470
+ },
1471
+
1472
+ handleStateChange: function(youTubeState, player, pluginMediaElement) {
1473
+ switch (youTubeState) {
1474
+ case -1: // not started
1475
+ pluginMediaElement.paused = true;
1476
+ pluginMediaElement.ended = true;
1477
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
1478
+ //createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
1479
+ break;
1480
+ case 0:
1481
+ pluginMediaElement.paused = false;
1482
+ pluginMediaElement.ended = true;
1483
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
1484
+ break;
1485
+ case 1:
1486
+ pluginMediaElement.paused = false;
1487
+ pluginMediaElement.ended = false;
1488
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
1489
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
1490
+ break;
1491
+ case 2:
1492
+ pluginMediaElement.paused = true;
1493
+ pluginMediaElement.ended = false;
1494
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
1495
+ break;
1496
+ case 3: // buffering
1497
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
1498
+ break;
1499
+ case 5:
1500
+ // cued?
1501
+ break;
1502
+
1503
+ }
1504
+
1505
+ }
1506
+ }
1507
+ // IFRAME
1508
+ function onYouTubePlayerAPIReady() {
1509
+ mejs.YouTubeApi.iFrameReady();
1510
+ }
1511
+ // FLASH
1512
+ function onYouTubePlayerReady(id) {
1513
+ mejs.YouTubeApi.flashReady(id);
1514
+ }
1515
+
1516
+ window.mejs = mejs;
1517
+ window.MediaElement = mejs.MediaElement;
1518
+
1519
+ /*!
1520
+ * MediaElementPlayer
1521
+ * http://mediaelementjs.com/
1522
+ *
1523
+ * Creates a controller bar for HTML5 <video> add <audio> tags
1524
+ * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
1525
+ *
1526
+ * Copyright 2010-2012, John Dyer (http://j.hn/)
1527
+ * Dual licensed under the MIT or GPL Version 2 licenses.
1528
+ *
1529
+ */
1530
+ if (typeof jQuery != 'undefined') {
1531
+ mejs.$ = jQuery;
1532
+ } else if (typeof ender != 'undefined') {
1533
+ mejs.$ = ender;
1534
+ }
1535
+ (function ($) {
1536
+
1537
+ // default player values
1538
+ mejs.MepDefaults = {
1539
+ // url to poster (to fix iOS 3.x)
1540
+ poster: '',
1541
+ // default if the <video width> is not specified
1542
+ defaultVideoWidth: 480,
1543
+ // default if the <video height> is not specified
1544
+ defaultVideoHeight: 270,
1545
+ // if set, overrides <video width>
1546
+ videoWidth: -1,
1547
+ // if set, overrides <video height>
1548
+ videoHeight: -1,
1549
+ // default if the user doesn't specify
1550
+ defaultAudioWidth: 400,
1551
+ // default if the user doesn't specify
1552
+ defaultAudioHeight: 30,
1553
+ // width of audio player
1554
+ audioWidth: -1,
1555
+ // height of audio player
1556
+ audioHeight: -1,
1557
+ // initial volume when the player starts (overrided by user cookie)
1558
+ startVolume: 0.8,
1559
+ // useful for <audio> player loops
1560
+ loop: false,
1561
+ // resize to media dimensions
1562
+ enableAutosize: true,
1563
+ // forces the hour marker (##:00:00)
1564
+ alwaysShowHours: false,
1565
+
1566
+ // show framecount in timecode (##:00:00:00)
1567
+ showTimecodeFrameCount: false,
1568
+ // used when showTimecodeFrameCount is set to true
1569
+ framesPerSecond: 25,
1570
+
1571
+ // automatically calculate the width of the progress bar based on the sizes of other elements
1572
+ autosizeProgress : true,
1573
+ // Hide controls when playing and mouse is not over the video
1574
+ alwaysShowControls: false,
1575
+ // force iPad's native controls
1576
+ iPadUseNativeControls: false,
1577
+ // force iPhone's native controls
1578
+ iPhoneUseNativeControls: false,
1579
+ // force Android's native controls
1580
+ AndroidUseNativeControls: false,
1581
+ // features to show
1582
+ features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
1583
+ // only for dynamic
1584
+ isVideo: true,
1585
+
1586
+ // turns keyboard support on and off for this instance
1587
+ enableKeyboard: true,
1588
+
1589
+ // whenthis player starts, it will pause other players
1590
+ pauseOtherPlayers: true,
1591
+
1592
+ // array of keyboard actions such as play pause
1593
+ keyActions: [
1594
+ {
1595
+ keys: [
1596
+ 32, // SPACE
1597
+ 179 // GOOGLE play/pause button
1598
+ ],
1599
+ action: function(player, media) {
1600
+ if (media.paused || media.ended) {
1601
+ media.play();
1602
+ } else {
1603
+ media.pause();
1604
+ }
1605
+ }
1606
+ },
1607
+ {
1608
+ keys: [38], // UP
1609
+ action: function(player, media) {
1610
+ var newVolume = Math.min(media.volume + 0.1, 1);
1611
+ media.setVolume(newVolume);
1612
+ }
1613
+ },
1614
+ {
1615
+ keys: [40], // DOWN
1616
+ action: function(player, media) {
1617
+ var newVolume = Math.max(media.volume - 0.1, 0);
1618
+ media.setVolume(newVolume);
1619
+ }
1620
+ },
1621
+ {
1622
+ keys: [
1623
+ 37, // LEFT
1624
+ 227 // Google TV rewind
1625
+ ],
1626
+ action: function(player, media) {
1627
+ if (!isNaN(media.duration) && media.duration > 0) {
1628
+ if (player.isVideo) {
1629
+ player.showControls();
1630
+ player.startControlsTimer();
1631
+ }
1632
+
1633
+ // 5%
1634
+ var newTime = Math.max(media.currentTime - (media.duration * 0.05), 0);
1635
+ media.setCurrentTime(newTime);
1636
+ }
1637
+ }
1638
+ },
1639
+ {
1640
+ keys: [
1641
+ 39, // RIGHT
1642
+ 228 // Google TV forward
1643
+ ],
1644
+ action: function(player, media) {
1645
+ if (!isNaN(media.duration) && media.duration > 0) {
1646
+ if (player.isVideo) {
1647
+ player.showControls();
1648
+ player.startControlsTimer();
1649
+ }
1650
+
1651
+ // 5%
1652
+ var newTime = Math.min(media.currentTime + (media.duration * 0.05), media.duration);
1653
+ media.setCurrentTime(newTime);
1654
+ }
1655
+ }
1656
+ },
1657
+ {
1658
+ keys: [70], // f
1659
+ action: function(player, media) {
1660
+ if (typeof player.enterFullScreen != 'undefined') {
1661
+ if (player.isFullScreen) {
1662
+ player.exitFullScreen();
1663
+ } else {
1664
+ player.enterFullScreen();
1665
+ }
1666
+ }
1667
+ }
1668
+ }
1669
+ ]
1670
+ };
1671
+
1672
+ mejs.mepIndex = 0;
1673
+
1674
+ mejs.players = [];
1675
+
1676
+ // wraps a MediaElement object in player controls
1677
+ mejs.MediaElementPlayer = function(node, o) {
1678
+ // enforce object, even without "new" (via John Resig)
1679
+ if ( !(this instanceof mejs.MediaElementPlayer) ) {
1680
+ return new mejs.MediaElementPlayer(node, o);
1681
+ }
1682
+
1683
+ var t = this;
1684
+
1685
+ // these will be reset after the MediaElement.success fires
1686
+ t.$media = t.$node = $(node);
1687
+ t.node = t.media = t.$media[0];
1688
+
1689
+ // check for existing player
1690
+ if (typeof t.node.player != 'undefined') {
1691
+ return t.node.player;
1692
+ } else {
1693
+ // attach player to DOM node for reference
1694
+ t.node.player = t;
1695
+ }
1696
+
1697
+
1698
+ // try to get options from data-mejsoptions
1699
+ if (typeof o == 'undefined') {
1700
+ o = t.$node.data('mejsoptions');
1701
+ }
1702
+
1703
+ // extend default options
1704
+ t.options = $.extend({},mejs.MepDefaults,o);
1705
+
1706
+ // add to player array (for focus events)
1707
+ mejs.players.push(t);
1708
+
1709
+ // start up
1710
+ t.init();
1711
+
1712
+ return t;
1713
+ };
1714
+
1715
+ // actual player
1716
+ mejs.MediaElementPlayer.prototype = {
1717
+
1718
+ hasFocus: false,
1719
+
1720
+ controlsAreVisible: true,
1721
+
1722
+ init: function() {
1723
+
1724
+ var
1725
+ t = this,
1726
+ mf = mejs.MediaFeatures,
1727
+ // options for MediaElement (shim)
1728
+ meOptions = $.extend(true, {}, t.options, {
1729
+ success: function(media, domNode) { t.meReady(media, domNode); },
1730
+ error: function(e) { t.handleError(e);}
1731
+ }),
1732
+ tagName = t.media.tagName.toLowerCase();
1733
+
1734
+ t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
1735
+
1736
+ if (t.isDynamic) {
1737
+ // get video from src or href?
1738
+ t.isVideo = t.options.isVideo;
1739
+ } else {
1740
+ t.isVideo = (tagName !== 'audio' && t.options.isVideo);
1741
+ }
1742
+
1743
+ // use native controls in iPad, iPhone, and Android
1744
+ if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
1745
+
1746
+ // add controls and stop
1747
+ t.$media.attr('controls', 'controls');
1748
+
1749
+ // attempt to fix iOS 3 bug
1750
+ //t.$media.removeAttr('poster');
1751
+ // no Issue found on iOS3 -ttroxell
1752
+
1753
+ // override Apple's autoplay override for iPads
1754
+ if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
1755
+ t.media.load();
1756
+ t.media.play();
1757
+ }
1758
+
1759
+ } else if (mf.isAndroid && t.AndroidUseNativeControls) {
1760
+
1761
+ // leave default player
1762
+
1763
+ } else {
1764
+
1765
+ // DESKTOP: use MediaElementPlayer controls
1766
+
1767
+ // remove native controls
1768
+ t.$media.removeAttr('controls');
1769
+
1770
+ // unique ID
1771
+ t.id = 'mep_' + mejs.mepIndex++;
1772
+
1773
+ // build container
1774
+ t.container =
1775
+ $('<div id="' + t.id + '" class="mejs-container">'+
1776
+ '<div class="mejs-inner">'+
1777
+ '<div class="mejs-mediaelement"></div>'+
1778
+ '<div class="mejs-layers"></div>'+
1779
+ '<div class="mejs-controls"></div>'+
1780
+ '<div class="mejs-clear"></div>'+
1781
+ '</div>' +
1782
+ '</div>')
1783
+ .addClass(t.$media[0].className)
1784
+ .insertBefore(t.$media);
1785
+
1786
+ // add classes for user and content
1787
+ t.container.addClass(
1788
+ (mf.isAndroid ? 'mejs-android ' : '') +
1789
+ (mf.isiOS ? 'mejs-ios ' : '') +
1790
+ (mf.isiPad ? 'mejs-ipad ' : '') +
1791
+ (mf.isiPhone ? 'mejs-iphone ' : '') +
1792
+ (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
1793
+ );
1794
+
1795
+
1796
+ // move the <video/video> tag into the right spot
1797
+ if (mf.isiOS) {
1798
+
1799
+ // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
1800
+ var $newMedia = t.$media.clone();
1801
+
1802
+ t.container.find('.mejs-mediaelement').append($newMedia);
1803
+
1804
+ t.$media.remove();
1805
+ t.$node = t.$media = $newMedia;
1806
+ t.node = t.media = $newMedia[0]
1807
+
1808
+ } else {
1809
+
1810
+ // normal way of moving it into place (doesn't work on iOS)
1811
+ t.container.find('.mejs-mediaelement').append(t.$media);
1812
+ }
1813
+
1814
+ // find parts
1815
+ t.controls = t.container.find('.mejs-controls');
1816
+ t.layers = t.container.find('.mejs-layers');
1817
+
1818
+ // determine the size
1819
+
1820
+ /* size priority:
1821
+ (1) videoWidth (forced),
1822
+ (2) style="width;height;"
1823
+ (3) width attribute,
1824
+ (4) defaultVideoWidth (for unspecified cases)
1825
+ */
1826
+
1827
+ var capsTagName = tagName.substring(0,1).toUpperCase() + tagName.substring(1);
1828
+
1829
+ if (t.options[tagName + 'Width'] > 0 || t.options[tagName + 'Width'].toString().indexOf('%') > -1) {
1830
+ t.width = t.options[tagName + 'Width'];
1831
+ } else if (t.media.style.width !== '' && t.media.style.width !== null) {
1832
+ t.width = t.media.style.width;
1833
+ } else if (t.media.getAttribute('width') !== null) {
1834
+ t.width = t.$media.attr('width');
1835
+ } else {
1836
+ t.width = t.options['default' + capsTagName + 'Width'];
1837
+ }
1838
+
1839
+ if (t.options[tagName + 'Height'] > 0 || t.options[tagName + 'Height'].toString().indexOf('%') > -1) {
1840
+ t.height = t.options[tagName + 'Height'];
1841
+ } else if (t.media.style.height !== '' && t.media.style.height !== null) {
1842
+ t.height = t.media.style.height;
1843
+ } else if (t.$media[0].getAttribute('height') !== null) {
1844
+ t.height = t.$media.attr('height');
1845
+ } else {
1846
+ t.height = t.options['default' + capsTagName + 'Height'];
1847
+ }
1848
+
1849
+ // set the size, while we wait for the plugins to load below
1850
+ t.setPlayerSize(t.width, t.height);
1851
+
1852
+ // create MediaElementShim
1853
+ meOptions.pluginWidth = t.height;
1854
+ meOptions.pluginHeight = t.width;
1855
+ }
1856
+
1857
+
1858
+
1859
+ // create MediaElement shim
1860
+ mejs.MediaElement(t.$media[0], meOptions);
1861
+ },
1862
+
1863
+ showControls: function(doAnimation) {
1864
+ var t = this;
1865
+
1866
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
1867
+
1868
+ if (t.controlsAreVisible)
1869
+ return;
1870
+
1871
+ if (doAnimation) {
1872
+ t.controls
1873
+ .css('visibility','visible')
1874
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
1875
+
1876
+ // any additional controls people might add and want to hide
1877
+ t.container.find('.mejs-control')
1878
+ .css('visibility','visible')
1879
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
1880
+
1881
+ } else {
1882
+ t.controls
1883
+ .css('visibility','visible')
1884
+ .css('display','block');
1885
+
1886
+ // any additional controls people might add and want to hide
1887
+ t.container.find('.mejs-control')
1888
+ .css('visibility','visible')
1889
+ .css('display','block');
1890
+
1891
+ t.controlsAreVisible = true;
1892
+ }
1893
+
1894
+ t.setControlsSize();
1895
+
1896
+ },
1897
+
1898
+ hideControls: function(doAnimation) {
1899
+ var t = this;
1900
+
1901
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
1902
+
1903
+ if (!t.controlsAreVisible)
1904
+ return;
1905
+
1906
+ if (doAnimation) {
1907
+ // fade out main controls
1908
+ t.controls.stop(true, true).fadeOut(200, function() {
1909
+ $(this)
1910
+ .css('visibility','hidden')
1911
+ .css('display','block');
1912
+
1913
+ t.controlsAreVisible = false;
1914
+ });
1915
+
1916
+ // any additional controls people might add and want to hide
1917
+ t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
1918
+ $(this)
1919
+ .css('visibility','hidden')
1920
+ .css('display','block');
1921
+ });
1922
+ } else {
1923
+
1924
+ // hide main controls
1925
+ t.controls
1926
+ .css('visibility','hidden')
1927
+ .css('display','block');
1928
+
1929
+ // hide others
1930
+ t.container.find('.mejs-control')
1931
+ .css('visibility','hidden')
1932
+ .css('display','block');
1933
+
1934
+ t.controlsAreVisible = false;
1935
+ }
1936
+ },
1937
+
1938
+ controlsTimer: null,
1939
+
1940
+ startControlsTimer: function(timeout) {
1941
+
1942
+ var t = this;
1943
+
1944
+ timeout = typeof timeout != 'undefined' ? timeout : 1500;
1945
+
1946
+ t.killControlsTimer('start');
1947
+
1948
+ t.controlsTimer = setTimeout(function() {
1949
+ //console.log('timer fired');
1950
+ t.hideControls();
1951
+ t.killControlsTimer('hide');
1952
+ }, timeout);
1953
+ },
1954
+
1955
+ killControlsTimer: function(src) {
1956
+
1957
+ var t = this;
1958
+
1959
+ if (t.controlsTimer !== null) {
1960
+ clearTimeout(t.controlsTimer);
1961
+ delete t.controlsTimer;
1962
+ t.controlsTimer = null;
1963
+ }
1964
+ },
1965
+
1966
+ controlsEnabled: true,
1967
+
1968
+ disableControls: function() {
1969
+ var t= this;
1970
+
1971
+ t.killControlsTimer();
1972
+ t.hideControls(false);
1973
+ this.controlsEnabled = false;
1974
+ },
1975
+
1976
+ enableControls: function() {
1977
+ var t= this;
1978
+
1979
+ t.showControls(false);
1980
+
1981
+ t.controlsEnabled = true;
1982
+ },
1983
+
1984
+
1985
+ // Sets up all controls and events
1986
+ meReady: function(media, domNode) {
1987
+
1988
+
1989
+ var t = this,
1990
+ mf = mejs.MediaFeatures,
1991
+ autoplayAttr = domNode.getAttribute('autoplay'),
1992
+ autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
1993
+ featureIndex,
1994
+ feature;
1995
+
1996
+ // make sure it can't create itself again if a plugin reloads
1997
+ if (t.created)
1998
+ return;
1999
+ else
2000
+ t.created = true;
2001
+
2002
+ t.media = media;
2003
+ t.domNode = domNode;
2004
+
2005
+ if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
2006
+
2007
+ // two built in features
2008
+ t.buildposter(t, t.controls, t.layers, t.media);
2009
+ t.buildkeyboard(t, t.controls, t.layers, t.media);
2010
+ t.buildoverlays(t, t.controls, t.layers, t.media);
2011
+
2012
+ // grab for use by features
2013
+ t.findTracks();
2014
+
2015
+ // add user-defined features/controls
2016
+ for (featureIndex in t.options.features) {
2017
+ feature = t.options.features[featureIndex];
2018
+ if (t['build' + feature]) {
2019
+ try {
2020
+ t['build' + feature](t, t.controls, t.layers, t.media);
2021
+ } catch (e) {
2022
+ // TODO: report control error
2023
+ //throw e;
2024
+ //console.log('error building ' + feature);
2025
+ //console.log(e);
2026
+ }
2027
+ }
2028
+ }
2029
+
2030
+ t.container.trigger('controlsready');
2031
+
2032
+ // reset all layers and controls
2033
+ t.setPlayerSize(t.width, t.height);
2034
+ t.setControlsSize();
2035
+
2036
+
2037
+ // controls fade
2038
+ if (t.isVideo) {
2039
+
2040
+ if (mejs.MediaFeatures.hasTouch) {
2041
+
2042
+ // for touch devices (iOS, Android)
2043
+ // show/hide without animation on touch
2044
+
2045
+ t.$media.bind('touchstart', function() {
2046
+
2047
+
2048
+ // toggle controls
2049
+ if (t.controlsAreVisible) {
2050
+ t.hideControls(false);
2051
+ } else {
2052
+ if (t.controlsEnabled) {
2053
+ t.showControls(false);
2054
+ }
2055
+ }
2056
+ });
2057
+
2058
+ } else {
2059
+ // click controls
2060
+ var clickElement = (t.media.pluginType == 'native') ? t.$media : $(t.media.pluginElement);
2061
+
2062
+ // click to play/pause
2063
+ clickElement.click(function() {
2064
+ if (media.paused) {
2065
+ media.play();
2066
+ } else {
2067
+ media.pause();
2068
+ }
2069
+ });
2070
+
2071
+
2072
+ // show/hide controls
2073
+ t.container
2074
+ .bind('mouseenter mouseover', function () {
2075
+ if (t.controlsEnabled) {
2076
+ if (!t.options.alwaysShowControls) {
2077
+ t.killControlsTimer('enter');
2078
+ t.showControls();
2079
+ t.startControlsTimer(2500);
2080
+ }
2081
+ }
2082
+ })
2083
+ .bind('mousemove', function() {
2084
+ if (t.controlsEnabled) {
2085
+ if (!t.controlsAreVisible) {
2086
+ t.showControls();
2087
+ }
2088
+ //t.killControlsTimer('move');
2089
+ if (!t.options.alwaysShowControls) {
2090
+ t.startControlsTimer(2500);
2091
+ }
2092
+ }
2093
+ })
2094
+ .bind('mouseleave', function () {
2095
+ if (t.controlsEnabled) {
2096
+ if (!t.media.paused && !t.options.alwaysShowControls) {
2097
+ t.startControlsTimer(1000);
2098
+ }
2099
+ }
2100
+ });
2101
+ }
2102
+
2103
+ // check for autoplay
2104
+ if (autoplay && !t.options.alwaysShowControls) {
2105
+ t.hideControls();
2106
+ }
2107
+
2108
+ // resizer
2109
+ if (t.options.enableAutosize) {
2110
+ t.media.addEventListener('loadedmetadata', function(e) {
2111
+ // if the <video height> was not set and the options.videoHeight was not set
2112
+ // then resize to the real dimensions
2113
+ if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
2114
+ t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
2115
+ t.setControlsSize();
2116
+ t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
2117
+ }
2118
+ }, false);
2119
+ }
2120
+ }
2121
+
2122
+ // EVENTS
2123
+
2124
+ // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
2125
+ media.addEventListener('play', function() {
2126
+
2127
+ // go through all other players
2128
+ for (var i=0, il=mejs.players.length; i<il; i++) {
2129
+ var p = mejs.players[i];
2130
+ if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
2131
+ p.pause();
2132
+ }
2133
+ p.hasFocus = false;
2134
+ }
2135
+
2136
+ t.hasFocus = true;
2137
+ },false);
2138
+
2139
+
2140
+ // ended for all
2141
+ t.media.addEventListener('ended', function (e) {
2142
+ try{
2143
+ t.media.setCurrentTime(0);
2144
+ } catch (exp) {
2145
+
2146
+ }
2147
+ t.media.pause();
2148
+
2149
+ if (t.setProgressRail)
2150
+ t.setProgressRail();
2151
+ if (t.setCurrentRail)
2152
+ t.setCurrentRail();
2153
+
2154
+ if (t.options.loop) {
2155
+ t.media.play();
2156
+ } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
2157
+ t.showControls();
2158
+ }
2159
+ }, false);
2160
+
2161
+ // resize on the first play
2162
+ t.media.addEventListener('loadedmetadata', function(e) {
2163
+ if (t.updateDuration) {
2164
+ t.updateDuration();
2165
+ }
2166
+ if (t.updateCurrent) {
2167
+ t.updateCurrent();
2168
+ }
2169
+
2170
+ if (!t.isFullScreen) {
2171
+ t.setPlayerSize(t.width, t.height);
2172
+ t.setControlsSize();
2173
+ }
2174
+ }, false);
2175
+
2176
+
2177
+ // webkit has trouble doing this without a delay
2178
+ setTimeout(function () {
2179
+ t.setPlayerSize(t.width, t.height);
2180
+ t.setControlsSize();
2181
+ }, 50);
2182
+
2183
+ // adjust controls whenever window sizes (used to be in fullscreen only)
2184
+ $(window).resize(function() {
2185
+
2186
+ // don't resize for fullscreen mode
2187
+ if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
2188
+ t.setPlayerSize(t.width, t.height);
2189
+ }
2190
+
2191
+ // always adjust controls
2192
+ t.setControlsSize();
2193
+ });
2194
+
2195
+ // TEMP: needs to be moved somewhere else
2196
+ if (t.media.pluginType == 'youtube') {
2197
+ t.container.find('.mejs-overlay-play').hide();
2198
+ }
2199
+ }
2200
+
2201
+ // force autoplay for HTML5
2202
+ if (autoplay && media.pluginType == 'native') {
2203
+ media.load();
2204
+ media.play();
2205
+ }
2206
+
2207
+
2208
+ if (t.options.success) {
2209
+
2210
+ if (typeof t.options.success == 'string') {
2211
+ window[t.options.success](t.media, t.domNode, t);
2212
+ } else {
2213
+ t.options.success(t.media, t.domNode, t);
2214
+ }
2215
+ }
2216
+ },
2217
+
2218
+ handleError: function(e) {
2219
+ var t = this;
2220
+
2221
+ t.controls.hide();
2222
+
2223
+ // Tell user that the file cannot be played
2224
+ if (t.options.error) {
2225
+ t.options.error(e);
2226
+ }
2227
+ },
2228
+
2229
+ setPlayerSize: function(width,height) {
2230
+ var t = this;
2231
+
2232
+ if (typeof width != 'undefined')
2233
+ t.width = width;
2234
+
2235
+ if (typeof height != 'undefined')
2236
+ t.height = height;
2237
+
2238
+ // detect 100% mode
2239
+ if (t.height.toString().indexOf('%') > 0) {
2240
+
2241
+ // do we have the native dimensions yet?
2242
+ var
2243
+ nativeWidth = (t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth,
2244
+ nativeHeight = (t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight,
2245
+ parentWidth = t.container.parent().width(),
2246
+ newHeight = parseInt(parentWidth * nativeHeight/nativeWidth, 10);
2247
+
2248
+ if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
2249
+ parentWidth = $(window).width();
2250
+ newHeight = $(window).height();
2251
+ }
2252
+
2253
+
2254
+ // set outer container size
2255
+ t.container
2256
+ .width(parentWidth)
2257
+ .height(newHeight);
2258
+
2259
+ // set native <video>
2260
+ t.$media
2261
+ .width('100%')
2262
+ .height('100%');
2263
+
2264
+ // set shims
2265
+ t.container.find('object, embed, iframe')
2266
+ .width('100%')
2267
+ .height('100%');
2268
+
2269
+ // if shim is ready, send the size to the embeded plugin
2270
+ if (t.media.setVideoSize)
2271
+ t.media.setVideoSize(parentWidth, newHeight);
2272
+
2273
+ // set the layers
2274
+ t.layers.children('.mejs-layer')
2275
+ .width('100%')
2276
+ .height('100%');
2277
+
2278
+
2279
+ } else {
2280
+
2281
+ t.container
2282
+ .width(t.width)
2283
+ .height(t.height);
2284
+
2285
+ t.layers.children('.mejs-layer')
2286
+ .width(t.width)
2287
+ .height(t.height);
2288
+
2289
+ }
2290
+ },
2291
+
2292
+ setControlsSize: function() {
2293
+ var t = this,
2294
+ usedWidth = 0,
2295
+ railWidth = 0,
2296
+ rail = t.controls.find('.mejs-time-rail'),
2297
+ total = t.controls.find('.mejs-time-total'),
2298
+ current = t.controls.find('.mejs-time-current'),
2299
+ loaded = t.controls.find('.mejs-time-loaded'),
2300
+ others = rail.siblings();
2301
+
2302
+
2303
+ // allow the size to come from custom CSS
2304
+ if (t.options && !t.options.autosizeProgress) {
2305
+ // Also, frontends devs can be more flexible
2306
+ // due the opportunity of absolute positioning.
2307
+ railWidth = parseInt(rail.css('width'));
2308
+ }
2309
+
2310
+ // attempt to autosize
2311
+ if (railWidth === 0 || !railWidth) {
2312
+
2313
+ // find the size of all the other controls besides the rail
2314
+ others.each(function() {
2315
+ if ($(this).css('position') != 'absolute') {
2316
+ usedWidth += $(this).outerWidth(true);
2317
+ }
2318
+ });
2319
+
2320
+ // fit the rail into the remaining space
2321
+ railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
2322
+ }
2323
+
2324
+ // outer area
2325
+ rail.width(railWidth);
2326
+ // dark space
2327
+ total.width(railWidth - (total.outerWidth(true) - total.width()));
2328
+
2329
+ if (t.setProgressRail)
2330
+ t.setProgressRail();
2331
+ if (t.setCurrentRail)
2332
+ t.setCurrentRail();
2333
+ },
2334
+
2335
+
2336
+ buildposter: function(player, controls, layers, media) {
2337
+ var t = this,
2338
+ poster =
2339
+ $('<div class="mejs-poster mejs-layer">' +
2340
+ '</div>')
2341
+ .appendTo(layers),
2342
+ posterUrl = player.$media.attr('poster');
2343
+
2344
+ // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
2345
+ if (player.options.poster !== '') {
2346
+ posterUrl = player.options.poster;
2347
+ }
2348
+
2349
+ // second, try the real poster
2350
+ if (posterUrl !== '' && posterUrl != null) {
2351
+ t.setPoster(posterUrl);
2352
+ } else {
2353
+ poster.hide();
2354
+ }
2355
+
2356
+ media.addEventListener('play',function() {
2357
+ poster.hide();
2358
+ }, false);
2359
+ },
2360
+
2361
+ setPoster: function(url) {
2362
+ var t = this,
2363
+ posterDiv = t.container.find('.mejs-poster'),
2364
+ posterImg = posterDiv.find('img');
2365
+
2366
+ if (posterImg.length == 0) {
2367
+ posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
2368
+ }
2369
+
2370
+ posterImg.attr('src', url);
2371
+ },
2372
+
2373
+ buildoverlays: function(player, controls, layers, media) {
2374
+ if (!player.isVideo)
2375
+ return;
2376
+
2377
+ var
2378
+ loading =
2379
+ $('<div class="mejs-overlay mejs-layer">'+
2380
+ '<div class="mejs-overlay-loading"><span></span></div>'+
2381
+ '</div>')
2382
+ .hide() // start out hidden
2383
+ .appendTo(layers),
2384
+ error =
2385
+ $('<div class="mejs-overlay mejs-layer">'+
2386
+ '<div class="mejs-overlay-error"></div>'+
2387
+ '</div>')
2388
+ .hide() // start out hidden
2389
+ .appendTo(layers),
2390
+ // this needs to come last so it's on top
2391
+ bigPlay =
2392
+ $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
2393
+ '<div class="mejs-overlay-button"></div>'+
2394
+ '</div>')
2395
+ .appendTo(layers)
2396
+ .click(function() {
2397
+ if (media.paused) {
2398
+ media.play();
2399
+ } else {
2400
+ media.pause();
2401
+ }
2402
+ });
2403
+
2404
+ /*
2405
+ if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
2406
+ bigPlay.remove();
2407
+ loading.remove();
2408
+ }
2409
+ */
2410
+
2411
+
2412
+ // show/hide big play button
2413
+ media.addEventListener('play',function() {
2414
+ bigPlay.hide();
2415
+ loading.hide();
2416
+ controls.find('.mejs-time-buffering').hide();
2417
+ error.hide();
2418
+ }, false);
2419
+
2420
+ media.addEventListener('playing', function() {
2421
+ bigPlay.hide();
2422
+ loading.hide();
2423
+ controls.find('.mejs-time-buffering').hide();
2424
+ error.hide();
2425
+ }, false);
2426
+
2427
+ media.addEventListener('seeking', function() {
2428
+ loading.show();
2429
+ controls.find('.mejs-time-buffering').show();
2430
+ }, false);
2431
+
2432
+ media.addEventListener('seeked', function() {
2433
+ loading.hide();
2434
+ controls.find('.mejs-time-buffering').hide();
2435
+ }, false);
2436
+
2437
+ media.addEventListener('pause',function() {
2438
+ if (!mejs.MediaFeatures.isiPhone) {
2439
+ bigPlay.show();
2440
+ }
2441
+ }, false);
2442
+
2443
+ media.addEventListener('waiting', function() {
2444
+ loading.show();
2445
+ controls.find('.mejs-time-buffering').show();
2446
+ }, false);
2447
+
2448
+
2449
+ // show/hide loading
2450
+ media.addEventListener('loadeddata',function() {
2451
+ // for some reason Chrome is firing this event
2452
+ //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
2453
+ // return;
2454
+
2455
+ loading.show();
2456
+ controls.find('.mejs-time-buffering').show();
2457
+ }, false);
2458
+ media.addEventListener('canplay',function() {
2459
+ loading.hide();
2460
+ controls.find('.mejs-time-buffering').hide();
2461
+ }, false);
2462
+
2463
+ // error handling
2464
+ media.addEventListener('error',function() {
2465
+ loading.hide();
2466
+ controls.find('.mejs-time-buffering').hide();
2467
+ error.show();
2468
+ error.find('mejs-overlay-error').html("Error loading this resource");
2469
+ }, false);
2470
+ },
2471
+
2472
+ buildkeyboard: function(player, controls, layers, media) {
2473
+
2474
+ var t = this;
2475
+
2476
+ // listen for key presses
2477
+ $(document).keydown(function(e) {
2478
+
2479
+ if (player.hasFocus && player.options.enableKeyboard) {
2480
+
2481
+ // find a matching key
2482
+ for (var i=0, il=player.options.keyActions.length; i<il; i++) {
2483
+ var keyAction = player.options.keyActions[i];
2484
+
2485
+ for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
2486
+ if (e.keyCode == keyAction.keys[j]) {
2487
+ e.preventDefault();
2488
+ keyAction.action(player, media);
2489
+ return false;
2490
+ }
2491
+ }
2492
+ }
2493
+ }
2494
+
2495
+ return true;
2496
+ });
2497
+
2498
+ // check if someone clicked outside a player region, then kill its focus
2499
+ $(document).click(function(event) {
2500
+ if ($(event.target).closest('.mejs-container').length == 0) {
2501
+ player.hasFocus = false;
2502
+ }
2503
+ });
2504
+
2505
+ },
2506
+
2507
+ findTracks: function() {
2508
+ var t = this,
2509
+ tracktags = t.$media.find('track');
2510
+
2511
+ // store for use by plugins
2512
+ t.tracks = [];
2513
+ tracktags.each(function(index, track) {
2514
+
2515
+ track = $(track);
2516
+
2517
+ t.tracks.push({
2518
+ srclang: track.attr('srclang').toLowerCase(),
2519
+ src: track.attr('src'),
2520
+ kind: track.attr('kind'),
2521
+ label: track.attr('label') || '',
2522
+ entries: [],
2523
+ isLoaded: false
2524
+ });
2525
+ });
2526
+ },
2527
+ changeSkin: function(className) {
2528
+ this.container[0].className = 'mejs-container ' + className;
2529
+ this.setPlayerSize(this.width, this.height);
2530
+ this.setControlsSize();
2531
+ },
2532
+ play: function() {
2533
+ this.media.play();
2534
+ },
2535
+ pause: function() {
2536
+ this.media.pause();
2537
+ },
2538
+ load: function() {
2539
+ this.media.load();
2540
+ },
2541
+ setMuted: function(muted) {
2542
+ this.media.setMuted(muted);
2543
+ },
2544
+ setCurrentTime: function(time) {
2545
+ this.media.setCurrentTime(time);
2546
+ },
2547
+ getCurrentTime: function() {
2548
+ return this.media.currentTime;
2549
+ },
2550
+ setVolume: function(volume) {
2551
+ this.media.setVolume(volume);
2552
+ },
2553
+ getVolume: function() {
2554
+ return this.media.volume;
2555
+ },
2556
+ setSrc: function(src) {
2557
+ this.media.setSrc(src);
2558
+ },
2559
+ remove: function() {
2560
+ var t = this;
2561
+
2562
+ if (t.media.pluginType == 'flash') {
2563
+ t.media.remove();
2564
+ } else if (t.media.pluginType == 'native') {
2565
+ t.media.prop('controls', true);
2566
+ }
2567
+
2568
+ // grab video and put it back in place
2569
+ if (!t.isDynamic) {
2570
+ t.$node.insertBefore(t.container)
2571
+ }
2572
+
2573
+ t.container.remove();
2574
+ }
2575
+ };
2576
+
2577
+ // turn into jQuery plugin
2578
+ if (typeof jQuery != 'undefined') {
2579
+ jQuery.fn.mediaelementplayer = function (options) {
2580
+ return this.each(function () {
2581
+ new mejs.MediaElementPlayer(this, options);
2582
+ });
2583
+ };
2584
+ }
2585
+
2586
+ $(document).ready(function() {
2587
+ // auto enable using JSON attribute
2588
+ $('.mejs-player').mediaelementplayer();
2589
+ });
2590
+
2591
+ // push out to window
2592
+ window.MediaElementPlayer = mejs.MediaElementPlayer;
2593
+
2594
+ })(mejs.$);
2595
+
2596
+ (function($) {
2597
+
2598
+ $.extend(mejs.MepDefaults, {
2599
+ playpauseText: 'Play/Pause'
2600
+ });
2601
+
2602
+ // PLAY/pause BUTTON
2603
+ $.extend(MediaElementPlayer.prototype, {
2604
+ buildplaypause: function(player, controls, layers, media) {
2605
+ var
2606
+ t = this,
2607
+ play =
2608
+ $('<div class="mejs-button mejs-playpause-button mejs-play" >' +
2609
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '"></button>' +
2610
+ '</div>')
2611
+ .appendTo(controls)
2612
+ .click(function(e) {
2613
+ e.preventDefault();
2614
+
2615
+ if (media.paused) {
2616
+ media.play();
2617
+ } else {
2618
+ media.pause();
2619
+ }
2620
+
2621
+ return false;
2622
+ });
2623
+
2624
+ media.addEventListener('play',function() {
2625
+ play.removeClass('mejs-play').addClass('mejs-pause');
2626
+ }, false);
2627
+ media.addEventListener('playing',function() {
2628
+ play.removeClass('mejs-play').addClass('mejs-pause');
2629
+ }, false);
2630
+
2631
+
2632
+ media.addEventListener('pause',function() {
2633
+ play.removeClass('mejs-pause').addClass('mejs-play');
2634
+ }, false);
2635
+ media.addEventListener('paused',function() {
2636
+ play.removeClass('mejs-pause').addClass('mejs-play');
2637
+ }, false);
2638
+ }
2639
+ });
2640
+
2641
+ })(mejs.$);
2642
+ (function($) {
2643
+
2644
+ $.extend(mejs.MepDefaults, {
2645
+ stopText: 'Stop'
2646
+ });
2647
+
2648
+ // STOP BUTTON
2649
+ $.extend(MediaElementPlayer.prototype, {
2650
+ buildstop: function(player, controls, layers, media) {
2651
+ var t = this,
2652
+ stop =
2653
+ $('<div class="mejs-button mejs-stop-button mejs-stop">' +
2654
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '"></button>' +
2655
+ '</div>')
2656
+ .appendTo(controls)
2657
+ .click(function() {
2658
+ if (!media.paused) {
2659
+ media.pause();
2660
+ }
2661
+ if (media.currentTime > 0) {
2662
+ media.setCurrentTime(0);
2663
+ controls.find('.mejs-time-current').width('0px');
2664
+ controls.find('.mejs-time-handle').css('left', '0px');
2665
+ controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
2666
+ controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );
2667
+ layers.find('.mejs-poster').show();
2668
+ }
2669
+ });
2670
+ }
2671
+ });
2672
+
2673
+ })(mejs.$);
2674
+ (function($) {
2675
+ // progress/loaded bar
2676
+ $.extend(MediaElementPlayer.prototype, {
2677
+ buildprogress: function(player, controls, layers, media) {
2678
+
2679
+ $('<div class="mejs-time-rail">'+
2680
+ '<span class="mejs-time-total">'+
2681
+ '<span class="mejs-time-buffering"></span>'+
2682
+ '<span class="mejs-time-loaded"></span>'+
2683
+ '<span class="mejs-time-current"></span>'+
2684
+ '<span class="mejs-time-handle"></span>'+
2685
+ '<span class="mejs-time-float">' +
2686
+ '<span class="mejs-time-float-current">00:00</span>' +
2687
+ '<span class="mejs-time-float-corner"></span>' +
2688
+ '</span>'+
2689
+ '</span>'+
2690
+ '</div>')
2691
+ .appendTo(controls);
2692
+ controls.find('.mejs-time-buffering').hide();
2693
+
2694
+ var
2695
+ t = this,
2696
+ total = controls.find('.mejs-time-total'),
2697
+ loaded = controls.find('.mejs-time-loaded'),
2698
+ current = controls.find('.mejs-time-current'),
2699
+ handle = controls.find('.mejs-time-handle'),
2700
+ timefloat = controls.find('.mejs-time-float'),
2701
+ timefloatcurrent = controls.find('.mejs-time-float-current'),
2702
+ handleMouseMove = function (e) {
2703
+ // mouse position relative to the object
2704
+ var x = e.pageX,
2705
+ offset = total.offset(),
2706
+ width = total.outerWidth(),
2707
+ percentage = 0,
2708
+ newTime = 0,
2709
+ pos = x - offset.left;
2710
+
2711
+
2712
+ if (x > offset.left && x <= width + offset.left && media.duration) {
2713
+ percentage = ((x - offset.left) / width);
2714
+ newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
2715
+
2716
+ // seek to where the mouse is
2717
+ if (mouseIsDown) {
2718
+ media.setCurrentTime(newTime);
2719
+ }
2720
+
2721
+ // position floating time box
2722
+ if (!mejs.MediaFeatures.hasTouch) {
2723
+ timefloat.css('left', pos);
2724
+ timefloatcurrent.html( mejs.Utility.secondsToTimeCode(newTime) );
2725
+ timefloat.show();
2726
+ }
2727
+ }
2728
+ },
2729
+ mouseIsDown = false,
2730
+ mouseIsOver = false;
2731
+
2732
+ // handle clicks
2733
+ //controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove);
2734
+ total
2735
+ .bind('mousedown', function (e) {
2736
+ // only handle left clicks
2737
+ if (e.which === 1) {
2738
+ mouseIsDown = true;
2739
+ handleMouseMove(e);
2740
+ $(document)
2741
+ .bind('mousemove.dur', function(e) {
2742
+ handleMouseMove(e);
2743
+ })
2744
+ .bind('mouseup.dur', function (e) {
2745
+ mouseIsDown = false;
2746
+ timefloat.hide();
2747
+ $(document).unbind('.dur');
2748
+ });
2749
+ return false;
2750
+ }
2751
+ })
2752
+ .bind('mouseenter', function(e) {
2753
+ mouseIsOver = true;
2754
+ $(document).bind('mousemove.dur', function(e) {
2755
+ handleMouseMove(e);
2756
+ });
2757
+ if (!mejs.MediaFeatures.hasTouch) {
2758
+ timefloat.show();
2759
+ }
2760
+ })
2761
+ .bind('mouseleave',function(e) {
2762
+ mouseIsOver = false;
2763
+ if (!mouseIsDown) {
2764
+ $(document).unbind('.dur');
2765
+ timefloat.hide();
2766
+ }
2767
+ });
2768
+
2769
+ // loading
2770
+ media.addEventListener('progress', function (e) {
2771
+ player.setProgressRail(e);
2772
+ player.setCurrentRail(e);
2773
+ }, false);
2774
+
2775
+ // current time
2776
+ media.addEventListener('timeupdate', function(e) {
2777
+ player.setProgressRail(e);
2778
+ player.setCurrentRail(e);
2779
+ }, false);
2780
+
2781
+
2782
+ // store for later use
2783
+ t.loaded = loaded;
2784
+ t.total = total;
2785
+ t.current = current;
2786
+ t.handle = handle;
2787
+ },
2788
+ setProgressRail: function(e) {
2789
+
2790
+ var
2791
+ t = this,
2792
+ target = (e != undefined) ? e.target : t.media,
2793
+ percent = null;
2794
+
2795
+ // newest HTML5 spec has buffered array (FF4, Webkit)
2796
+ if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
2797
+ // TODO: account for a real array with multiple values (only Firefox 4 has this so far)
2798
+ percent = target.buffered.end(0) / target.duration;
2799
+ }
2800
+ // Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
2801
+ // to be anything other than 0. If the byte count is available we use this instead.
2802
+ // Browsers that support the else if do not seem to have the bufferedBytes value and
2803
+ // should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
2804
+ else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
2805
+ percent = target.bufferedBytes / target.bytesTotal;
2806
+ }
2807
+ // Firefox 3 with an Ogg file seems to go this way
2808
+ else if (e && e.lengthComputable && e.total != 0) {
2809
+ percent = e.loaded/e.total;
2810
+ }
2811
+
2812
+ // finally update the progress bar
2813
+ if (percent !== null) {
2814
+ percent = Math.min(1, Math.max(0, percent));
2815
+ // update loaded bar
2816
+ if (t.loaded && t.total) {
2817
+ t.loaded.width(t.total.width() * percent);
2818
+ }
2819
+ }
2820
+ },
2821
+ setCurrentRail: function() {
2822
+
2823
+ var t = this;
2824
+
2825
+ if (t.media.currentTime != undefined && t.media.duration) {
2826
+
2827
+ // update bar and handle
2828
+ if (t.total && t.handle) {
2829
+ var
2830
+ newWidth = t.total.width() * t.media.currentTime / t.media.duration,
2831
+ handlePos = newWidth - (t.handle.outerWidth(true) / 2);
2832
+
2833
+ t.current.width(newWidth);
2834
+ t.handle.css('left', handlePos);
2835
+ }
2836
+ }
2837
+
2838
+ }
2839
+ });
2840
+ })(mejs.$);
2841
+ (function($) {
2842
+
2843
+ // options
2844
+ $.extend(mejs.MepDefaults, {
2845
+ duration: -1,
2846
+ timeAndDurationSeparator: ' <span> | </span> '
2847
+ });
2848
+
2849
+
2850
+ // current and duration 00:00 / 00:00
2851
+ $.extend(MediaElementPlayer.prototype, {
2852
+ buildcurrent: function(player, controls, layers, media) {
2853
+ var t = this;
2854
+
2855
+ $('<div class="mejs-time">'+
2856
+ '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
2857
+ + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
2858
+ '</div>')
2859
+ .appendTo(controls);
2860
+
2861
+ t.currenttime = t.controls.find('.mejs-currenttime');
2862
+
2863
+ media.addEventListener('timeupdate',function() {
2864
+ player.updateCurrent();
2865
+ }, false);
2866
+ },
2867
+
2868
+
2869
+ buildduration: function(player, controls, layers, media) {
2870
+ var t = this;
2871
+
2872
+ if (controls.children().last().find('.mejs-currenttime').length > 0) {
2873
+ $(t.options.timeAndDurationSeparator +
2874
+ '<span class="mejs-duration">' +
2875
+ (t.options.duration > 0 ?
2876
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
2877
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
2878
+ ) +
2879
+ '</span>')
2880
+ .appendTo(controls.find('.mejs-time'));
2881
+ } else {
2882
+
2883
+ // add class to current time
2884
+ controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
2885
+
2886
+ $('<div class="mejs-time mejs-duration-container">'+
2887
+ '<span class="mejs-duration">' +
2888
+ (t.options.duration > 0 ?
2889
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
2890
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
2891
+ ) +
2892
+ '</span>' +
2893
+ '</div>')
2894
+ .appendTo(controls);
2895
+ }
2896
+
2897
+ t.durationD = t.controls.find('.mejs-duration');
2898
+
2899
+ media.addEventListener('timeupdate',function() {
2900
+ player.updateDuration();
2901
+ }, false);
2902
+ },
2903
+
2904
+ updateCurrent: function() {
2905
+ var t = this;
2906
+
2907
+ if (t.currenttime) {
2908
+ t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
2909
+ }
2910
+ },
2911
+
2912
+ updateDuration: function() {
2913
+ var t = this;
2914
+
2915
+ if (t.media.duration && t.durationD) {
2916
+ t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
2917
+ }
2918
+ }
2919
+ });
2920
+
2921
+ })(mejs.$);
2922
+ (function($) {
2923
+
2924
+ $.extend(mejs.MepDefaults, {
2925
+ muteText: 'Mute Toggle',
2926
+ hideVolumeOnTouchDevices: true,
2927
+
2928
+ audioVolume: 'horizontal',
2929
+ videoVolume: 'vertical'
2930
+ });
2931
+
2932
+ $.extend(MediaElementPlayer.prototype, {
2933
+ buildvolume: function(player, controls, layers, media) {
2934
+
2935
+ // Android and iOS don't support volume controls
2936
+ if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices)
2937
+ return;
2938
+
2939
+ var t = this,
2940
+ mode = (t.isVideo) ? t.options.videoVolume : t.options.audioVolume,
2941
+ mute = (mode == 'horizontal') ?
2942
+
2943
+ // horizontal version
2944
+ $('<div class="mejs-button mejs-volume-button mejs-mute">'+
2945
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
2946
+ '</div>' +
2947
+ '<div class="mejs-horizontal-volume-slider">'+ // outer background
2948
+ '<div class="mejs-horizontal-volume-total"></div>'+ // line background
2949
+ '<div class="mejs-horizontal-volume-current"></div>'+ // current volume
2950
+ '<div class="mejs-horizontal-volume-handle"></div>'+ // handle
2951
+ '</div>'
2952
+ )
2953
+ .appendTo(controls) :
2954
+
2955
+ // vertical version
2956
+ $('<div class="mejs-button mejs-volume-button mejs-mute">'+
2957
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
2958
+ '<div class="mejs-volume-slider">'+ // outer background
2959
+ '<div class="mejs-volume-total"></div>'+ // line background
2960
+ '<div class="mejs-volume-current"></div>'+ // current volume
2961
+ '<div class="mejs-volume-handle"></div>'+ // handle
2962
+ '</div>'+
2963
+ '</div>')
2964
+ .appendTo(controls),
2965
+ volumeSlider = t.container.find('.mejs-volume-slider, .mejs-horizontal-volume-slider'),
2966
+ volumeTotal = t.container.find('.mejs-volume-total, .mejs-horizontal-volume-total'),
2967
+ volumeCurrent = t.container.find('.mejs-volume-current, .mejs-horizontal-volume-current'),
2968
+ volumeHandle = t.container.find('.mejs-volume-handle, .mejs-horizontal-volume-handle'),
2969
+
2970
+ positionVolumeHandle = function(volume, secondTry) {
2971
+
2972
+ if (!volumeSlider.is(':visible') && typeof secondTry != 'undefined') {
2973
+ volumeSlider.show();
2974
+ positionVolumeHandle(volume, true);
2975
+ volumeSlider.hide()
2976
+ return;
2977
+ }
2978
+
2979
+ // correct to 0-1
2980
+ volume = Math.max(0,volume);
2981
+ volume = Math.min(volume,1);
2982
+
2983
+ // ajust mute button style
2984
+ if (volume == 0) {
2985
+ mute.removeClass('mejs-mute').addClass('mejs-unmute');
2986
+ } else {
2987
+ mute.removeClass('mejs-unmute').addClass('mejs-mute');
2988
+ }
2989
+
2990
+ // position slider
2991
+ if (mode == 'vertical') {
2992
+ var
2993
+
2994
+ // height of the full size volume slider background
2995
+ totalHeight = volumeTotal.height(),
2996
+
2997
+ // top/left of full size volume slider background
2998
+ totalPosition = volumeTotal.position(),
2999
+
3000
+ // the new top position based on the current volume
3001
+ // 70% volume on 100px height == top:30px
3002
+ newTop = totalHeight - (totalHeight * volume);
3003
+
3004
+ // handle
3005
+ volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2));
3006
+
3007
+ // show the current visibility
3008
+ volumeCurrent.height(totalHeight - newTop );
3009
+ volumeCurrent.css('top', totalPosition.top + newTop);
3010
+ } else {
3011
+ var
3012
+
3013
+ // height of the full size volume slider background
3014
+ totalWidth = volumeTotal.width(),
3015
+
3016
+ // top/left of full size volume slider background
3017
+ totalPosition = volumeTotal.position(),
3018
+
3019
+ // the new left position based on the current volume
3020
+ newLeft = totalWidth * volume;
3021
+
3022
+ // handle
3023
+ volumeHandle.css('left', totalPosition.left + newLeft - (volumeHandle.width() / 2));
3024
+
3025
+ // rezize the current part of the volume bar
3026
+ volumeCurrent.width( newLeft );
3027
+ }
3028
+ },
3029
+ handleVolumeMove = function(e) {
3030
+
3031
+ var volume = null,
3032
+ totalOffset = volumeTotal.offset();
3033
+
3034
+ // calculate the new volume based on the moust position
3035
+ if (mode == 'vertical') {
3036
+
3037
+ var
3038
+ railHeight = volumeTotal.height(),
3039
+ totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10),
3040
+ newY = e.pageY - totalOffset.top;
3041
+
3042
+ volume = (railHeight - newY) / railHeight;
3043
+
3044
+ // the controls just hide themselves (usually when mouse moves too far up)
3045
+ if (totalOffset.top == 0 || totalOffset.left == 0)
3046
+ return;
3047
+
3048
+ } else {
3049
+ var
3050
+ railWidth = volumeTotal.width(),
3051
+ newX = e.pageX - totalOffset.left;
3052
+
3053
+ volume = newX / railWidth;
3054
+ }
3055
+
3056
+ // ensure the volume isn't outside 0-1
3057
+ volume = Math.max(0,volume);
3058
+ volume = Math.min(volume,1);
3059
+
3060
+ // position the slider and handle
3061
+ positionVolumeHandle(volume);
3062
+
3063
+ // set the media object (this will trigger the volumechanged event)
3064
+ if (volume == 0) {
3065
+ media.setMuted(true);
3066
+ } else {
3067
+ media.setMuted(false);
3068
+ }
3069
+ media.setVolume(volume);
3070
+ },
3071
+ mouseIsDown = false,
3072
+ mouseIsOver = false;
3073
+
3074
+ // SLIDER
3075
+
3076
+ mute
3077
+ .hover(function() {
3078
+ volumeSlider.show();
3079
+ mouseIsOver = true;
3080
+ }, function() {
3081
+ mouseIsOver = false;
3082
+
3083
+ if (!mouseIsDown && mode == 'vertical') {
3084
+ volumeSlider.hide();
3085
+ }
3086
+ });
3087
+
3088
+ volumeSlider
3089
+ .bind('mouseover', function() {
3090
+ mouseIsOver = true;
3091
+ })
3092
+ .bind('mousedown', function (e) {
3093
+ handleVolumeMove(e);
3094
+ $(document)
3095
+ .bind('mousemove.vol', function(e) {
3096
+ handleVolumeMove(e);
3097
+ })
3098
+ .bind('mouseup.vol', function () {
3099
+ mouseIsDown = false;
3100
+ $(document).unbind('.vol');
3101
+
3102
+ if (!mouseIsOver && mode == 'vertical') {
3103
+ volumeSlider.hide();
3104
+ }
3105
+ });
3106
+ mouseIsDown = true;
3107
+
3108
+ return false;
3109
+ });
3110
+
3111
+
3112
+ // MUTE button
3113
+ mute.find('button').click(function() {
3114
+ media.setMuted( !media.muted );
3115
+ });
3116
+
3117
+ // listen for volume change events from other sources
3118
+ media.addEventListener('volumechange', function(e) {
3119
+ if (!mouseIsDown) {
3120
+ if (media.muted) {
3121
+ positionVolumeHandle(0);
3122
+ mute.removeClass('mejs-mute').addClass('mejs-unmute');
3123
+ } else {
3124
+ positionVolumeHandle(media.volume);
3125
+ mute.removeClass('mejs-unmute').addClass('mejs-mute');
3126
+ }
3127
+ }
3128
+ }, false);
3129
+
3130
+ if (t.container.is(':visible')) {
3131
+ // set initial volume
3132
+ positionVolumeHandle(player.options.startVolume);
3133
+
3134
+ // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
3135
+ if (media.pluginType === 'native') {
3136
+ media.setVolume(player.options.startVolume);
3137
+ }
3138
+ }
3139
+ }
3140
+ });
3141
+
3142
+ })(mejs.$);
3143
+
3144
+ (function($) {
3145
+
3146
+ $.extend(mejs.MepDefaults, {
3147
+ usePluginFullScreen: true,
3148
+ newWindowCallback: function() { return '';},
3149
+ fullscreenText: 'Fullscreen'
3150
+ });
3151
+
3152
+ $.extend(MediaElementPlayer.prototype, {
3153
+
3154
+ isFullScreen: false,
3155
+
3156
+ isNativeFullScreen: false,
3157
+
3158
+ docStyleOverflow: null,
3159
+
3160
+ isInIframe: false,
3161
+
3162
+ buildfullscreen: function(player, controls, layers, media) {
3163
+
3164
+ if (!player.isVideo)
3165
+ return;
3166
+
3167
+ player.isInIframe = (window.location != window.parent.location);
3168
+
3169
+ // native events
3170
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
3171
+
3172
+ // chrome doesn't alays fire this in an iframe
3173
+ var target = null;
3174
+
3175
+ if (mejs.MediaFeatures.hasMozNativeFullScreen) {
3176
+ target = $(document);
3177
+ } else {
3178
+ target = player.container;
3179
+ }
3180
+
3181
+ target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
3182
+ //player.container.bind('webkitfullscreenchange', function(e) {
3183
+
3184
+
3185
+ if (mejs.MediaFeatures.isFullScreen()) {
3186
+ player.isNativeFullScreen = true;
3187
+ // reset the controls once we are fully in full screen
3188
+ player.setControlsSize();
3189
+ } else {
3190
+ player.isNativeFullScreen = false;
3191
+ // when a user presses ESC
3192
+ // make sure to put the player back into place
3193
+ player.exitFullScreen();
3194
+ }
3195
+ });
3196
+ }
3197
+
3198
+ var t = this,
3199
+ normalHeight = 0,
3200
+ normalWidth = 0,
3201
+ container = player.container,
3202
+ fullscreenBtn =
3203
+ $('<div class="mejs-button mejs-fullscreen-button">' +
3204
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
3205
+ '</div>')
3206
+ .appendTo(controls);
3207
+
3208
+ if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
3209
+
3210
+ fullscreenBtn.click(function() {
3211
+ var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
3212
+
3213
+ if (isFullScreen) {
3214
+ player.exitFullScreen();
3215
+ } else {
3216
+ player.enterFullScreen();
3217
+ }
3218
+ });
3219
+
3220
+ } else {
3221
+
3222
+ var hideTimeout = null,
3223
+ supportsPointerEvents = (function() {
3224
+ // TAKEN FROM MODERNIZR
3225
+ var element = document.createElement('x'),
3226
+ documentElement = document.documentElement,
3227
+ getComputedStyle = window.getComputedStyle,
3228
+ supports;
3229
+ if(!('pointerEvents' in element.style)){
3230
+ return false;
3231
+ }
3232
+ element.style.pointerEvents = 'auto';
3233
+ element.style.pointerEvents = 'x';
3234
+ documentElement.appendChild(element);
3235
+ supports = getComputedStyle &&
3236
+ getComputedStyle(element, '').pointerEvents === 'auto';
3237
+ documentElement.removeChild(element);
3238
+ return !!supports;
3239
+ })();
3240
+
3241
+ console.log('supportsPointerEvents', supportsPointerEvents);
3242
+
3243
+ if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
3244
+
3245
+ // allows clicking through the fullscreen button and controls down directly to Flash
3246
+
3247
+ /*
3248
+ When a user puts his mouse over the fullscreen button, the controls are disabled
3249
+ So we put a div over the video and another one on iether side of the fullscreen button
3250
+ that caputre mouse movement
3251
+ and restore the controls once the mouse moves outside of the fullscreen button
3252
+ */
3253
+
3254
+ var fullscreenIsDisabled = false,
3255
+ restoreControls = function() {
3256
+ if (fullscreenIsDisabled) {
3257
+ // hide the hovers
3258
+ videoHoverDiv.hide();
3259
+ controlsLeftHoverDiv.hide();
3260
+ controlsRightHoverDiv.hide();
3261
+
3262
+ // restore the control bar
3263
+ fullscreenBtn.css('pointer-events', '');
3264
+ t.controls.css('pointer-events', '');
3265
+
3266
+ // store for later
3267
+ fullscreenIsDisabled = false;
3268
+ }
3269
+ },
3270
+ videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
3271
+ controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
3272
+ controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
3273
+ positionHoverDivs = function() {
3274
+ var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
3275
+ videoHoverDiv.css(style);
3276
+ controlsLeftHoverDiv.css(style);
3277
+ controlsRightHoverDiv.css(style);
3278
+
3279
+ // over video, but not controls
3280
+ videoHoverDiv
3281
+ .width( t.container.width() )
3282
+ .height( t.container.height() - t.controls.height() );
3283
+
3284
+ // over controls, but not the fullscreen button
3285
+ var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
3286
+ fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
3287
+
3288
+ controlsLeftHoverDiv
3289
+ .width( fullScreenBtnOffset )
3290
+ .height( t.controls.height() )
3291
+ .css({top: t.container.height() - t.controls.height()});
3292
+
3293
+ // after the fullscreen button
3294
+ controlsRightHoverDiv
3295
+ .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
3296
+ .height( t.controls.height() )
3297
+ .css({top: t.container.height() - t.controls.height(),
3298
+ left: fullScreenBtnOffset + fullScreenBtnWidth});
3299
+ };
3300
+
3301
+ $(document).resize(function() {
3302
+ positionHoverDivs();
3303
+ });
3304
+
3305
+ // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
3306
+ fullscreenBtn
3307
+ .mouseover(function() {
3308
+
3309
+ if (!t.isFullScreen) {
3310
+
3311
+ var buttonPos = fullscreenBtn.offset(),
3312
+ containerPos = player.container.offset();
3313
+
3314
+ // move the button in Flash into place
3315
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
3316
+
3317
+ // allows click through
3318
+ fullscreenBtn.css('pointer-events', 'none');
3319
+ t.controls.css('pointer-events', 'none');
3320
+
3321
+ // show the divs that will restore things
3322
+ videoHoverDiv.show();
3323
+ controlsRightHoverDiv.show();
3324
+ controlsLeftHoverDiv.show();
3325
+ positionHoverDivs();
3326
+
3327
+ fullscreenIsDisabled = true;
3328
+ }
3329
+
3330
+ });
3331
+
3332
+ // restore controls anytime the user enters or leaves fullscreen
3333
+ media.addEventListener('fullscreenchange', function(e) {
3334
+ restoreControls();
3335
+ });
3336
+
3337
+
3338
+ // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
3339
+ // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
3340
+ /*
3341
+ $(document).mousemove(function(e) {
3342
+
3343
+ // if the mouse is anywhere but the fullsceen button, then restore it all
3344
+ if (fullscreenIsDisabled) {
3345
+
3346
+ var fullscreenBtnPos = fullscreenBtn.offset();
3347
+
3348
+
3349
+ if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
3350
+ e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
3351
+ ) {
3352
+
3353
+ fullscreenBtn.css('pointer-events', '');
3354
+ t.controls.css('pointer-events', '');
3355
+
3356
+ fullscreenIsDisabled = false;
3357
+ }
3358
+ }
3359
+ });
3360
+ */
3361
+
3362
+
3363
+ } else {
3364
+
3365
+ // the hover state will show the fullscreen button in Flash to hover up and click
3366
+
3367
+ fullscreenBtn
3368
+ .mouseover(function() {
3369
+
3370
+ if (hideTimeout !== null) {
3371
+ clearTimeout(hideTimeout);
3372
+ delete hideTimeout;
3373
+ }
3374
+
3375
+ var buttonPos = fullscreenBtn.offset(),
3376
+ containerPos = player.container.offset();
3377
+
3378
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
3379
+
3380
+ })
3381
+ .mouseout(function() {
3382
+
3383
+ if (hideTimeout !== null) {
3384
+ clearTimeout(hideTimeout);
3385
+ delete hideTimeout;
3386
+ }
3387
+
3388
+ hideTimeout = setTimeout(function() {
3389
+ media.hideFullscreenButton();
3390
+ }, 1500);
3391
+
3392
+
3393
+ });
3394
+ }
3395
+ }
3396
+
3397
+ player.fullscreenBtn = fullscreenBtn;
3398
+
3399
+ $(document).bind('keydown',function (e) {
3400
+ if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
3401
+ player.exitFullScreen();
3402
+ }
3403
+ });
3404
+
3405
+ },
3406
+ enterFullScreen: function() {
3407
+
3408
+ var t = this;
3409
+
3410
+ // firefox+flash can't adjust plugin sizes without resetting :(
3411
+ if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
3412
+ //t.media.setFullscreen(true);
3413
+ //player.isFullScreen = true;
3414
+ return;
3415
+ }
3416
+
3417
+ // store overflow
3418
+ docStyleOverflow = document.documentElement.style.overflow;
3419
+ // set it to not show scroll bars so 100% will work
3420
+ document.documentElement.style.overflow = 'hidden';
3421
+
3422
+ // store sizing
3423
+ normalHeight = t.container.height();
3424
+ normalWidth = t.container.width();
3425
+
3426
+ // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
3427
+ if (t.media.pluginType === 'native') {
3428
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
3429
+
3430
+ mejs.MediaFeatures.requestFullScreen(t.container[0]);
3431
+ //return;
3432
+
3433
+ if (t.isInIframe) {
3434
+ // sometimes exiting from fullscreen doesn't work
3435
+ // notably in Chrome <iframe>. Fixed in version 17
3436
+ setTimeout(function checkFullscreen() {
3437
+
3438
+ if (t.isNativeFullScreen) {
3439
+
3440
+ // check if the video is suddenly not really fullscreen
3441
+ if ($(window).width() !== screen.width) {
3442
+ // manually exit
3443
+ t.exitFullScreen();
3444
+ } else {
3445
+ // test again
3446
+ setTimeout(checkFullscreen, 500);
3447
+ }
3448
+ }
3449
+
3450
+
3451
+ }, 500);
3452
+ }
3453
+
3454
+ } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
3455
+ t.media.webkitEnterFullscreen();
3456
+ return;
3457
+ }
3458
+ }
3459
+
3460
+ // check for iframe launch
3461
+ if (t.isInIframe) {
3462
+ var url = t.options.newWindowCallback(this);
3463
+
3464
+
3465
+ if (url !== '') {
3466
+
3467
+ // launch immediately
3468
+ if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
3469
+ t.pause();
3470
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
3471
+ return;
3472
+ } else {
3473
+ setTimeout(function() {
3474
+ if (!t.isNativeFullScreen) {
3475
+ t.pause();
3476
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
3477
+ }
3478
+ }, 250);
3479
+ }
3480
+ }
3481
+
3482
+ }
3483
+
3484
+ // full window code
3485
+
3486
+
3487
+
3488
+ // make full size
3489
+ t.container
3490
+ .addClass('mejs-container-fullscreen')
3491
+ .width('100%')
3492
+ .height('100%');
3493
+ //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
3494
+
3495
+ // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
3496
+ // Actually, it seems to be needed for IE8, too
3497
+ //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
3498
+ setTimeout(function() {
3499
+ t.container.css({width: '100%', height: '100%'});
3500
+ t.setControlsSize();
3501
+ }, 500);
3502
+ //}
3503
+
3504
+ if (t.pluginType === 'native') {
3505
+ t.$media
3506
+ .width('100%')
3507
+ .height('100%');
3508
+ } else {
3509
+ t.container.find('object, embed, iframe')
3510
+ .width('100%')
3511
+ .height('100%');
3512
+
3513
+ //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
3514
+ t.media.setVideoSize($(window).width(),$(window).height());
3515
+ //}
3516
+ }
3517
+
3518
+ t.layers.children('div')
3519
+ .width('100%')
3520
+ .height('100%');
3521
+
3522
+ if (t.fullscreenBtn) {
3523
+ t.fullscreenBtn
3524
+ .removeClass('mejs-fullscreen')
3525
+ .addClass('mejs-unfullscreen');
3526
+ }
3527
+
3528
+ t.setControlsSize();
3529
+ t.isFullScreen = true;
3530
+ },
3531
+
3532
+ exitFullScreen: function() {
3533
+
3534
+ var t = this;
3535
+
3536
+ // firefox can't adjust plugins
3537
+ if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
3538
+ t.media.setFullscreen(false);
3539
+ //player.isFullScreen = false;
3540
+ return;
3541
+ }
3542
+
3543
+ // come outo of native fullscreen
3544
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
3545
+ mejs.MediaFeatures.cancelFullScreen();
3546
+ }
3547
+
3548
+ // restore scroll bars to document
3549
+ document.documentElement.style.overflow = docStyleOverflow;
3550
+
3551
+ t.container
3552
+ .removeClass('mejs-container-fullscreen')
3553
+ .width(normalWidth)
3554
+ .height(normalHeight);
3555
+ //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
3556
+
3557
+ if (t.pluginType === 'native') {
3558
+ t.$media
3559
+ .width(normalWidth)
3560
+ .height(normalHeight);
3561
+ } else {
3562
+ t.container.find('object embed')
3563
+ .width(normalWidth)
3564
+ .height(normalHeight);
3565
+
3566
+ t.media.setVideoSize(normalWidth, normalHeight);
3567
+ }
3568
+
3569
+ t.layers.children('div')
3570
+ .width(normalWidth)
3571
+ .height(normalHeight);
3572
+
3573
+ t.fullscreenBtn
3574
+ .removeClass('mejs-unfullscreen')
3575
+ .addClass('mejs-fullscreen');
3576
+
3577
+ t.setControlsSize();
3578
+ t.isFullScreen = false;
3579
+ }
3580
+ });
3581
+
3582
+ })(mejs.$);
3583
+
3584
+ (function($) {
3585
+
3586
+ // add extra default options
3587
+ $.extend(mejs.MepDefaults, {
3588
+ // this will automatically turn on a <track>
3589
+ startLanguage: '',
3590
+
3591
+ tracksText: 'Captions/Subtitles'
3592
+ });
3593
+
3594
+ $.extend(MediaElementPlayer.prototype, {
3595
+
3596
+ hasChapters: false,
3597
+
3598
+ buildtracks: function(player, controls, layers, media) {
3599
+ if (!player.isVideo)
3600
+ return;
3601
+
3602
+ if (player.tracks.length == 0)
3603
+ return;
3604
+
3605
+ var t= this, i, options = '';
3606
+
3607
+ player.chapters =
3608
+ $('<div class="mejs-chapters mejs-layer"></div>')
3609
+ .prependTo(layers).hide();
3610
+ player.captions =
3611
+ $('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>')
3612
+ .prependTo(layers).hide();
3613
+ player.captionsText = player.captions.find('.mejs-captions-text');
3614
+ player.captionsButton =
3615
+ $('<div class="mejs-button mejs-captions-button">'+
3616
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '"></button>'+
3617
+ '<div class="mejs-captions-selector">'+
3618
+ '<ul>'+
3619
+ '<li>'+
3620
+ '<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
3621
+ '<label for="' + player.id + '_captions_none">None</label>'+
3622
+ '</li>' +
3623
+ '</ul>'+
3624
+ '</div>'+
3625
+ '</div>')
3626
+ .appendTo(controls)
3627
+
3628
+ // hover
3629
+ .hover(function() {
3630
+ $(this).find('.mejs-captions-selector').css('visibility','visible');
3631
+ }, function() {
3632
+ $(this).find('.mejs-captions-selector').css('visibility','hidden');
3633
+ })
3634
+
3635
+ // handle clicks to the language radio buttons
3636
+ .delegate('input[type=radio]','click',function() {
3637
+ lang = this.value;
3638
+
3639
+ if (lang == 'none') {
3640
+ player.selectedTrack = null;
3641
+ } else {
3642
+ for (i=0; i<player.tracks.length; i++) {
3643
+ if (player.tracks[i].srclang == lang) {
3644
+ player.selectedTrack = player.tracks[i];
3645
+ player.captions.attr('lang', player.selectedTrack.srclang);
3646
+ player.displayCaptions();
3647
+ break;
3648
+ }
3649
+ }
3650
+ }
3651
+ });
3652
+ //.bind('mouseenter', function() {
3653
+ // player.captionsButton.find('.mejs-captions-selector').css('visibility','visible')
3654
+ //});
3655
+
3656
+ if (!player.options.alwaysShowControls) {
3657
+ // move with controls
3658
+ player.container
3659
+ .bind('mouseenter', function () {
3660
+ // push captions above controls
3661
+ player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
3662
+
3663
+ })
3664
+ .bind('mouseleave', function () {
3665
+ if (!media.paused) {
3666
+ // move back to normal place
3667
+ player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
3668
+ }
3669
+ });
3670
+ } else {
3671
+ player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
3672
+ }
3673
+
3674
+ player.trackToLoad = -1;
3675
+ player.selectedTrack = null;
3676
+ player.isLoadingTrack = false;
3677
+
3678
+
3679
+
3680
+ // add to list
3681
+ for (i=0; i<player.tracks.length; i++) {
3682
+ if (player.tracks[i].kind == 'subtitles') {
3683
+ player.addTrackButton(player.tracks[i].srclang, player.tracks[i].label);
3684
+ }
3685
+ }
3686
+
3687
+ player.loadNextTrack();
3688
+
3689
+
3690
+ media.addEventListener('timeupdate',function(e) {
3691
+ player.displayCaptions();
3692
+ }, false);
3693
+
3694
+ media.addEventListener('loadedmetadata', function(e) {
3695
+ player.displayChapters();
3696
+ }, false);
3697
+
3698
+ player.container.hover(
3699
+ function () {
3700
+ // chapters
3701
+ if (player.hasChapters) {
3702
+ player.chapters.css('visibility','visible');
3703
+ player.chapters.fadeIn(200).height(player.chapters.find('.mejs-chapter').outerHeight());
3704
+ }
3705
+ },
3706
+ function () {
3707
+ if (player.hasChapters && !media.paused) {
3708
+ player.chapters.fadeOut(200, function() {
3709
+ $(this).css('visibility','hidden');
3710
+ $(this).css('display','block');
3711
+ });
3712
+ }
3713
+ });
3714
+
3715
+ // check for autoplay
3716
+ if (player.node.getAttribute('autoplay') !== null) {
3717
+ player.chapters.css('visibility','hidden');
3718
+ }
3719
+ },
3720
+
3721
+ loadNextTrack: function() {
3722
+ var t = this;
3723
+
3724
+ t.trackToLoad++;
3725
+ if (t.trackToLoad < t.tracks.length) {
3726
+ t.isLoadingTrack = true;
3727
+ t.loadTrack(t.trackToLoad);
3728
+ } else {
3729
+ // add done?
3730
+ t.isLoadingTrack = false;
3731
+ }
3732
+ },
3733
+
3734
+ loadTrack: function(index){
3735
+ var
3736
+ t = this,
3737
+ track = t.tracks[index],
3738
+ after = function() {
3739
+
3740
+ track.isLoaded = true;
3741
+
3742
+ // create button
3743
+ //t.addTrackButton(track.srclang);
3744
+ t.enableTrackButton(track.srclang, track.label);
3745
+
3746
+ t.loadNextTrack();
3747
+
3748
+ };
3749
+
3750
+ if (track.isTranslation) {
3751
+
3752
+ // translate the first track
3753
+ mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {
3754
+
3755
+ // store the new translation
3756
+ track.entries = newOne;
3757
+
3758
+ after();
3759
+ });
3760
+
3761
+ } else {
3762
+ $.ajax({
3763
+ url: track.src,
3764
+ success: function(d) {
3765
+
3766
+ // parse the loaded file
3767
+ track.entries = mejs.TrackFormatParser.parse(d);
3768
+ after();
3769
+
3770
+ if (track.kind == 'chapters' && t.media.duration > 0) {
3771
+ t.drawChapters(track);
3772
+ }
3773
+ },
3774
+ error: function() {
3775
+ t.loadNextTrack();
3776
+ }
3777
+ });
3778
+ }
3779
+ },
3780
+
3781
+ enableTrackButton: function(lang, label) {
3782
+ var t = this;
3783
+
3784
+ if (label === '') {
3785
+ label = mejs.language.codes[lang] || lang;
3786
+ }
3787
+
3788
+ t.captionsButton
3789
+ .find('input[value=' + lang + ']')
3790
+ .prop('disabled',false)
3791
+ .siblings('label')
3792
+ .html( label );
3793
+
3794
+ // auto select
3795
+ if (t.options.startLanguage == lang) {
3796
+ $('#' + t.id + '_captions_' + lang).click();
3797
+ }
3798
+
3799
+ t.adjustLanguageBox();
3800
+ },
3801
+
3802
+ addTrackButton: function(lang, label) {
3803
+ var t = this;
3804
+ if (label === '') {
3805
+ label = mejs.language.codes[lang] || lang;
3806
+ }
3807
+
3808
+ t.captionsButton.find('ul').append(
3809
+ $('<li>'+
3810
+ '<input type="radio" name="' + t.id + '_captions" id="' + t.id + '_captions_' + lang + '" value="' + lang + '" disabled="disabled" />' +
3811
+ '<label for="' + t.id + '_captions_' + lang + '">' + label + ' (loading)' + '</label>'+
3812
+ '</li>')
3813
+ );
3814
+
3815
+ t.adjustLanguageBox();
3816
+
3817
+ // remove this from the dropdownlist (if it exists)
3818
+ t.container.find('.mejs-captions-translations option[value=' + lang + ']').remove();
3819
+ },
3820
+
3821
+ adjustLanguageBox:function() {
3822
+ var t = this;
3823
+ // adjust the size of the outer box
3824
+ t.captionsButton.find('.mejs-captions-selector').height(
3825
+ t.captionsButton.find('.mejs-captions-selector ul').outerHeight(true) +
3826
+ t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
3827
+ );
3828
+ },
3829
+
3830
+ displayCaptions: function() {
3831
+
3832
+ if (typeof this.tracks == 'undefined')
3833
+ return;
3834
+
3835
+ var
3836
+ t = this,
3837
+ i,
3838
+ track = t.selectedTrack;
3839
+
3840
+ if (track != null && track.isLoaded) {
3841
+ for (i=0; i<track.entries.times.length; i++) {
3842
+ if (t.media.currentTime >= track.entries.times[i].start && t.media.currentTime <= track.entries.times[i].stop){
3843
+ t.captionsText.html(track.entries.text[i]);
3844
+ t.captions.show().height(0);
3845
+ return; // exit out if one is visible;
3846
+ }
3847
+ }
3848
+ t.captions.hide();
3849
+ } else {
3850
+ t.captions.hide();
3851
+ }
3852
+ },
3853
+
3854
+ displayChapters: function() {
3855
+ var
3856
+ t = this,
3857
+ i;
3858
+
3859
+ for (i=0; i<t.tracks.length; i++) {
3860
+ if (t.tracks[i].kind == 'chapters' && t.tracks[i].isLoaded) {
3861
+ t.drawChapters(t.tracks[i]);
3862
+ t.hasChapters = true;
3863
+ break;
3864
+ }
3865
+ }
3866
+ },
3867
+
3868
+ drawChapters: function(chapters) {
3869
+ var
3870
+ t = this,
3871
+ i,
3872
+ dur,
3873
+ //width,
3874
+ //left,
3875
+ percent = 0,
3876
+ usedPercent = 0;
3877
+
3878
+ t.chapters.empty();
3879
+
3880
+ for (i=0; i<chapters.entries.times.length; i++) {
3881
+ dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
3882
+ percent = Math.floor(dur / t.media.duration * 100);
3883
+ if (percent + usedPercent > 100 || // too large
3884
+ i == chapters.entries.times.length-1 && percent + usedPercent < 100) // not going to fill it in
3885
+ {
3886
+ percent = 100 - usedPercent;
3887
+ }
3888
+ //width = Math.floor(t.width * dur / t.media.duration);
3889
+ //left = Math.floor(t.width * chapters.entries.times[i].start / t.media.duration);
3890
+ //if (left + width > t.width) {
3891
+ // width = t.width - left;
3892
+ //}
3893
+
3894
+ t.chapters.append( $(
3895
+ '<div class="mejs-chapter" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' +
3896
+ '<div class="mejs-chapter-block' + ((i==chapters.entries.times.length-1) ? ' mejs-chapter-block-last' : '') + '">' +
3897
+ '<span class="ch-title">' + chapters.entries.text[i] + '</span>' +
3898
+ '<span class="ch-time">' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].start) + '&ndash;' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' +
3899
+ '</div>' +
3900
+ '</div>'));
3901
+ usedPercent += percent;
3902
+ }
3903
+
3904
+ t.chapters.find('div.mejs-chapter').click(function() {
3905
+ t.media.setCurrentTime( parseFloat( $(this).attr('rel') ) );
3906
+ if (t.media.paused) {
3907
+ t.media.play();
3908
+ }
3909
+ });
3910
+
3911
+ t.chapters.show();
3912
+ }
3913
+ });
3914
+
3915
+
3916
+
3917
+ mejs.language = {
3918
+ codes: {
3919
+ af:'Afrikaans',
3920
+ sq:'Albanian',
3921
+ ar:'Arabic',
3922
+ be:'Belarusian',
3923
+ bg:'Bulgarian',
3924
+ ca:'Catalan',
3925
+ zh:'Chinese',
3926
+ 'zh-cn':'Chinese Simplified',
3927
+ 'zh-tw':'Chinese Traditional',
3928
+ hr:'Croatian',
3929
+ cs:'Czech',
3930
+ da:'Danish',
3931
+ nl:'Dutch',
3932
+ en:'English',
3933
+ et:'Estonian',
3934
+ tl:'Filipino',
3935
+ fi:'Finnish',
3936
+ fr:'French',
3937
+ gl:'Galician',
3938
+ de:'German',
3939
+ el:'Greek',
3940
+ ht:'Haitian Creole',
3941
+ iw:'Hebrew',
3942
+ hi:'Hindi',
3943
+ hu:'Hungarian',
3944
+ is:'Icelandic',
3945
+ id:'Indonesian',
3946
+ ga:'Irish',
3947
+ it:'Italian',
3948
+ ja:'Japanese',
3949
+ ko:'Korean',
3950
+ lv:'Latvian',
3951
+ lt:'Lithuanian',
3952
+ mk:'Macedonian',
3953
+ ms:'Malay',
3954
+ mt:'Maltese',
3955
+ no:'Norwegian',
3956
+ fa:'Persian',
3957
+ pl:'Polish',
3958
+ pt:'Portuguese',
3959
+ //'pt-pt':'Portuguese (Portugal)',
3960
+ ro:'Romanian',
3961
+ ru:'Russian',
3962
+ sr:'Serbian',
3963
+ sk:'Slovak',
3964
+ sl:'Slovenian',
3965
+ es:'Spanish',
3966
+ sw:'Swahili',
3967
+ sv:'Swedish',
3968
+ tl:'Tagalog',
3969
+ th:'Thai',
3970
+ tr:'Turkish',
3971
+ uk:'Ukrainian',
3972
+ vi:'Vietnamese',
3973
+ cy:'Welsh',
3974
+ yi:'Yiddish'
3975
+ }
3976
+ };
3977
+
3978
+ /*
3979
+ Parses WebVVT format which should be formatted as
3980
+ ================================
3981
+ WEBVTT
3982
+
3983
+ 1
3984
+ 00:00:01,1 --> 00:00:05,000
3985
+ A line of text
3986
+
3987
+ 2
3988
+ 00:01:15,1 --> 00:02:05,000
3989
+ A second line of text
3990
+
3991
+ ===============================
3992
+
3993
+ Adapted from: http://www.delphiki.com/html5/playr
3994
+ */
3995
+ mejs.TrackFormatParser = {
3996
+ // match start "chapter-" (or anythingelse)
3997
+ pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
3998
+ pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
3999
+
4000
+ split2: function (text, regex) {
4001
+ // normal version for compliant browsers
4002
+ // see below for IE fix
4003
+ return text.split(regex);
4004
+ },
4005
+ parse: function(trackText) {
4006
+ var
4007
+ i = 0,
4008
+ lines = this.split2(trackText, /\r?\n/),
4009
+ entries = {text:[], times:[]},
4010
+ timecode,
4011
+ text;
4012
+
4013
+ for(; i<lines.length; i++) {
4014
+ // check for the line number
4015
+ if (this.pattern_identifier.exec(lines[i])){
4016
+ // skip to the next line where the start --> end time code should be
4017
+ i++;
4018
+ timecode = this.pattern_timecode.exec(lines[i]);
4019
+
4020
+ if (timecode && i<lines.length){
4021
+ i++;
4022
+ // grab all the (possibly multi-line) text that follows
4023
+ text = lines[i];
4024
+ i++;
4025
+ while(lines[i] !== '' && i<lines.length){
4026
+ text = text + '\n' + lines[i];
4027
+ i++;
4028
+ }
4029
+
4030
+ // Text is in a different array so I can use .join
4031
+ entries.text.push(text);
4032
+ entries.times.push(
4033
+ {
4034
+ start: mejs.Utility.timeCodeToSeconds(timecode[1]),
4035
+ stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
4036
+ settings: timecode[5]
4037
+ });
4038
+ }
4039
+ }
4040
+ }
4041
+
4042
+ return entries;
4043
+ }
4044
+ };
4045
+
4046
+ // test for browsers with bad String.split method.
4047
+ if ('x\n\ny'.split(/\n/gi).length != 3) {
4048
+ // add super slow IE8 and below version
4049
+ mejs.TrackFormatParser.split2 = function(text, regex) {
4050
+ var
4051
+ parts = [],
4052
+ chunk = '',
4053
+ i;
4054
+
4055
+ for (i=0; i<text.length; i++) {
4056
+ chunk += text.substring(i,i+1);
4057
+ if (regex.test(chunk)) {
4058
+ parts.push(chunk.replace(regex, ''));
4059
+ chunk = '';
4060
+ }
4061
+ }
4062
+ parts.push(chunk);
4063
+ return parts;
4064
+ }
4065
+ }
4066
+
4067
+ })(mejs.$);
4068
+
4069
+ /*
4070
+ * ContextMenu Plugin
4071
+ *
4072
+ *
4073
+ */
4074
+
4075
+ (function($) {
4076
+
4077
+ $.extend(mejs.MepDefaults,
4078
+ { 'contextMenuItems': [
4079
+ // demo of a fullscreen option
4080
+ {
4081
+ render: function(player) {
4082
+
4083
+ // check for fullscreen plugin
4084
+ if (typeof player.enterFullScreen == 'undefined')
4085
+ return null;
4086
+
4087
+ if (player.isFullScreen) {
4088
+ return "Turn off Fullscreen";
4089
+ } else {
4090
+ return "Go Fullscreen";
4091
+ }
4092
+ },
4093
+ click: function(player) {
4094
+ if (player.isFullScreen) {
4095
+ player.exitFullScreen();
4096
+ } else {
4097
+ player.enterFullScreen();
4098
+ }
4099
+ }
4100
+ }
4101
+ ,
4102
+ // demo of a mute/unmute button
4103
+ {
4104
+ render: function(player) {
4105
+ if (player.media.muted) {
4106
+ return "Unmute";
4107
+ } else {
4108
+ return "Mute";
4109
+ }
4110
+ },
4111
+ click: function(player) {
4112
+ if (player.media.muted) {
4113
+ player.setMuted(false);
4114
+ } else {
4115
+ player.setMuted(true);
4116
+ }
4117
+ }
4118
+ },
4119
+ // separator
4120
+ {
4121
+ isSeparator: true
4122
+ }
4123
+ ,
4124
+ // demo of simple download video
4125
+ {
4126
+ render: function(player) {
4127
+ return "Download Video";
4128
+ },
4129
+ click: function(player) {
4130
+ window.location.href = player.media.currentSrc;
4131
+ }
4132
+ }
4133
+ ]}
4134
+ );
4135
+
4136
+
4137
+ $.extend(MediaElementPlayer.prototype, {
4138
+ buildcontextmenu: function(player, controls, layers, media) {
4139
+
4140
+ // create context menu
4141
+ player.contextMenu = $('<div class="mejs-contextmenu"></div>')
4142
+ .appendTo($('body'))
4143
+ .hide();
4144
+
4145
+ // create events for showing context menu
4146
+ player.container.bind('contextmenu', function(e) {
4147
+ if (player.isContextMenuEnabled) {
4148
+ e.preventDefault();
4149
+ player.renderContextMenu(e.clientX-1, e.clientY-1);
4150
+ return false;
4151
+ }
4152
+ });
4153
+ player.container.bind('click', function() {
4154
+ player.contextMenu.hide();
4155
+ });
4156
+ player.contextMenu.bind('mouseleave', function() {
4157
+
4158
+ //console.log('context hover out');
4159
+ player.startContextMenuTimer();
4160
+
4161
+ });
4162
+ },
4163
+
4164
+ isContextMenuEnabled: true,
4165
+ enableContextMenu: function() {
4166
+ this.isContextMenuEnabled = true;
4167
+ },
4168
+ disableContextMenu: function() {
4169
+ this.isContextMenuEnabled = false;
4170
+ },
4171
+
4172
+ contextMenuTimeout: null,
4173
+ startContextMenuTimer: function() {
4174
+ //console.log('startContextMenuTimer');
4175
+
4176
+ var t = this;
4177
+
4178
+ t.killContextMenuTimer();
4179
+
4180
+ t.contextMenuTimer = setTimeout(function() {
4181
+ t.hideContextMenu();
4182
+ t.killContextMenuTimer();
4183
+ }, 750);
4184
+ },
4185
+ killContextMenuTimer: function() {
4186
+ var timer = this.contextMenuTimer;
4187
+
4188
+ //console.log('killContextMenuTimer', timer);
4189
+
4190
+ if (timer != null) {
4191
+ clearTimeout(timer);
4192
+ delete timer;
4193
+ timer = null;
4194
+ }
4195
+ },
4196
+
4197
+ hideContextMenu: function() {
4198
+ this.contextMenu.hide();
4199
+ },
4200
+
4201
+ renderContextMenu: function(x,y) {
4202
+
4203
+ // alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
4204
+ var t = this,
4205
+ html = '',
4206
+ items = t.options.contextMenuItems;
4207
+
4208
+ for (var i=0, il=items.length; i<il; i++) {
4209
+
4210
+ if (items[i].isSeparator) {
4211
+ html += '<div class="mejs-contextmenu-separator"></div>';
4212
+ } else {
4213
+
4214
+ var rendered = items[i].render(t);
4215
+
4216
+ // render can return null if the item doesn't need to be used at the moment
4217
+ if (rendered != null) {
4218
+ html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
4219
+ }
4220
+ }
4221
+ }
4222
+
4223
+ // position and show the context menu
4224
+ t.contextMenu
4225
+ .empty()
4226
+ .append($(html))
4227
+ .css({top:y, left:x})
4228
+ .show();
4229
+
4230
+ // bind events
4231
+ t.contextMenu.find('.mejs-contextmenu-item').each(function() {
4232
+
4233
+ // which one is this?
4234
+ var $dom = $(this),
4235
+ itemIndex = parseInt( $dom.data('itemindex'), 10 ),
4236
+ item = t.options.contextMenuItems[itemIndex];
4237
+
4238
+ // bind extra functionality?
4239
+ if (typeof item.show != 'undefined')
4240
+ item.show( $dom , t);
4241
+
4242
+ // bind click action
4243
+ $dom.click(function() {
4244
+ // perform click action
4245
+ if (typeof item.click != 'undefined')
4246
+ item.click(t);
4247
+
4248
+ // close
4249
+ t.contextMenu.hide();
4250
+ });
4251
+ });
4252
+
4253
+ // stop the controls from hiding
4254
+ setTimeout(function() {
4255
+ t.killControlsTimer('rev3');
4256
+ }, 100);
4257
+
4258
+ }
4259
+ });
4260
+
4261
+ })(mejs.$);
4262
+
includes/media-element/mediaelement-and-player.min.js ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * MediaElement.js
3
+ * HTML5 <video> and <audio> shim and player
4
+ * http://mediaelementjs.com/
5
+ *
6
+ * Creates a JavaScript object that mimics HTML5 MediaElement API
7
+ * for browsers that don't understand HTML5 or can't play the provided codec
8
+ * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
9
+ *
10
+ * Copyright 2010-2012, John Dyer (http://j.hn)
11
+ * Dual licensed under the MIT or GPL Version 2 licenses.
12
+ *
13
+ */var mejs=mejs||{};mejs.version="2.9.1";mejs.meIndex=0;mejs.plugins={silverlight:[{version:[3,0],types:["video/mp4","video/m4v","video/mov","video/wmv","audio/wma","audio/m4a","audio/mp3","audio/wav","audio/mpeg"]}],flash:[{version:[9,0,124],types:["video/mp4","video/m4v","video/mov","video/flv","video/x-flv","audio/flv","audio/x-flv","audio/mp3","audio/m4a","audio/mpeg","video/youtube","video/x-youtube"]}],youtube:[{version:null,types:["video/youtube","video/x-youtube"]}],vimeo:[{version:null,types:["video/vimeo"]}]};
14
+ mejs.Utility={encodeUrl:function(a){return encodeURIComponent(a)},escapeHTML:function(a){return a.toString().split("&").join("&amp;").split("<").join("&lt;").split('"').join("&quot;")},absolutizeUrl:function(a){var b=document.createElement("div");b.innerHTML='<a href="'+this.escapeHTML(a)+'">x</a>';return b.firstChild.href},getScriptPath:function(a){for(var b=0,c,d="",e="",g,f=document.getElementsByTagName("script"),j=f.length,h=a.length;b<j;b++){g=f[b].src;for(c=0;c<h;c++){e=a[c];if(g.indexOf(e)>
15
+ -1){d=g.substring(0,g.indexOf(e));break}}if(d!=="")break}return d},secondsToTimeCode:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;var e=Math.floor(a/3600)%24,g=Math.floor(a/60)%60,f=Math.floor(a%60);a=Math.floor((a%1*d).toFixed(3));return(b||e>0?(e<10?"0"+e:e)+":":"")+(g<10?"0"+g:g)+":"+(f<10?"0"+f:f)+(c?":"+(a<10?"0"+a:a):"")},timeCodeToSeconds:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;a=a.split(":");b=parseInt(a[0],
16
+ 10);var e=parseInt(a[1],10),g=parseInt(a[2],10),f=0,j=0;if(c)f=parseInt(a[3])/d;return j=b*3600+e*60+g+f},removeSwf:function(a){var b=document.getElementById(a);if(b&&b.nodeName=="OBJECT")if(mejs.MediaFeatures.isIE){b.style.display="none";(function(){b.readyState==4?mejs.Utility.removeObjectInIE(a):setTimeout(arguments.callee,10)})()}else b.parentNode.removeChild(b)},removeObjectInIE:function(a){if(a=document.getElementById(a)){for(var b in a)if(typeof a[b]=="function")a[b]=null;a.parentNode.removeChild(a)}}};
17
+ mejs.PluginDetector={hasPluginVersion:function(a,b){var c=this.plugins[a];b[1]=b[1]||0;b[2]=b[2]||0;return c[0]>b[0]||c[0]==b[0]&&c[1]>b[1]||c[0]==b[0]&&c[1]==b[1]&&c[2]>=b[2]?true:false},nav:window.navigator,ua:window.navigator.userAgent.toLowerCase(),plugins:[],addPlugin:function(a,b,c,d,e){this.plugins[a]=this.detectPlugin(b,c,d,e)},detectPlugin:function(a,b,c,d){var e=[0,0,0],g;if(typeof this.nav.plugins!="undefined"&&typeof this.nav.plugins[a]=="object"){if((c=this.nav.plugins[a].description)&&
18
+ !(typeof this.nav.mimeTypes!="undefined"&&this.nav.mimeTypes[b]&&!this.nav.mimeTypes[b].enabledPlugin)){e=c.replace(a,"").replace(/^\s+/,"").replace(/\sr/gi,".").split(".");for(a=0;a<e.length;a++)e[a]=parseInt(e[a].match(/\d+/),10)}}else if(typeof window.ActiveXObject!="undefined")try{if(g=new ActiveXObject(c))e=d(g)}catch(f){}return e}};
19
+ mejs.PluginDetector.addPlugin("flash","Shockwave Flash","application/x-shockwave-flash","ShockwaveFlash.ShockwaveFlash",function(a){var b=[];if(a=a.GetVariable("$version")){a=a.split(" ")[1].split(",");b=[parseInt(a[0],10),parseInt(a[1],10),parseInt(a[2],10)]}return b});
20
+ mejs.PluginDetector.addPlugin("silverlight","Silverlight Plug-In","application/x-silverlight-2","AgControl.AgControl",function(a){var b=[0,0,0,0],c=function(d,e,g,f){for(;d.isVersionSupported(e[0]+"."+e[1]+"."+e[2]+"."+e[3]);)e[g]+=f;e[g]-=f};c(a,b,0,1);c(a,b,1,1);c(a,b,2,1E4);c(a,b,2,1E3);c(a,b,2,100);c(a,b,2,10);c(a,b,2,1);c(a,b,3,1);return b});
21
+ mejs.MediaFeatures={init:function(){var a=this,b=document,c=mejs.PluginDetector.nav,d=mejs.PluginDetector.ua.toLowerCase(),e,g=["source","track","audio","video"];a.isiPad=d.match(/ipad/i)!==null;a.isiPhone=d.match(/iphone/i)!==null;a.isiOS=a.isiPhone||a.isiPad;a.isAndroid=d.match(/android/i)!==null;a.isBustedAndroid=d.match(/android 2\.[12]/)!==null;a.isIE=c.appName.toLowerCase().indexOf("microsoft")!=-1;a.isChrome=d.match(/chrome/gi)!==null;a.isFirefox=d.match(/firefox/gi)!==null;a.isWebkit=d.match(/webkit/gi)!==
22
+ null;a.isGecko=d.match(/gecko/gi)!==null&&!a.isWebkit;a.isOpera=d.match(/opera/gi)!==null;a.hasTouch="ontouchstart"in window;for(c=0;c<g.length;c++)e=document.createElement(g[c]);a.supportsMediaTag=typeof e.canPlayType!=="undefined"||a.isBustedAndroid;a.hasSemiNativeFullScreen=typeof e.webkitEnterFullscreen!=="undefined";a.hasWebkitNativeFullScreen=typeof e.webkitRequestFullScreen!=="undefined";a.hasMozNativeFullScreen=typeof e.mozRequestFullScreen!=="undefined";a.hasTrueNativeFullScreen=a.hasWebkitNativeFullScreen||
23
+ a.hasMozNativeFullScreen;a.nativeFullScreenEnabled=a.hasTrueNativeFullScreen;if(a.hasMozNativeFullScreen)a.nativeFullScreenEnabled=e.mozFullScreenEnabled;if(this.isChrome)a.hasSemiNativeFullScreen=false;if(a.hasTrueNativeFullScreen){a.fullScreenEventName=a.hasWebkitNativeFullScreen?"webkitfullscreenchange":"mozfullscreenchange";a.isFullScreen=function(){if(e.mozRequestFullScreen)return b.mozFullScreen;else if(e.webkitRequestFullScreen)return b.webkitIsFullScreen};a.requestFullScreen=function(f){if(a.hasWebkitNativeFullScreen)f.webkitRequestFullScreen();
24
+ else a.hasMozNativeFullScreen&&f.mozRequestFullScreen()};a.cancelFullScreen=function(){if(a.hasWebkitNativeFullScreen)document.webkitCancelFullScreen();else a.hasMozNativeFullScreen&&document.mozCancelFullScreen()}}if(a.hasSemiNativeFullScreen&&d.match(/mac os x 10_5/i)){a.hasNativeFullScreen=false;a.hasSemiNativeFullScreen=false}}};mejs.MediaFeatures.init();
25
+ mejs.HtmlMediaElement={pluginType:"native",isFullScreen:false,setCurrentTime:function(a){this.currentTime=a},setMuted:function(a){this.muted=a},setVolume:function(a){this.volume=a},stop:function(){this.pause()},setSrc:function(a){for(var b=this.getElementsByTagName("source");b.length>0;)this.removeChild(b[0]);if(typeof a=="string")this.src=a;else{var c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type))this.src=c.src}}},setVideoSize:function(a,b){this.width=a;this.height=b}};
26
+ mejs.PluginMediaElement=function(a,b,c){this.id=a;this.pluginType=b;this.src=c;this.events={}};
27
+ mejs.PluginMediaElement.prototype={pluginElement:null,pluginType:"",isFullScreen:false,playbackRate:-1,defaultPlaybackRate:-1,seekable:[],played:[],paused:true,ended:false,seeking:false,duration:0,error:null,tagName:"",muted:false,volume:1,currentTime:0,play:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.playVideo():this.pluginApi.playMedia();this.paused=false}},load:function(){if(this.pluginApi!=null){this.pluginType!="youtube"&&this.pluginApi.loadMedia();this.paused=
28
+ false}},pause:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.pauseVideo():this.pluginApi.pauseMedia();this.paused=true}},stop:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.stopVideo():this.pluginApi.stopMedia();this.paused=true}},canPlayType:function(a){var b,c,d,e=mejs.plugins[this.pluginType];for(b=0;b<e.length;b++){d=e[b];if(mejs.PluginDetector.hasPluginVersion(this.pluginType,d.version))for(c=0;c<d.types.length;c++)if(a==d.types[c])return true}return false},
29
+ positionFullscreenButton:function(a,b,c){this.pluginApi!=null&&this.pluginApi.positionFullscreenButton&&this.pluginApi.positionFullscreenButton(a,b,c)},hideFullscreenButton:function(){this.pluginApi!=null&&this.pluginApi.hideFullscreenButton&&this.pluginApi.hideFullscreenButton()},setSrc:function(a){if(typeof a=="string"){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(a));this.src=mejs.Utility.absolutizeUrl(a)}else{var b,c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type)){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(c.src));
30
+ this.src=mejs.Utility.absolutizeUrl(a)}}}},setCurrentTime:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.seekTo(a):this.pluginApi.setCurrentTime(a);this.currentTime=a}},setVolume:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.setVolume(a*100):this.pluginApi.setVolume(a);this.volume=a}},setMuted:function(a){if(this.pluginApi!=null){if(this.pluginType=="youtube"){a?this.pluginApi.mute():this.pluginApi.unMute();this.muted=a;this.dispatchEvent("volumechange")}else this.pluginApi.setMuted(a);
31
+ this.muted=a}},setVideoSize:function(a,b){if(this.pluginElement.style){this.pluginElement.style.width=a+"px";this.pluginElement.style.height=b+"px"}this.pluginApi!=null&&this.pluginApi.setVideoSize&&this.pluginApi.setVideoSize(a,b)},setFullscreen:function(a){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.pluginApi.setFullscreen(a)},enterFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.setFullscreen(true)},exitFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&
32
+ this.setFullscreen(false)},addEventListener:function(a,b){this.events[a]=this.events[a]||[];this.events[a].push(b)},removeEventListener:function(a,b){if(!a){this.events={};return true}var c=this.events[a];if(!c)return true;if(!b){this.events[a]=[];return true}for(i=0;i<c.length;i++)if(c[i]===b){this.events[a].splice(i,1);return true}return false},dispatchEvent:function(a){var b,c,d=this.events[a];if(d){c=Array.prototype.slice.call(arguments,1);for(b=0;b<d.length;b++)d[b].apply(null,c)}},attributes:{},
33
+ hasAttribute:function(a){return a in this.attributes},removeAttribute:function(a){delete this.attributes[a]},getAttribute:function(a){if(this.hasAttribute(a))return this.attributes[a];return""},setAttribute:function(a,b){this.attributes[a]=b},remove:function(){mejs.Utility.removeSwf(this.pluginElement.id)}};
34
+ mejs.MediaPluginBridge={pluginMediaElements:{},htmlMediaElements:{},registerPluginElement:function(a,b,c){this.pluginMediaElements[a]=b;this.htmlMediaElements[a]=c},initPlugin:function(a){var b=this.pluginMediaElements[a],c=this.htmlMediaElements[a];if(b){switch(b.pluginType){case "flash":b.pluginElement=b.pluginApi=document.getElementById(a);break;case "silverlight":b.pluginElement=document.getElementById(b.id);b.pluginApi=b.pluginElement.Content.MediaElementJS}b.pluginApi!=null&&b.success&&b.success(b,
35
+ c)}},fireEvent:function(a,b,c){var d,e;a=this.pluginMediaElements[a];a.ended=false;a.paused=true;b={type:b,target:a};for(d in c){a[d]=c[d];b[d]=c[d]}e=c.bufferedTime||0;b.target.buffered=b.buffered={start:function(){return 0},end:function(){return e},length:1};a.dispatchEvent(b.type,b)}};
36
+ mejs.MediaElementDefaults={mode:"auto",plugins:["flash","silverlight","youtube","vimeo"],enablePluginDebug:false,type:"",pluginPath:mejs.Utility.getScriptPath(["mediaelement.js","mediaelement.min.js","mediaelement-and-player.js","mediaelement-and-player.min.js"]),flashName:"flashmediaelement.swf",enablePluginSmoothing:false,silverlightName:"silverlightmediaelement.xap",defaultVideoWidth:480,defaultVideoHeight:270,pluginWidth:-1,pluginHeight:-1,pluginVars:[],timerRate:250,startVolume:0.8,success:function(){},
37
+ error:function(){}};mejs.MediaElement=function(a,b){return mejs.HtmlMediaElementShim.create(a,b)};
38
+ mejs.HtmlMediaElementShim={create:function(a,b){var c=mejs.MediaElementDefaults,d=typeof a=="string"?document.getElementById(a):a,e=d.tagName.toLowerCase(),g=e==="audio"||e==="video",f=g?d.getAttribute("src"):d.getAttribute("href");e=d.getAttribute("poster");var j=d.getAttribute("autoplay"),h=d.getAttribute("preload"),l=d.getAttribute("controls"),k;for(k in b)c[k]=b[k];f=typeof f=="undefined"||f===null||f==""?null:f;e=typeof e=="undefined"||e===null?"":e;h=typeof h=="undefined"||h===null||h==="false"?
39
+ "none":h;j=!(typeof j=="undefined"||j===null||j==="false");l=!(typeof l=="undefined"||l===null||l==="false");k=this.determinePlayback(d,c,mejs.MediaFeatures.supportsMediaTag,g,f);k.url=k.url!==null?mejs.Utility.absolutizeUrl(k.url):"";if(k.method=="native"){if(mejs.MediaFeatures.isBustedAndroid){d.src=k.url;d.addEventListener("click",function(){d.play()},false)}return this.updateNative(k,c,j,h)}else if(k.method!=="")return this.createPlugin(k,c,e,j,h,l);else{this.createErrorMessage(k,c,e);return this}},
40
+ determinePlayback:function(a,b,c,d,e){var g=[],f,j,h={method:"",url:"",htmlMediaElement:a,isVideo:a.tagName.toLowerCase()!="audio"},l,k;if(typeof b.type!="undefined"&&b.type!=="")if(typeof b.type=="string")g.push({type:b.type,url:e});else for(f=0;f<b.type.length;f++)g.push({type:b.type[f],url:e});else if(e!==null){j=this.formatType(e,a.getAttribute("type"));g.push({type:j,url:e})}else for(f=0;f<a.childNodes.length;f++){j=a.childNodes[f];if(j.nodeType==1&&j.tagName.toLowerCase()=="source"){e=j.getAttribute("src");
41
+ j=this.formatType(e,j.getAttribute("type"));g.push({type:j,url:e})}}if(!d&&g.length>0&&g[0].url!==null&&this.getTypeFromFile(g[0].url).indexOf("audio")>-1)h.isVideo=false;if(mejs.MediaFeatures.isBustedAndroid)a.canPlayType=function(m){return m.match(/video\/(mp4|m4v)/gi)!==null?"maybe":""};if(c&&(b.mode==="auto"||b.mode==="native")){if(!d){f=document.createElement(h.isVideo?"video":"audio");a.parentNode.insertBefore(f,a);a.style.display="none";h.htmlMediaElement=a=f}for(f=0;f<g.length;f++)if(a.canPlayType(g[f].type).replace(/no/,
42
+ "")!==""||a.canPlayType(g[f].type.replace(/mp3/,"mpeg")).replace(/no/,"")!==""){h.method="native";h.url=g[f].url;break}if(h.method==="native"){if(h.url!==null)a.src=h.url;return h}}if(b.mode==="auto"||b.mode==="shim")for(f=0;f<g.length;f++){j=g[f].type;for(a=0;a<b.plugins.length;a++){e=b.plugins[a];l=mejs.plugins[e];for(c=0;c<l.length;c++){k=l[c];if(k.version==null||mejs.PluginDetector.hasPluginVersion(e,k.version))for(d=0;d<k.types.length;d++)if(j==k.types[d]){h.method=e;h.url=g[f].url;return h}}}}if(h.method===
43
+ ""&&g.length>0)h.url=g[0].url;return h},formatType:function(a,b){return a&&!b?this.getTypeFromFile(a):b&&~b.indexOf(";")?b.substr(0,b.indexOf(";")):b},getTypeFromFile:function(a){a=a.substring(a.lastIndexOf(".")+1);return(/(mp4|m4v|ogg|ogv|webm|flv|wmv|mpeg|mov)/gi.test(a)?"video":"audio")+"/"+a},createErrorMessage:function(a,b,c){var d=a.htmlMediaElement,e=document.createElement("div");e.className="me-cannotplay";try{e.style.width=d.width+"px";e.style.height=d.height+"px"}catch(g){}e.innerHTML=c!==
44
+ ""?'<a href="'+a.url+'"><img src="'+c+'" width="100%" height="100%" /></a>':'<a href="'+a.url+'"><span>Download File</span></a>';d.parentNode.insertBefore(e,d);d.style.display="none";b.error(d)},createPlugin:function(a,b,c,d,e,g){c=a.htmlMediaElement;var f=1,j=1,h="me_"+a.method+"_"+mejs.meIndex++,l=new mejs.PluginMediaElement(h,a.method,a.url),k=document.createElement("div"),m;l.tagName=c.tagName;for(m=0;m<c.attributes.length;m++){var n=c.attributes[m];n.specified==true&&l.setAttribute(n.name,n.value)}for(m=
45
+ c.parentNode;m!==null&&m.tagName.toLowerCase()!="body";){if(m.parentNode.tagName.toLowerCase()=="p"){m.parentNode.parentNode.insertBefore(m,m.parentNode);break}m=m.parentNode}if(a.isVideo){f=b.videoWidth>0?b.videoWidth:c.getAttribute("width")!==null?c.getAttribute("width"):b.defaultVideoWidth;j=b.videoHeight>0?b.videoHeight:c.getAttribute("height")!==null?c.getAttribute("height"):b.defaultVideoHeight;f=mejs.Utility.encodeUrl(f);j=mejs.Utility.encodeUrl(j)}else if(b.enablePluginDebug){f=320;j=240}l.success=
46
+ b.success;mejs.MediaPluginBridge.registerPluginElement(h,l,c);k.className="me-plugin";k.id=h+"_container";a.isVideo?c.parentNode.insertBefore(k,c):document.body.insertBefore(k,document.body.childNodes[0]);d=["id="+h,"isvideo="+(a.isVideo?"true":"false"),"autoplay="+(d?"true":"false"),"preload="+e,"width="+f,"startvolume="+b.startVolume,"timerrate="+b.timerRate,"height="+j];if(a.url!==null)a.method=="flash"?d.push("file="+mejs.Utility.encodeUrl(a.url)):d.push("file="+a.url);b.enablePluginDebug&&d.push("debug=true");
47
+ b.enablePluginSmoothing&&d.push("smoothing=true");g&&d.push("controls=true");if(b.pluginVars)d=d.concat(b.pluginVars);switch(a.method){case "silverlight":k.innerHTML='<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="'+h+'" name="'+h+'" width="'+f+'" height="'+j+'"><param name="initParams" value="'+d.join(",")+'" /><param name="windowless" value="true" /><param name="background" value="black" /><param name="minRuntimeVersion" value="3.0.0.0" /><param name="autoUpgrade" value="true" /><param name="source" value="'+
48
+ b.pluginPath+b.silverlightName+'" /></object>';break;case "flash":if(mejs.MediaFeatures.isIE){a=document.createElement("div");k.appendChild(a);a.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+h+'" width="'+f+'" height="'+j+'"><param name="movie" value="'+b.pluginPath+b.flashName+"?x="+new Date+'" /><param name="flashvars" value="'+d.join("&amp;")+'" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else k.innerHTML=
49
+ '<embed id="'+h+'" name="'+h+'" play="true" loop="false" quality="high" bgcolor="#000000" wmode="transparent" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" src="'+b.pluginPath+b.flashName+'" flashvars="'+d.join("&")+'" width="'+f+'" height="'+j+'"></embed>';break;case "youtube":b=a.url.substr(a.url.lastIndexOf("=")+1);youtubeSettings={container:k,containerId:k.id,pluginMediaElement:l,pluginId:h,videoId:b,
50
+ height:j,width:f};mejs.PluginDetector.hasPluginVersion("flash",[10,0,0])?mejs.YouTubeApi.createFlash(youtubeSettings):mejs.YouTubeApi.enqueueIframe(youtubeSettings);break;case "vimeo":console.log("vimeoid");l.vimeoid=a.url.substr(a.url.lastIndexOf("/")+1);k.innerHTML='<object width="'+f+'" height="'+j+'"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="flashvars" value="api=1" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id='+
51
+ l.vimeoid+'&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id='+l.vimeoid+'&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="'+f+'" height="'+j+'"></embed></object>'}c.style.display=
52
+ "none";return l},updateNative:function(a,b){var c=a.htmlMediaElement,d;for(d in mejs.HtmlMediaElement)c[d]=mejs.HtmlMediaElement[d];b.success(c,c);return c}};
53
+ mejs.YouTubeApi={isIframeStarted:false,isIframeLoaded:false,loadIframeApi:function(){if(!this.isIframeStarted){var a=document.createElement("script");a.src="http://www.youtube.com/player_api";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);this.isIframeStarted=true}},iframeQueue:[],enqueueIframe:function(a){if(this.isLoaded)this.createIframe(a);else{this.loadIframeApi();this.iframeQueue.push(a)}},createIframe:function(a){var b=a.pluginMediaElement,c=new YT.Player(a.containerId,
54
+ {height:a.height,width:a.width,videoId:a.videoId,playerVars:{controls:0},events:{onReady:function(){a.pluginMediaElement.pluginApi=c;mejs.MediaPluginBridge.initPlugin(a.pluginId);setInterval(function(){mejs.YouTubeApi.createEvent(c,b,"timeupdate")},250)},onStateChange:function(d){mejs.YouTubeApi.handleStateChange(d.data,c,b)}}})},createEvent:function(a,b,c){c={type:c,target:b};if(a&&a.getDuration){b.currentTime=c.currentTime=a.getCurrentTime();b.duration=c.duration=a.getDuration();c.paused=b.paused;
55
+ c.ended=b.ended;c.muted=a.isMuted();c.volume=a.getVolume()/100;c.bytesTotal=a.getVideoBytesTotal();c.bufferedBytes=a.getVideoBytesLoaded();var d=c.bufferedBytes/c.bytesTotal*c.duration;c.target.buffered=c.buffered={start:function(){return 0},end:function(){return d},length:1}}b.dispatchEvent(c.type,c)},iFrameReady:function(){for(this.isIframeLoaded=this.isLoaded=true;this.iframeQueue.length>0;)this.createIframe(this.iframeQueue.pop())},flashPlayers:{},createFlash:function(a){this.flashPlayers[a.pluginId]=
56
+ a;var b,c="http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid="+a.pluginId+"&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0";if(mejs.MediaFeatures.isIE){b=document.createElement("div");a.container.appendChild(b);b.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+a.pluginId+'" width="'+a.width+'" height="'+a.height+'"><param name="movie" value="'+c+'" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else a.container.innerHTML=
57
+ '<object type="application/x-shockwave-flash" id="'+a.pluginId+'" data="'+c+'" width="'+a.width+'" height="'+a.height+'" style="visibility: visible; "><param name="allowScriptAccess" value="always"><param name="wmode" value="transparent"></object>'},flashReady:function(a){var b=this.flashPlayers[a],c=document.getElementById(a),d=b.pluginMediaElement;d.pluginApi=d.pluginElement=c;mejs.MediaPluginBridge.initPlugin(a);c.cueVideoById(b.videoId);a=b.containerId+"_callback";window[a]=function(e){mejs.YouTubeApi.handleStateChange(e,
58
+ c,d)};c.addEventListener("onStateChange",a);setInterval(function(){mejs.YouTubeApi.createEvent(c,d,"timeupdate")},250)},handleStateChange:function(a,b,c){switch(a){case -1:c.paused=true;c.ended=true;mejs.YouTubeApi.createEvent(b,c,"loadedmetadata");break;case 0:c.paused=false;c.ended=true;mejs.YouTubeApi.createEvent(b,c,"ended");break;case 1:c.paused=false;c.ended=false;mejs.YouTubeApi.createEvent(b,c,"play");mejs.YouTubeApi.createEvent(b,c,"playing");break;case 2:c.paused=true;c.ended=false;mejs.YouTubeApi.createEvent(b,
59
+ c,"pause");break;case 3:mejs.YouTubeApi.createEvent(b,c,"progress")}}};function onYouTubePlayerAPIReady(){mejs.YouTubeApi.iFrameReady()}function onYouTubePlayerReady(a){mejs.YouTubeApi.flashReady(a)}window.mejs=mejs;window.MediaElement=mejs.MediaElement;
60
+
61
+ /*!
62
+ * MediaElementPlayer
63
+ * http://mediaelementjs.com/
64
+ *
65
+ * Creates a controller bar for HTML5 <video> add <audio> tags
66
+ * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
67
+ *
68
+ * Copyright 2010-2012, John Dyer (http://j.hn/)
69
+ * Dual licensed under the MIT or GPL Version 2 licenses.
70
+ *
71
+ */if(typeof jQuery!="undefined")mejs.$=jQuery;else if(typeof ender!="undefined")mejs.$=ender;
72
+ (function(f){mejs.MepDefaults={poster:"",defaultVideoWidth:480,defaultVideoHeight:270,videoWidth:-1,videoHeight:-1,defaultAudioWidth:400,defaultAudioHeight:30,audioWidth:-1,audioHeight:-1,startVolume:0.8,loop:false,enableAutosize:true,alwaysShowHours:false,showTimecodeFrameCount:false,framesPerSecond:25,autosizeProgress:true,alwaysShowControls:false,iPadUseNativeControls:false,iPhoneUseNativeControls:false,AndroidUseNativeControls:false,features:["playpause","current","progress","duration","tracks",
73
+ "volume","fullscreen"],isVideo:true,enableKeyboard:true,pauseOtherPlayers:true,keyActions:[{keys:[32,179],action:function(a,b){b.paused||b.ended?b.play():b.pause()}},{keys:[38],action:function(a,b){b.setVolume(Math.min(b.volume+0.1,1))}},{keys:[40],action:function(a,b){b.setVolume(Math.max(b.volume-0.1,0))}},{keys:[37,227],action:function(a,b){if(!isNaN(b.duration)&&b.duration>0){if(a.isVideo){a.showControls();a.startControlsTimer()}b.setCurrentTime(Math.max(b.currentTime-b.duration*0.05,0))}}},{keys:[39,
74
+ 228],action:function(a,b){if(!isNaN(b.duration)&&b.duration>0){if(a.isVideo){a.showControls();a.startControlsTimer()}b.setCurrentTime(Math.min(b.currentTime+b.duration*0.05,b.duration))}}},{keys:[70],action:function(a){if(typeof a.enterFullScreen!="undefined")a.isFullScreen?a.exitFullScreen():a.enterFullScreen()}}]};mejs.mepIndex=0;mejs.players=[];mejs.MediaElementPlayer=function(a,b){if(!(this instanceof mejs.MediaElementPlayer))return new mejs.MediaElementPlayer(a,b);this.$media=this.$node=f(a);
75
+ this.node=this.media=this.$media[0];if(typeof this.node.player!="undefined")return this.node.player;else this.node.player=this;if(typeof b=="undefined")b=this.$node.data("mejsoptions");this.options=f.extend({},mejs.MepDefaults,b);mejs.players.push(this);this.init();return this};mejs.MediaElementPlayer.prototype={hasFocus:false,controlsAreVisible:true,init:function(){var a=this,b=mejs.MediaFeatures,c=f.extend(true,{},a.options,{success:function(e,g){a.meReady(e,g)},error:function(e){a.handleError(e)}}),
76
+ d=a.media.tagName.toLowerCase();a.isDynamic=d!=="audio"&&d!=="video";a.isVideo=a.isDynamic?a.options.isVideo:d!=="audio"&&a.options.isVideo;if(b.isiPad&&a.options.iPadUseNativeControls||b.isiPhone&&a.options.iPhoneUseNativeControls){a.$media.attr("controls","controls");if(b.isiPad&&a.media.getAttribute("autoplay")!==null){a.media.load();a.media.play()}}else if(!(b.isAndroid&&a.AndroidUseNativeControls)){a.$media.removeAttr("controls");a.id="mep_"+mejs.mepIndex++;a.container=f('<div id="'+a.id+'" class="mejs-container"><div class="mejs-inner"><div class="mejs-mediaelement"></div><div class="mejs-layers"></div><div class="mejs-controls"></div><div class="mejs-clear"></div></div></div>').addClass(a.$media[0].className).insertBefore(a.$media);
77
+ a.container.addClass((b.isAndroid?"mejs-android ":"")+(b.isiOS?"mejs-ios ":"")+(b.isiPad?"mejs-ipad ":"")+(b.isiPhone?"mejs-iphone ":"")+(a.isVideo?"mejs-video ":"mejs-audio "));if(b.isiOS){b=a.$media.clone();a.container.find(".mejs-mediaelement").append(b);a.$media.remove();a.$node=a.$media=b;a.node=a.media=b[0]}else a.container.find(".mejs-mediaelement").append(a.$media);a.controls=a.container.find(".mejs-controls");a.layers=a.container.find(".mejs-layers");b=d.substring(0,1).toUpperCase()+d.substring(1);
78
+ a.width=a.options[d+"Width"]>0||a.options[d+"Width"].toString().indexOf("%")>-1?a.options[d+"Width"]:a.media.style.width!==""&&a.media.style.width!==null?a.media.style.width:a.media.getAttribute("width")!==null?a.$media.attr("width"):a.options["default"+b+"Width"];a.height=a.options[d+"Height"]>0||a.options[d+"Height"].toString().indexOf("%")>-1?a.options[d+"Height"]:a.media.style.height!==""&&a.media.style.height!==null?a.media.style.height:a.$media[0].getAttribute("height")!==null?a.$media.attr("height"):
79
+ a.options["default"+b+"Height"];a.setPlayerSize(a.width,a.height);c.pluginWidth=a.height;c.pluginHeight=a.width}mejs.MediaElement(a.$media[0],c)},showControls:function(a){var b=this;a=typeof a=="undefined"||a;if(!b.controlsAreVisible){if(a){b.controls.css("visibility","visible").stop(true,true).fadeIn(200,function(){b.controlsAreVisible=true});b.container.find(".mejs-control").css("visibility","visible").stop(true,true).fadeIn(200,function(){b.controlsAreVisible=true})}else{b.controls.css("visibility",
80
+ "visible").css("display","block");b.container.find(".mejs-control").css("visibility","visible").css("display","block");b.controlsAreVisible=true}b.setControlsSize()}},hideControls:function(a){var b=this;a=typeof a=="undefined"||a;if(b.controlsAreVisible)if(a){b.controls.stop(true,true).fadeOut(200,function(){f(this).css("visibility","hidden").css("display","block");b.controlsAreVisible=false});b.container.find(".mejs-control").stop(true,true).fadeOut(200,function(){f(this).css("visibility","hidden").css("display",
81
+ "block")})}else{b.controls.css("visibility","hidden").css("display","block");b.container.find(".mejs-control").css("visibility","hidden").css("display","block");b.controlsAreVisible=false}},controlsTimer:null,startControlsTimer:function(a){var b=this;a=typeof a!="undefined"?a:1500;b.killControlsTimer("start");b.controlsTimer=setTimeout(function(){b.hideControls();b.killControlsTimer("hide")},a)},killControlsTimer:function(){if(this.controlsTimer!==null){clearTimeout(this.controlsTimer);delete this.controlsTimer;
82
+ this.controlsTimer=null}},controlsEnabled:true,disableControls:function(){this.killControlsTimer();this.hideControls(false);this.controlsEnabled=false},enableControls:function(){this.showControls(false);this.controlsEnabled=true},meReady:function(a,b){var c=this,d=mejs.MediaFeatures,e=b.getAttribute("autoplay");e=!(typeof e=="undefined"||e===null||e==="false");var g;if(!c.created){c.created=true;c.media=a;c.domNode=b;if(!(d.isAndroid&&c.options.AndroidUseNativeControls)&&!(d.isiPad&&c.options.iPadUseNativeControls)&&
83
+ !(d.isiPhone&&c.options.iPhoneUseNativeControls)){c.buildposter(c,c.controls,c.layers,c.media);c.buildkeyboard(c,c.controls,c.layers,c.media);c.buildoverlays(c,c.controls,c.layers,c.media);c.findTracks();for(g in c.options.features){d=c.options.features[g];if(c["build"+d])try{c["build"+d](c,c.controls,c.layers,c.media)}catch(k){}}c.container.trigger("controlsready");c.setPlayerSize(c.width,c.height);c.setControlsSize();if(c.isVideo){if(mejs.MediaFeatures.hasTouch)c.$media.bind("touchstart",function(){if(c.controlsAreVisible)c.hideControls(false);
84
+ else c.controlsEnabled&&c.showControls(false)});else{(c.media.pluginType=="native"?c.$media:f(c.media.pluginElement)).click(function(){a.paused?a.play():a.pause()});c.container.bind("mouseenter mouseover",function(){if(c.controlsEnabled)if(!c.options.alwaysShowControls){c.killControlsTimer("enter");c.showControls();c.startControlsTimer(2500)}}).bind("mousemove",function(){if(c.controlsEnabled){c.controlsAreVisible||c.showControls();c.options.alwaysShowControls||c.startControlsTimer(2500)}}).bind("mouseleave",
85
+ function(){c.controlsEnabled&&!c.media.paused&&!c.options.alwaysShowControls&&c.startControlsTimer(1E3)})}e&&!c.options.alwaysShowControls&&c.hideControls();c.options.enableAutosize&&c.media.addEventListener("loadedmetadata",function(h){if(c.options.videoHeight<=0&&c.domNode.getAttribute("height")===null&&!isNaN(h.target.videoHeight)){c.setPlayerSize(h.target.videoWidth,h.target.videoHeight);c.setControlsSize();c.media.setVideoSize(h.target.videoWidth,h.target.videoHeight)}},false)}a.addEventListener("play",
86
+ function(){for(var h=0,o=mejs.players.length;h<o;h++){var n=mejs.players[h];n.id!=c.id&&c.options.pauseOtherPlayers&&!n.paused&&!n.ended&&n.pause();n.hasFocus=false}c.hasFocus=true},false);c.media.addEventListener("ended",function(){try{c.media.setCurrentTime(0)}catch(h){}c.media.pause();c.setProgressRail&&c.setProgressRail();c.setCurrentRail&&c.setCurrentRail();if(c.options.loop)c.media.play();else!c.options.alwaysShowControls&&c.controlsEnabled&&c.showControls()},false);c.media.addEventListener("loadedmetadata",
87
+ function(){c.updateDuration&&c.updateDuration();c.updateCurrent&&c.updateCurrent();if(!c.isFullScreen){c.setPlayerSize(c.width,c.height);c.setControlsSize()}},false);setTimeout(function(){c.setPlayerSize(c.width,c.height);c.setControlsSize()},50);f(window).resize(function(){c.isFullScreen||mejs.MediaFeatures.hasTrueNativeFullScreen&&document.webkitIsFullScreen||c.setPlayerSize(c.width,c.height);c.setControlsSize()});c.media.pluginType=="youtube"&&c.container.find(".mejs-overlay-play").hide()}if(e&&
88
+ a.pluginType=="native"){a.load();a.play()}if(c.options.success)typeof c.options.success=="string"?window[c.options.success](c.media,c.domNode,c):c.options.success(c.media,c.domNode,c)}},handleError:function(a){this.controls.hide();this.options.error&&this.options.error(a)},setPlayerSize:function(a,b){if(typeof a!="undefined")this.width=a;if(typeof b!="undefined")this.height=b;if(this.height.toString().indexOf("%")>0){var c=this.media.videoWidth&&this.media.videoWidth>0?this.media.videoWidth:this.options.defaultVideoWidth,
89
+ d=this.media.videoHeight&&this.media.videoHeight>0?this.media.videoHeight:this.options.defaultVideoHeight,e=this.container.parent().width();c=parseInt(e*d/c,10);if(this.container.parent()[0].tagName.toLowerCase()==="body"){e=f(window).width();c=f(window).height()}this.container.width(e).height(c);this.$media.width("100%").height("100%");this.container.find("object, embed, iframe").width("100%").height("100%");this.media.setVideoSize&&this.media.setVideoSize(e,c);this.layers.children(".mejs-layer").width("100%").height("100%")}else{this.container.width(this.width).height(this.height);
90
+ this.layers.children(".mejs-layer").width(this.width).height(this.height)}},setControlsSize:function(){var a=0,b=0,c=this.controls.find(".mejs-time-rail"),d=this.controls.find(".mejs-time-total");this.controls.find(".mejs-time-current");this.controls.find(".mejs-time-loaded");var e=c.siblings();if(this.options&&!this.options.autosizeProgress)b=parseInt(c.css("width"));if(b===0||!b){e.each(function(){if(f(this).css("position")!="absolute")a+=f(this).outerWidth(true)});b=this.controls.width()-a-(c.outerWidth(true)-
91
+ c.width())}c.width(b);d.width(b-(d.outerWidth(true)-d.width()));this.setProgressRail&&this.setProgressRail();this.setCurrentRail&&this.setCurrentRail()},buildposter:function(a,b,c,d){var e=f('<div class="mejs-poster mejs-layer"></div>').appendTo(c);b=a.$media.attr("poster");if(a.options.poster!=="")b=a.options.poster;b!==""&&b!=null?this.setPoster(b):e.hide();d.addEventListener("play",function(){e.hide()},false)},setPoster:function(a){var b=this.container.find(".mejs-poster"),c=b.find("img");if(c.length==
92
+ 0)c=f('<img width="100%" height="100%" />').appendTo(b);c.attr("src",a)},buildoverlays:function(a,b,c,d){if(a.isVideo){var e=f('<div class="mejs-overlay mejs-layer"><div class="mejs-overlay-loading"><span></span></div></div>').hide().appendTo(c),g=f('<div class="mejs-overlay mejs-layer"><div class="mejs-overlay-error"></div></div>').hide().appendTo(c),k=f('<div class="mejs-overlay mejs-layer mejs-overlay-play"><div class="mejs-overlay-button"></div></div>').appendTo(c).click(function(){d.paused?d.play():
93
+ d.pause()});d.addEventListener("play",function(){k.hide();e.hide();b.find(".mejs-time-buffering").hide();g.hide()},false);d.addEventListener("playing",function(){k.hide();e.hide();b.find(".mejs-time-buffering").hide();g.hide()},false);d.addEventListener("seeking",function(){e.show();b.find(".mejs-time-buffering").show()},false);d.addEventListener("seeked",function(){e.hide();b.find(".mejs-time-buffering").hide()},false);d.addEventListener("pause",function(){mejs.MediaFeatures.isiPhone||k.show()},
94
+ false);d.addEventListener("waiting",function(){e.show();b.find(".mejs-time-buffering").show()},false);d.addEventListener("loadeddata",function(){e.show();b.find(".mejs-time-buffering").show()},false);d.addEventListener("canplay",function(){e.hide();b.find(".mejs-time-buffering").hide()},false);d.addEventListener("error",function(){e.hide();b.find(".mejs-time-buffering").hide();g.show();g.find("mejs-overlay-error").html("Error loading this resource")},false)}},buildkeyboard:function(a,b,c,d){f(document).keydown(function(e){if(a.hasFocus&&
95
+ a.options.enableKeyboard)for(var g=0,k=a.options.keyActions.length;g<k;g++)for(var h=a.options.keyActions[g],o=0,n=h.keys.length;o<n;o++)if(e.keyCode==h.keys[o]){e.preventDefault();h.action(a,d);return false}return true});f(document).click(function(e){if(f(e.target).closest(".mejs-container").length==0)a.hasFocus=false})},findTracks:function(){var a=this,b=a.$media.find("track");a.tracks=[];b.each(function(c,d){d=f(d);a.tracks.push({srclang:d.attr("srclang").toLowerCase(),src:d.attr("src"),kind:d.attr("kind"),
96
+ label:d.attr("label")||"",entries:[],isLoaded:false})})},changeSkin:function(a){this.container[0].className="mejs-container "+a;this.setPlayerSize(this.width,this.height);this.setControlsSize()},play:function(){this.media.play()},pause:function(){this.media.pause()},load:function(){this.media.load()},setMuted:function(a){this.media.setMuted(a)},setCurrentTime:function(a){this.media.setCurrentTime(a)},getCurrentTime:function(){return this.media.currentTime},setVolume:function(a){this.media.setVolume(a)},
97
+ getVolume:function(){return this.media.volume},setSrc:function(a){this.media.setSrc(a)},remove:function(){if(this.media.pluginType=="flash")this.media.remove();else this.media.pluginType=="native"&&this.media.prop("controls",true);this.isDynamic||this.$node.insertBefore(this.container);this.container.remove()}};if(typeof jQuery!="undefined")jQuery.fn.mediaelementplayer=function(a){return this.each(function(){new mejs.MediaElementPlayer(this,a)})};f(document).ready(function(){f(".mejs-player").mediaelementplayer()});
98
+ window.MediaElementPlayer=mejs.MediaElementPlayer})(mejs.$);
99
+ (function(f){f.extend(mejs.MepDefaults,{playpauseText:"Play/Pause"});f.extend(MediaElementPlayer.prototype,{buildplaypause:function(a,b,c,d){var e=f('<div class="mejs-button mejs-playpause-button mejs-play" ><button type="button" aria-controls="'+this.id+'" title="'+this.options.playpauseText+'"></button></div>').appendTo(b).click(function(g){g.preventDefault();d.paused?d.play():d.pause();return false});d.addEventListener("play",function(){e.removeClass("mejs-play").addClass("mejs-pause")},false);
100
+ d.addEventListener("playing",function(){e.removeClass("mejs-play").addClass("mejs-pause")},false);d.addEventListener("pause",function(){e.removeClass("mejs-pause").addClass("mejs-play")},false);d.addEventListener("paused",function(){e.removeClass("mejs-pause").addClass("mejs-play")},false)}})})(mejs.$);
101
+ (function(f){f.extend(mejs.MepDefaults,{stopText:"Stop"});f.extend(MediaElementPlayer.prototype,{buildstop:function(a,b,c,d){f('<div class="mejs-button mejs-stop-button mejs-stop"><button type="button" aria-controls="'+this.id+'" title="'+this.options.stopText+'"></button></div>').appendTo(b).click(function(){d.paused||d.pause();if(d.currentTime>0){d.setCurrentTime(0);b.find(".mejs-time-current").width("0px");b.find(".mejs-time-handle").css("left","0px");b.find(".mejs-time-float-current").html(mejs.Utility.secondsToTimeCode(0));
102
+ b.find(".mejs-currenttime").html(mejs.Utility.secondsToTimeCode(0));c.find(".mejs-poster").show()}})}})})(mejs.$);
103
+ (function(f){f.extend(MediaElementPlayer.prototype,{buildprogress:function(a,b,c,d){f('<div class="mejs-time-rail"><span class="mejs-time-total"><span class="mejs-time-buffering"></span><span class="mejs-time-loaded"></span><span class="mejs-time-current"></span><span class="mejs-time-handle"></span><span class="mejs-time-float"><span class="mejs-time-float-current">00:00</span><span class="mejs-time-float-corner"></span></span></span></div>').appendTo(b);b.find(".mejs-time-buffering").hide();var e=
104
+ b.find(".mejs-time-total");c=b.find(".mejs-time-loaded");var g=b.find(".mejs-time-current"),k=b.find(".mejs-time-handle"),h=b.find(".mejs-time-float"),o=b.find(".mejs-time-float-current"),n=function(l){l=l.pageX;var q=e.offset(),i=e.outerWidth(),j=0;j=0;var m=l-q.left;if(l>q.left&&l<=i+q.left&&d.duration){j=(l-q.left)/i;j=j<=0.02?0:j*d.duration;p&&d.setCurrentTime(j);if(!mejs.MediaFeatures.hasTouch){h.css("left",m);o.html(mejs.Utility.secondsToTimeCode(j));h.show()}}},p=false;e.bind("mousedown",function(l){if(l.which===
105
+ 1){p=true;n(l);f(document).bind("mousemove.dur",function(q){n(q)}).bind("mouseup.dur",function(){p=false;h.hide();f(document).unbind(".dur")});return false}}).bind("mouseenter",function(){f(document).bind("mousemove.dur",function(l){n(l)});mejs.MediaFeatures.hasTouch||h.show()}).bind("mouseleave",function(){if(!p){f(document).unbind(".dur");h.hide()}});d.addEventListener("progress",function(l){a.setProgressRail(l);a.setCurrentRail(l)},false);d.addEventListener("timeupdate",function(l){a.setProgressRail(l);
106
+ a.setCurrentRail(l)},false);this.loaded=c;this.total=e;this.current=g;this.handle=k},setProgressRail:function(a){var b=a!=undefined?a.target:this.media,c=null;if(b&&b.buffered&&b.buffered.length>0&&b.buffered.end&&b.duration)c=b.buffered.end(0)/b.duration;else if(b&&b.bytesTotal!=undefined&&b.bytesTotal>0&&b.bufferedBytes!=undefined)c=b.bufferedBytes/b.bytesTotal;else if(a&&a.lengthComputable&&a.total!=0)c=a.loaded/a.total;if(c!==null){c=Math.min(1,Math.max(0,c));this.loaded&&this.total&&this.loaded.width(this.total.width()*
107
+ c)}},setCurrentRail:function(){if(this.media.currentTime!=undefined&&this.media.duration)if(this.total&&this.handle){var a=this.total.width()*this.media.currentTime/this.media.duration,b=a-this.handle.outerWidth(true)/2;this.current.width(a);this.handle.css("left",b)}}})})(mejs.$);
108
+ (function(f){f.extend(mejs.MepDefaults,{duration:-1,timeAndDurationSeparator:" <span> | </span> "});f.extend(MediaElementPlayer.prototype,{buildcurrent:function(a,b,c,d){f('<div class="mejs-time"><span class="mejs-currenttime">'+(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00")+"</span></div>").appendTo(b);this.currenttime=this.controls.find(".mejs-currenttime");d.addEventListener("timeupdate",function(){a.updateCurrent()},false)},buildduration:function(a,
109
+ b,c,d){if(b.children().last().find(".mejs-currenttime").length>0)f(this.options.timeAndDurationSeparator+'<span class="mejs-duration">'+(this.options.duration>0?mejs.Utility.secondsToTimeCode(this.options.duration,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25):(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00"))+"</span>").appendTo(b.find(".mejs-time"));else{b.find(".mejs-currenttime").parent().addClass("mejs-currenttime-container");
110
+ f('<div class="mejs-time mejs-duration-container"><span class="mejs-duration">'+(this.options.duration>0?mejs.Utility.secondsToTimeCode(this.options.duration,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25):(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00"))+"</span></div>").appendTo(b)}this.durationD=this.controls.find(".mejs-duration");d.addEventListener("timeupdate",function(){a.updateDuration()},
111
+ false)},updateCurrent:function(){if(this.currenttime)this.currenttime.html(mejs.Utility.secondsToTimeCode(this.media.currentTime,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25))},updateDuration:function(){if(this.media.duration&&this.durationD)this.durationD.html(mejs.Utility.secondsToTimeCode(this.media.duration,this.options.alwaysShowHours,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25))}})})(mejs.$);
112
+ (function(f){f.extend(mejs.MepDefaults,{muteText:"Mute Toggle",hideVolumeOnTouchDevices:true,audioVolume:"horizontal",videoVolume:"vertical"});f.extend(MediaElementPlayer.prototype,{buildvolume:function(a,b,c,d){if(!(mejs.MediaFeatures.hasTouch&&this.options.hideVolumeOnTouchDevices)){var e=this.isVideo?this.options.videoVolume:this.options.audioVolume,g=e=="horizontal"?f('<div class="mejs-button mejs-volume-button mejs-mute"><button type="button" aria-controls="'+this.id+'" title="'+this.options.muteText+
113
+ '"></button></div><div class="mejs-horizontal-volume-slider"><div class="mejs-horizontal-volume-total"></div><div class="mejs-horizontal-volume-current"></div><div class="mejs-horizontal-volume-handle"></div></div>').appendTo(b):f('<div class="mejs-button mejs-volume-button mejs-mute"><button type="button" aria-controls="'+this.id+'" title="'+this.options.muteText+'"></button><div class="mejs-volume-slider"><div class="mejs-volume-total"></div><div class="mejs-volume-current"></div><div class="mejs-volume-handle"></div></div></div>').appendTo(b),
114
+ k=this.container.find(".mejs-volume-slider, .mejs-horizontal-volume-slider"),h=this.container.find(".mejs-volume-total, .mejs-horizontal-volume-total"),o=this.container.find(".mejs-volume-current, .mejs-horizontal-volume-current"),n=this.container.find(".mejs-volume-handle, .mejs-horizontal-volume-handle"),p=function(j,m){if(!k.is(":visible")&&typeof m!="undefined"){k.show();p(j,true);k.hide()}else{j=Math.max(0,j);j=Math.min(j,1);j==0?g.removeClass("mejs-mute").addClass("mejs-unmute"):g.removeClass("mejs-unmute").addClass("mejs-mute");
115
+ if(e=="vertical"){var r=h.height(),s=h.position(),t=r-r*j;n.css("top",s.top+t-n.height()/2);o.height(r-t);o.css("top",s.top+t)}else{r=h.width();s=h.position();r=r*j;n.css("left",s.left+r-n.width()/2);o.width(r)}}},l=function(j){var m=null,r=h.offset();if(e=="vertical"){m=h.height();parseInt(h.css("top").replace(/px/,""),10);m=(m-(j.pageY-r.top))/m;if(r.top==0||r.left==0)return}else{m=h.width();m=(j.pageX-r.left)/m}m=Math.max(0,m);m=Math.min(m,1);p(m);m==0?d.setMuted(true):d.setMuted(false);d.setVolume(m)},
116
+ q=false,i=false;g.hover(function(){k.show();i=true},function(){i=false;!q&&e=="vertical"&&k.hide()});k.bind("mouseover",function(){i=true}).bind("mousedown",function(j){l(j);f(document).bind("mousemove.vol",function(m){l(m)}).bind("mouseup.vol",function(){q=false;f(document).unbind(".vol");!i&&e=="vertical"&&k.hide()});q=true;return false});g.find("button").click(function(){d.setMuted(!d.muted)});d.addEventListener("volumechange",function(){if(!q)if(d.muted){p(0);g.removeClass("mejs-mute").addClass("mejs-unmute")}else{p(d.volume);
117
+ g.removeClass("mejs-unmute").addClass("mejs-mute")}},false);if(this.container.is(":visible")){p(a.options.startVolume);d.pluginType==="native"&&d.setVolume(a.options.startVolume)}}}})})(mejs.$);
118
+ (function(f){f.extend(mejs.MepDefaults,{usePluginFullScreen:true,newWindowCallback:function(){return""},fullscreenText:"Fullscreen"});f.extend(MediaElementPlayer.prototype,{isFullScreen:false,isNativeFullScreen:false,docStyleOverflow:null,isInIframe:false,buildfullscreen:function(a,b,c,d){if(a.isVideo){a.isInIframe=window.location!=window.parent.location;if(mejs.MediaFeatures.hasTrueNativeFullScreen){c=null;c=mejs.MediaFeatures.hasMozNativeFullScreen?f(document):a.container;c.bind(mejs.MediaFeatures.fullScreenEventName,
119
+ function(){if(mejs.MediaFeatures.isFullScreen()){a.isNativeFullScreen=true;a.setControlsSize()}else{a.isNativeFullScreen=false;a.exitFullScreen()}})}var e=this,g=f('<div class="mejs-button mejs-fullscreen-button"><button type="button" aria-controls="'+e.id+'" title="'+e.options.fullscreenText+'"></button></div>').appendTo(b);if(e.media.pluginType==="native"||!e.options.usePluginFullScreen&&!mejs.MediaFeatures.isFirefox)g.click(function(){mejs.MediaFeatures.hasTrueNativeFullScreen&&mejs.MediaFeatures.isFullScreen()||
120
+ a.isFullScreen?a.exitFullScreen():a.enterFullScreen()});else{var k=null;b=function(){var i=document.createElement("x"),j=document.documentElement,m=window.getComputedStyle;if(!("pointerEvents"in i.style))return false;i.style.pointerEvents="auto";i.style.pointerEvents="x";j.appendChild(i);m=m&&m(i,"").pointerEvents==="auto";j.removeChild(i);return!!m}();console.log("supportsPointerEvents",b);if(b&&!mejs.MediaFeatures.isOpera){var h=false,o=function(){if(h){n.hide();p.hide();l.hide();g.css("pointer-events",
121
+ "");e.controls.css("pointer-events","");h=false}},n=f('<div class="mejs-fullscreen-hover" />').appendTo(e.container).mouseover(o),p=f('<div class="mejs-fullscreen-hover" />').appendTo(e.container).mouseover(o),l=f('<div class="mejs-fullscreen-hover" />').appendTo(e.container).mouseover(o),q=function(){var i={position:"absolute",top:0,left:0};n.css(i);p.css(i);l.css(i);n.width(e.container.width()).height(e.container.height()-e.controls.height());i=g.offset().left-e.container.offset().left;fullScreenBtnWidth=
122
+ g.outerWidth(true);p.width(i).height(e.controls.height()).css({top:e.container.height()-e.controls.height()});l.width(e.container.width()-i-fullScreenBtnWidth).height(e.controls.height()).css({top:e.container.height()-e.controls.height(),left:i+fullScreenBtnWidth})};f(document).resize(function(){q()});g.mouseover(function(){if(!e.isFullScreen){var i=g.offset(),j=a.container.offset();d.positionFullscreenButton(i.left-j.left,i.top-j.top,false);g.css("pointer-events","none");e.controls.css("pointer-events",
123
+ "none");n.show();l.show();p.show();q();h=true}});d.addEventListener("fullscreenchange",function(){o()})}else g.mouseover(function(){if(k!==null){clearTimeout(k);delete k}var i=g.offset(),j=a.container.offset();d.positionFullscreenButton(i.left-j.left,i.top-j.top,true)}).mouseout(function(){if(k!==null){clearTimeout(k);delete k}k=setTimeout(function(){d.hideFullscreenButton()},1500)})}a.fullscreenBtn=g;f(document).bind("keydown",function(i){if((mejs.MediaFeatures.hasTrueNativeFullScreen&&mejs.MediaFeatures.isFullScreen()||
124
+ e.isFullScreen)&&i.keyCode==27)a.exitFullScreen()})}},enterFullScreen:function(){var a=this;if(!(a.media.pluginType!=="native"&&(mejs.MediaFeatures.isFirefox||a.options.usePluginFullScreen))){docStyleOverflow=document.documentElement.style.overflow;document.documentElement.style.overflow="hidden";normalHeight=a.container.height();normalWidth=a.container.width();if(a.media.pluginType==="native")if(mejs.MediaFeatures.hasTrueNativeFullScreen){mejs.MediaFeatures.requestFullScreen(a.container[0]);a.isInIframe&&
125
+ setTimeout(function c(){if(a.isNativeFullScreen)f(window).width()!==screen.width?a.exitFullScreen():setTimeout(c,500)},500)}else if(mejs.MediaFeatures.hasSemiNativeFullScreen){a.media.webkitEnterFullscreen();return}if(a.isInIframe){var b=a.options.newWindowCallback(this);if(b!=="")if(mejs.MediaFeatures.hasTrueNativeFullScreen)setTimeout(function(){if(!a.isNativeFullScreen){a.pause();window.open(b,a.id,"top=0,left=0,width="+screen.availWidth+",height="+screen.availHeight+",resizable=yes,scrollbars=no,status=no,toolbar=no")}},
126
+ 250);else{a.pause();window.open(b,a.id,"top=0,left=0,width="+screen.availWidth+",height="+screen.availHeight+",resizable=yes,scrollbars=no,status=no,toolbar=no");return}}a.container.addClass("mejs-container-fullscreen").width("100%").height("100%");setTimeout(function(){a.container.css({width:"100%",height:"100%"});a.setControlsSize()},500);if(a.pluginType==="native")a.$media.width("100%").height("100%");else{a.container.find("object, embed, iframe").width("100%").height("100%");a.media.setVideoSize(f(window).width(),
127
+ f(window).height())}a.layers.children("div").width("100%").height("100%");a.fullscreenBtn&&a.fullscreenBtn.removeClass("mejs-fullscreen").addClass("mejs-unfullscreen");a.setControlsSize();a.isFullScreen=true}},exitFullScreen:function(){if(this.media.pluginType!=="native"&&mejs.MediaFeatures.isFirefox)this.media.setFullscreen(false);else{if(mejs.MediaFeatures.hasTrueNativeFullScreen&&(mejs.MediaFeatures.isFullScreen()||this.isFullScreen))mejs.MediaFeatures.cancelFullScreen();document.documentElement.style.overflow=
128
+ docStyleOverflow;this.container.removeClass("mejs-container-fullscreen").width(normalWidth).height(normalHeight);if(this.pluginType==="native")this.$media.width(normalWidth).height(normalHeight);else{this.container.find("object embed").width(normalWidth).height(normalHeight);this.media.setVideoSize(normalWidth,normalHeight)}this.layers.children("div").width(normalWidth).height(normalHeight);this.fullscreenBtn.removeClass("mejs-unfullscreen").addClass("mejs-fullscreen");this.setControlsSize();this.isFullScreen=
129
+ false}}})})(mejs.$);
130
+ (function(f){f.extend(mejs.MepDefaults,{startLanguage:"",tracksText:"Captions/Subtitles"});f.extend(MediaElementPlayer.prototype,{hasChapters:false,buildtracks:function(a,b,c,d){if(a.isVideo)if(a.tracks.length!=0){var e;a.chapters=f('<div class="mejs-chapters mejs-layer"></div>').prependTo(c).hide();a.captions=f('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>').prependTo(c).hide();a.captionsText=a.captions.find(".mejs-captions-text");
131
+ a.captionsButton=f('<div class="mejs-button mejs-captions-button"><button type="button" aria-controls="'+this.id+'" title="'+this.options.tracksText+'"></button><div class="mejs-captions-selector"><ul><li><input type="radio" name="'+a.id+'_captions" id="'+a.id+'_captions_none" value="none" checked="checked" /><label for="'+a.id+'_captions_none">None</label></li></ul></div></div>').appendTo(b).hover(function(){f(this).find(".mejs-captions-selector").css("visibility","visible")},function(){f(this).find(".mejs-captions-selector").css("visibility",
132
+ "hidden")}).delegate("input[type=radio]","click",function(){lang=this.value;if(lang=="none")a.selectedTrack=null;else for(e=0;e<a.tracks.length;e++)if(a.tracks[e].srclang==lang){a.selectedTrack=a.tracks[e];a.captions.attr("lang",a.selectedTrack.srclang);a.displayCaptions();break}});a.options.alwaysShowControls?a.container.find(".mejs-captions-position").addClass("mejs-captions-position-hover"):a.container.bind("mouseenter",function(){a.container.find(".mejs-captions-position").addClass("mejs-captions-position-hover")}).bind("mouseleave",
133
+ function(){d.paused||a.container.find(".mejs-captions-position").removeClass("mejs-captions-position-hover")});a.trackToLoad=-1;a.selectedTrack=null;a.isLoadingTrack=false;for(e=0;e<a.tracks.length;e++)a.tracks[e].kind=="subtitles"&&a.addTrackButton(a.tracks[e].srclang,a.tracks[e].label);a.loadNextTrack();d.addEventListener("timeupdate",function(){a.displayCaptions()},false);d.addEventListener("loadedmetadata",function(){a.displayChapters()},false);a.container.hover(function(){if(a.hasChapters){a.chapters.css("visibility",
134
+ "visible");a.chapters.fadeIn(200).height(a.chapters.find(".mejs-chapter").outerHeight())}},function(){a.hasChapters&&!d.paused&&a.chapters.fadeOut(200,function(){f(this).css("visibility","hidden");f(this).css("display","block")})});a.node.getAttribute("autoplay")!==null&&a.chapters.css("visibility","hidden")}},loadNextTrack:function(){this.trackToLoad++;if(this.trackToLoad<this.tracks.length){this.isLoadingTrack=true;this.loadTrack(this.trackToLoad)}else this.isLoadingTrack=false},loadTrack:function(a){var b=
135
+ this,c=b.tracks[a],d=function(){c.isLoaded=true;b.enableTrackButton(c.srclang,c.label);b.loadNextTrack()};c.isTranslation?mejs.TrackFormatParser.translateTrackText(b.tracks[0].entries,b.tracks[0].srclang,c.srclang,b.options.googleApiKey,function(e){c.entries=e;d()}):f.ajax({url:c.src,success:function(e){c.entries=mejs.TrackFormatParser.parse(e);d();c.kind=="chapters"&&b.media.duration>0&&b.drawChapters(c)},error:function(){b.loadNextTrack()}})},enableTrackButton:function(a,b){if(b==="")b=mejs.language.codes[a]||
136
+ a;this.captionsButton.find("input[value="+a+"]").prop("disabled",false).siblings("label").html(b);this.options.startLanguage==a&&f("#"+this.id+"_captions_"+a).click();this.adjustLanguageBox()},addTrackButton:function(a,b){if(b==="")b=mejs.language.codes[a]||a;this.captionsButton.find("ul").append(f('<li><input type="radio" name="'+this.id+'_captions" id="'+this.id+"_captions_"+a+'" value="'+a+'" disabled="disabled" /><label for="'+this.id+"_captions_"+a+'">'+b+" (loading)</label></li>"));this.adjustLanguageBox();
137
+ this.container.find(".mejs-captions-translations option[value="+a+"]").remove()},adjustLanguageBox:function(){this.captionsButton.find(".mejs-captions-selector").height(this.captionsButton.find(".mejs-captions-selector ul").outerHeight(true)+this.captionsButton.find(".mejs-captions-translations").outerHeight(true))},displayCaptions:function(){if(typeof this.tracks!="undefined"){var a,b=this.selectedTrack;if(b!=null&&b.isLoaded)for(a=0;a<b.entries.times.length;a++)if(this.media.currentTime>=b.entries.times[a].start&&
138
+ this.media.currentTime<=b.entries.times[a].stop){this.captionsText.html(b.entries.text[a]);this.captions.show().height(0);return}this.captions.hide()}},displayChapters:function(){var a;for(a=0;a<this.tracks.length;a++)if(this.tracks[a].kind=="chapters"&&this.tracks[a].isLoaded){this.drawChapters(this.tracks[a]);this.hasChapters=true;break}},drawChapters:function(a){var b=this,c,d,e=d=0;b.chapters.empty();for(c=0;c<a.entries.times.length;c++){d=a.entries.times[c].stop-a.entries.times[c].start;d=Math.floor(d/
139
+ b.media.duration*100);if(d+e>100||c==a.entries.times.length-1&&d+e<100)d=100-e;b.chapters.append(f('<div class="mejs-chapter" rel="'+a.entries.times[c].start+'" style="left: '+e.toString()+"%;width: "+d.toString()+'%;"><div class="mejs-chapter-block'+(c==a.entries.times.length-1?" mejs-chapter-block-last":"")+'"><span class="ch-title">'+a.entries.text[c]+'</span><span class="ch-time">'+mejs.Utility.secondsToTimeCode(a.entries.times[c].start)+"&ndash;"+mejs.Utility.secondsToTimeCode(a.entries.times[c].stop)+
140
+ "</span></div></div>"));e+=d}b.chapters.find("div.mejs-chapter").click(function(){b.media.setCurrentTime(parseFloat(f(this).attr("rel")));b.media.paused&&b.media.play()});b.chapters.show()}});mejs.language={codes:{af:"Afrikaans",sq:"Albanian",ar:"Arabic",be:"Belarusian",bg:"Bulgarian",ca:"Catalan",zh:"Chinese","zh-cn":"Chinese Simplified","zh-tw":"Chinese Traditional",hr:"Croatian",cs:"Czech",da:"Danish",nl:"Dutch",en:"English",et:"Estonian",tl:"Filipino",fi:"Finnish",fr:"French",gl:"Galician",de:"German",
141
+ el:"Greek",ht:"Haitian Creole",iw:"Hebrew",hi:"Hindi",hu:"Hungarian",is:"Icelandic",id:"Indonesian",ga:"Irish",it:"Italian",ja:"Japanese",ko:"Korean",lv:"Latvian",lt:"Lithuanian",mk:"Macedonian",ms:"Malay",mt:"Maltese",no:"Norwegian",fa:"Persian",pl:"Polish",pt:"Portuguese",ro:"Romanian",ru:"Russian",sr:"Serbian",sk:"Slovak",sl:"Slovenian",es:"Spanish",sw:"Swahili",sv:"Swedish",tl:"Tagalog",th:"Thai",tr:"Turkish",uk:"Ukrainian",vi:"Vietnamese",cy:"Welsh",yi:"Yiddish"}};mejs.TrackFormatParser={pattern_identifier:/^([a-zA-z]+-)?[0-9]+$/,
142
+ pattern_timecode:/^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,split2:function(a,b){return a.split(b)},parse:function(a){var b=0;a=this.split2(a,/\r?\n/);for(var c={text:[],times:[]},d,e;b<a.length;b++)if(this.pattern_identifier.exec(a[b])){b++;if((d=this.pattern_timecode.exec(a[b]))&&b<a.length){b++;e=a[b];for(b++;a[b]!==""&&b<a.length;){e=e+"\n"+a[b];b++}c.text.push(e);c.times.push({start:mejs.Utility.timeCodeToSeconds(d[1]),stop:mejs.Utility.timeCodeToSeconds(d[3]),
143
+ settings:d[5]})}}return c}};if("x\n\ny".split(/\n/gi).length!=3)mejs.TrackFormatParser.split2=function(a,b){var c=[],d="",e;for(e=0;e<a.length;e++){d+=a.substring(e,e+1);if(b.test(d)){c.push(d.replace(b,""));d=""}}c.push(d);return c}})(mejs.$);
144
+ (function(f){f.extend(mejs.MepDefaults,{contextMenuItems:[{render:function(a){if(typeof a.enterFullScreen=="undefined")return null;return a.isFullScreen?"Turn off Fullscreen":"Go Fullscreen"},click:function(a){a.isFullScreen?a.exitFullScreen():a.enterFullScreen()}},{render:function(a){return a.media.muted?"Unmute":"Mute"},click:function(a){a.media.muted?a.setMuted(false):a.setMuted(true)}},{isSeparator:true},{render:function(){return"Download Video"},click:function(a){window.location.href=a.media.currentSrc}}]});
145
+ f.extend(MediaElementPlayer.prototype,{buildcontextmenu:function(a){a.contextMenu=f('<div class="mejs-contextmenu"></div>').appendTo(f("body")).hide();a.container.bind("contextmenu",function(b){if(a.isContextMenuEnabled){b.preventDefault();a.renderContextMenu(b.clientX-1,b.clientY-1);return false}});a.container.bind("click",function(){a.contextMenu.hide()});a.contextMenu.bind("mouseleave",function(){a.startContextMenuTimer()})},isContextMenuEnabled:true,enableContextMenu:function(){this.isContextMenuEnabled=
146
+ true},disableContextMenu:function(){this.isContextMenuEnabled=false},contextMenuTimeout:null,startContextMenuTimer:function(){var a=this;a.killContextMenuTimer();a.contextMenuTimer=setTimeout(function(){a.hideContextMenu();a.killContextMenuTimer()},750)},killContextMenuTimer:function(){var a=this.contextMenuTimer;if(a!=null){clearTimeout(a);delete a}},hideContextMenu:function(){this.contextMenu.hide()},renderContextMenu:function(a,b){for(var c=this,d="",e=c.options.contextMenuItems,g=0,k=e.length;g<
147
+ k;g++)if(e[g].isSeparator)d+='<div class="mejs-contextmenu-separator"></div>';else{var h=e[g].render(c);if(h!=null)d+='<div class="mejs-contextmenu-item" data-itemindex="'+g+'" id="element-'+Math.random()*1E6+'">'+h+"</div>"}c.contextMenu.empty().append(f(d)).css({top:b,left:a}).show();c.contextMenu.find(".mejs-contextmenu-item").each(function(){var o=f(this),n=parseInt(o.data("itemindex"),10),p=c.options.contextMenuItems[n];typeof p.show!="undefined"&&p.show(o,c);o.click(function(){typeof p.click!=
148
+ "undefined"&&p.click(c);c.contextMenu.hide()})});setTimeout(function(){c.killControlsTimer("rev3")},100)}})})(mejs.$);
149
+
includes/media-element/mediaelement.js ADDED
@@ -0,0 +1,1517 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * MediaElement.js
3
+ * HTML5 <video> and <audio> shim and player
4
+ * http://mediaelementjs.com/
5
+ *
6
+ * Creates a JavaScript object that mimics HTML5 MediaElement API
7
+ * for browsers that don't understand HTML5 or can't play the provided codec
8
+ * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
9
+ *
10
+ * Copyright 2010-2012, John Dyer (http://j.hn)
11
+ * Dual licensed under the MIT or GPL Version 2 licenses.
12
+ *
13
+ */
14
+ // Namespace
15
+ var mejs = mejs || {};
16
+
17
+ // version number
18
+ mejs.version = '2.9.1';
19
+
20
+ // player number (for missing, same id attr)
21
+ mejs.meIndex = 0;
22
+
23
+ // media types accepted by plugins
24
+ mejs.plugins = {
25
+ silverlight: [
26
+ {version: [3,0], types: ['video/mp4','video/m4v','video/mov','video/wmv','audio/wma','audio/m4a','audio/mp3','audio/wav','audio/mpeg']}
27
+ ],
28
+ flash: [
29
+ {version: [9,0,124], types: ['video/mp4','video/m4v','video/mov','video/flv','video/x-flv','audio/flv','audio/x-flv','audio/mp3','audio/m4a','audio/mpeg', 'video/youtube', 'video/x-youtube']}
30
+ //,{version: [12,0], types: ['video/webm']} // for future reference (hopefully!)
31
+ ],
32
+ youtube: [
33
+ {version: null, types: ['video/youtube', 'video/x-youtube']}
34
+ ],
35
+ vimeo: [
36
+ {version: null, types: ['video/vimeo']}
37
+ ]
38
+ };
39
+
40
+ /*
41
+ Utility methods
42
+ */
43
+ mejs.Utility = {
44
+ encodeUrl: function(url) {
45
+ return encodeURIComponent(url); //.replace(/\?/gi,'%3F').replace(/=/gi,'%3D').replace(/&/gi,'%26');
46
+ },
47
+ escapeHTML: function(s) {
48
+ return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
49
+ },
50
+ absolutizeUrl: function(url) {
51
+ var el = document.createElement('div');
52
+ el.innerHTML = '<a href="' + this.escapeHTML(url) + '">x</a>';
53
+ return el.firstChild.href;
54
+ },
55
+ getScriptPath: function(scriptNames) {
56
+ var
57
+ i = 0,
58
+ j,
59
+ path = '',
60
+ name = '',
61
+ script,
62
+ scripts = document.getElementsByTagName('script'),
63
+ il = scripts.length,
64
+ jl = scriptNames.length;
65
+
66
+ for (; i < il; i++) {
67
+ script = scripts[i].src;
68
+ for (j = 0; j < jl; j++) {
69
+ name = scriptNames[j];
70
+ if (script.indexOf(name) > -1) {
71
+ path = script.substring(0, script.indexOf(name));
72
+ break;
73
+ }
74
+ }
75
+ if (path !== '') {
76
+ break;
77
+ }
78
+ }
79
+ return path;
80
+ },
81
+ secondsToTimeCode: function(time, forceHours, showFrameCount, fps) {
82
+ //add framecount
83
+ if (typeof showFrameCount == 'undefined') {
84
+ showFrameCount=false;
85
+ } else if(typeof fps == 'undefined') {
86
+ fps = 25;
87
+ }
88
+
89
+ var hours = Math.floor(time / 3600) % 24,
90
+ minutes = Math.floor(time / 60) % 60,
91
+ seconds = Math.floor(time % 60),
92
+ frames = Math.floor(((time % 1)*fps).toFixed(3)),
93
+ result =
94
+ ( (forceHours || hours > 0) ? (hours < 10 ? '0' + hours : hours) + ':' : '')
95
+ + (minutes < 10 ? '0' + minutes : minutes) + ':'
96
+ + (seconds < 10 ? '0' + seconds : seconds)
97
+ + ((showFrameCount) ? ':' + (frames < 10 ? '0' + frames : frames) : '');
98
+
99
+ return result;
100
+ },
101
+
102
+ timeCodeToSeconds: function(hh_mm_ss_ff, forceHours, showFrameCount, fps){
103
+ if (typeof showFrameCount == 'undefined') {
104
+ showFrameCount=false;
105
+ } else if(typeof fps == 'undefined') {
106
+ fps = 25;
107
+ }
108
+
109
+ var tc_array = hh_mm_ss_ff.split(":"),
110
+ tc_hh = parseInt(tc_array[0], 10),
111
+ tc_mm = parseInt(tc_array[1], 10),
112
+ tc_ss = parseInt(tc_array[2], 10),
113
+ tc_ff = 0,
114
+ tc_in_seconds = 0;
115
+
116
+ if (showFrameCount) {
117
+ tc_ff = parseInt(tc_array[3])/fps;
118
+ }
119
+
120
+ tc_in_seconds = ( tc_hh * 3600 ) + ( tc_mm * 60 ) + tc_ss + tc_ff;
121
+
122
+ return tc_in_seconds;
123
+ },
124
+
125
+ /* borrowed from SWFObject: http://code.google.com/p/swfobject/source/browse/trunk/swfobject/src/swfobject.js#474 */
126
+ removeSwf: function(id) {
127
+ var obj = document.getElementById(id);
128
+ if (obj && obj.nodeName == "OBJECT") {
129
+ if (mejs.MediaFeatures.isIE) {
130
+ obj.style.display = "none";
131
+ (function(){
132
+ if (obj.readyState == 4) {
133
+ mejs.Utility.removeObjectInIE(id);
134
+ } else {
135
+ setTimeout(arguments.callee, 10);
136
+ }
137
+ })();
138
+ } else {
139
+ obj.parentNode.removeChild(obj);
140
+ }
141
+ }
142
+ },
143
+ removeObjectInIE: function(id) {
144
+ var obj = document.getElementById(id);
145
+ if (obj) {
146
+ for (var i in obj) {
147
+ if (typeof obj[i] == "function") {
148
+ obj[i] = null;
149
+ }
150
+ }
151
+ obj.parentNode.removeChild(obj);
152
+ }
153
+ }
154
+ };
155
+
156
+
157
+ // Core detector, plugins are added below
158
+ mejs.PluginDetector = {
159
+
160
+ // main public function to test a plug version number PluginDetector.hasPluginVersion('flash',[9,0,125]);
161
+ hasPluginVersion: function(plugin, v) {
162
+ var pv = this.plugins[plugin];
163
+ v[1] = v[1] || 0;
164
+ v[2] = v[2] || 0;
165
+ return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
166
+ },
167
+
168
+ // cached values
169
+ nav: window.navigator,
170
+ ua: window.navigator.userAgent.toLowerCase(),
171
+
172
+ // stored version numbers
173
+ plugins: [],
174
+
175
+ // runs detectPlugin() and stores the version number
176
+ addPlugin: function(p, pluginName, mimeType, activeX, axDetect) {
177
+ this.plugins[p] = this.detectPlugin(pluginName, mimeType, activeX, axDetect);
178
+ },
179
+
180
+ // get the version number from the mimetype (all but IE) or ActiveX (IE)
181
+ detectPlugin: function(pluginName, mimeType, activeX, axDetect) {
182
+
183
+ var version = [0,0,0],
184
+ description,
185
+ i,
186
+ ax;
187
+
188
+ // Firefox, Webkit, Opera
189
+ if (typeof(this.nav.plugins) != 'undefined' && typeof this.nav.plugins[pluginName] == 'object') {
190
+ description = this.nav.plugins[pluginName].description;
191
+ if (description && !(typeof this.nav.mimeTypes != 'undefined' && this.nav.mimeTypes[mimeType] && !this.nav.mimeTypes[mimeType].enabledPlugin)) {
192
+ version = description.replace(pluginName, '').replace(/^\s+/,'').replace(/\sr/gi,'.').split('.');
193
+ for (i=0; i<version.length; i++) {
194
+ version[i] = parseInt(version[i].match(/\d+/), 10);
195
+ }
196
+ }
197
+ // Internet Explorer / ActiveX
198
+ } else if (typeof(window.ActiveXObject) != 'undefined') {
199
+ try {
200
+ ax = new ActiveXObject(activeX);
201
+ if (ax) {
202
+ version = axDetect(ax);
203
+ }
204
+ }
205
+ catch (e) { }
206
+ }
207
+ return version;
208
+ }
209
+ };
210
+
211
+ // Add Flash detection
212
+ mejs.PluginDetector.addPlugin('flash','Shockwave Flash','application/x-shockwave-flash','ShockwaveFlash.ShockwaveFlash', function(ax) {
213
+ // adapted from SWFObject
214
+ var version = [],
215
+ d = ax.GetVariable("$version");
216
+ if (d) {
217
+ d = d.split(" ")[1].split(",");
218
+ version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
219
+ }
220
+ return version;
221
+ });
222
+
223
+ // Add Silverlight detection
224
+ mejs.PluginDetector.addPlugin('silverlight','Silverlight Plug-In','application/x-silverlight-2','AgControl.AgControl', function (ax) {
225
+ // Silverlight cannot report its version number to IE
226
+ // but it does have a isVersionSupported function, so we have to loop through it to get a version number.
227
+ // adapted from http://www.silverlightversion.com/
228
+ var v = [0,0,0,0],
229
+ loopMatch = function(ax, v, i, n) {
230
+ while(ax.isVersionSupported(v[0]+ "."+ v[1] + "." + v[2] + "." + v[3])){
231
+ v[i]+=n;
232
+ }
233
+ v[i] -= n;
234
+ };
235
+ loopMatch(ax, v, 0, 1);
236
+ loopMatch(ax, v, 1, 1);
237
+ loopMatch(ax, v, 2, 10000); // the third place in the version number is usually 5 digits (4.0.xxxxx)
238
+ loopMatch(ax, v, 2, 1000);
239
+ loopMatch(ax, v, 2, 100);
240
+ loopMatch(ax, v, 2, 10);
241
+ loopMatch(ax, v, 2, 1);
242
+ loopMatch(ax, v, 3, 1);
243
+
244
+ return v;
245
+ });
246
+ // add adobe acrobat
247
+ /*
248
+ PluginDetector.addPlugin('acrobat','Adobe Acrobat','application/pdf','AcroPDF.PDF', function (ax) {
249
+ var version = [],
250
+ d = ax.GetVersions().split(',')[0].split('=')[1].split('.');
251
+
252
+ if (d) {
253
+ version = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
254
+ }
255
+ return version;
256
+ });
257
+ */
258
+ // necessary detection (fixes for <IE9)
259
+ mejs.MediaFeatures = {
260
+ init: function() {
261
+ var
262
+ t = this,
263
+ d = document,
264
+ nav = mejs.PluginDetector.nav,
265
+ ua = mejs.PluginDetector.ua.toLowerCase(),
266
+ i,
267
+ v,
268
+ html5Elements = ['source','track','audio','video'];
269
+
270
+ // detect browsers (only the ones that have some kind of quirk we need to work around)
271
+ t.isiPad = (ua.match(/ipad/i) !== null);
272
+ t.isiPhone = (ua.match(/iphone/i) !== null);
273
+ t.isiOS = t.isiPhone || t.isiPad;
274
+ t.isAndroid = (ua.match(/android/i) !== null);
275
+ t.isBustedAndroid = (ua.match(/android 2\.[12]/) !== null);
276
+ t.isIE = (nav.appName.toLowerCase().indexOf("microsoft") != -1);
277
+ t.isChrome = (ua.match(/chrome/gi) !== null);
278
+ t.isFirefox = (ua.match(/firefox/gi) !== null);
279
+ t.isWebkit = (ua.match(/webkit/gi) !== null);
280
+ t.isGecko = (ua.match(/gecko/gi) !== null) && !t.isWebkit;
281
+ t.isOpera = (ua.match(/opera/gi) !== null);
282
+ t.hasTouch = ('ontouchstart' in window);
283
+
284
+ // create HTML5 media elements for IE before 9, get a <video> element for fullscreen detection
285
+ for (i=0; i<html5Elements.length; i++) {
286
+ v = document.createElement(html5Elements[i]);
287
+ }
288
+
289
+ t.supportsMediaTag = (typeof v.canPlayType !== 'undefined' || t.isBustedAndroid);
290
+
291
+ // detect native JavaScript fullscreen (Safari/Firefox only, Chrome still fails)
292
+
293
+ // iOS
294
+ t.hasSemiNativeFullScreen = (typeof v.webkitEnterFullscreen !== 'undefined');
295
+
296
+ // Webkit/firefox
297
+ t.hasWebkitNativeFullScreen = (typeof v.webkitRequestFullScreen !== 'undefined');
298
+ t.hasMozNativeFullScreen = (typeof v.mozRequestFullScreen !== 'undefined');
299
+
300
+ t.hasTrueNativeFullScreen = (t.hasWebkitNativeFullScreen || t.hasMozNativeFullScreen);
301
+ t.nativeFullScreenEnabled = t.hasTrueNativeFullScreen;
302
+ if (t.hasMozNativeFullScreen) {
303
+ t.nativeFullScreenEnabled = v.mozFullScreenEnabled;
304
+ }
305
+
306
+
307
+ if (this.isChrome) {
308
+ t.hasSemiNativeFullScreen = false;
309
+ }
310
+
311
+ if (t.hasTrueNativeFullScreen) {
312
+ t.fullScreenEventName = (t.hasWebkitNativeFullScreen) ? 'webkitfullscreenchange' : 'mozfullscreenchange';
313
+
314
+
315
+ t.isFullScreen = function() {
316
+ if (v.mozRequestFullScreen) {
317
+ return d.mozFullScreen;
318
+ } else if (v.webkitRequestFullScreen) {
319
+ return d.webkitIsFullScreen;
320
+ }
321
+ }
322
+
323
+ t.requestFullScreen = function(el) {
324
+
325
+ if (t.hasWebkitNativeFullScreen) {
326
+ el.webkitRequestFullScreen();
327
+ } else if (t.hasMozNativeFullScreen) {
328
+ el.mozRequestFullScreen();
329
+ }
330
+ }
331
+
332
+ t.cancelFullScreen = function() {
333
+ if (t.hasWebkitNativeFullScreen) {
334
+ document.webkitCancelFullScreen();
335
+ } else if (t.hasMozNativeFullScreen) {
336
+ document.mozCancelFullScreen();
337
+ }
338
+ }
339
+
340
+ }
341
+
342
+
343
+ // OS X 10.5 can't do this even if it says it can :(
344
+ if (t.hasSemiNativeFullScreen && ua.match(/mac os x 10_5/i)) {
345
+ t.hasNativeFullScreen = false;
346
+ t.hasSemiNativeFullScreen = false;
347
+ }
348
+
349
+ }
350
+ };
351
+ mejs.MediaFeatures.init();
352
+
353
+
354
+ /*
355
+ extension methods to <video> or <audio> object to bring it into parity with PluginMediaElement (see below)
356
+ */
357
+ mejs.HtmlMediaElement = {
358
+ pluginType: 'native',
359
+ isFullScreen: false,
360
+
361
+ setCurrentTime: function (time) {
362
+ this.currentTime = time;
363
+ },
364
+
365
+ setMuted: function (muted) {
366
+ this.muted = muted;
367
+ },
368
+
369
+ setVolume: function (volume) {
370
+ this.volume = volume;
371
+ },
372
+
373
+ // for parity with the plugin versions
374
+ stop: function () {
375
+ this.pause();
376
+ },
377
+
378
+ // This can be a url string
379
+ // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
380
+ setSrc: function (url) {
381
+
382
+ // Fix for IE9 which can't set .src when there are <source> elements. Awesome, right?
383
+ var
384
+ existingSources = this.getElementsByTagName('source');
385
+ while (existingSources.length > 0){
386
+ this.removeChild(existingSources[0]);
387
+ }
388
+
389
+ if (typeof url == 'string') {
390
+ this.src = url;
391
+ } else {
392
+ var i, media;
393
+
394
+ for (i=0; i<url.length; i++) {
395
+ media = url[i];
396
+ if (this.canPlayType(media.type)) {
397
+ this.src = media.src;
398
+ }
399
+ }
400
+ }
401
+ },
402
+
403
+ setVideoSize: function (width, height) {
404
+ this.width = width;
405
+ this.height = height;
406
+ }
407
+ };
408
+
409
+ /*
410
+ Mimics the <video/audio> element by calling Flash's External Interface or Silverlights [ScriptableMember]
411
+ */
412
+ mejs.PluginMediaElement = function (pluginid, pluginType, mediaUrl) {
413
+ this.id = pluginid;
414
+ this.pluginType = pluginType;
415
+ this.src = mediaUrl;
416
+ this.events = {};
417
+ };
418
+
419
+ // JavaScript values and ExternalInterface methods that match HTML5 video properties methods
420
+ // http://www.adobe.com/livedocs/flash/9.0/ActionScriptLangRefV3/fl/video/FLVPlayback.html
421
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
422
+ mejs.PluginMediaElement.prototype = {
423
+
424
+ // special
425
+ pluginElement: null,
426
+ pluginType: '',
427
+ isFullScreen: false,
428
+
429
+ // not implemented :(
430
+ playbackRate: -1,
431
+ defaultPlaybackRate: -1,
432
+ seekable: [],
433
+ played: [],
434
+
435
+ // HTML5 read-only properties
436
+ paused: true,
437
+ ended: false,
438
+ seeking: false,
439
+ duration: 0,
440
+ error: null,
441
+ tagName: '',
442
+
443
+ // HTML5 get/set properties, but only set (updated by event handlers)
444
+ muted: false,
445
+ volume: 1,
446
+ currentTime: 0,
447
+
448
+ // HTML5 methods
449
+ play: function () {
450
+ if (this.pluginApi != null) {
451
+ if (this.pluginType == 'youtube') {
452
+ this.pluginApi.playVideo();
453
+ } else {
454
+ this.pluginApi.playMedia();
455
+ }
456
+ this.paused = false;
457
+ }
458
+ },
459
+ load: function () {
460
+ if (this.pluginApi != null) {
461
+ if (this.pluginType == 'youtube') {
462
+ } else {
463
+ this.pluginApi.loadMedia();
464
+ }
465
+
466
+ this.paused = false;
467
+ }
468
+ },
469
+ pause: function () {
470
+ if (this.pluginApi != null) {
471
+ if (this.pluginType == 'youtube') {
472
+ this.pluginApi.pauseVideo();
473
+ } else {
474
+ this.pluginApi.pauseMedia();
475
+ }
476
+
477
+
478
+ this.paused = true;
479
+ }
480
+ },
481
+ stop: function () {
482
+ if (this.pluginApi != null) {
483
+ if (this.pluginType == 'youtube') {
484
+ this.pluginApi.stopVideo();
485
+ } else {
486
+ this.pluginApi.stopMedia();
487
+ }
488
+ this.paused = true;
489
+ }
490
+ },
491
+ canPlayType: function(type) {
492
+ var i,
493
+ j,
494
+ pluginInfo,
495
+ pluginVersions = mejs.plugins[this.pluginType];
496
+
497
+ for (i=0; i<pluginVersions.length; i++) {
498
+ pluginInfo = pluginVersions[i];
499
+
500
+ // test if user has the correct plugin version
501
+ if (mejs.PluginDetector.hasPluginVersion(this.pluginType, pluginInfo.version)) {
502
+
503
+ // test for plugin playback types
504
+ for (j=0; j<pluginInfo.types.length; j++) {
505
+ // find plugin that can play the type
506
+ if (type == pluginInfo.types[j]) {
507
+ return true;
508
+ }
509
+ }
510
+ }
511
+ }
512
+
513
+ return false;
514
+ },
515
+
516
+ positionFullscreenButton: function(x,y,visibleAndAbove) {
517
+ if (this.pluginApi != null && this.pluginApi.positionFullscreenButton) {
518
+ this.pluginApi.positionFullscreenButton(x,y,visibleAndAbove);
519
+ }
520
+ },
521
+
522
+ hideFullscreenButton: function() {
523
+ if (this.pluginApi != null && this.pluginApi.hideFullscreenButton) {
524
+ this.pluginApi.hideFullscreenButton();
525
+ }
526
+ },
527
+
528
+
529
+ // custom methods since not all JavaScript implementations support get/set
530
+
531
+ // This can be a url string
532
+ // or an array [{src:'file.mp4',type:'video/mp4'},{src:'file.webm',type:'video/webm'}]
533
+ setSrc: function (url) {
534
+ if (typeof url == 'string') {
535
+ this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(url));
536
+ this.src = mejs.Utility.absolutizeUrl(url);
537
+ } else {
538
+ var i, media;
539
+
540
+ for (i=0; i<url.length; i++) {
541
+ media = url[i];
542
+ if (this.canPlayType(media.type)) {
543
+ this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(media.src));
544
+ this.src = mejs.Utility.absolutizeUrl(url);
545
+ }
546
+ }
547
+ }
548
+
549
+ },
550
+ setCurrentTime: function (time) {
551
+ if (this.pluginApi != null) {
552
+ if (this.pluginType == 'youtube') {
553
+ this.pluginApi.seekTo(time);
554
+ } else {
555
+ this.pluginApi.setCurrentTime(time);
556
+ }
557
+
558
+
559
+
560
+ this.currentTime = time;
561
+ }
562
+ },
563
+ setVolume: function (volume) {
564
+ if (this.pluginApi != null) {
565
+ // same on YouTube and MEjs
566
+ if (this.pluginType == 'youtube') {
567
+ this.pluginApi.setVolume(volume * 100);
568
+ } else {
569
+ this.pluginApi.setVolume(volume);
570
+ }
571
+ this.volume = volume;
572
+ }
573
+ },
574
+ setMuted: function (muted) {
575
+ if (this.pluginApi != null) {
576
+ if (this.pluginType == 'youtube') {
577
+ if (muted) {
578
+ this.pluginApi.mute();
579
+ } else {
580
+ this.pluginApi.unMute();
581
+ }
582
+ this.muted = muted;
583
+ this.dispatchEvent('volumechange');
584
+ } else {
585
+ this.pluginApi.setMuted(muted);
586
+ }
587
+ this.muted = muted;
588
+ }
589
+ },
590
+
591
+ // additional non-HTML5 methods
592
+ setVideoSize: function (width, height) {
593
+
594
+ //if (this.pluginType == 'flash' || this.pluginType == 'silverlight') {
595
+ if ( this.pluginElement.style) {
596
+ this.pluginElement.style.width = width + 'px';
597
+ this.pluginElement.style.height = height + 'px';
598
+ }
599
+ if (this.pluginApi != null && this.pluginApi.setVideoSize) {
600
+ this.pluginApi.setVideoSize(width, height);
601
+ }
602
+ //}
603
+ },
604
+
605
+ setFullscreen: function (fullscreen) {
606
+ if (this.pluginApi != null && this.pluginApi.setFullscreen) {
607
+ this.pluginApi.setFullscreen(fullscreen);
608
+ }
609
+ },
610
+
611
+ enterFullScreen: function() {
612
+ if (this.pluginApi != null && this.pluginApi.setFullscreen) {
613
+ this.setFullscreen(true);
614
+ }
615
+
616
+ },
617
+
618
+ exitFullScreen: function() {
619
+ if (this.pluginApi != null && this.pluginApi.setFullscreen) {
620
+ this.setFullscreen(false);
621
+ }
622
+ },
623
+
624
+ // start: fake events
625
+ addEventListener: function (eventName, callback, bubble) {
626
+ this.events[eventName] = this.events[eventName] || [];
627
+ this.events[eventName].push(callback);
628
+ },
629
+ removeEventListener: function (eventName, callback) {
630
+ if (!eventName) { this.events = {}; return true; }
631
+ var callbacks = this.events[eventName];
632
+ if (!callbacks) return true;
633
+ if (!callback) { this.events[eventName] = []; return true; }
634
+ for (i = 0; i < callbacks.length; i++) {
635
+ if (callbacks[i] === callback) {
636
+ this.events[eventName].splice(i, 1);
637
+ return true;
638
+ }
639
+ }
640
+ return false;
641
+ },
642
+ dispatchEvent: function (eventName) {
643
+ var i,
644
+ args,
645
+ callbacks = this.events[eventName];
646
+
647
+ if (callbacks) {
648
+ args = Array.prototype.slice.call(arguments, 1);
649
+ for (i = 0; i < callbacks.length; i++) {
650
+ callbacks[i].apply(null, args);
651
+ }
652
+ }
653
+ },
654
+ // end: fake events
655
+
656
+ // fake DOM attribute methods
657
+ attributes: {},
658
+ hasAttribute: function(name){
659
+ return (name in this.attributes);
660
+ },
661
+ removeAttribute: function(name){
662
+ delete this.attributes[name];
663
+ },
664
+ getAttribute: function(name){
665
+ if (this.hasAttribute(name)) {
666
+ return this.attributes[name];
667
+ }
668
+ return '';
669
+ },
670
+ setAttribute: function(name, value){
671
+ this.attributes[name] = value;
672
+ },
673
+
674
+ remove: function() {
675
+ mejs.Utility.removeSwf(this.pluginElement.id);
676
+ }
677
+ };
678
+
679
+ // Handles calls from Flash/Silverlight and reports them as native <video/audio> events and properties
680
+ mejs.MediaPluginBridge = {
681
+
682
+ pluginMediaElements:{},
683
+ htmlMediaElements:{},
684
+
685
+ registerPluginElement: function (id, pluginMediaElement, htmlMediaElement) {
686
+ this.pluginMediaElements[id] = pluginMediaElement;
687
+ this.htmlMediaElements[id] = htmlMediaElement;
688
+ },
689
+
690
+ // when Flash/Silverlight is ready, it calls out to this method
691
+ initPlugin: function (id) {
692
+
693
+ var pluginMediaElement = this.pluginMediaElements[id],
694
+ htmlMediaElement = this.htmlMediaElements[id];
695
+
696
+ if (pluginMediaElement) {
697
+ // find the javascript bridge
698
+ switch (pluginMediaElement.pluginType) {
699
+ case "flash":
700
+ pluginMediaElement.pluginElement = pluginMediaElement.pluginApi = document.getElementById(id);
701
+ break;
702
+ case "silverlight":
703
+ pluginMediaElement.pluginElement = document.getElementById(pluginMediaElement.id);
704
+ pluginMediaElement.pluginApi = pluginMediaElement.pluginElement.Content.MediaElementJS;
705
+ break;
706
+ }
707
+
708
+ if (pluginMediaElement.pluginApi != null && pluginMediaElement.success) {
709
+ pluginMediaElement.success(pluginMediaElement, htmlMediaElement);
710
+ }
711
+ }
712
+ },
713
+
714
+ // receives events from Flash/Silverlight and sends them out as HTML5 media events
715
+ // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html
716
+ fireEvent: function (id, eventName, values) {
717
+
718
+ var
719
+ e,
720
+ i,
721
+ bufferedTime,
722
+ pluginMediaElement = this.pluginMediaElements[id];
723
+
724
+ pluginMediaElement.ended = false;
725
+ pluginMediaElement.paused = true;
726
+
727
+ // fake event object to mimic real HTML media event.
728
+ e = {
729
+ type: eventName,
730
+ target: pluginMediaElement
731
+ };
732
+
733
+ // attach all values to element and event object
734
+ for (i in values) {
735
+ pluginMediaElement[i] = values[i];
736
+ e[i] = values[i];
737
+ }
738
+
739
+ // fake the newer W3C buffered TimeRange (loaded and total have been removed)
740
+ bufferedTime = values.bufferedTime || 0;
741
+
742
+ e.target.buffered = e.buffered = {
743
+ start: function(index) {
744
+ return 0;
745
+ },
746
+ end: function (index) {
747
+ return bufferedTime;
748
+ },
749
+ length: 1
750
+ };
751
+
752
+ pluginMediaElement.dispatchEvent(e.type, e);
753
+ }
754
+ };
755
+
756
+ /*
757
+ Default options
758
+ */
759
+ mejs.MediaElementDefaults = {
760
+ // allows testing on HTML5, flash, silverlight
761
+ // auto: attempts to detect what the browser can do
762
+ // native: forces HTML5 playback
763
+ // shim: disallows HTML5, will attempt either Flash or Silverlight
764
+ // none: forces fallback view
765
+ mode: 'auto',
766
+ // remove or reorder to change plugin priority and availability
767
+ plugins: ['flash','silverlight','youtube','vimeo'],
768
+ // shows debug errors on screen
769
+ enablePluginDebug: false,
770
+ // overrides the type specified, useful for dynamic instantiation
771
+ type: '',
772
+ // path to Flash and Silverlight plugins
773
+ pluginPath: mejs.Utility.getScriptPath(['mediaelement.js','mediaelement.min.js','mediaelement-and-player.js','mediaelement-and-player.min.js']),
774
+ // name of flash file
775
+ flashName: 'flashmediaelement.swf',
776
+ // turns on the smoothing filter in Flash
777
+ enablePluginSmoothing: false,
778
+ // name of silverlight file
779
+ silverlightName: 'silverlightmediaelement.xap',
780
+ // default if the <video width> is not specified
781
+ defaultVideoWidth: 480,
782
+ // default if the <video height> is not specified
783
+ defaultVideoHeight: 270,
784
+ // overrides <video width>
785
+ pluginWidth: -1,
786
+ // overrides <video height>
787
+ pluginHeight: -1,
788
+ // additional plugin variables in 'key=value' form
789
+ pluginVars: [],
790
+ // rate in milliseconds for Flash and Silverlight to fire the timeupdate event
791
+ // larger number is less accurate, but less strain on plugin->JavaScript bridge
792
+ timerRate: 250,
793
+ // initial volume for player
794
+ startVolume: 0.8,
795
+ success: function () { },
796
+ error: function () { }
797
+ };
798
+
799
+ /*
800
+ Determines if a browser supports the <video> or <audio> element
801
+ and returns either the native element or a Flash/Silverlight version that
802
+ mimics HTML5 MediaElement
803
+ */
804
+ mejs.MediaElement = function (el, o) {
805
+ return mejs.HtmlMediaElementShim.create(el,o);
806
+ };
807
+
808
+ mejs.HtmlMediaElementShim = {
809
+
810
+ create: function(el, o) {
811
+ var
812
+ options = mejs.MediaElementDefaults,
813
+ htmlMediaElement = (typeof(el) == 'string') ? document.getElementById(el) : el,
814
+ tagName = htmlMediaElement.tagName.toLowerCase(),
815
+ isMediaTag = (tagName === 'audio' || tagName === 'video'),
816
+ src = (isMediaTag) ? htmlMediaElement.getAttribute('src') : htmlMediaElement.getAttribute('href'),
817
+ poster = htmlMediaElement.getAttribute('poster'),
818
+ autoplay = htmlMediaElement.getAttribute('autoplay'),
819
+ preload = htmlMediaElement.getAttribute('preload'),
820
+ controls = htmlMediaElement.getAttribute('controls'),
821
+ playback,
822
+ prop;
823
+
824
+ // extend options
825
+ for (prop in o) {
826
+ options[prop] = o[prop];
827
+ }
828
+
829
+ // clean up attributes
830
+ src = (typeof src == 'undefined' || src === null || src == '') ? null : src;
831
+ poster = (typeof poster == 'undefined' || poster === null) ? '' : poster;
832
+ preload = (typeof preload == 'undefined' || preload === null || preload === 'false') ? 'none' : preload;
833
+ autoplay = !(typeof autoplay == 'undefined' || autoplay === null || autoplay === 'false');
834
+ controls = !(typeof controls == 'undefined' || controls === null || controls === 'false');
835
+
836
+ // test for HTML5 and plugin capabilities
837
+ playback = this.determinePlayback(htmlMediaElement, options, mejs.MediaFeatures.supportsMediaTag, isMediaTag, src);
838
+ playback.url = (playback.url !== null) ? mejs.Utility.absolutizeUrl(playback.url) : '';
839
+
840
+ if (playback.method == 'native') {
841
+ // second fix for android
842
+ if (mejs.MediaFeatures.isBustedAndroid) {
843
+ htmlMediaElement.src = playback.url;
844
+ htmlMediaElement.addEventListener('click', function() {
845
+ htmlMediaElement.play();
846
+ }, false);
847
+ }
848
+
849
+ // add methods to native HTMLMediaElement
850
+ return this.updateNative(playback, options, autoplay, preload);
851
+ } else if (playback.method !== '') {
852
+ // create plugin to mimic HTMLMediaElement
853
+
854
+ return this.createPlugin( playback, options, poster, autoplay, preload, controls);
855
+ } else {
856
+ // boo, no HTML5, no Flash, no Silverlight.
857
+ this.createErrorMessage( playback, options, poster );
858
+
859
+ return this;
860
+ }
861
+ },
862
+
863
+ determinePlayback: function(htmlMediaElement, options, supportsMediaTag, isMediaTag, src) {
864
+ var
865
+ mediaFiles = [],
866
+ i,
867
+ j,
868
+ k,
869
+ l,
870
+ n,
871
+ type,
872
+ result = { method: '', url: '', htmlMediaElement: htmlMediaElement, isVideo: (htmlMediaElement.tagName.toLowerCase() != 'audio')},
873
+ pluginName,
874
+ pluginVersions,
875
+ pluginInfo,
876
+ dummy;
877
+
878
+ // STEP 1: Get URL and type from <video src> or <source src>
879
+
880
+ // supplied type overrides <video type> and <source type>
881
+ if (typeof options.type != 'undefined' && options.type !== '') {
882
+
883
+ // accept either string or array of types
884
+ if (typeof options.type == 'string') {
885
+ mediaFiles.push({type:options.type, url:src});
886
+ } else {
887
+
888
+ for (i=0; i<options.type.length; i++) {
889
+ mediaFiles.push({type:options.type[i], url:src});
890
+ }
891
+ }
892
+
893
+ // test for src attribute first
894
+ } else if (src !== null) {
895
+ type = this.formatType(src, htmlMediaElement.getAttribute('type'));
896
+ mediaFiles.push({type:type, url:src});
897
+
898
+ // then test for <source> elements
899
+ } else {
900
+ // test <source> types to see if they are usable
901
+ for (i = 0; i < htmlMediaElement.childNodes.length; i++) {
902
+ n = htmlMediaElement.childNodes[i];
903
+ if (n.nodeType == 1 && n.tagName.toLowerCase() == 'source') {
904
+ src = n.getAttribute('src');
905
+ type = this.formatType(src, n.getAttribute('type'));
906
+ mediaFiles.push({type:type, url:src});
907
+ }
908
+ }
909
+ }
910
+
911
+ // in the case of dynamicly created players
912
+ // check for audio types
913
+ if (!isMediaTag && mediaFiles.length > 0 && mediaFiles[0].url !== null && this.getTypeFromFile(mediaFiles[0].url).indexOf('audio') > -1) {
914
+ result.isVideo = false;
915
+ }
916
+
917
+
918
+ // STEP 2: Test for playback method
919
+
920
+ // special case for Android which sadly doesn't implement the canPlayType function (always returns '')
921
+ if (mejs.MediaFeatures.isBustedAndroid) {
922
+ htmlMediaElement.canPlayType = function(type) {
923
+ return (type.match(/video\/(mp4|m4v)/gi) !== null) ? 'maybe' : '';
924
+ };
925
+ }
926
+
927
+
928
+ // test for native playback first
929
+ if (supportsMediaTag && (options.mode === 'auto' || options.mode === 'native')) {
930
+
931
+ if (!isMediaTag) {
932
+
933
+ // create a real HTML5 Media Element
934
+ dummy = document.createElement( result.isVideo ? 'video' : 'audio');
935
+ htmlMediaElement.parentNode.insertBefore(dummy, htmlMediaElement);
936
+ htmlMediaElement.style.display = 'none';
937
+
938
+ // use this one from now on
939
+ result.htmlMediaElement = htmlMediaElement = dummy;
940
+ }
941
+
942
+ for (i=0; i<mediaFiles.length; i++) {
943
+ // normal check
944
+ if (htmlMediaElement.canPlayType(mediaFiles[i].type).replace(/no/, '') !== ''
945
+ // special case for Mac/Safari 5.0.3 which answers '' to canPlayType('audio/mp3') but 'maybe' to canPlayType('audio/mpeg')
946
+ || htmlMediaElement.canPlayType(mediaFiles[i].type.replace(/mp3/,'mpeg')).replace(/no/, '') !== '') {
947
+ result.method = 'native';
948
+ result.url = mediaFiles[i].url;
949
+ break;
950
+ }
951
+ }
952
+
953
+ if (result.method === 'native') {
954
+ if (result.url !== null) {
955
+ htmlMediaElement.src = result.url;
956
+ }
957
+
958
+ return result;
959
+ }
960
+ }
961
+
962
+ // if native playback didn't work, then test plugins
963
+ if (options.mode === 'auto' || options.mode === 'shim') {
964
+ for (i=0; i<mediaFiles.length; i++) {
965
+ type = mediaFiles[i].type;
966
+
967
+ // test all plugins in order of preference [silverlight, flash]
968
+ for (j=0; j<options.plugins.length; j++) {
969
+
970
+ pluginName = options.plugins[j];
971
+
972
+ // test version of plugin (for future features)
973
+ pluginVersions = mejs.plugins[pluginName];
974
+
975
+ for (k=0; k<pluginVersions.length; k++) {
976
+ pluginInfo = pluginVersions[k];
977
+
978
+ // test if user has the correct plugin version
979
+
980
+ // for youtube/vimeo
981
+ if (pluginInfo.version == null ||
982
+
983
+ mejs.PluginDetector.hasPluginVersion(pluginName, pluginInfo.version)) {
984
+
985
+ // test for plugin playback types
986
+ for (l=0; l<pluginInfo.types.length; l++) {
987
+ // find plugin that can play the type
988
+ if (type == pluginInfo.types[l]) {
989
+ result.method = pluginName;
990
+ result.url = mediaFiles[i].url;
991
+ return result;
992
+ }
993
+ }
994
+ }
995
+ }
996
+ }
997
+ }
998
+ }
999
+
1000
+ // what if there's nothing to play? just grab the first available
1001
+ if (result.method === '' && mediaFiles.length > 0) {
1002
+ result.url = mediaFiles[0].url;
1003
+ }
1004
+
1005
+ return result;
1006
+ },
1007
+
1008
+ formatType: function(url, type) {
1009
+ var ext;
1010
+
1011
+ // if no type is supplied, fake it with the extension
1012
+ if (url && !type) {
1013
+ return this.getTypeFromFile(url);
1014
+ } else {
1015
+ // only return the mime part of the type in case the attribute contains the codec
1016
+ // see http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#the-source-element
1017
+ // `video/mp4; codecs="avc1.42E01E, mp4a.40.2"` becomes `video/mp4`
1018
+
1019
+ if (type && ~type.indexOf(';')) {
1020
+ return type.substr(0, type.indexOf(';'));
1021
+ } else {
1022
+ return type;
1023
+ }
1024
+ }
1025
+ },
1026
+
1027
+ getTypeFromFile: function(url) {
1028
+ var ext = url.substring(url.lastIndexOf('.') + 1);
1029
+ return (/(mp4|m4v|ogg|ogv|webm|flv|wmv|mpeg|mov)/gi.test(ext) ? 'video' : 'audio') + '/' + ext;
1030
+ },
1031
+
1032
+ createErrorMessage: function(playback, options, poster) {
1033
+ var
1034
+ htmlMediaElement = playback.htmlMediaElement,
1035
+ errorContainer = document.createElement('div');
1036
+
1037
+ errorContainer.className = 'me-cannotplay';
1038
+
1039
+ try {
1040
+ errorContainer.style.width = htmlMediaElement.width + 'px';
1041
+ errorContainer.style.height = htmlMediaElement.height + 'px';
1042
+ } catch (e) {}
1043
+
1044
+ errorContainer.innerHTML = (poster !== '') ?
1045
+ '<a href="' + playback.url + '"><img src="' + poster + '" width="100%" height="100%" /></a>' :
1046
+ '<a href="' + playback.url + '"><span>Download File</span></a>';
1047
+
1048
+ htmlMediaElement.parentNode.insertBefore(errorContainer, htmlMediaElement);
1049
+ htmlMediaElement.style.display = 'none';
1050
+
1051
+ options.error(htmlMediaElement);
1052
+ },
1053
+
1054
+ createPlugin:function(playback, options, poster, autoplay, preload, controls) {
1055
+ var
1056
+ htmlMediaElement = playback.htmlMediaElement,
1057
+ width = 1,
1058
+ height = 1,
1059
+ pluginid = 'me_' + playback.method + '_' + (mejs.meIndex++),
1060
+ pluginMediaElement = new mejs.PluginMediaElement(pluginid, playback.method, playback.url),
1061
+ container = document.createElement('div'),
1062
+ specialIEContainer,
1063
+ node,
1064
+ initVars;
1065
+
1066
+ // copy tagName from html media element
1067
+ pluginMediaElement.tagName = htmlMediaElement.tagName
1068
+
1069
+ // copy attributes from html media element to plugin media element
1070
+ for (var i = 0; i < htmlMediaElement.attributes.length; i++) {
1071
+ var attribute = htmlMediaElement.attributes[i];
1072
+ if (attribute.specified == true) {
1073
+ pluginMediaElement.setAttribute(attribute.name, attribute.value);
1074
+ }
1075
+ }
1076
+
1077
+ // check for placement inside a <p> tag (sometimes WYSIWYG editors do this)
1078
+ node = htmlMediaElement.parentNode;
1079
+ while (node !== null && node.tagName.toLowerCase() != 'body') {
1080
+ if (node.parentNode.tagName.toLowerCase() == 'p') {
1081
+ node.parentNode.parentNode.insertBefore(node, node.parentNode);
1082
+ break;
1083
+ }
1084
+ node = node.parentNode;
1085
+ }
1086
+
1087
+ if (playback.isVideo) {
1088
+ width = (options.videoWidth > 0) ? options.videoWidth : (htmlMediaElement.getAttribute('width') !== null) ? htmlMediaElement.getAttribute('width') : options.defaultVideoWidth;
1089
+ height = (options.videoHeight > 0) ? options.videoHeight : (htmlMediaElement.getAttribute('height') !== null) ? htmlMediaElement.getAttribute('height') : options.defaultVideoHeight;
1090
+
1091
+ // in case of '%' make sure it's encoded
1092
+ width = mejs.Utility.encodeUrl(width);
1093
+ height = mejs.Utility.encodeUrl(height);
1094
+
1095
+ } else {
1096
+ if (options.enablePluginDebug) {
1097
+ width = 320;
1098
+ height = 240;
1099
+ }
1100
+ }
1101
+
1102
+ // register plugin
1103
+ pluginMediaElement.success = options.success;
1104
+ mejs.MediaPluginBridge.registerPluginElement(pluginid, pluginMediaElement, htmlMediaElement);
1105
+
1106
+ // add container (must be added to DOM before inserting HTML for IE)
1107
+ container.className = 'me-plugin';
1108
+ container.id = pluginid + '_container';
1109
+
1110
+ if (playback.isVideo) {
1111
+ htmlMediaElement.parentNode.insertBefore(container, htmlMediaElement);
1112
+ } else {
1113
+ document.body.insertBefore(container, document.body.childNodes[0]);
1114
+ }
1115
+
1116
+ // flash/silverlight vars
1117
+ initVars = [
1118
+ 'id=' + pluginid,
1119
+ 'isvideo=' + ((playback.isVideo) ? "true" : "false"),
1120
+ 'autoplay=' + ((autoplay) ? "true" : "false"),
1121
+ 'preload=' + preload,
1122
+ 'width=' + width,
1123
+ 'startvolume=' + options.startVolume,
1124
+ 'timerrate=' + options.timerRate,
1125
+ 'height=' + height];
1126
+
1127
+ if (playback.url !== null) {
1128
+ if (playback.method == 'flash') {
1129
+ initVars.push('file=' + mejs.Utility.encodeUrl(playback.url));
1130
+ } else {
1131
+ initVars.push('file=' + playback.url);
1132
+ }
1133
+ }
1134
+ if (options.enablePluginDebug) {
1135
+ initVars.push('debug=true');
1136
+ }
1137
+ if (options.enablePluginSmoothing) {
1138
+ initVars.push('smoothing=true');
1139
+ }
1140
+ if (controls) {
1141
+ initVars.push('controls=true'); // shows controls in the plugin if desired
1142
+ }
1143
+ if (options.pluginVars) {
1144
+ initVars = initVars.concat(options.pluginVars);
1145
+ }
1146
+
1147
+ switch (playback.method) {
1148
+ case 'silverlight':
1149
+ container.innerHTML =
1150
+ '<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="' + pluginid + '" name="' + pluginid + '" width="' + width + '" height="' + height + '">' +
1151
+ '<param name="initParams" value="' + initVars.join(',') + '" />' +
1152
+ '<param name="windowless" value="true" />' +
1153
+ '<param name="background" value="black" />' +
1154
+ '<param name="minRuntimeVersion" value="3.0.0.0" />' +
1155
+ '<param name="autoUpgrade" value="true" />' +
1156
+ '<param name="source" value="' + options.pluginPath + options.silverlightName + '" />' +
1157
+ '</object>';
1158
+ break;
1159
+
1160
+ case 'flash':
1161
+
1162
+ if (mejs.MediaFeatures.isIE) {
1163
+ specialIEContainer = document.createElement('div');
1164
+ container.appendChild(specialIEContainer);
1165
+ specialIEContainer.outerHTML =
1166
+ '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
1167
+ 'id="' + pluginid + '" width="' + width + '" height="' + height + '">' +
1168
+ '<param name="movie" value="' + options.pluginPath + options.flashName + '?x=' + (new Date()) + '" />' +
1169
+ '<param name="flashvars" value="' + initVars.join('&amp;') + '" />' +
1170
+ '<param name="quality" value="high" />' +
1171
+ '<param name="bgcolor" value="#000000" />' +
1172
+ '<param name="wmode" value="transparent" />' +
1173
+ '<param name="allowScriptAccess" value="always" />' +
1174
+ '<param name="allowFullScreen" value="true" />' +
1175
+ '</object>';
1176
+
1177
+ } else {
1178
+
1179
+ container.innerHTML =
1180
+ '<embed id="' + pluginid + '" name="' + pluginid + '" ' +
1181
+ 'play="true" ' +
1182
+ 'loop="false" ' +
1183
+ 'quality="high" ' +
1184
+ 'bgcolor="#000000" ' +
1185
+ 'wmode="transparent" ' +
1186
+ 'allowScriptAccess="always" ' +
1187
+ 'allowFullScreen="true" ' +
1188
+ 'type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" ' +
1189
+ 'src="' + options.pluginPath + options.flashName + '" ' +
1190
+ 'flashvars="' + initVars.join('&') + '" ' +
1191
+ 'width="' + width + '" ' +
1192
+ 'height="' + height + '"></embed>';
1193
+ }
1194
+ break;
1195
+
1196
+ case 'youtube':
1197
+
1198
+
1199
+ var
1200
+ videoId = playback.url.substr(playback.url.lastIndexOf('=')+1);
1201
+ youtubeSettings = {
1202
+ container: container,
1203
+ containerId: container.id,
1204
+ pluginMediaElement: pluginMediaElement,
1205
+ pluginId: pluginid,
1206
+ videoId: videoId,
1207
+ height: height,
1208
+ width: width
1209
+ };
1210
+
1211
+ if (mejs.PluginDetector.hasPluginVersion('flash', [10,0,0]) ) {
1212
+ mejs.YouTubeApi.createFlash(youtubeSettings);
1213
+ } else {
1214
+ mejs.YouTubeApi.enqueueIframe(youtubeSettings);
1215
+ }
1216
+
1217
+ break;
1218
+
1219
+ // DEMO Code. Does NOT work.
1220
+ case 'vimeo':
1221
+ console.log('vimeoid');
1222
+
1223
+ pluginMediaElement.vimeoid = playback.url.substr(playback.url.lastIndexOf('/')+1);
1224
+
1225
+ container.innerHTML =
1226
+ '<object width="' + width + '" height="' + height + '">' +
1227
+ '<param name="allowfullscreen" value="true" />' +
1228
+ '<param name="allowscriptaccess" value="always" />' +
1229
+ '<param name="flashvars" value="api=1" />' +
1230
+ '<param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" />' +
1231
+ '<embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id=' + pluginMediaElement.vimeoid + '&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="' + width + '" height="' + height + '"></embed>' +
1232
+ '</object>';
1233
+
1234
+ break;
1235
+ }
1236
+ // hide original element
1237
+ htmlMediaElement.style.display = 'none';
1238
+
1239
+ // FYI: options.success will be fired by the MediaPluginBridge
1240
+
1241
+ return pluginMediaElement;
1242
+ },
1243
+
1244
+ updateNative: function(playback, options, autoplay, preload) {
1245
+
1246
+ var htmlMediaElement = playback.htmlMediaElement,
1247
+ m;
1248
+
1249
+
1250
+ // add methods to video object to bring it into parity with Flash Object
1251
+ for (m in mejs.HtmlMediaElement) {
1252
+ htmlMediaElement[m] = mejs.HtmlMediaElement[m];
1253
+ }
1254
+
1255
+ /*
1256
+ Chrome now supports preload="none"
1257
+ if (mejs.MediaFeatures.isChrome) {
1258
+
1259
+ // special case to enforce preload attribute (Chrome doesn't respect this)
1260
+ if (preload === 'none' && !autoplay) {
1261
+
1262
+ // forces the browser to stop loading (note: fails in IE9)
1263
+ htmlMediaElement.src = '';
1264
+ htmlMediaElement.load();
1265
+ htmlMediaElement.canceledPreload = true;
1266
+
1267
+ htmlMediaElement.addEventListener('play',function() {
1268
+ if (htmlMediaElement.canceledPreload) {
1269
+ htmlMediaElement.src = playback.url;
1270
+ htmlMediaElement.load();
1271
+ htmlMediaElement.play();
1272
+ htmlMediaElement.canceledPreload = false;
1273
+ }
1274
+ }, false);
1275
+ // for some reason Chrome forgets how to autoplay sometimes.
1276
+ } else if (autoplay) {
1277
+ htmlMediaElement.load();
1278
+ htmlMediaElement.play();
1279
+ }
1280
+ }
1281
+ */
1282
+
1283
+ // fire success code
1284
+ options.success(htmlMediaElement, htmlMediaElement);
1285
+
1286
+ return htmlMediaElement;
1287
+ }
1288
+ };
1289
+
1290
+ /*
1291
+ - test on IE (object vs. embed)
1292
+ - determine when to use iframe (Firefox, Safari, Mobile) vs. Flash (Chrome, IE)
1293
+ - fullscreen?
1294
+ */
1295
+
1296
+ // YouTube Flash and Iframe API
1297
+ mejs.YouTubeApi = {
1298
+ isIframeStarted: false,
1299
+ isIframeLoaded: false,
1300
+ loadIframeApi: function() {
1301
+ if (!this.isIframeStarted) {
1302
+ var tag = document.createElement('script');
1303
+ tag.src = "http://www.youtube.com/player_api";
1304
+ var firstScriptTag = document.getElementsByTagName('script')[0];
1305
+ firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1306
+ this.isIframeStarted = true;
1307
+ }
1308
+ },
1309
+ iframeQueue: [],
1310
+ enqueueIframe: function(yt) {
1311
+
1312
+ if (this.isLoaded) {
1313
+ this.createIframe(yt);
1314
+ } else {
1315
+ this.loadIframeApi();
1316
+ this.iframeQueue.push(yt);
1317
+ }
1318
+ },
1319
+ createIframe: function(settings) {
1320
+
1321
+ var
1322
+ pluginMediaElement = settings.pluginMediaElement,
1323
+ player = new YT.Player(settings.containerId, {
1324
+ height: settings.height,
1325
+ width: settings.width,
1326
+ videoId: settings.videoId,
1327
+ playerVars: {controls:0},
1328
+ events: {
1329
+ 'onReady': function() {
1330
+
1331
+ // hook up iframe object to MEjs
1332
+ settings.pluginMediaElement.pluginApi = player;
1333
+
1334
+ // init mejs
1335
+ mejs.MediaPluginBridge.initPlugin(settings.pluginId);
1336
+
1337
+ // create timer
1338
+ setInterval(function() {
1339
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
1340
+ }, 250);
1341
+ },
1342
+ 'onStateChange': function(e) {
1343
+
1344
+ mejs.YouTubeApi.handleStateChange(e.data, player, pluginMediaElement);
1345
+
1346
+ }
1347
+ }
1348
+ });
1349
+ },
1350
+
1351
+ createEvent: function (player, pluginMediaElement, eventName) {
1352
+ var obj = {
1353
+ type: eventName,
1354
+ target: pluginMediaElement
1355
+ };
1356
+
1357
+ if (player && player.getDuration) {
1358
+
1359
+ // time
1360
+ pluginMediaElement.currentTime = obj.currentTime = player.getCurrentTime();
1361
+ pluginMediaElement.duration = obj.duration = player.getDuration();
1362
+
1363
+ // state
1364
+ obj.paused = pluginMediaElement.paused;
1365
+ obj.ended = pluginMediaElement.ended;
1366
+
1367
+ // sound
1368
+ obj.muted = player.isMuted();
1369
+ obj.volume = player.getVolume() / 100;
1370
+
1371
+ // progress
1372
+ obj.bytesTotal = player.getVideoBytesTotal();
1373
+ obj.bufferedBytes = player.getVideoBytesLoaded();
1374
+
1375
+ // fake the W3C buffered TimeRange
1376
+ var bufferedTime = obj.bufferedBytes / obj.bytesTotal * obj.duration;
1377
+
1378
+ obj.target.buffered = obj.buffered = {
1379
+ start: function(index) {
1380
+ return 0;
1381
+ },
1382
+ end: function (index) {
1383
+ return bufferedTime;
1384
+ },
1385
+ length: 1
1386
+ };
1387
+
1388
+ }
1389
+
1390
+ // send event up the chain
1391
+ pluginMediaElement.dispatchEvent(obj.type, obj);
1392
+ },
1393
+
1394
+ iFrameReady: function() {
1395
+
1396
+ this.isLoaded = true;
1397
+ this.isIframeLoaded = true;
1398
+
1399
+ while (this.iframeQueue.length > 0) {
1400
+ var settings = this.iframeQueue.pop();
1401
+ this.createIframe(settings);
1402
+ }
1403
+ },
1404
+
1405
+ // FLASH!
1406
+ flashPlayers: {},
1407
+ createFlash: function(settings) {
1408
+
1409
+ this.flashPlayers[settings.pluginId] = settings;
1410
+
1411
+ /*
1412
+ settings.container.innerHTML =
1413
+ '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="//www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0" ' +
1414
+ 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
1415
+ '<param name="allowScriptAccess" value="always">' +
1416
+ '<param name="wmode" value="transparent">' +
1417
+ '</object>';
1418
+ */
1419
+
1420
+ var specialIEContainer,
1421
+ youtubeUrl = 'http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid=' + settings.pluginId + '&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0';
1422
+
1423
+ if (mejs.MediaFeatures.isIE) {
1424
+
1425
+ specialIEContainer = document.createElement('div');
1426
+ settings.container.appendChild(specialIEContainer);
1427
+ specialIEContainer.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" ' +
1428
+ 'id="' + settings.pluginId + '" width="' + settings.width + '" height="' + settings.height + '">' +
1429
+ '<param name="movie" value="' + youtubeUrl + '" />' +
1430
+ '<param name="wmode" value="transparent" />' +
1431
+ '<param name="allowScriptAccess" value="always" />' +
1432
+ '<param name="allowFullScreen" value="true" />' +
1433
+ '</object>';
1434
+ } else {
1435
+ settings.container.innerHTML =
1436
+ '<object type="application/x-shockwave-flash" id="' + settings.pluginId + '" data="' + youtubeUrl + '" ' +
1437
+ 'width="' + settings.width + '" height="' + settings.height + '" style="visibility: visible; ">' +
1438
+ '<param name="allowScriptAccess" value="always">' +
1439
+ '<param name="wmode" value="transparent">' +
1440
+ '</object>';
1441
+ }
1442
+
1443
+ },
1444
+
1445
+ flashReady: function(id) {
1446
+ var
1447
+ settings = this.flashPlayers[id],
1448
+ player = document.getElementById(id),
1449
+ pluginMediaElement = settings.pluginMediaElement;
1450
+
1451
+ // hook up and return to MediaELementPlayer.success
1452
+ pluginMediaElement.pluginApi =
1453
+ pluginMediaElement.pluginElement = player;
1454
+ mejs.MediaPluginBridge.initPlugin(id);
1455
+
1456
+ // load the youtube video
1457
+ player.cueVideoById(settings.videoId);
1458
+
1459
+ var callbackName = settings.containerId + '_callback'
1460
+
1461
+ window[callbackName] = function(e) {
1462
+ mejs.YouTubeApi.handleStateChange(e, player, pluginMediaElement);
1463
+ }
1464
+
1465
+ player.addEventListener('onStateChange', callbackName);
1466
+
1467
+ setInterval(function() {
1468
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'timeupdate');
1469
+ }, 250);
1470
+ },
1471
+
1472
+ handleStateChange: function(youTubeState, player, pluginMediaElement) {
1473
+ switch (youTubeState) {
1474
+ case -1: // not started
1475
+ pluginMediaElement.paused = true;
1476
+ pluginMediaElement.ended = true;
1477
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'loadedmetadata');
1478
+ //createYouTubeEvent(player, pluginMediaElement, 'loadeddata');
1479
+ break;
1480
+ case 0:
1481
+ pluginMediaElement.paused = false;
1482
+ pluginMediaElement.ended = true;
1483
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'ended');
1484
+ break;
1485
+ case 1:
1486
+ pluginMediaElement.paused = false;
1487
+ pluginMediaElement.ended = false;
1488
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'play');
1489
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'playing');
1490
+ break;
1491
+ case 2:
1492
+ pluginMediaElement.paused = true;
1493
+ pluginMediaElement.ended = false;
1494
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'pause');
1495
+ break;
1496
+ case 3: // buffering
1497
+ mejs.YouTubeApi.createEvent(player, pluginMediaElement, 'progress');
1498
+ break;
1499
+ case 5:
1500
+ // cued?
1501
+ break;
1502
+
1503
+ }
1504
+
1505
+ }
1506
+ }
1507
+ // IFRAME
1508
+ function onYouTubePlayerAPIReady() {
1509
+ mejs.YouTubeApi.iFrameReady();
1510
+ }
1511
+ // FLASH
1512
+ function onYouTubePlayerReady(id) {
1513
+ mejs.YouTubeApi.flashReady(id);
1514
+ }
1515
+
1516
+ window.mejs = mejs;
1517
+ window.MediaElement = mejs.MediaElement;
includes/media-element/mediaelement.min.js ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * MediaElement.js
3
+ * HTML5 <video> and <audio> shim and player
4
+ * http://mediaelementjs.com/
5
+ *
6
+ * Creates a JavaScript object that mimics HTML5 MediaElement API
7
+ * for browsers that don't understand HTML5 or can't play the provided codec
8
+ * Can play MP4 (H.264), Ogg, WebM, FLV, WMV, WMA, ACC, and MP3
9
+ *
10
+ * Copyright 2010-2012, John Dyer (http://j.hn)
11
+ * Dual licensed under the MIT or GPL Version 2 licenses.
12
+ *
13
+ */var mejs=mejs||{};mejs.version="2.9.1";mejs.meIndex=0;mejs.plugins={silverlight:[{version:[3,0],types:["video/mp4","video/m4v","video/mov","video/wmv","audio/wma","audio/m4a","audio/mp3","audio/wav","audio/mpeg"]}],flash:[{version:[9,0,124],types:["video/mp4","video/m4v","video/mov","video/flv","video/x-flv","audio/flv","audio/x-flv","audio/mp3","audio/m4a","audio/mpeg","video/youtube","video/x-youtube"]}],youtube:[{version:null,types:["video/youtube","video/x-youtube"]}],vimeo:[{version:null,types:["video/vimeo"]}]};
14
+ mejs.Utility={encodeUrl:function(a){return encodeURIComponent(a)},escapeHTML:function(a){return a.toString().split("&").join("&amp;").split("<").join("&lt;").split('"').join("&quot;")},absolutizeUrl:function(a){var b=document.createElement("div");b.innerHTML='<a href="'+this.escapeHTML(a)+'">x</a>';return b.firstChild.href},getScriptPath:function(a){for(var b=0,c,d="",e="",g,f=document.getElementsByTagName("script"),j=f.length,h=a.length;b<j;b++){g=f[b].src;for(c=0;c<h;c++){e=a[c];if(g.indexOf(e)>
15
+ -1){d=g.substring(0,g.indexOf(e));break}}if(d!=="")break}return d},secondsToTimeCode:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;var e=Math.floor(a/3600)%24,g=Math.floor(a/60)%60,f=Math.floor(a%60);a=Math.floor((a%1*d).toFixed(3));return(b||e>0?(e<10?"0"+e:e)+":":"")+(g<10?"0"+g:g)+":"+(f<10?"0"+f:f)+(c?":"+(a<10?"0"+a:a):"")},timeCodeToSeconds:function(a,b,c,d){if(typeof c=="undefined")c=false;else if(typeof d=="undefined")d=25;a=a.split(":");b=parseInt(a[0],
16
+ 10);var e=parseInt(a[1],10),g=parseInt(a[2],10),f=0,j=0;if(c)f=parseInt(a[3])/d;return j=b*3600+e*60+g+f},removeSwf:function(a){var b=document.getElementById(a);if(b&&b.nodeName=="OBJECT")if(mejs.MediaFeatures.isIE){b.style.display="none";(function(){b.readyState==4?mejs.Utility.removeObjectInIE(a):setTimeout(arguments.callee,10)})()}else b.parentNode.removeChild(b)},removeObjectInIE:function(a){if(a=document.getElementById(a)){for(var b in a)if(typeof a[b]=="function")a[b]=null;a.parentNode.removeChild(a)}}};
17
+ mejs.PluginDetector={hasPluginVersion:function(a,b){var c=this.plugins[a];b[1]=b[1]||0;b[2]=b[2]||0;return c[0]>b[0]||c[0]==b[0]&&c[1]>b[1]||c[0]==b[0]&&c[1]==b[1]&&c[2]>=b[2]?true:false},nav:window.navigator,ua:window.navigator.userAgent.toLowerCase(),plugins:[],addPlugin:function(a,b,c,d,e){this.plugins[a]=this.detectPlugin(b,c,d,e)},detectPlugin:function(a,b,c,d){var e=[0,0,0],g;if(typeof this.nav.plugins!="undefined"&&typeof this.nav.plugins[a]=="object"){if((c=this.nav.plugins[a].description)&&
18
+ !(typeof this.nav.mimeTypes!="undefined"&&this.nav.mimeTypes[b]&&!this.nav.mimeTypes[b].enabledPlugin)){e=c.replace(a,"").replace(/^\s+/,"").replace(/\sr/gi,".").split(".");for(a=0;a<e.length;a++)e[a]=parseInt(e[a].match(/\d+/),10)}}else if(typeof window.ActiveXObject!="undefined")try{if(g=new ActiveXObject(c))e=d(g)}catch(f){}return e}};
19
+ mejs.PluginDetector.addPlugin("flash","Shockwave Flash","application/x-shockwave-flash","ShockwaveFlash.ShockwaveFlash",function(a){var b=[];if(a=a.GetVariable("$version")){a=a.split(" ")[1].split(",");b=[parseInt(a[0],10),parseInt(a[1],10),parseInt(a[2],10)]}return b});
20
+ mejs.PluginDetector.addPlugin("silverlight","Silverlight Plug-In","application/x-silverlight-2","AgControl.AgControl",function(a){var b=[0,0,0,0],c=function(d,e,g,f){for(;d.isVersionSupported(e[0]+"."+e[1]+"."+e[2]+"."+e[3]);)e[g]+=f;e[g]-=f};c(a,b,0,1);c(a,b,1,1);c(a,b,2,1E4);c(a,b,2,1E3);c(a,b,2,100);c(a,b,2,10);c(a,b,2,1);c(a,b,3,1);return b});
21
+ mejs.MediaFeatures={init:function(){var a=this,b=document,c=mejs.PluginDetector.nav,d=mejs.PluginDetector.ua.toLowerCase(),e,g=["source","track","audio","video"];a.isiPad=d.match(/ipad/i)!==null;a.isiPhone=d.match(/iphone/i)!==null;a.isiOS=a.isiPhone||a.isiPad;a.isAndroid=d.match(/android/i)!==null;a.isBustedAndroid=d.match(/android 2\.[12]/)!==null;a.isIE=c.appName.toLowerCase().indexOf("microsoft")!=-1;a.isChrome=d.match(/chrome/gi)!==null;a.isFirefox=d.match(/firefox/gi)!==null;a.isWebkit=d.match(/webkit/gi)!==
22
+ null;a.isGecko=d.match(/gecko/gi)!==null&&!a.isWebkit;a.isOpera=d.match(/opera/gi)!==null;a.hasTouch="ontouchstart"in window;for(c=0;c<g.length;c++)e=document.createElement(g[c]);a.supportsMediaTag=typeof e.canPlayType!=="undefined"||a.isBustedAndroid;a.hasSemiNativeFullScreen=typeof e.webkitEnterFullscreen!=="undefined";a.hasWebkitNativeFullScreen=typeof e.webkitRequestFullScreen!=="undefined";a.hasMozNativeFullScreen=typeof e.mozRequestFullScreen!=="undefined";a.hasTrueNativeFullScreen=a.hasWebkitNativeFullScreen||
23
+ a.hasMozNativeFullScreen;a.nativeFullScreenEnabled=a.hasTrueNativeFullScreen;if(a.hasMozNativeFullScreen)a.nativeFullScreenEnabled=e.mozFullScreenEnabled;if(this.isChrome)a.hasSemiNativeFullScreen=false;if(a.hasTrueNativeFullScreen){a.fullScreenEventName=a.hasWebkitNativeFullScreen?"webkitfullscreenchange":"mozfullscreenchange";a.isFullScreen=function(){if(e.mozRequestFullScreen)return b.mozFullScreen;else if(e.webkitRequestFullScreen)return b.webkitIsFullScreen};a.requestFullScreen=function(f){if(a.hasWebkitNativeFullScreen)f.webkitRequestFullScreen();
24
+ else a.hasMozNativeFullScreen&&f.mozRequestFullScreen()};a.cancelFullScreen=function(){if(a.hasWebkitNativeFullScreen)document.webkitCancelFullScreen();else a.hasMozNativeFullScreen&&document.mozCancelFullScreen()}}if(a.hasSemiNativeFullScreen&&d.match(/mac os x 10_5/i)){a.hasNativeFullScreen=false;a.hasSemiNativeFullScreen=false}}};mejs.MediaFeatures.init();
25
+ mejs.HtmlMediaElement={pluginType:"native",isFullScreen:false,setCurrentTime:function(a){this.currentTime=a},setMuted:function(a){this.muted=a},setVolume:function(a){this.volume=a},stop:function(){this.pause()},setSrc:function(a){for(var b=this.getElementsByTagName("source");b.length>0;)this.removeChild(b[0]);if(typeof a=="string")this.src=a;else{var c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type))this.src=c.src}}},setVideoSize:function(a,b){this.width=a;this.height=b}};
26
+ mejs.PluginMediaElement=function(a,b,c){this.id=a;this.pluginType=b;this.src=c;this.events={}};
27
+ mejs.PluginMediaElement.prototype={pluginElement:null,pluginType:"",isFullScreen:false,playbackRate:-1,defaultPlaybackRate:-1,seekable:[],played:[],paused:true,ended:false,seeking:false,duration:0,error:null,tagName:"",muted:false,volume:1,currentTime:0,play:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.playVideo():this.pluginApi.playMedia();this.paused=false}},load:function(){if(this.pluginApi!=null){this.pluginType!="youtube"&&this.pluginApi.loadMedia();this.paused=
28
+ false}},pause:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.pauseVideo():this.pluginApi.pauseMedia();this.paused=true}},stop:function(){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.stopVideo():this.pluginApi.stopMedia();this.paused=true}},canPlayType:function(a){var b,c,d,e=mejs.plugins[this.pluginType];for(b=0;b<e.length;b++){d=e[b];if(mejs.PluginDetector.hasPluginVersion(this.pluginType,d.version))for(c=0;c<d.types.length;c++)if(a==d.types[c])return true}return false},
29
+ positionFullscreenButton:function(a,b,c){this.pluginApi!=null&&this.pluginApi.positionFullscreenButton&&this.pluginApi.positionFullscreenButton(a,b,c)},hideFullscreenButton:function(){this.pluginApi!=null&&this.pluginApi.hideFullscreenButton&&this.pluginApi.hideFullscreenButton()},setSrc:function(a){if(typeof a=="string"){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(a));this.src=mejs.Utility.absolutizeUrl(a)}else{var b,c;for(b=0;b<a.length;b++){c=a[b];if(this.canPlayType(c.type)){this.pluginApi.setSrc(mejs.Utility.absolutizeUrl(c.src));
30
+ this.src=mejs.Utility.absolutizeUrl(a)}}}},setCurrentTime:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.seekTo(a):this.pluginApi.setCurrentTime(a);this.currentTime=a}},setVolume:function(a){if(this.pluginApi!=null){this.pluginType=="youtube"?this.pluginApi.setVolume(a*100):this.pluginApi.setVolume(a);this.volume=a}},setMuted:function(a){if(this.pluginApi!=null){if(this.pluginType=="youtube"){a?this.pluginApi.mute():this.pluginApi.unMute();this.muted=a;this.dispatchEvent("volumechange")}else this.pluginApi.setMuted(a);
31
+ this.muted=a}},setVideoSize:function(a,b){if(this.pluginElement.style){this.pluginElement.style.width=a+"px";this.pluginElement.style.height=b+"px"}this.pluginApi!=null&&this.pluginApi.setVideoSize&&this.pluginApi.setVideoSize(a,b)},setFullscreen:function(a){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.pluginApi.setFullscreen(a)},enterFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&this.setFullscreen(true)},exitFullScreen:function(){this.pluginApi!=null&&this.pluginApi.setFullscreen&&
32
+ this.setFullscreen(false)},addEventListener:function(a,b){this.events[a]=this.events[a]||[];this.events[a].push(b)},removeEventListener:function(a,b){if(!a){this.events={};return true}var c=this.events[a];if(!c)return true;if(!b){this.events[a]=[];return true}for(i=0;i<c.length;i++)if(c[i]===b){this.events[a].splice(i,1);return true}return false},dispatchEvent:function(a){var b,c,d=this.events[a];if(d){c=Array.prototype.slice.call(arguments,1);for(b=0;b<d.length;b++)d[b].apply(null,c)}},attributes:{},
33
+ hasAttribute:function(a){return a in this.attributes},removeAttribute:function(a){delete this.attributes[a]},getAttribute:function(a){if(this.hasAttribute(a))return this.attributes[a];return""},setAttribute:function(a,b){this.attributes[a]=b},remove:function(){mejs.Utility.removeSwf(this.pluginElement.id)}};
34
+ mejs.MediaPluginBridge={pluginMediaElements:{},htmlMediaElements:{},registerPluginElement:function(a,b,c){this.pluginMediaElements[a]=b;this.htmlMediaElements[a]=c},initPlugin:function(a){var b=this.pluginMediaElements[a],c=this.htmlMediaElements[a];if(b){switch(b.pluginType){case "flash":b.pluginElement=b.pluginApi=document.getElementById(a);break;case "silverlight":b.pluginElement=document.getElementById(b.id);b.pluginApi=b.pluginElement.Content.MediaElementJS}b.pluginApi!=null&&b.success&&b.success(b,
35
+ c)}},fireEvent:function(a,b,c){var d,e;a=this.pluginMediaElements[a];a.ended=false;a.paused=true;b={type:b,target:a};for(d in c){a[d]=c[d];b[d]=c[d]}e=c.bufferedTime||0;b.target.buffered=b.buffered={start:function(){return 0},end:function(){return e},length:1};a.dispatchEvent(b.type,b)}};
36
+ mejs.MediaElementDefaults={mode:"auto",plugins:["flash","silverlight","youtube","vimeo"],enablePluginDebug:false,type:"",pluginPath:mejs.Utility.getScriptPath(["mediaelement.js","mediaelement.min.js","mediaelement-and-player.js","mediaelement-and-player.min.js"]),flashName:"flashmediaelement.swf",enablePluginSmoothing:false,silverlightName:"silverlightmediaelement.xap",defaultVideoWidth:480,defaultVideoHeight:270,pluginWidth:-1,pluginHeight:-1,pluginVars:[],timerRate:250,startVolume:0.8,success:function(){},
37
+ error:function(){}};mejs.MediaElement=function(a,b){return mejs.HtmlMediaElementShim.create(a,b)};
38
+ mejs.HtmlMediaElementShim={create:function(a,b){var c=mejs.MediaElementDefaults,d=typeof a=="string"?document.getElementById(a):a,e=d.tagName.toLowerCase(),g=e==="audio"||e==="video",f=g?d.getAttribute("src"):d.getAttribute("href");e=d.getAttribute("poster");var j=d.getAttribute("autoplay"),h=d.getAttribute("preload"),l=d.getAttribute("controls"),k;for(k in b)c[k]=b[k];f=typeof f=="undefined"||f===null||f==""?null:f;e=typeof e=="undefined"||e===null?"":e;h=typeof h=="undefined"||h===null||h==="false"?
39
+ "none":h;j=!(typeof j=="undefined"||j===null||j==="false");l=!(typeof l=="undefined"||l===null||l==="false");k=this.determinePlayback(d,c,mejs.MediaFeatures.supportsMediaTag,g,f);k.url=k.url!==null?mejs.Utility.absolutizeUrl(k.url):"";if(k.method=="native"){if(mejs.MediaFeatures.isBustedAndroid){d.src=k.url;d.addEventListener("click",function(){d.play()},false)}return this.updateNative(k,c,j,h)}else if(k.method!=="")return this.createPlugin(k,c,e,j,h,l);else{this.createErrorMessage(k,c,e);return this}},
40
+ determinePlayback:function(a,b,c,d,e){var g=[],f,j,h={method:"",url:"",htmlMediaElement:a,isVideo:a.tagName.toLowerCase()!="audio"},l,k;if(typeof b.type!="undefined"&&b.type!=="")if(typeof b.type=="string")g.push({type:b.type,url:e});else for(f=0;f<b.type.length;f++)g.push({type:b.type[f],url:e});else if(e!==null){j=this.formatType(e,a.getAttribute("type"));g.push({type:j,url:e})}else for(f=0;f<a.childNodes.length;f++){j=a.childNodes[f];if(j.nodeType==1&&j.tagName.toLowerCase()=="source"){e=j.getAttribute("src");
41
+ j=this.formatType(e,j.getAttribute("type"));g.push({type:j,url:e})}}if(!d&&g.length>0&&g[0].url!==null&&this.getTypeFromFile(g[0].url).indexOf("audio")>-1)h.isVideo=false;if(mejs.MediaFeatures.isBustedAndroid)a.canPlayType=function(m){return m.match(/video\/(mp4|m4v)/gi)!==null?"maybe":""};if(c&&(b.mode==="auto"||b.mode==="native")){if(!d){f=document.createElement(h.isVideo?"video":"audio");a.parentNode.insertBefore(f,a);a.style.display="none";h.htmlMediaElement=a=f}for(f=0;f<g.length;f++)if(a.canPlayType(g[f].type).replace(/no/,
42
+ "")!==""||a.canPlayType(g[f].type.replace(/mp3/,"mpeg")).replace(/no/,"")!==""){h.method="native";h.url=g[f].url;break}if(h.method==="native"){if(h.url!==null)a.src=h.url;return h}}if(b.mode==="auto"||b.mode==="shim")for(f=0;f<g.length;f++){j=g[f].type;for(a=0;a<b.plugins.length;a++){e=b.plugins[a];l=mejs.plugins[e];for(c=0;c<l.length;c++){k=l[c];if(k.version==null||mejs.PluginDetector.hasPluginVersion(e,k.version))for(d=0;d<k.types.length;d++)if(j==k.types[d]){h.method=e;h.url=g[f].url;return h}}}}if(h.method===
43
+ ""&&g.length>0)h.url=g[0].url;return h},formatType:function(a,b){return a&&!b?this.getTypeFromFile(a):b&&~b.indexOf(";")?b.substr(0,b.indexOf(";")):b},getTypeFromFile:function(a){a=a.substring(a.lastIndexOf(".")+1);return(/(mp4|m4v|ogg|ogv|webm|flv|wmv|mpeg|mov)/gi.test(a)?"video":"audio")+"/"+a},createErrorMessage:function(a,b,c){var d=a.htmlMediaElement,e=document.createElement("div");e.className="me-cannotplay";try{e.style.width=d.width+"px";e.style.height=d.height+"px"}catch(g){}e.innerHTML=c!==
44
+ ""?'<a href="'+a.url+'"><img src="'+c+'" width="100%" height="100%" /></a>':'<a href="'+a.url+'"><span>Download File</span></a>';d.parentNode.insertBefore(e,d);d.style.display="none";b.error(d)},createPlugin:function(a,b,c,d,e,g){c=a.htmlMediaElement;var f=1,j=1,h="me_"+a.method+"_"+mejs.meIndex++,l=new mejs.PluginMediaElement(h,a.method,a.url),k=document.createElement("div"),m;l.tagName=c.tagName;for(m=0;m<c.attributes.length;m++){var n=c.attributes[m];n.specified==true&&l.setAttribute(n.name,n.value)}for(m=
45
+ c.parentNode;m!==null&&m.tagName.toLowerCase()!="body";){if(m.parentNode.tagName.toLowerCase()=="p"){m.parentNode.parentNode.insertBefore(m,m.parentNode);break}m=m.parentNode}if(a.isVideo){f=b.videoWidth>0?b.videoWidth:c.getAttribute("width")!==null?c.getAttribute("width"):b.defaultVideoWidth;j=b.videoHeight>0?b.videoHeight:c.getAttribute("height")!==null?c.getAttribute("height"):b.defaultVideoHeight;f=mejs.Utility.encodeUrl(f);j=mejs.Utility.encodeUrl(j)}else if(b.enablePluginDebug){f=320;j=240}l.success=
46
+ b.success;mejs.MediaPluginBridge.registerPluginElement(h,l,c);k.className="me-plugin";k.id=h+"_container";a.isVideo?c.parentNode.insertBefore(k,c):document.body.insertBefore(k,document.body.childNodes[0]);d=["id="+h,"isvideo="+(a.isVideo?"true":"false"),"autoplay="+(d?"true":"false"),"preload="+e,"width="+f,"startvolume="+b.startVolume,"timerrate="+b.timerRate,"height="+j];if(a.url!==null)a.method=="flash"?d.push("file="+mejs.Utility.encodeUrl(a.url)):d.push("file="+a.url);b.enablePluginDebug&&d.push("debug=true");
47
+ b.enablePluginSmoothing&&d.push("smoothing=true");g&&d.push("controls=true");if(b.pluginVars)d=d.concat(b.pluginVars);switch(a.method){case "silverlight":k.innerHTML='<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" id="'+h+'" name="'+h+'" width="'+f+'" height="'+j+'"><param name="initParams" value="'+d.join(",")+'" /><param name="windowless" value="true" /><param name="background" value="black" /><param name="minRuntimeVersion" value="3.0.0.0" /><param name="autoUpgrade" value="true" /><param name="source" value="'+
48
+ b.pluginPath+b.silverlightName+'" /></object>';break;case "flash":if(mejs.MediaFeatures.isIE){a=document.createElement("div");k.appendChild(a);a.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+h+'" width="'+f+'" height="'+j+'"><param name="movie" value="'+b.pluginPath+b.flashName+"?x="+new Date+'" /><param name="flashvars" value="'+d.join("&amp;")+'" /><param name="quality" value="high" /><param name="bgcolor" value="#000000" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else k.innerHTML=
49
+ '<embed id="'+h+'" name="'+h+'" play="true" loop="false" quality="high" bgcolor="#000000" wmode="transparent" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="//www.macromedia.com/go/getflashplayer" src="'+b.pluginPath+b.flashName+'" flashvars="'+d.join("&")+'" width="'+f+'" height="'+j+'"></embed>';break;case "youtube":b=a.url.substr(a.url.lastIndexOf("=")+1);youtubeSettings={container:k,containerId:k.id,pluginMediaElement:l,pluginId:h,videoId:b,
50
+ height:j,width:f};mejs.PluginDetector.hasPluginVersion("flash",[10,0,0])?mejs.YouTubeApi.createFlash(youtubeSettings):mejs.YouTubeApi.enqueueIframe(youtubeSettings);break;case "vimeo":console.log("vimeoid");l.vimeoid=a.url.substr(a.url.lastIndexOf("/")+1);k.innerHTML='<object width="'+f+'" height="'+j+'"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="flashvars" value="api=1" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id='+
51
+ l.vimeoid+'&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" /><embed src="//vimeo.com/moogaloop.swf?api=1&amp;clip_id='+l.vimeoid+'&amp;server=vimeo.com&amp;show_title=0&amp;show_byline=0&amp;show_portrait=0&amp;color=00adef&amp;fullscreen=1&amp;autoplay=0&amp;loop=0" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="'+f+'" height="'+j+'"></embed></object>'}c.style.display=
52
+ "none";return l},updateNative:function(a,b){var c=a.htmlMediaElement,d;for(d in mejs.HtmlMediaElement)c[d]=mejs.HtmlMediaElement[d];b.success(c,c);return c}};
53
+ mejs.YouTubeApi={isIframeStarted:false,isIframeLoaded:false,loadIframeApi:function(){if(!this.isIframeStarted){var a=document.createElement("script");a.src="http://www.youtube.com/player_api";var b=document.getElementsByTagName("script")[0];b.parentNode.insertBefore(a,b);this.isIframeStarted=true}},iframeQueue:[],enqueueIframe:function(a){if(this.isLoaded)this.createIframe(a);else{this.loadIframeApi();this.iframeQueue.push(a)}},createIframe:function(a){var b=a.pluginMediaElement,c=new YT.Player(a.containerId,
54
+ {height:a.height,width:a.width,videoId:a.videoId,playerVars:{controls:0},events:{onReady:function(){a.pluginMediaElement.pluginApi=c;mejs.MediaPluginBridge.initPlugin(a.pluginId);setInterval(function(){mejs.YouTubeApi.createEvent(c,b,"timeupdate")},250)},onStateChange:function(d){mejs.YouTubeApi.handleStateChange(d.data,c,b)}}})},createEvent:function(a,b,c){c={type:c,target:b};if(a&&a.getDuration){b.currentTime=c.currentTime=a.getCurrentTime();b.duration=c.duration=a.getDuration();c.paused=b.paused;
55
+ c.ended=b.ended;c.muted=a.isMuted();c.volume=a.getVolume()/100;c.bytesTotal=a.getVideoBytesTotal();c.bufferedBytes=a.getVideoBytesLoaded();var d=c.bufferedBytes/c.bytesTotal*c.duration;c.target.buffered=c.buffered={start:function(){return 0},end:function(){return d},length:1}}b.dispatchEvent(c.type,c)},iFrameReady:function(){for(this.isIframeLoaded=this.isLoaded=true;this.iframeQueue.length>0;)this.createIframe(this.iframeQueue.pop())},flashPlayers:{},createFlash:function(a){this.flashPlayers[a.pluginId]=
56
+ a;var b,c="http://www.youtube.com/apiplayer?enablejsapi=1&amp;playerapiid="+a.pluginId+"&amp;version=3&amp;autoplay=0&amp;controls=0&amp;modestbranding=1&loop=0";if(mejs.MediaFeatures.isIE){b=document.createElement("div");a.container.appendChild(b);b.outerHTML='<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="//download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab" id="'+a.pluginId+'" width="'+a.width+'" height="'+a.height+'"><param name="movie" value="'+c+'" /><param name="wmode" value="transparent" /><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="true" /></object>'}else a.container.innerHTML=
57
+ '<object type="application/x-shockwave-flash" id="'+a.pluginId+'" data="'+c+'" width="'+a.width+'" height="'+a.height+'" style="visibility: visible; "><param name="allowScriptAccess" value="always"><param name="wmode" value="transparent"></object>'},flashReady:function(a){var b=this.flashPlayers[a],c=document.getElementById(a),d=b.pluginMediaElement;d.pluginApi=d.pluginElement=c;mejs.MediaPluginBridge.initPlugin(a);c.cueVideoById(b.videoId);a=b.containerId+"_callback";window[a]=function(e){mejs.YouTubeApi.handleStateChange(e,
58
+ c,d)};c.addEventListener("onStateChange",a);setInterval(function(){mejs.YouTubeApi.createEvent(c,d,"timeupdate")},250)},handleStateChange:function(a,b,c){switch(a){case -1:c.paused=true;c.ended=true;mejs.YouTubeApi.createEvent(b,c,"loadedmetadata");break;case 0:c.paused=false;c.ended=true;mejs.YouTubeApi.createEvent(b,c,"ended");break;case 1:c.paused=false;c.ended=false;mejs.YouTubeApi.createEvent(b,c,"play");mejs.YouTubeApi.createEvent(b,c,"playing");break;case 2:c.paused=true;c.ended=false;mejs.YouTubeApi.createEvent(b,
59
+ c,"pause");break;case 3:mejs.YouTubeApi.createEvent(b,c,"progress")}}};function onYouTubePlayerAPIReady(){mejs.YouTubeApi.iFrameReady()}function onYouTubePlayerReady(a){mejs.YouTubeApi.flashReady(a)}window.mejs=mejs;window.MediaElement=mejs.MediaElement;
includes/media-element/mediaelementplayer.css ADDED
@@ -0,0 +1,801 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .mejs-container {
2
+ position: relative;
3
+ background: #000;
4
+ font-family: Helvetica, Arial;
5
+ text-align: left;
6
+ vertical-align: top;
7
+ }
8
+
9
+ .me-plugin {
10
+ position: absolute;
11
+ }
12
+
13
+ .mejs-embed, .mejs-embed body {
14
+ width: 100%;
15
+ height: 100%;
16
+ margin: 0;
17
+ padding: 0;
18
+ background: #000;
19
+ overflow: hidden;
20
+ }
21
+
22
+ .mejs-container-fullscreen {
23
+ position: fixed;
24
+ left: 0;
25
+ top: 0;
26
+ right: 0;
27
+ bottom: 0;
28
+ overflow: hidden;
29
+ z-index: 1000;
30
+ }
31
+ .mejs-container-fullscreen .mejs-mediaelement,
32
+ .mejs-container-fullscreen video {
33
+ width: 100%;
34
+ height: 100%;
35
+ }
36
+
37
+ /* Start: LAYERS */
38
+ .mejs-background {
39
+ position: absolute;
40
+ top: 0;
41
+ left: 0;
42
+ }
43
+ .mejs-mediaelement {
44
+ position: absolute;
45
+ top: 0;
46
+ left: 0;
47
+ width: 100%;
48
+ height: 100%;
49
+ }
50
+ .mejs-poster {
51
+ position: absolute;
52
+ top: 0;
53
+ left: 0;
54
+ }
55
+ .mejs-poster img {
56
+ border: 0;
57
+ padding: 0;
58
+ border: 0;
59
+ display: block;
60
+ }
61
+ .mejs-overlay {
62
+ position: absolute;
63
+ top: 0;
64
+ left: 0;
65
+ }
66
+ .mejs-overlay-play {
67
+ cursor: pointer;
68
+ }
69
+ .mejs-overlay-button {
70
+ position: absolute;
71
+ top: 50%;
72
+ left: 50%;
73
+ width: 100px;
74
+ height: 100px;
75
+ margin: -50px 0 0 -50px;
76
+ background: url(bigplay.png) no-repeat;
77
+ }
78
+ .mejs-overlay:hover .mejs-overlay-button{
79
+ background-position: 0 -100px ;
80
+ }
81
+ .mejs-overlay-loading {
82
+ position: absolute;
83
+ top: 50%;
84
+ left: 50%;
85
+ width: 80px;
86
+ height: 80px;
87
+ margin: -40px 0 0 -40px;
88
+ background: #333;
89
+ background: url(background.png);
90
+ background: rgba(0, 0, 0, 0.9);
91
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.9)), to(rgba(0,0,0,0.9)));
92
+ background: -webkit-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9));
93
+ background: -moz-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9));
94
+ background: -o-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9));
95
+ background: -ms-linear-gradient(top, rgba(50,50,50,0.9), rgba(0,0,0,0.9));
96
+ background: linear-gradient(rgba(50,50,50,0.9), rgba(0,0,0,0.9));
97
+ }
98
+ .mejs-overlay-loading span {
99
+ display:block;
100
+ width: 80px;
101
+ height: 80px;
102
+ background: transparent url(loading.gif) 50% 50% no-repeat;
103
+ }
104
+
105
+ /* End: LAYERS */
106
+
107
+ /* Start: CONTROL BAR */
108
+ .mejs-container .mejs-controls {
109
+ position: absolute;
110
+ background: none;
111
+ list-style-type: none;
112
+ margin: 0;
113
+ padding: 0;
114
+ bottom: 0;
115
+ left: 0;
116
+ background: url(background.png);
117
+ background: rgba(0, 0, 0, 0.7);
118
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.7)), to(rgba(0,0,0,0.7)));
119
+ background: -webkit-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
120
+ background: -moz-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
121
+ background: -o-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
122
+ background: -ms-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
123
+ background: linear-gradient(rgba(50,50,50,0.7), rgba(0,0,0,0.7));
124
+ height: 30px;
125
+ width: 100%;
126
+ }
127
+ .mejs-container .mejs-controls div {
128
+ list-style-type: none;
129
+ background-image: none;
130
+ display: block;
131
+ float: left;
132
+ margin: 0;
133
+ padding: 0;
134
+ width: 26px;
135
+ height: 26px;
136
+ font-size: 11px;
137
+ line-height: 11px;
138
+ background: 0;
139
+ font-family: Helvetica, Arial;
140
+ border: 0;
141
+ }
142
+
143
+ .mejs-controls .mejs-button button {
144
+ cursor: pointer;
145
+ display: block;
146
+ font-size: 0;
147
+ line-height: 0;
148
+ text-decoration: none;
149
+ margin: 7px 5px;
150
+ padding: 0;
151
+ position: absolute;
152
+ height: 16px;
153
+ width: 16px;
154
+ border: 0;
155
+ background: transparent url(controls.png) no-repeat;
156
+ }
157
+
158
+ /* :focus for accessibility */
159
+ .mejs-controls .mejs-button button:focus {
160
+ outline: solid 1px yellow;
161
+ }
162
+
163
+ /* End: CONTROL BAR */
164
+
165
+ /* Start: Time (current / duration) */
166
+ .mejs-container .mejs-controls .mejs-time {
167
+ color: #fff;
168
+ display: block;
169
+ height: 17px;
170
+ width: auto;
171
+ padding: 8px 3px 0 3px ;
172
+ overflow: hidden;
173
+ text-align: center;
174
+ padding: auto 4px;
175
+ box-sizing: content-box;
176
+ -moz-box-sizing: content-box;
177
+ -webkit-box-sizing: content-box;
178
+ }
179
+ .mejs-container .mejs-controls .mejs-time span {
180
+ font-size: 11px;
181
+ color: #fff;
182
+ line-height: 12px;
183
+ display: block;
184
+ float: left;
185
+ margin: 1px 2px 0 0;
186
+ width: auto;
187
+ }
188
+ /* End: Time (current / duration) */
189
+
190
+
191
+ /* Start: Play/pause */
192
+ .mejs-controls .mejs-play button {
193
+ background-position:0 0;
194
+ }
195
+ .mejs-controls .mejs-pause button {
196
+ background-position:0 -16px;
197
+ }
198
+ /* End: Play/pause */
199
+
200
+
201
+ /* Stop */
202
+ .mejs-controls .mejs-stop button {
203
+ background-position: -112px 0;
204
+ }
205
+ /* End: Play/pause */
206
+
207
+ /* Start: Progress bar */
208
+ .mejs-controls div.mejs-time-rail {
209
+ width: 200px;
210
+ padding-top: 5px;
211
+ }
212
+ .mejs-controls .mejs-time-rail span {
213
+ display: block;
214
+ position: absolute;
215
+ width: 180px;
216
+ height: 10px;
217
+ -webkit-border-radius: 2px;
218
+ -moz-border-radius: 2px;
219
+ border-radius: 2px;
220
+ cursor: pointer;
221
+ }
222
+ .mejs-controls .mejs-time-rail .mejs-time-total {
223
+ margin: 5px;
224
+ background: #333;
225
+ background: rgba(50,50,50,0.8);
226
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(30,30,30,0.8)), to(rgba(60,60,60,0.8)));
227
+ background: -webkit-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
228
+ background: -moz-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
229
+ background: -o-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
230
+ background: -ms-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
231
+ background: linear-gradient(rgba(30,30,30,0.8), rgba(60,60,60,0.8));
232
+ }
233
+ .mejs-controls .mejs-time-rail .mejs-time-buffering {
234
+ width:100%;
235
+ background-image: -o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
236
+ background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));
237
+ background-image: -webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
238
+ background-image: -moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
239
+ background-image: -ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
240
+ background-image: linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
241
+ -webkit-background-size: 15px 15px;
242
+ -moz-background-size: 15px 15px;
243
+ -o-background-size: 15px 15px;
244
+ background-size: 15px 15px;
245
+ -webkit-animation: buffering-stripes 2s linear infinite;
246
+ -moz-animation: buffering-stripes 2s linear infinite;
247
+ -ms-animation: buffering-stripes 2s linear infinite;
248
+ -o-animation: buffering-stripes 2s linear infinite;
249
+ animation: buffering-stripes 2s linear infinite;
250
+ }
251
+
252
+ @-webkit-keyframes buffering-stripes { from {background-position: 0 0;} to {background-position: 30px 0;} }
253
+ @-moz-keyframes buffering-stripes { from {background-position: 0 0;} to {background-position: 30px 0;} }
254
+ @-ms-keyframes buffering-stripes { from {background-position: 0 0;} to {background-position: 30px 0;} }
255
+ @-o-keyframes buffering-stripes { from {background-position: 0 0;} to {background-position: 30px 0;} }
256
+ @keyframes buffering-stripes { from {background-position: 0 0;} to {background-position: 30px 0;} }
257
+
258
+ .mejs-controls .mejs-time-rail .mejs-time-loaded {
259
+ background: #3caac8;
260
+ background: rgba(60,170,200,0.8);
261
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(44,124,145,0.8)), to(rgba(78,183,212,0.8)));
262
+ background: -webkit-linear-gradient(top, rgba(44,124,145,0.8), rgba(78,183,212,0.8));
263
+ background: -moz-linear-gradient(top, rgba(44,124,145,0.8), rgba(78,183,212,0.8));
264
+ background: -o-linear-gradient(top, rgba(44,124,145,0.8), rgba(78,183,212,0.8));
265
+ background: -ms-linear-gradient(top, rgba(44,124,145,0.8), rgba(78,183,212,0.8));
266
+ background: linear-gradient(rgba(44,124,145,0.8), rgba(78,183,212,0.8));
267
+ width: 0;
268
+ }
269
+ .mejs-controls .mejs-time-rail .mejs-time-current {
270
+ width: 0;
271
+ background: #fff;
272
+ background: rgba(255,255,255,0.8);
273
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255,255,255,0.9)), to(rgba(200,200,200,0.8)));
274
+ background: -webkit-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
275
+ background: -moz-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
276
+ background: -o-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
277
+ background: -ms-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
278
+ background: linear-gradient(rgba(255,255,255,0.9), rgba(200,200,200,0.8));
279
+ }
280
+
281
+ .mejs-controls .mejs-time-rail .mejs-time-handle {
282
+ display: none;
283
+ position: absolute;
284
+ margin: 0;
285
+ width: 10px;
286
+ background: #fff;
287
+ -webkit-border-radius: 5px;
288
+ -moz-border-radius: 5px;
289
+ border-radius: 5px;
290
+ cursor: pointer;
291
+ border: solid 2px #333;
292
+ top: -2px;
293
+ text-align: center;
294
+ }
295
+
296
+ .mejs-controls .mejs-time-rail .mejs-time-float {
297
+ position: absolute;
298
+ display: none;
299
+ background: #eee;
300
+ width: 36px;
301
+ height: 17px;
302
+ border: solid 1px #333;
303
+ top: -26px;
304
+ margin-left: -18px;
305
+ text-align: center;
306
+ color: #111;
307
+ }
308
+
309
+ .mejs-controls .mejs-time-rail .mejs-time-float-current {
310
+ margin: 2px;
311
+ width: 30px;
312
+ display: block;
313
+ text-align: center;
314
+ left: 0;
315
+ }
316
+ .mejs-controls .mejs-time-rail .mejs-time-float-corner {
317
+ position: absolute;
318
+ display: block;
319
+ width: 0;
320
+ height: 0;
321
+ line-height: 0;
322
+ border: solid 5px #eee;
323
+ border-color: #eee transparent transparent transparent;
324
+ -webkit-border-radius: 0;
325
+ -moz-border-radius: 0;
326
+ border-radius: 0;
327
+ top: 15px;
328
+ left: 13px;
329
+
330
+ }
331
+
332
+
333
+
334
+
335
+ /*
336
+ .mejs-controls .mejs-time-rail:hover .mejs-time-handle {
337
+ visibility:visible;
338
+ }
339
+ */
340
+ /* End: Progress bar */
341
+
342
+ /* Start: Fullscreen */
343
+ .mejs-controls .mejs-fullscreen-button button {
344
+ background-position:-32px 0;
345
+ }
346
+ .mejs-controls .mejs-unfullscreen button {
347
+ background-position:-32px -16px;
348
+ }
349
+ /* End: Fullscreen */
350
+
351
+
352
+ /* Start: Mute/Volume */
353
+ .mejs-controls .mejs-volume-button {
354
+ }
355
+
356
+ .mejs-controls .mejs-mute button {
357
+ background-position:-16px -16px;
358
+ }
359
+
360
+ .mejs-controls .mejs-unmute button {
361
+ background-position:-16px 0;
362
+ }
363
+
364
+ .mejs-controls .mejs-volume-button {
365
+ position: relative;
366
+ }
367
+
368
+ .mejs-controls .mejs-volume-button .mejs-volume-slider {
369
+ display: none;
370
+ height: 115px;
371
+ width: 25px;
372
+ background: url(background.png);
373
+ background: rgba(50, 50, 50, 0.7);
374
+ -webkit-border-radius: 0;
375
+ -moz-border-radius: 0;
376
+ border-radius: 0;
377
+ top: -115px;
378
+ left: 0;
379
+ z-index: 1;
380
+ position: absolute;
381
+ margin: 0;
382
+ }
383
+ .mejs-controls .mejs-volume-button:hover {
384
+ -webkit-border-radius: 0 0 4px 4px;
385
+ -moz-border-radius: 0 0 4px 4px;
386
+ border-radius: 0 0 4px 4px;
387
+ }
388
+ /*
389
+ .mejs-controls .mejs-volume-button:hover .mejs-volume-slider {
390
+ display: block;
391
+ }
392
+ */
393
+
394
+ .mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-total {
395
+ position: absolute;
396
+ left: 11px;
397
+ top: 8px;
398
+ width: 2px;
399
+ height: 100px;
400
+ background: #ddd;
401
+ background: rgba(255, 255, 255, 0.5);
402
+ margin: 0;
403
+ }
404
+
405
+ .mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-current {
406
+ position: absolute;
407
+ left: 11px;
408
+ top: 8px;
409
+ width: 2px;
410
+ height: 100px;
411
+ background: #ddd;
412
+ background: rgba(255, 255, 255, 0.9);
413
+ margin: 0;
414
+ }
415
+
416
+ .mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-handle {
417
+ position: absolute;
418
+ left: 4px;
419
+ top: -3px;
420
+ width: 16px;
421
+ height: 6px;
422
+ background: #ddd;
423
+ background: rgba(255, 255, 255, 0.9);
424
+ cursor: N-resize;
425
+ -webkit-border-radius: 1px;
426
+ -moz-border-radius: 1px;
427
+ border-radius: 1px;
428
+ margin: 0;
429
+ }
430
+
431
+
432
+ /* horizontal version */
433
+
434
+ .mejs-controls div.mejs-horizontal-volume-slider {
435
+ height: 26px;
436
+ width: 60px;
437
+ position: relative;
438
+ }
439
+
440
+ .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total {
441
+ position: absolute;
442
+ left: 0;
443
+ top: 11px;
444
+ width: 50px;
445
+ height: 8px;
446
+ margin: 0;
447
+ padding: 0;
448
+ font-size: 1px;
449
+
450
+ -webkit-border-radius: 2px;
451
+ -moz-border-radius: 2px;
452
+ border-radius: 2px;
453
+
454
+ background: #333;
455
+ background: rgba(50,50,50,0.8);
456
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(30,30,30,0.8)), to(rgba(60,60,60,0.8)));
457
+ background: -webkit-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
458
+ background: -moz-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
459
+ background: -o-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
460
+ background: -ms-linear-gradient(top, rgba(30,30,30,0.8), rgba(60,60,60,0.8));
461
+ background: linear-gradient(rgba(30,30,30,0.8), rgba(60,60,60,0.8));
462
+
463
+ }
464
+
465
+ .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current {
466
+ position: absolute;
467
+ left: 0;
468
+ top: 11px;
469
+ width: 50px;
470
+ height: 8px;
471
+ margin: 0;
472
+ padding: 0;
473
+ font-size: 1px;
474
+
475
+ -webkit-border-radius: 2px;
476
+ -moz-border-radius: 2px;
477
+ border-radius: 2px;
478
+
479
+ background: #fff;
480
+ background: rgba(255,255,255,0.8);
481
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(255,255,255,0.9)), to(rgba(200,200,200,0.8)));
482
+ background: -webkit-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
483
+ background: -moz-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
484
+ background: -o-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
485
+ background: -ms-linear-gradient(top, rgba(255,255,255,0.9), rgba(200,200,200,0.8));
486
+ background: linear-gradient(rgba(255,255,255,0.9), rgba(200,200,200,0.8));
487
+
488
+ }
489
+
490
+
491
+ .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-handle {
492
+ display: none;
493
+ }
494
+
495
+ /* End: Mute/Volume */
496
+
497
+
498
+
499
+
500
+ /* Start: TRACK (Captions and Chapters) */
501
+ .mejs-controls .mejs-captions-button {
502
+ position: relative;
503
+ }
504
+
505
+ .mejs-controls .mejs-captions-button button {
506
+ background-position:-48px 0;
507
+ }
508
+ .mejs-controls .mejs-captions-button .mejs-captions-selector {
509
+ visibility: hidden;
510
+ position: absolute;
511
+ bottom: 26px;
512
+ right: -10px;
513
+ width: 130px;
514
+ height: 100px;
515
+ background: url(background.png);
516
+ background: rgba(50,50,50,0.7);
517
+ border: solid 1px transparent;
518
+ padding: 10px;
519
+ overflow: hidden;
520
+ -webkit-border-radius: 0;
521
+ -moz-border-radius: 0;
522
+ border-radius: 0;
523
+ }
524
+ /*
525
+ .mejs-controls .mejs-captions-button:hover .mejs-captions-selector {
526
+ visibility: visible;
527
+ }
528
+ */
529
+
530
+ .mejs-controls .mejs-captions-button .mejs-captions-selector ul {
531
+ margin: 0;
532
+ padding: 0;
533
+ display: block;
534
+ list-style-type: none !important;
535
+ overflow: hidden;
536
+ }
537
+ .mejs-controls .mejs-captions-button .mejs-captions-selector ul li{
538
+ margin: 0 0 6px 0;
539
+ padding: 0;
540
+ list-style-type: none !important;
541
+ display:block;
542
+ color: #fff;
543
+ overflow: hidden;
544
+ }
545
+ .mejs-controls .mejs-captions-button .mejs-captions-selector ul li input{
546
+ clear: both;
547
+ float: left;
548
+ margin: 3px 3px 0 5px;
549
+ }
550
+ .mejs-controls .mejs-captions-button .mejs-captions-selector ul li label{
551
+ width: 100px;
552
+ float: left;
553
+ padding: 4px 0 0 0;
554
+ line-height: 15px;
555
+ font-family: helvetica, arial;
556
+ font-size: 10px;
557
+ }
558
+
559
+ .mejs-controls .mejs-captions-button .mejs-captions-translations {
560
+ font-size: 10px;
561
+ margin: 0 0 5px 0;
562
+ }
563
+
564
+
565
+ .mejs-chapters {
566
+ position: absolute;
567
+ top: 0;
568
+ left: 0;
569
+ -xborder-right: solid 1px #fff;
570
+ width: 10000px;
571
+ z-index: 1;
572
+ }
573
+ .mejs-chapters .mejs-chapter {
574
+ position: absolute;
575
+ float: left;
576
+ background: #222;
577
+ background: rgba(0, 0, 0, 0.7);
578
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(50,50,50,0.7)), to(rgba(0,0,0,0.7)));
579
+ background: -webkit-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
580
+ background: -moz-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
581
+ background: -o-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
582
+ background: -ms-linear-gradient(top, rgba(50,50,50,0.7), rgba(0,0,0,0.7));
583
+ background: linear-gradient(rgba(50,50,50,0.7), rgba(0,0,0,0.7));
584
+ filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr=#323232,endColorstr=#000000);
585
+ overflow: hidden;
586
+ border: 0;
587
+ }
588
+ .mejs-chapters .mejs-chapter .mejs-chapter-block {
589
+ font-size: 11px;
590
+ color: #fff;
591
+ padding: 5px;
592
+ display: block;
593
+ border-right: solid 1px #333;
594
+ border-bottom: solid 1px #333;
595
+ cursor: pointer;
596
+ }
597
+ .mejs-chapters .mejs-chapter .mejs-chapter-block-last {
598
+ border-right: none;
599
+ }
600
+
601
+ .mejs-chapters .mejs-chapter .mejs-chapter-block:hover {
602
+ /*background: #333;*/
603
+ background: #666;
604
+ background: rgba(102,102,102, 0.7);
605
+ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(102,102,102,0.7)), to(rgba(50,50,50,0.6)));
606
+ background: -webkit-linear-gradient(top, rgba(102,102,102,0.7), rgba(50,50,50,0.6));
607
+ background: -moz-linear-gradient(top, rgba(102,102,102,0.7), rgba(50,50,50,0.6));
608
+ background: -o-linear-gradient(top, rgba(102,102,102,0.7), rgba(50,50,50,0.6));
609
+ background: -ms-linear-gradient(top, rgba(102,102,102,0.7), rgba(50,50,50,0.6));
610
+ background: linear-gradient(rgba(102,102,102,0.7), rgba(50,50,50,0.6));
611
+ filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, startColorstr=#666666,endColorstr=#323232);
612
+ }
613
+ .mejs-chapters .mejs-chapter .mejs-chapter-block .ch-title{
614
+ font-size: 12px;
615
+ font-weight: bold;
616
+ display: block;
617
+ white-space:nowrap;
618
+ text-overflow: ellipsis;
619
+ margin: 0 0 3px 0;
620
+ line-height: 12px;
621
+ }
622
+ .mejs-chapters .mejs-chapter .mejs-chapter-block .ch-timespan{
623
+ font-size: 12px;
624
+ line-height: 12px;
625
+ margin: 3px 0 4px 0;
626
+ display: block;
627
+ white-space:nowrap;
628
+ text-overflow: ellipsis;
629
+ }
630
+
631
+
632
+ .mejs-captions-layer {
633
+ position: absolute;
634
+ bottom: 0;
635
+ left: 0;
636
+ text-align:center;
637
+ /*font-weight: bold;*/
638
+ line-height: 22px;
639
+ font-size: 12px;
640
+ color: #fff;
641
+ }
642
+ .mejs-captions-layer a {
643
+ color: #fff;
644
+ text-decoration: underline;
645
+ }
646
+ .mejs-captions-layer[lang=ar] {
647
+ font-size: 20px;
648
+ font-weight: normal;
649
+ }
650
+
651
+ .mejs-captions-position {
652
+ position: absolute;
653
+ width: 100%;
654
+ bottom: 15px;
655
+ left: 0;
656
+ }
657
+
658
+ .mejs-captions-position-hover {
659
+ bottom: 45px;
660
+ }
661
+
662
+ .mejs-captions-text {
663
+ padding: 3px 5px;
664
+ background: url(background.png);
665
+ background: rgba(20, 20, 20, 0.8);
666
+
667
+ }
668
+ /* End: TRACK (Captions and Chapters) */
669
+
670
+
671
+
672
+ .mejs-clear {
673
+ clear: both;
674
+ }
675
+
676
+ /* Start: ERROR */
677
+ .me-cannotplay {
678
+ }
679
+ .me-cannotplay a {
680
+ color: #fff;
681
+ font-weight: bold;
682
+ }
683
+ .me-cannotplay span {
684
+ padding: 15px;
685
+ display: block;
686
+ }
687
+ /* End: ERROR */
688
+
689
+
690
+ /* Start: Loop */
691
+ .mejs-controls .mejs-loop-off button{
692
+ background-position: -64px -16px;
693
+ }
694
+ .mejs-controls .mejs-loop-on button {
695
+ background-position: -64px 0;
696
+ }
697
+ /* End: Loop */
698
+
699
+ /* Start: backlight */
700
+ .mejs-controls .mejs-backlight-off button{
701
+ background-position: -80px -16px;
702
+ }
703
+ .mejs-controls .mejs-backlight-on button {
704
+ background-position: -80px 0;
705
+ }
706
+ /* End: backlight */
707
+
708
+
709
+ /* Start: picture controls */
710
+ .mejs-controls .mejs-picturecontrols-button{
711
+ background-position: -96px 0;
712
+ }
713
+ /* End: picture controls */
714
+
715
+
716
+ /* context menu */
717
+ .mejs-contextmenu {
718
+ position: absolute;
719
+ width: 150px;
720
+ padding: 10px;
721
+ border-radius: 4px;
722
+ top: 0;
723
+ left: 0;
724
+ background: #fff;
725
+ border: solid 1px #999;
726
+ z-index: 1001; /* make sure it shows on fullscreen */
727
+ }
728
+ .mejs-contextmenu .mejs-contextmenu-separator {
729
+ height: 1px;
730
+ font-size: 0;
731
+ margin: 5px 6px;
732
+ background: #333;
733
+ }
734
+
735
+ .mejs-contextmenu .mejs-contextmenu-item {
736
+ font-family: Helvetica, Arial;
737
+ font-size: 12px;
738
+ padding: 4px 6px;
739
+ cursor: pointer;
740
+ color: #333;
741
+ }
742
+ .mejs-contextmenu .mejs-contextmenu-item:hover {
743
+ background: #2C7C91;
744
+ color: #fff;
745
+ }
746
+
747
+
748
+ /* Start: SourceChooser */
749
+ .mejs-controls .mejs-sourcechooser-button {
750
+ position: relative;
751
+ }
752
+
753
+ .mejs-controls .mejs-sourcechooser-button button {
754
+ background-position: -128px 0;
755
+ }
756
+ .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector {
757
+ visibility: hidden;
758
+ position: absolute;
759
+ bottom: 26px;
760
+ right: -10px;
761
+ width: 130px;
762
+ height: 100px;
763
+ background: url(background.png);
764
+ background: rgba(50,50,50,0.7);
765
+ border: solid 1px transparent;
766
+ padding: 10px;
767
+ overflow: hidden;
768
+ -webkit-border-radius: 0;
769
+ -moz-border-radius: 0;
770
+ border-radius: 0;
771
+ }
772
+
773
+ .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul {
774
+ margin: 0;
775
+ padding: 0;
776
+ display: block;
777
+ list-style-type: none !important;
778
+ overflow: hidden;
779
+ }
780
+ .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li{
781
+ margin: 0 0 6px 0;
782
+ padding: 0;
783
+ list-style-type: none !important;
784
+ display:block;
785
+ color: #fff;
786
+ overflow: hidden;
787
+ }
788
+ .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li input{
789
+ clear: both;
790
+ float: left;
791
+ margin: 3px 3px 0 5px;
792
+ }
793
+ .mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li label{
794
+ width: 100px;
795
+ float: left;
796
+ padding: 4px 0 0 0;
797
+ line-height: 15px;
798
+ font-family: helvetica, arial;
799
+ font-size: 10px;
800
+ }
801
+ /* End: SourceChooser */
includes/media-element/mediaelementplayer.js ADDED
@@ -0,0 +1,2743 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * MediaElementPlayer
3
+ * http://mediaelementjs.com/
4
+ *
5
+ * Creates a controller bar for HTML5 <video> add <audio> tags
6
+ * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
7
+ *
8
+ * Copyright 2010-2012, John Dyer (http://j.hn/)
9
+ * Dual licensed under the MIT or GPL Version 2 licenses.
10
+ *
11
+ */
12
+ if (typeof jQuery != 'undefined') {
13
+ mejs.$ = jQuery;
14
+ } else if (typeof ender != 'undefined') {
15
+ mejs.$ = ender;
16
+ }
17
+ (function ($) {
18
+
19
+ // default player values
20
+ mejs.MepDefaults = {
21
+ // url to poster (to fix iOS 3.x)
22
+ poster: '',
23
+ // default if the <video width> is not specified
24
+ defaultVideoWidth: 480,
25
+ // default if the <video height> is not specified
26
+ defaultVideoHeight: 270,
27
+ // if set, overrides <video width>
28
+ videoWidth: -1,
29
+ // if set, overrides <video height>
30
+ videoHeight: -1,
31
+ // default if the user doesn't specify
32
+ defaultAudioWidth: 400,
33
+ // default if the user doesn't specify
34
+ defaultAudioHeight: 30,
35
+ // width of audio player
36
+ audioWidth: -1,
37
+ // height of audio player
38
+ audioHeight: -1,
39
+ // initial volume when the player starts (overrided by user cookie)
40
+ startVolume: 0.8,
41
+ // useful for <audio> player loops
42
+ loop: false,
43
+ // resize to media dimensions
44
+ enableAutosize: true,
45
+ // forces the hour marker (##:00:00)
46
+ alwaysShowHours: false,
47
+
48
+ // show framecount in timecode (##:00:00:00)
49
+ showTimecodeFrameCount: false,
50
+ // used when showTimecodeFrameCount is set to true
51
+ framesPerSecond: 25,
52
+
53
+ // automatically calculate the width of the progress bar based on the sizes of other elements
54
+ autosizeProgress : true,
55
+ // Hide controls when playing and mouse is not over the video
56
+ alwaysShowControls: false,
57
+ // force iPad's native controls
58
+ iPadUseNativeControls: false,
59
+ // force iPhone's native controls
60
+ iPhoneUseNativeControls: false,
61
+ // force Android's native controls
62
+ AndroidUseNativeControls: false,
63
+ // features to show
64
+ features: ['playpause','current','progress','duration','tracks','volume','fullscreen'],
65
+ // only for dynamic
66
+ isVideo: true,
67
+
68
+ // turns keyboard support on and off for this instance
69
+ enableKeyboard: true,
70
+
71
+ // whenthis player starts, it will pause other players
72
+ pauseOtherPlayers: true,
73
+
74
+ // array of keyboard actions such as play pause
75
+ keyActions: [
76
+ {
77
+ keys: [
78
+ 32, // SPACE
79
+ 179 // GOOGLE play/pause button
80
+ ],
81
+ action: function(player, media) {
82
+ if (media.paused || media.ended) {
83
+ media.play();
84
+ } else {
85
+ media.pause();
86
+ }
87
+ }
88
+ },
89
+ {
90
+ keys: [38], // UP
91
+ action: function(player, media) {
92
+ var newVolume = Math.min(media.volume + 0.1, 1);
93
+ media.setVolume(newVolume);
94
+ }
95
+ },
96
+ {
97
+ keys: [40], // DOWN
98
+ action: function(player, media) {
99
+ var newVolume = Math.max(media.volume - 0.1, 0);
100
+ media.setVolume(newVolume);
101
+ }
102
+ },
103
+ {
104
+ keys: [
105
+ 37, // LEFT
106
+ 227 // Google TV rewind
107
+ ],
108
+ action: function(player, media) {
109
+ if (!isNaN(media.duration) && media.duration > 0) {
110
+ if (player.isVideo) {
111
+ player.showControls();
112
+ player.startControlsTimer();
113
+ }
114
+
115
+ // 5%
116
+ var newTime = Math.max(media.currentTime - (media.duration * 0.05), 0);
117
+ media.setCurrentTime(newTime);
118
+ }
119
+ }
120
+ },
121
+ {
122
+ keys: [
123
+ 39, // RIGHT
124
+ 228 // Google TV forward
125
+ ],
126
+ action: function(player, media) {
127
+ if (!isNaN(media.duration) && media.duration > 0) {
128
+ if (player.isVideo) {
129
+ player.showControls();
130
+ player.startControlsTimer();
131
+ }
132
+
133
+ // 5%
134
+ var newTime = Math.min(media.currentTime + (media.duration * 0.05), media.duration);
135
+ media.setCurrentTime(newTime);
136
+ }
137
+ }
138
+ },
139
+ {
140
+ keys: [70], // f
141
+ action: function(player, media) {
142
+ if (typeof player.enterFullScreen != 'undefined') {
143
+ if (player.isFullScreen) {
144
+ player.exitFullScreen();
145
+ } else {
146
+ player.enterFullScreen();
147
+ }
148
+ }
149
+ }
150
+ }
151
+ ]
152
+ };
153
+
154
+ mejs.mepIndex = 0;
155
+
156
+ mejs.players = [];
157
+
158
+ // wraps a MediaElement object in player controls
159
+ mejs.MediaElementPlayer = function(node, o) {
160
+ // enforce object, even without "new" (via John Resig)
161
+ if ( !(this instanceof mejs.MediaElementPlayer) ) {
162
+ return new mejs.MediaElementPlayer(node, o);
163
+ }
164
+
165
+ var t = this;
166
+
167
+ // these will be reset after the MediaElement.success fires
168
+ t.$media = t.$node = $(node);
169
+ t.node = t.media = t.$media[0];
170
+
171
+ // check for existing player
172
+ if (typeof t.node.player != 'undefined') {
173
+ return t.node.player;
174
+ } else {
175
+ // attach player to DOM node for reference
176
+ t.node.player = t;
177
+ }
178
+
179
+
180
+ // try to get options from data-mejsoptions
181
+ if (typeof o == 'undefined') {
182
+ o = t.$node.data('mejsoptions');
183
+ }
184
+
185
+ // extend default options
186
+ t.options = $.extend({},mejs.MepDefaults,o);
187
+
188
+ // add to player array (for focus events)
189
+ mejs.players.push(t);
190
+
191
+ // start up
192
+ t.init();
193
+
194
+ return t;
195
+ };
196
+
197
+ // actual player
198
+ mejs.MediaElementPlayer.prototype = {
199
+
200
+ hasFocus: false,
201
+
202
+ controlsAreVisible: true,
203
+
204
+ init: function() {
205
+
206
+ var
207
+ t = this,
208
+ mf = mejs.MediaFeatures,
209
+ // options for MediaElement (shim)
210
+ meOptions = $.extend(true, {}, t.options, {
211
+ success: function(media, domNode) { t.meReady(media, domNode); },
212
+ error: function(e) { t.handleError(e);}
213
+ }),
214
+ tagName = t.media.tagName.toLowerCase();
215
+
216
+ t.isDynamic = (tagName !== 'audio' && tagName !== 'video');
217
+
218
+ if (t.isDynamic) {
219
+ // get video from src or href?
220
+ t.isVideo = t.options.isVideo;
221
+ } else {
222
+ t.isVideo = (tagName !== 'audio' && t.options.isVideo);
223
+ }
224
+
225
+ // use native controls in iPad, iPhone, and Android
226
+ if ((mf.isiPad && t.options.iPadUseNativeControls) || (mf.isiPhone && t.options.iPhoneUseNativeControls)) {
227
+
228
+ // add controls and stop
229
+ t.$media.attr('controls', 'controls');
230
+
231
+ // attempt to fix iOS 3 bug
232
+ //t.$media.removeAttr('poster');
233
+ // no Issue found on iOS3 -ttroxell
234
+
235
+ // override Apple's autoplay override for iPads
236
+ if (mf.isiPad && t.media.getAttribute('autoplay') !== null) {
237
+ t.media.load();
238
+ t.media.play();
239
+ }
240
+
241
+ } else if (mf.isAndroid && t.AndroidUseNativeControls) {
242
+
243
+ // leave default player
244
+
245
+ } else {
246
+
247
+ // DESKTOP: use MediaElementPlayer controls
248
+
249
+ // remove native controls
250
+ t.$media.removeAttr('controls');
251
+
252
+ // unique ID
253
+ t.id = 'mep_' + mejs.mepIndex++;
254
+
255
+ // build container
256
+ t.container =
257
+ $('<div id="' + t.id + '" class="mejs-container">'+
258
+ '<div class="mejs-inner">'+
259
+ '<div class="mejs-mediaelement"></div>'+
260
+ '<div class="mejs-layers"></div>'+
261
+ '<div class="mejs-controls"></div>'+
262
+ '<div class="mejs-clear"></div>'+
263
+ '</div>' +
264
+ '</div>')
265
+ .addClass(t.$media[0].className)
266
+ .insertBefore(t.$media);
267
+
268
+ // add classes for user and content
269
+ t.container.addClass(
270
+ (mf.isAndroid ? 'mejs-android ' : '') +
271
+ (mf.isiOS ? 'mejs-ios ' : '') +
272
+ (mf.isiPad ? 'mejs-ipad ' : '') +
273
+ (mf.isiPhone ? 'mejs-iphone ' : '') +
274
+ (t.isVideo ? 'mejs-video ' : 'mejs-audio ')
275
+ );
276
+
277
+
278
+ // move the <video/video> tag into the right spot
279
+ if (mf.isiOS) {
280
+
281
+ // sadly, you can't move nodes in iOS, so we have to destroy and recreate it!
282
+ var $newMedia = t.$media.clone();
283
+
284
+ t.container.find('.mejs-mediaelement').append($newMedia);
285
+
286
+ t.$media.remove();
287
+ t.$node = t.$media = $newMedia;
288
+ t.node = t.media = $newMedia[0]
289
+
290
+ } else {
291
+
292
+ // normal way of moving it into place (doesn't work on iOS)
293
+ t.container.find('.mejs-mediaelement').append(t.$media);
294
+ }
295
+
296
+ // find parts
297
+ t.controls = t.container.find('.mejs-controls');
298
+ t.layers = t.container.find('.mejs-layers');
299
+
300
+ // determine the size
301
+
302
+ /* size priority:
303
+ (1) videoWidth (forced),
304
+ (2) style="width;height;"
305
+ (3) width attribute,
306
+ (4) defaultVideoWidth (for unspecified cases)
307
+ */
308
+
309
+ var capsTagName = tagName.substring(0,1).toUpperCase() + tagName.substring(1);
310
+
311
+ if (t.options[tagName + 'Width'] > 0 || t.options[tagName + 'Width'].toString().indexOf('%') > -1) {
312
+ t.width = t.options[tagName + 'Width'];
313
+ } else if (t.media.style.width !== '' && t.media.style.width !== null) {
314
+ t.width = t.media.style.width;
315
+ } else if (t.media.getAttribute('width') !== null) {
316
+ t.width = t.$media.attr('width');
317
+ } else {
318
+ t.width = t.options['default' + capsTagName + 'Width'];
319
+ }
320
+
321
+ if (t.options[tagName + 'Height'] > 0 || t.options[tagName + 'Height'].toString().indexOf('%') > -1) {
322
+ t.height = t.options[tagName + 'Height'];
323
+ } else if (t.media.style.height !== '' && t.media.style.height !== null) {
324
+ t.height = t.media.style.height;
325
+ } else if (t.$media[0].getAttribute('height') !== null) {
326
+ t.height = t.$media.attr('height');
327
+ } else {
328
+ t.height = t.options['default' + capsTagName + 'Height'];
329
+ }
330
+
331
+ // set the size, while we wait for the plugins to load below
332
+ t.setPlayerSize(t.width, t.height);
333
+
334
+ // create MediaElementShim
335
+ meOptions.pluginWidth = t.height;
336
+ meOptions.pluginHeight = t.width;
337
+ }
338
+
339
+
340
+
341
+ // create MediaElement shim
342
+ mejs.MediaElement(t.$media[0], meOptions);
343
+ },
344
+
345
+ showControls: function(doAnimation) {
346
+ var t = this;
347
+
348
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
349
+
350
+ if (t.controlsAreVisible)
351
+ return;
352
+
353
+ if (doAnimation) {
354
+ t.controls
355
+ .css('visibility','visible')
356
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
357
+
358
+ // any additional controls people might add and want to hide
359
+ t.container.find('.mejs-control')
360
+ .css('visibility','visible')
361
+ .stop(true, true).fadeIn(200, function() {t.controlsAreVisible = true;});
362
+
363
+ } else {
364
+ t.controls
365
+ .css('visibility','visible')
366
+ .css('display','block');
367
+
368
+ // any additional controls people might add and want to hide
369
+ t.container.find('.mejs-control')
370
+ .css('visibility','visible')
371
+ .css('display','block');
372
+
373
+ t.controlsAreVisible = true;
374
+ }
375
+
376
+ t.setControlsSize();
377
+
378
+ },
379
+
380
+ hideControls: function(doAnimation) {
381
+ var t = this;
382
+
383
+ doAnimation = typeof doAnimation == 'undefined' || doAnimation;
384
+
385
+ if (!t.controlsAreVisible)
386
+ return;
387
+
388
+ if (doAnimation) {
389
+ // fade out main controls
390
+ t.controls.stop(true, true).fadeOut(200, function() {
391
+ $(this)
392
+ .css('visibility','hidden')
393
+ .css('display','block');
394
+
395
+ t.controlsAreVisible = false;
396
+ });
397
+
398
+ // any additional controls people might add and want to hide
399
+ t.container.find('.mejs-control').stop(true, true).fadeOut(200, function() {
400
+ $(this)
401
+ .css('visibility','hidden')
402
+ .css('display','block');
403
+ });
404
+ } else {
405
+
406
+ // hide main controls
407
+ t.controls
408
+ .css('visibility','hidden')
409
+ .css('display','block');
410
+
411
+ // hide others
412
+ t.container.find('.mejs-control')
413
+ .css('visibility','hidden')
414
+ .css('display','block');
415
+
416
+ t.controlsAreVisible = false;
417
+ }
418
+ },
419
+
420
+ controlsTimer: null,
421
+
422
+ startControlsTimer: function(timeout) {
423
+
424
+ var t = this;
425
+
426
+ timeout = typeof timeout != 'undefined' ? timeout : 1500;
427
+
428
+ t.killControlsTimer('start');
429
+
430
+ t.controlsTimer = setTimeout(function() {
431
+ //console.log('timer fired');
432
+ t.hideControls();
433
+ t.killControlsTimer('hide');
434
+ }, timeout);
435
+ },
436
+
437
+ killControlsTimer: function(src) {
438
+
439
+ var t = this;
440
+
441
+ if (t.controlsTimer !== null) {
442
+ clearTimeout(t.controlsTimer);
443
+ delete t.controlsTimer;
444
+ t.controlsTimer = null;
445
+ }
446
+ },
447
+
448
+ controlsEnabled: true,
449
+
450
+ disableControls: function() {
451
+ var t= this;
452
+
453
+ t.killControlsTimer();
454
+ t.hideControls(false);
455
+ this.controlsEnabled = false;
456
+ },
457
+
458
+ enableControls: function() {
459
+ var t= this;
460
+
461
+ t.showControls(false);
462
+
463
+ t.controlsEnabled = true;
464
+ },
465
+
466
+
467
+ // Sets up all controls and events
468
+ meReady: function(media, domNode) {
469
+
470
+
471
+ var t = this,
472
+ mf = mejs.MediaFeatures,
473
+ autoplayAttr = domNode.getAttribute('autoplay'),
474
+ autoplay = !(typeof autoplayAttr == 'undefined' || autoplayAttr === null || autoplayAttr === 'false'),
475
+ featureIndex,
476
+ feature;
477
+
478
+ // make sure it can't create itself again if a plugin reloads
479
+ if (t.created)
480
+ return;
481
+ else
482
+ t.created = true;
483
+
484
+ t.media = media;
485
+ t.domNode = domNode;
486
+
487
+ if (!(mf.isAndroid && t.options.AndroidUseNativeControls) && !(mf.isiPad && t.options.iPadUseNativeControls) && !(mf.isiPhone && t.options.iPhoneUseNativeControls)) {
488
+
489
+ // two built in features
490
+ t.buildposter(t, t.controls, t.layers, t.media);
491
+ t.buildkeyboard(t, t.controls, t.layers, t.media);
492
+ t.buildoverlays(t, t.controls, t.layers, t.media);
493
+
494
+ // grab for use by features
495
+ t.findTracks();
496
+
497
+ // add user-defined features/controls
498
+ for (featureIndex in t.options.features) {
499
+ feature = t.options.features[featureIndex];
500
+ if (t['build' + feature]) {
501
+ try {
502
+ t['build' + feature](t, t.controls, t.layers, t.media);
503
+ } catch (e) {
504
+ // TODO: report control error
505
+ //throw e;
506
+ //console.log('error building ' + feature);
507
+ //console.log(e);
508
+ }
509
+ }
510
+ }
511
+
512
+ t.container.trigger('controlsready');
513
+
514
+ // reset all layers and controls
515
+ t.setPlayerSize(t.width, t.height);
516
+ t.setControlsSize();
517
+
518
+
519
+ // controls fade
520
+ if (t.isVideo) {
521
+
522
+ if (mejs.MediaFeatures.hasTouch) {
523
+
524
+ // for touch devices (iOS, Android)
525
+ // show/hide without animation on touch
526
+
527
+ t.$media.bind('touchstart', function() {
528
+
529
+
530
+ // toggle controls
531
+ if (t.controlsAreVisible) {
532
+ t.hideControls(false);
533
+ } else {
534
+ if (t.controlsEnabled) {
535
+ t.showControls(false);
536
+ }
537
+ }
538
+ });
539
+
540
+ } else {
541
+ // click controls
542
+ var clickElement = (t.media.pluginType == 'native') ? t.$media : $(t.media.pluginElement);
543
+
544
+ // click to play/pause
545
+ clickElement.click(function() {
546
+ if (media.paused) {
547
+ media.play();
548
+ } else {
549
+ media.pause();
550
+ }
551
+ });
552
+
553
+
554
+ // show/hide controls
555
+ t.container
556
+ .bind('mouseenter mouseover', function () {
557
+ if (t.controlsEnabled) {
558
+ if (!t.options.alwaysShowControls) {
559
+ t.killControlsTimer('enter');
560
+ t.showControls();
561
+ t.startControlsTimer(2500);
562
+ }
563
+ }
564
+ })
565
+ .bind('mousemove', function() {
566
+ if (t.controlsEnabled) {
567
+ if (!t.controlsAreVisible) {
568
+ t.showControls();
569
+ }
570
+ //t.killControlsTimer('move');
571
+ if (!t.options.alwaysShowControls) {
572
+ t.startControlsTimer(2500);
573
+ }
574
+ }
575
+ })
576
+ .bind('mouseleave', function () {
577
+ if (t.controlsEnabled) {
578
+ if (!t.media.paused && !t.options.alwaysShowControls) {
579
+ t.startControlsTimer(1000);
580
+ }
581
+ }
582
+ });
583
+ }
584
+
585
+ // check for autoplay
586
+ if (autoplay && !t.options.alwaysShowControls) {
587
+ t.hideControls();
588
+ }
589
+
590
+ // resizer
591
+ if (t.options.enableAutosize) {
592
+ t.media.addEventListener('loadedmetadata', function(e) {
593
+ // if the <video height> was not set and the options.videoHeight was not set
594
+ // then resize to the real dimensions
595
+ if (t.options.videoHeight <= 0 && t.domNode.getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
596
+ t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
597
+ t.setControlsSize();
598
+ t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
599
+ }
600
+ }, false);
601
+ }
602
+ }
603
+
604
+ // EVENTS
605
+
606
+ // FOCUS: when a video starts playing, it takes focus from other players (possibily pausing them)
607
+ media.addEventListener('play', function() {
608
+
609
+ // go through all other players
610
+ for (var i=0, il=mejs.players.length; i<il; i++) {
611
+ var p = mejs.players[i];
612
+ if (p.id != t.id && t.options.pauseOtherPlayers && !p.paused && !p.ended) {
613
+ p.pause();
614
+ }
615
+ p.hasFocus = false;
616
+ }
617
+
618
+ t.hasFocus = true;
619
+ },false);
620
+
621
+
622
+ // ended for all
623
+ t.media.addEventListener('ended', function (e) {
624
+ try{
625
+ t.media.setCurrentTime(0);
626
+ } catch (exp) {
627
+
628
+ }
629
+ t.media.pause();
630
+
631
+ if (t.setProgressRail)
632
+ t.setProgressRail();
633
+ if (t.setCurrentRail)
634
+ t.setCurrentRail();
635
+
636
+ if (t.options.loop) {
637
+ t.media.play();
638
+ } else if (!t.options.alwaysShowControls && t.controlsEnabled) {
639
+ t.showControls();
640
+ }
641
+ }, false);
642
+
643
+ // resize on the first play
644
+ t.media.addEventListener('loadedmetadata', function(e) {
645
+ if (t.updateDuration) {
646
+ t.updateDuration();
647
+ }
648
+ if (t.updateCurrent) {
649
+ t.updateCurrent();
650
+ }
651
+
652
+ if (!t.isFullScreen) {
653
+ t.setPlayerSize(t.width, t.height);
654
+ t.setControlsSize();
655
+ }
656
+ }, false);
657
+
658
+
659
+ // webkit has trouble doing this without a delay
660
+ setTimeout(function () {
661
+ t.setPlayerSize(t.width, t.height);
662
+ t.setControlsSize();
663
+ }, 50);
664
+
665
+ // adjust controls whenever window sizes (used to be in fullscreen only)
666
+ $(window).resize(function() {
667
+
668
+ // don't resize for fullscreen mode
669
+ if ( !(t.isFullScreen || (mejs.MediaFeatures.hasTrueNativeFullScreen && document.webkitIsFullScreen)) ) {
670
+ t.setPlayerSize(t.width, t.height);
671
+ }
672
+
673
+ // always adjust controls
674
+ t.setControlsSize();
675
+ });
676
+
677
+ // TEMP: needs to be moved somewhere else
678
+ if (t.media.pluginType == 'youtube') {
679
+ t.container.find('.mejs-overlay-play').hide();
680
+ }
681
+ }
682
+
683
+ // force autoplay for HTML5
684
+ if (autoplay && media.pluginType == 'native') {
685
+ media.load();
686
+ media.play();
687
+ }
688
+
689
+
690
+ if (t.options.success) {
691
+
692
+ if (typeof t.options.success == 'string') {
693
+ window[t.options.success](t.media, t.domNode, t);
694
+ } else {
695
+ t.options.success(t.media, t.domNode, t);
696
+ }
697
+ }
698
+ },
699
+
700
+ handleError: function(e) {
701
+ var t = this;
702
+
703
+ t.controls.hide();
704
+
705
+ // Tell user that the file cannot be played
706
+ if (t.options.error) {
707
+ t.options.error(e);
708
+ }
709
+ },
710
+
711
+ setPlayerSize: function(width,height) {
712
+ var t = this;
713
+
714
+ if (typeof width != 'undefined')
715
+ t.width = width;
716
+
717
+ if (typeof height != 'undefined')
718
+ t.height = height;
719
+
720
+ // detect 100% mode
721
+ if (t.height.toString().indexOf('%') > 0) {
722
+
723
+ // do we have the native dimensions yet?
724
+ var
725
+ nativeWidth = (t.media.videoWidth && t.media.videoWidth > 0) ? t.media.videoWidth : t.options.defaultVideoWidth,
726
+ nativeHeight = (t.media.videoHeight && t.media.videoHeight > 0) ? t.media.videoHeight : t.options.defaultVideoHeight,
727
+ parentWidth = t.container.parent().width(),
728
+ newHeight = parseInt(parentWidth * nativeHeight/nativeWidth, 10);
729
+
730
+ if (t.container.parent()[0].tagName.toLowerCase() === 'body') { // && t.container.siblings().count == 0) {
731
+ parentWidth = $(window).width();
732
+ newHeight = $(window).height();
733
+ }
734
+
735
+
736
+ // set outer container size
737
+ t.container
738
+ .width(parentWidth)
739
+ .height(newHeight);
740
+
741
+ // set native <video>
742
+ t.$media
743
+ .width('100%')
744
+ .height('100%');
745
+
746
+ // set shims
747
+ t.container.find('object, embed, iframe')
748
+ .width('100%')
749
+ .height('100%');
750
+
751
+ // if shim is ready, send the size to the embeded plugin
752
+ if (t.media.setVideoSize)
753
+ t.media.setVideoSize(parentWidth, newHeight);
754
+
755
+ // set the layers
756
+ t.layers.children('.mejs-layer')
757
+ .width('100%')
758
+ .height('100%');
759
+
760
+
761
+ } else {
762
+
763
+ t.container
764
+ .width(t.width)
765
+ .height(t.height);
766
+
767
+ t.layers.children('.mejs-layer')
768
+ .width(t.width)
769
+ .height(t.height);
770
+
771
+ }
772
+ },
773
+
774
+ setControlsSize: function() {
775
+ var t = this,
776
+ usedWidth = 0,
777
+ railWidth = 0,
778
+ rail = t.controls.find('.mejs-time-rail'),
779
+ total = t.controls.find('.mejs-time-total'),
780
+ current = t.controls.find('.mejs-time-current'),
781
+ loaded = t.controls.find('.mejs-time-loaded'),
782
+ others = rail.siblings();
783
+
784
+
785
+ // allow the size to come from custom CSS
786
+ if (t.options && !t.options.autosizeProgress) {
787
+ // Also, frontends devs can be more flexible
788
+ // due the opportunity of absolute positioning.
789
+ railWidth = parseInt(rail.css('width'));
790
+ }
791
+
792
+ // attempt to autosize
793
+ if (railWidth === 0 || !railWidth) {
794
+
795
+ // find the size of all the other controls besides the rail
796
+ others.each(function() {
797
+ if ($(this).css('position') != 'absolute') {
798
+ usedWidth += $(this).outerWidth(true);
799
+ }
800
+ });
801
+
802
+ // fit the rail into the remaining space
803
+ railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.width());
804
+ }
805
+
806
+ // outer area
807
+ rail.width(railWidth);
808
+ // dark space
809
+ total.width(railWidth - (total.outerWidth(true) - total.width()));
810
+
811
+ if (t.setProgressRail)
812
+ t.setProgressRail();
813
+ if (t.setCurrentRail)
814
+ t.setCurrentRail();
815
+ },
816
+
817
+
818
+ buildposter: function(player, controls, layers, media) {
819
+ var t = this,
820
+ poster =
821
+ $('<div class="mejs-poster mejs-layer">' +
822
+ '</div>')
823
+ .appendTo(layers),
824
+ posterUrl = player.$media.attr('poster');
825
+
826
+ // prioriy goes to option (this is useful if you need to support iOS 3.x (iOS completely fails with poster)
827
+ if (player.options.poster !== '') {
828
+ posterUrl = player.options.poster;
829
+ }
830
+
831
+ // second, try the real poster
832
+ if (posterUrl !== '' && posterUrl != null) {
833
+ t.setPoster(posterUrl);
834
+ } else {
835
+ poster.hide();
836
+ }
837
+
838
+ media.addEventListener('play',function() {
839
+ poster.hide();
840
+ }, false);
841
+ },
842
+
843
+ setPoster: function(url) {
844
+ var t = this,
845
+ posterDiv = t.container.find('.mejs-poster'),
846
+ posterImg = posterDiv.find('img');
847
+
848
+ if (posterImg.length == 0) {
849
+ posterImg = $('<img width="100%" height="100%" />').appendTo(posterDiv);
850
+ }
851
+
852
+ posterImg.attr('src', url);
853
+ },
854
+
855
+ buildoverlays: function(player, controls, layers, media) {
856
+ if (!player.isVideo)
857
+ return;
858
+
859
+ var
860
+ loading =
861
+ $('<div class="mejs-overlay mejs-layer">'+
862
+ '<div class="mejs-overlay-loading"><span></span></div>'+
863
+ '</div>')
864
+ .hide() // start out hidden
865
+ .appendTo(layers),
866
+ error =
867
+ $('<div class="mejs-overlay mejs-layer">'+
868
+ '<div class="mejs-overlay-error"></div>'+
869
+ '</div>')
870
+ .hide() // start out hidden
871
+ .appendTo(layers),
872
+ // this needs to come last so it's on top
873
+ bigPlay =
874
+ $('<div class="mejs-overlay mejs-layer mejs-overlay-play">'+
875
+ '<div class="mejs-overlay-button"></div>'+
876
+ '</div>')
877
+ .appendTo(layers)
878
+ .click(function() {
879
+ if (media.paused) {
880
+ media.play();
881
+ } else {
882
+ media.pause();
883
+ }
884
+ });
885
+
886
+ /*
887
+ if (mejs.MediaFeatures.isiOS || mejs.MediaFeatures.isAndroid) {
888
+ bigPlay.remove();
889
+ loading.remove();
890
+ }
891
+ */
892
+
893
+
894
+ // show/hide big play button
895
+ media.addEventListener('play',function() {
896
+ bigPlay.hide();
897
+ loading.hide();
898
+ controls.find('.mejs-time-buffering').hide();
899
+ error.hide();
900
+ }, false);
901
+
902
+ media.addEventListener('playing', function() {
903
+ bigPlay.hide();
904
+ loading.hide();
905
+ controls.find('.mejs-time-buffering').hide();
906
+ error.hide();
907
+ }, false);
908
+
909
+ media.addEventListener('seeking', function() {
910
+ loading.show();
911
+ controls.find('.mejs-time-buffering').show();
912
+ }, false);
913
+
914
+ media.addEventListener('seeked', function() {
915
+ loading.hide();
916
+ controls.find('.mejs-time-buffering').hide();
917
+ }, false);
918
+
919
+ media.addEventListener('pause',function() {
920
+ if (!mejs.MediaFeatures.isiPhone) {
921
+ bigPlay.show();
922
+ }
923
+ }, false);
924
+
925
+ media.addEventListener('waiting', function() {
926
+ loading.show();
927
+ controls.find('.mejs-time-buffering').show();
928
+ }, false);
929
+
930
+
931
+ // show/hide loading
932
+ media.addEventListener('loadeddata',function() {
933
+ // for some reason Chrome is firing this event
934
+ //if (mejs.MediaFeatures.isChrome && media.getAttribute && media.getAttribute('preload') === 'none')
935
+ // return;
936
+
937
+ loading.show();
938
+ controls.find('.mejs-time-buffering').show();
939
+ }, false);
940
+ media.addEventListener('canplay',function() {
941
+ loading.hide();
942
+ controls.find('.mejs-time-buffering').hide();
943
+ }, false);
944
+
945
+ // error handling
946
+ media.addEventListener('error',function() {
947
+ loading.hide();
948
+ controls.find('.mejs-time-buffering').hide();
949
+ error.show();
950
+ error.find('mejs-overlay-error').html("Error loading this resource");
951
+ }, false);
952
+ },
953
+
954
+ buildkeyboard: function(player, controls, layers, media) {
955
+
956
+ var t = this;
957
+
958
+ // listen for key presses
959
+ $(document).keydown(function(e) {
960
+
961
+ if (player.hasFocus && player.options.enableKeyboard) {
962
+
963
+ // find a matching key
964
+ for (var i=0, il=player.options.keyActions.length; i<il; i++) {
965
+ var keyAction = player.options.keyActions[i];
966
+
967
+ for (var j=0, jl=keyAction.keys.length; j<jl; j++) {
968
+ if (e.keyCode == keyAction.keys[j]) {
969
+ e.preventDefault();
970
+ keyAction.action(player, media);
971
+ return false;
972
+ }
973
+ }
974
+ }
975
+ }
976
+
977
+ return true;
978
+ });
979
+
980
+ // check if someone clicked outside a player region, then kill its focus
981
+ $(document).click(function(event) {
982
+ if ($(event.target).closest('.mejs-container').length == 0) {
983
+ player.hasFocus = false;
984
+ }
985
+ });
986
+
987
+ },
988
+
989
+ findTracks: function() {
990
+ var t = this,
991
+ tracktags = t.$media.find('track');
992
+
993
+ // store for use by plugins
994
+ t.tracks = [];
995
+ tracktags.each(function(index, track) {
996
+
997
+ track = $(track);
998
+
999
+ t.tracks.push({
1000
+ srclang: track.attr('srclang').toLowerCase(),
1001
+ src: track.attr('src'),
1002
+ kind: track.attr('kind'),
1003
+ label: track.attr('label') || '',
1004
+ entries: [],
1005
+ isLoaded: false
1006
+ });
1007
+ });
1008
+ },
1009
+ changeSkin: function(className) {
1010
+ this.container[0].className = 'mejs-container ' + className;
1011
+ this.setPlayerSize(this.width, this.height);
1012
+ this.setControlsSize();
1013
+ },
1014
+ play: function() {
1015
+ this.media.play();
1016
+ },
1017
+ pause: function() {
1018
+ this.media.pause();
1019
+ },
1020
+ load: function() {
1021
+ this.media.load();
1022
+ },
1023
+ setMuted: function(muted) {
1024
+ this.media.setMuted(muted);
1025
+ },
1026
+ setCurrentTime: function(time) {
1027
+ this.media.setCurrentTime(time);
1028
+ },
1029
+ getCurrentTime: function() {
1030
+ return this.media.currentTime;
1031
+ },
1032
+ setVolume: function(volume) {
1033
+ this.media.setVolume(volume);
1034
+ },
1035
+ getVolume: function() {
1036
+ return this.media.volume;
1037
+ },
1038
+ setSrc: function(src) {
1039
+ this.media.setSrc(src);
1040
+ },
1041
+ remove: function() {
1042
+ var t = this;
1043
+
1044
+ if (t.media.pluginType == 'flash') {
1045
+ t.media.remove();
1046
+ } else if (t.media.pluginType == 'native') {
1047
+ t.media.prop('controls', true);
1048
+ }
1049
+
1050
+ // grab video and put it back in place
1051
+ if (!t.isDynamic) {
1052
+ t.$node.insertBefore(t.container)
1053
+ }
1054
+
1055
+ t.container.remove();
1056
+ }
1057
+ };
1058
+
1059
+ // turn into jQuery plugin
1060
+ if (typeof jQuery != 'undefined') {
1061
+ jQuery.fn.mediaelementplayer = function (options) {
1062
+ return this.each(function () {
1063
+ new mejs.MediaElementPlayer(this, options);
1064
+ });
1065
+ };
1066
+ }
1067
+
1068
+ $(document).ready(function() {
1069
+ // auto enable using JSON attribute
1070
+ $('.mejs-player').mediaelementplayer();
1071
+ });
1072
+
1073
+ // push out to window
1074
+ window.MediaElementPlayer = mejs.MediaElementPlayer;
1075
+
1076
+ })(mejs.$);
1077
+
1078
+ (function($) {
1079
+
1080
+ $.extend(mejs.MepDefaults, {
1081
+ playpauseText: 'Play/Pause'
1082
+ });
1083
+
1084
+ // PLAY/pause BUTTON
1085
+ $.extend(MediaElementPlayer.prototype, {
1086
+ buildplaypause: function(player, controls, layers, media) {
1087
+ var
1088
+ t = this,
1089
+ play =
1090
+ $('<div class="mejs-button mejs-playpause-button mejs-play" >' +
1091
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.playpauseText + '"></button>' +
1092
+ '</div>')
1093
+ .appendTo(controls)
1094
+ .click(function(e) {
1095
+ e.preventDefault();
1096
+
1097
+ if (media.paused) {
1098
+ media.play();
1099
+ } else {
1100
+ media.pause();
1101
+ }
1102
+
1103
+ return false;
1104
+ });
1105
+
1106
+ media.addEventListener('play',function() {
1107
+ play.removeClass('mejs-play').addClass('mejs-pause');
1108
+ }, false);
1109
+ media.addEventListener('playing',function() {
1110
+ play.removeClass('mejs-play').addClass('mejs-pause');
1111
+ }, false);
1112
+
1113
+
1114
+ media.addEventListener('pause',function() {
1115
+ play.removeClass('mejs-pause').addClass('mejs-play');
1116
+ }, false);
1117
+ media.addEventListener('paused',function() {
1118
+ play.removeClass('mejs-pause').addClass('mejs-play');
1119
+ }, false);
1120
+ }
1121
+ });
1122
+
1123
+ })(mejs.$);
1124
+ (function($) {
1125
+
1126
+ $.extend(mejs.MepDefaults, {
1127
+ stopText: 'Stop'
1128
+ });
1129
+
1130
+ // STOP BUTTON
1131
+ $.extend(MediaElementPlayer.prototype, {
1132
+ buildstop: function(player, controls, layers, media) {
1133
+ var t = this,
1134
+ stop =
1135
+ $('<div class="mejs-button mejs-stop-button mejs-stop">' +
1136
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.stopText + '"></button>' +
1137
+ '</div>')
1138
+ .appendTo(controls)
1139
+ .click(function() {
1140
+ if (!media.paused) {
1141
+ media.pause();
1142
+ }
1143
+ if (media.currentTime > 0) {
1144
+ media.setCurrentTime(0);
1145
+ controls.find('.mejs-time-current').width('0px');
1146
+ controls.find('.mejs-time-handle').css('left', '0px');
1147
+ controls.find('.mejs-time-float-current').html( mejs.Utility.secondsToTimeCode(0) );
1148
+ controls.find('.mejs-currenttime').html( mejs.Utility.secondsToTimeCode(0) );
1149
+ layers.find('.mejs-poster').show();
1150
+ }
1151
+ });
1152
+ }
1153
+ });
1154
+
1155
+ })(mejs.$);
1156
+ (function($) {
1157
+ // progress/loaded bar
1158
+ $.extend(MediaElementPlayer.prototype, {
1159
+ buildprogress: function(player, controls, layers, media) {
1160
+
1161
+ $('<div class="mejs-time-rail">'+
1162
+ '<span class="mejs-time-total">'+
1163
+ '<span class="mejs-time-buffering"></span>'+
1164
+ '<span class="mejs-time-loaded"></span>'+
1165
+ '<span class="mejs-time-current"></span>'+
1166
+ '<span class="mejs-time-handle"></span>'+
1167
+ '<span class="mejs-time-float">' +
1168
+ '<span class="mejs-time-float-current">00:00</span>' +
1169
+ '<span class="mejs-time-float-corner"></span>' +
1170
+ '</span>'+
1171
+ '</span>'+
1172
+ '</div>')
1173
+ .appendTo(controls);
1174
+ controls.find('.mejs-time-buffering').hide();
1175
+
1176
+ var
1177
+ t = this,
1178
+ total = controls.find('.mejs-time-total'),
1179
+ loaded = controls.find('.mejs-time-loaded'),
1180
+ current = controls.find('.mejs-time-current'),
1181
+ handle = controls.find('.mejs-time-handle'),
1182
+ timefloat = controls.find('.mejs-time-float'),
1183
+ timefloatcurrent = controls.find('.mejs-time-float-current'),
1184
+ handleMouseMove = function (e) {
1185
+ // mouse position relative to the object
1186
+ var x = e.pageX,
1187
+ offset = total.offset(),
1188
+ width = total.outerWidth(),
1189
+ percentage = 0,
1190
+ newTime = 0,
1191
+ pos = x - offset.left;
1192
+
1193
+
1194
+ if (x > offset.left && x <= width + offset.left && media.duration) {
1195
+ percentage = ((x - offset.left) / width);
1196
+ newTime = (percentage <= 0.02) ? 0 : percentage * media.duration;
1197
+
1198
+ // seek to where the mouse is
1199
+ if (mouseIsDown) {
1200
+ media.setCurrentTime(newTime);
1201
+ }
1202
+
1203
+ // position floating time box
1204
+ if (!mejs.MediaFeatures.hasTouch) {
1205
+ timefloat.css('left', pos);
1206
+ timefloatcurrent.html( mejs.Utility.secondsToTimeCode(newTime) );
1207
+ timefloat.show();
1208
+ }
1209
+ }
1210
+ },
1211
+ mouseIsDown = false,
1212
+ mouseIsOver = false;
1213
+
1214
+ // handle clicks
1215
+ //controls.find('.mejs-time-rail').delegate('span', 'click', handleMouseMove);
1216
+ total
1217
+ .bind('mousedown', function (e) {
1218
+ // only handle left clicks
1219
+ if (e.which === 1) {
1220
+ mouseIsDown = true;
1221
+ handleMouseMove(e);
1222
+ $(document)
1223
+ .bind('mousemove.dur', function(e) {
1224
+ handleMouseMove(e);
1225
+ })
1226
+ .bind('mouseup.dur', function (e) {
1227
+ mouseIsDown = false;
1228
+ timefloat.hide();
1229
+ $(document).unbind('.dur');
1230
+ });
1231
+ return false;
1232
+ }
1233
+ })
1234
+ .bind('mouseenter', function(e) {
1235
+ mouseIsOver = true;
1236
+ $(document).bind('mousemove.dur', function(e) {
1237
+ handleMouseMove(e);
1238
+ });
1239
+ if (!mejs.MediaFeatures.hasTouch) {
1240
+ timefloat.show();
1241
+ }
1242
+ })
1243
+ .bind('mouseleave',function(e) {
1244
+ mouseIsOver = false;
1245
+ if (!mouseIsDown) {
1246
+ $(document).unbind('.dur');
1247
+ timefloat.hide();
1248
+ }
1249
+ });
1250
+
1251
+ // loading
1252
+ media.addEventListener('progress', function (e) {
1253
+ player.setProgressRail(e);
1254
+ player.setCurrentRail(e);
1255
+ }, false);
1256
+
1257
+ // current time
1258
+ media.addEventListener('timeupdate', function(e) {
1259
+ player.setProgressRail(e);
1260
+ player.setCurrentRail(e);
1261
+ }, false);
1262
+
1263
+
1264
+ // store for later use
1265
+ t.loaded = loaded;
1266
+ t.total = total;
1267
+ t.current = current;
1268
+ t.handle = handle;
1269
+ },
1270
+ setProgressRail: function(e) {
1271
+
1272
+ var
1273
+ t = this,
1274
+ target = (e != undefined) ? e.target : t.media,
1275
+ percent = null;
1276
+
1277
+ // newest HTML5 spec has buffered array (FF4, Webkit)
1278
+ if (target && target.buffered && target.buffered.length > 0 && target.buffered.end && target.duration) {
1279
+ // TODO: account for a real array with multiple values (only Firefox 4 has this so far)
1280
+ percent = target.buffered.end(0) / target.duration;
1281
+ }
1282
+ // Some browsers (e.g., FF3.6 and Safari 5) cannot calculate target.bufferered.end()
1283
+ // to be anything other than 0. If the byte count is available we use this instead.
1284
+ // Browsers that support the else if do not seem to have the bufferedBytes value and
1285
+ // should skip to there. Tested in Safari 5, Webkit head, FF3.6, Chrome 6, IE 7/8.
1286
+ else if (target && target.bytesTotal != undefined && target.bytesTotal > 0 && target.bufferedBytes != undefined) {
1287
+ percent = target.bufferedBytes / target.bytesTotal;
1288
+ }
1289
+ // Firefox 3 with an Ogg file seems to go this way
1290
+ else if (e && e.lengthComputable && e.total != 0) {
1291
+ percent = e.loaded/e.total;
1292
+ }
1293
+
1294
+ // finally update the progress bar
1295
+ if (percent !== null) {
1296
+ percent = Math.min(1, Math.max(0, percent));
1297
+ // update loaded bar
1298
+ if (t.loaded && t.total) {
1299
+ t.loaded.width(t.total.width() * percent);
1300
+ }
1301
+ }
1302
+ },
1303
+ setCurrentRail: function() {
1304
+
1305
+ var t = this;
1306
+
1307
+ if (t.media.currentTime != undefined && t.media.duration) {
1308
+
1309
+ // update bar and handle
1310
+ if (t.total && t.handle) {
1311
+ var
1312
+ newWidth = t.total.width() * t.media.currentTime / t.media.duration,
1313
+ handlePos = newWidth - (t.handle.outerWidth(true) / 2);
1314
+
1315
+ t.current.width(newWidth);
1316
+ t.handle.css('left', handlePos);
1317
+ }
1318
+ }
1319
+
1320
+ }
1321
+ });
1322
+ })(mejs.$);
1323
+ (function($) {
1324
+
1325
+ // options
1326
+ $.extend(mejs.MepDefaults, {
1327
+ duration: -1,
1328
+ timeAndDurationSeparator: ' <span> | </span> '
1329
+ });
1330
+
1331
+
1332
+ // current and duration 00:00 / 00:00
1333
+ $.extend(MediaElementPlayer.prototype, {
1334
+ buildcurrent: function(player, controls, layers, media) {
1335
+ var t = this;
1336
+
1337
+ $('<div class="mejs-time">'+
1338
+ '<span class="mejs-currenttime">' + (player.options.alwaysShowHours ? '00:' : '')
1339
+ + (player.options.showTimecodeFrameCount? '00:00:00':'00:00')+ '</span>'+
1340
+ '</div>')
1341
+ .appendTo(controls);
1342
+
1343
+ t.currenttime = t.controls.find('.mejs-currenttime');
1344
+
1345
+ media.addEventListener('timeupdate',function() {
1346
+ player.updateCurrent();
1347
+ }, false);
1348
+ },
1349
+
1350
+
1351
+ buildduration: function(player, controls, layers, media) {
1352
+ var t = this;
1353
+
1354
+ if (controls.children().last().find('.mejs-currenttime').length > 0) {
1355
+ $(t.options.timeAndDurationSeparator +
1356
+ '<span class="mejs-duration">' +
1357
+ (t.options.duration > 0 ?
1358
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
1359
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
1360
+ ) +
1361
+ '</span>')
1362
+ .appendTo(controls.find('.mejs-time'));
1363
+ } else {
1364
+
1365
+ // add class to current time
1366
+ controls.find('.mejs-currenttime').parent().addClass('mejs-currenttime-container');
1367
+
1368
+ $('<div class="mejs-time mejs-duration-container">'+
1369
+ '<span class="mejs-duration">' +
1370
+ (t.options.duration > 0 ?
1371
+ mejs.Utility.secondsToTimeCode(t.options.duration, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25) :
1372
+ ((player.options.alwaysShowHours ? '00:' : '') + (player.options.showTimecodeFrameCount? '00:00:00':'00:00'))
1373
+ ) +
1374
+ '</span>' +
1375
+ '</div>')
1376
+ .appendTo(controls);
1377
+ }
1378
+
1379
+ t.durationD = t.controls.find('.mejs-duration');
1380
+
1381
+ media.addEventListener('timeupdate',function() {
1382
+ player.updateDuration();
1383
+ }, false);
1384
+ },
1385
+
1386
+ updateCurrent: function() {
1387
+ var t = this;
1388
+
1389
+ if (t.currenttime) {
1390
+ t.currenttime.html(mejs.Utility.secondsToTimeCode(t.media.currentTime, t.options.alwaysShowHours || t.media.duration > 3600, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1391
+ }
1392
+ },
1393
+
1394
+ updateDuration: function() {
1395
+ var t = this;
1396
+
1397
+ if (t.media.duration && t.durationD) {
1398
+ t.durationD.html(mejs.Utility.secondsToTimeCode(t.media.duration, t.options.alwaysShowHours, t.options.showTimecodeFrameCount, t.options.framesPerSecond || 25));
1399
+ }
1400
+ }
1401
+ });
1402
+
1403
+ })(mejs.$);
1404
+ (function($) {
1405
+
1406
+ $.extend(mejs.MepDefaults, {
1407
+ muteText: 'Mute Toggle',
1408
+ hideVolumeOnTouchDevices: true,
1409
+
1410
+ audioVolume: 'horizontal',
1411
+ videoVolume: 'vertical'
1412
+ });
1413
+
1414
+ $.extend(MediaElementPlayer.prototype, {
1415
+ buildvolume: function(player, controls, layers, media) {
1416
+
1417
+ // Android and iOS don't support volume controls
1418
+ if (mejs.MediaFeatures.hasTouch && this.options.hideVolumeOnTouchDevices)
1419
+ return;
1420
+
1421
+ var t = this,
1422
+ mode = (t.isVideo) ? t.options.videoVolume : t.options.audioVolume,
1423
+ mute = (mode == 'horizontal') ?
1424
+
1425
+ // horizontal version
1426
+ $('<div class="mejs-button mejs-volume-button mejs-mute">'+
1427
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
1428
+ '</div>' +
1429
+ '<div class="mejs-horizontal-volume-slider">'+ // outer background
1430
+ '<div class="mejs-horizontal-volume-total"></div>'+ // line background
1431
+ '<div class="mejs-horizontal-volume-current"></div>'+ // current volume
1432
+ '<div class="mejs-horizontal-volume-handle"></div>'+ // handle
1433
+ '</div>'
1434
+ )
1435
+ .appendTo(controls) :
1436
+
1437
+ // vertical version
1438
+ $('<div class="mejs-button mejs-volume-button mejs-mute">'+
1439
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.muteText + '"></button>'+
1440
+ '<div class="mejs-volume-slider">'+ // outer background
1441
+ '<div class="mejs-volume-total"></div>'+ // line background
1442
+ '<div class="mejs-volume-current"></div>'+ // current volume
1443
+ '<div class="mejs-volume-handle"></div>'+ // handle
1444
+ '</div>'+
1445
+ '</div>')
1446
+ .appendTo(controls),
1447
+ volumeSlider = t.container.find('.mejs-volume-slider, .mejs-horizontal-volume-slider'),
1448
+ volumeTotal = t.container.find('.mejs-volume-total, .mejs-horizontal-volume-total'),
1449
+ volumeCurrent = t.container.find('.mejs-volume-current, .mejs-horizontal-volume-current'),
1450
+ volumeHandle = t.container.find('.mejs-volume-handle, .mejs-horizontal-volume-handle'),
1451
+
1452
+ positionVolumeHandle = function(volume, secondTry) {
1453
+
1454
+ if (!volumeSlider.is(':visible') && typeof secondTry != 'undefined') {
1455
+ volumeSlider.show();
1456
+ positionVolumeHandle(volume, true);
1457
+ volumeSlider.hide()
1458
+ return;
1459
+ }
1460
+
1461
+ // correct to 0-1
1462
+ volume = Math.max(0,volume);
1463
+ volume = Math.min(volume,1);
1464
+
1465
+ // ajust mute button style
1466
+ if (volume == 0) {
1467
+ mute.removeClass('mejs-mute').addClass('mejs-unmute');
1468
+ } else {
1469
+ mute.removeClass('mejs-unmute').addClass('mejs-mute');
1470
+ }
1471
+
1472
+ // position slider
1473
+ if (mode == 'vertical') {
1474
+ var
1475
+
1476
+ // height of the full size volume slider background
1477
+ totalHeight = volumeTotal.height(),
1478
+
1479
+ // top/left of full size volume slider background
1480
+ totalPosition = volumeTotal.position(),
1481
+
1482
+ // the new top position based on the current volume
1483
+ // 70% volume on 100px height == top:30px
1484
+ newTop = totalHeight - (totalHeight * volume);
1485
+
1486
+ // handle
1487
+ volumeHandle.css('top', totalPosition.top + newTop - (volumeHandle.height() / 2));
1488
+
1489
+ // show the current visibility
1490
+ volumeCurrent.height(totalHeight - newTop );
1491
+ volumeCurrent.css('top', totalPosition.top + newTop);
1492
+ } else {
1493
+ var
1494
+
1495
+ // height of the full size volume slider background
1496
+ totalWidth = volumeTotal.width(),
1497
+
1498
+ // top/left of full size volume slider background
1499
+ totalPosition = volumeTotal.position(),
1500
+
1501
+ // the new left position based on the current volume
1502
+ newLeft = totalWidth * volume;
1503
+
1504
+ // handle
1505
+ volumeHandle.css('left', totalPosition.left + newLeft - (volumeHandle.width() / 2));
1506
+
1507
+ // rezize the current part of the volume bar
1508
+ volumeCurrent.width( newLeft );
1509
+ }
1510
+ },
1511
+ handleVolumeMove = function(e) {
1512
+
1513
+ var volume = null,
1514
+ totalOffset = volumeTotal.offset();
1515
+
1516
+ // calculate the new volume based on the moust position
1517
+ if (mode == 'vertical') {
1518
+
1519
+ var
1520
+ railHeight = volumeTotal.height(),
1521
+ totalTop = parseInt(volumeTotal.css('top').replace(/px/,''),10),
1522
+ newY = e.pageY - totalOffset.top;
1523
+
1524
+ volume = (railHeight - newY) / railHeight;
1525
+
1526
+ // the controls just hide themselves (usually when mouse moves too far up)
1527
+ if (totalOffset.top == 0 || totalOffset.left == 0)
1528
+ return;
1529
+
1530
+ } else {
1531
+ var
1532
+ railWidth = volumeTotal.width(),
1533
+ newX = e.pageX - totalOffset.left;
1534
+
1535
+ volume = newX / railWidth;
1536
+ }
1537
+
1538
+ // ensure the volume isn't outside 0-1
1539
+ volume = Math.max(0,volume);
1540
+ volume = Math.min(volume,1);
1541
+
1542
+ // position the slider and handle
1543
+ positionVolumeHandle(volume);
1544
+
1545
+ // set the media object (this will trigger the volumechanged event)
1546
+ if (volume == 0) {
1547
+ media.setMuted(true);
1548
+ } else {
1549
+ media.setMuted(false);
1550
+ }
1551
+ media.setVolume(volume);
1552
+ },
1553
+ mouseIsDown = false,
1554
+ mouseIsOver = false;
1555
+
1556
+ // SLIDER
1557
+
1558
+ mute
1559
+ .hover(function() {
1560
+ volumeSlider.show();
1561
+ mouseIsOver = true;
1562
+ }, function() {
1563
+ mouseIsOver = false;
1564
+
1565
+ if (!mouseIsDown && mode == 'vertical') {
1566
+ volumeSlider.hide();
1567
+ }
1568
+ });
1569
+
1570
+ volumeSlider
1571
+ .bind('mouseover', function() {
1572
+ mouseIsOver = true;
1573
+ })
1574
+ .bind('mousedown', function (e) {
1575
+ handleVolumeMove(e);
1576
+ $(document)
1577
+ .bind('mousemove.vol', function(e) {
1578
+ handleVolumeMove(e);
1579
+ })
1580
+ .bind('mouseup.vol', function () {
1581
+ mouseIsDown = false;
1582
+ $(document).unbind('.vol');
1583
+
1584
+ if (!mouseIsOver && mode == 'vertical') {
1585
+ volumeSlider.hide();
1586
+ }
1587
+ });
1588
+ mouseIsDown = true;
1589
+
1590
+ return false;
1591
+ });
1592
+
1593
+
1594
+ // MUTE button
1595
+ mute.find('button').click(function() {
1596
+ media.setMuted( !media.muted );
1597
+ });
1598
+
1599
+ // listen for volume change events from other sources
1600
+ media.addEventListener('volumechange', function(e) {
1601
+ if (!mouseIsDown) {
1602
+ if (media.muted) {
1603
+ positionVolumeHandle(0);
1604
+ mute.removeClass('mejs-mute').addClass('mejs-unmute');
1605
+ } else {
1606
+ positionVolumeHandle(media.volume);
1607
+ mute.removeClass('mejs-unmute').addClass('mejs-mute');
1608
+ }
1609
+ }
1610
+ }, false);
1611
+
1612
+ if (t.container.is(':visible')) {
1613
+ // set initial volume
1614
+ positionVolumeHandle(player.options.startVolume);
1615
+
1616
+ // shim gets the startvolume as a parameter, but we have to set it on the native <video> and <audio> elements
1617
+ if (media.pluginType === 'native') {
1618
+ media.setVolume(player.options.startVolume);
1619
+ }
1620
+ }
1621
+ }
1622
+ });
1623
+
1624
+ })(mejs.$);
1625
+
1626
+ (function($) {
1627
+
1628
+ $.extend(mejs.MepDefaults, {
1629
+ usePluginFullScreen: true,
1630
+ newWindowCallback: function() { return '';},
1631
+ fullscreenText: 'Fullscreen'
1632
+ });
1633
+
1634
+ $.extend(MediaElementPlayer.prototype, {
1635
+
1636
+ isFullScreen: false,
1637
+
1638
+ isNativeFullScreen: false,
1639
+
1640
+ docStyleOverflow: null,
1641
+
1642
+ isInIframe: false,
1643
+
1644
+ buildfullscreen: function(player, controls, layers, media) {
1645
+
1646
+ if (!player.isVideo)
1647
+ return;
1648
+
1649
+ player.isInIframe = (window.location != window.parent.location);
1650
+
1651
+ // native events
1652
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1653
+
1654
+ // chrome doesn't alays fire this in an iframe
1655
+ var target = null;
1656
+
1657
+ if (mejs.MediaFeatures.hasMozNativeFullScreen) {
1658
+ target = $(document);
1659
+ } else {
1660
+ target = player.container;
1661
+ }
1662
+
1663
+ target.bind(mejs.MediaFeatures.fullScreenEventName, function(e) {
1664
+ //player.container.bind('webkitfullscreenchange', function(e) {
1665
+
1666
+
1667
+ if (mejs.MediaFeatures.isFullScreen()) {
1668
+ player.isNativeFullScreen = true;
1669
+ // reset the controls once we are fully in full screen
1670
+ player.setControlsSize();
1671
+ } else {
1672
+ player.isNativeFullScreen = false;
1673
+ // when a user presses ESC
1674
+ // make sure to put the player back into place
1675
+ player.exitFullScreen();
1676
+ }
1677
+ });
1678
+ }
1679
+
1680
+ var t = this,
1681
+ normalHeight = 0,
1682
+ normalWidth = 0,
1683
+ container = player.container,
1684
+ fullscreenBtn =
1685
+ $('<div class="mejs-button mejs-fullscreen-button">' +
1686
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.fullscreenText + '"></button>' +
1687
+ '</div>')
1688
+ .appendTo(controls);
1689
+
1690
+ if (t.media.pluginType === 'native' || (!t.options.usePluginFullScreen && !mejs.MediaFeatures.isFirefox)) {
1691
+
1692
+ fullscreenBtn.click(function() {
1693
+ var isFullScreen = (mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || player.isFullScreen;
1694
+
1695
+ if (isFullScreen) {
1696
+ player.exitFullScreen();
1697
+ } else {
1698
+ player.enterFullScreen();
1699
+ }
1700
+ });
1701
+
1702
+ } else {
1703
+
1704
+ var hideTimeout = null,
1705
+ supportsPointerEvents = (function() {
1706
+ // TAKEN FROM MODERNIZR
1707
+ var element = document.createElement('x'),
1708
+ documentElement = document.documentElement,
1709
+ getComputedStyle = window.getComputedStyle,
1710
+ supports;
1711
+ if(!('pointerEvents' in element.style)){
1712
+ return false;
1713
+ }
1714
+ element.style.pointerEvents = 'auto';
1715
+ element.style.pointerEvents = 'x';
1716
+ documentElement.appendChild(element);
1717
+ supports = getComputedStyle &&
1718
+ getComputedStyle(element, '').pointerEvents === 'auto';
1719
+ documentElement.removeChild(element);
1720
+ return !!supports;
1721
+ })();
1722
+
1723
+ console.log('supportsPointerEvents', supportsPointerEvents);
1724
+
1725
+ if (supportsPointerEvents && !mejs.MediaFeatures.isOpera) { // opera doesn't allow this :(
1726
+
1727
+ // allows clicking through the fullscreen button and controls down directly to Flash
1728
+
1729
+ /*
1730
+ When a user puts his mouse over the fullscreen button, the controls are disabled
1731
+ So we put a div over the video and another one on iether side of the fullscreen button
1732
+ that caputre mouse movement
1733
+ and restore the controls once the mouse moves outside of the fullscreen button
1734
+ */
1735
+
1736
+ var fullscreenIsDisabled = false,
1737
+ restoreControls = function() {
1738
+ if (fullscreenIsDisabled) {
1739
+ // hide the hovers
1740
+ videoHoverDiv.hide();
1741
+ controlsLeftHoverDiv.hide();
1742
+ controlsRightHoverDiv.hide();
1743
+
1744
+ // restore the control bar
1745
+ fullscreenBtn.css('pointer-events', '');
1746
+ t.controls.css('pointer-events', '');
1747
+
1748
+ // store for later
1749
+ fullscreenIsDisabled = false;
1750
+ }
1751
+ },
1752
+ videoHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1753
+ controlsLeftHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1754
+ controlsRightHoverDiv = $('<div class="mejs-fullscreen-hover" />').appendTo(t.container).mouseover(restoreControls),
1755
+ positionHoverDivs = function() {
1756
+ var style = {position: 'absolute', top: 0, left: 0}; //, backgroundColor: '#f00'};
1757
+ videoHoverDiv.css(style);
1758
+ controlsLeftHoverDiv.css(style);
1759
+ controlsRightHoverDiv.css(style);
1760
+
1761
+ // over video, but not controls
1762
+ videoHoverDiv
1763
+ .width( t.container.width() )
1764
+ .height( t.container.height() - t.controls.height() );
1765
+
1766
+ // over controls, but not the fullscreen button
1767
+ var fullScreenBtnOffset = fullscreenBtn.offset().left - t.container.offset().left;
1768
+ fullScreenBtnWidth = fullscreenBtn.outerWidth(true);
1769
+
1770
+ controlsLeftHoverDiv
1771
+ .width( fullScreenBtnOffset )
1772
+ .height( t.controls.height() )
1773
+ .css({top: t.container.height() - t.controls.height()});
1774
+
1775
+ // after the fullscreen button
1776
+ controlsRightHoverDiv
1777
+ .width( t.container.width() - fullScreenBtnOffset - fullScreenBtnWidth )
1778
+ .height( t.controls.height() )
1779
+ .css({top: t.container.height() - t.controls.height(),
1780
+ left: fullScreenBtnOffset + fullScreenBtnWidth});
1781
+ };
1782
+
1783
+ $(document).resize(function() {
1784
+ positionHoverDivs();
1785
+ });
1786
+
1787
+ // on hover, kill the fullscreen button's HTML handling, allowing clicks down to Flash
1788
+ fullscreenBtn
1789
+ .mouseover(function() {
1790
+
1791
+ if (!t.isFullScreen) {
1792
+
1793
+ var buttonPos = fullscreenBtn.offset(),
1794
+ containerPos = player.container.offset();
1795
+
1796
+ // move the button in Flash into place
1797
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, false);
1798
+
1799
+ // allows click through
1800
+ fullscreenBtn.css('pointer-events', 'none');
1801
+ t.controls.css('pointer-events', 'none');
1802
+
1803
+ // show the divs that will restore things
1804
+ videoHoverDiv.show();
1805
+ controlsRightHoverDiv.show();
1806
+ controlsLeftHoverDiv.show();
1807
+ positionHoverDivs();
1808
+
1809
+ fullscreenIsDisabled = true;
1810
+ }
1811
+
1812
+ });
1813
+
1814
+ // restore controls anytime the user enters or leaves fullscreen
1815
+ media.addEventListener('fullscreenchange', function(e) {
1816
+ restoreControls();
1817
+ });
1818
+
1819
+
1820
+ // the mouseout event doesn't work on the fullscren button, because we already killed the pointer-events
1821
+ // so we use the document.mousemove event to restore controls when the mouse moves outside the fullscreen button
1822
+ /*
1823
+ $(document).mousemove(function(e) {
1824
+
1825
+ // if the mouse is anywhere but the fullsceen button, then restore it all
1826
+ if (fullscreenIsDisabled) {
1827
+
1828
+ var fullscreenBtnPos = fullscreenBtn.offset();
1829
+
1830
+
1831
+ if (e.pageY < fullscreenBtnPos.top || e.pageY > fullscreenBtnPos.top + fullscreenBtn.outerHeight(true) ||
1832
+ e.pageX < fullscreenBtnPos.left || e.pageX > fullscreenBtnPos.left + fullscreenBtn.outerWidth(true)
1833
+ ) {
1834
+
1835
+ fullscreenBtn.css('pointer-events', '');
1836
+ t.controls.css('pointer-events', '');
1837
+
1838
+ fullscreenIsDisabled = false;
1839
+ }
1840
+ }
1841
+ });
1842
+ */
1843
+
1844
+
1845
+ } else {
1846
+
1847
+ // the hover state will show the fullscreen button in Flash to hover up and click
1848
+
1849
+ fullscreenBtn
1850
+ .mouseover(function() {
1851
+
1852
+ if (hideTimeout !== null) {
1853
+ clearTimeout(hideTimeout);
1854
+ delete hideTimeout;
1855
+ }
1856
+
1857
+ var buttonPos = fullscreenBtn.offset(),
1858
+ containerPos = player.container.offset();
1859
+
1860
+ media.positionFullscreenButton(buttonPos.left - containerPos.left, buttonPos.top - containerPos.top, true);
1861
+
1862
+ })
1863
+ .mouseout(function() {
1864
+
1865
+ if (hideTimeout !== null) {
1866
+ clearTimeout(hideTimeout);
1867
+ delete hideTimeout;
1868
+ }
1869
+
1870
+ hideTimeout = setTimeout(function() {
1871
+ media.hideFullscreenButton();
1872
+ }, 1500);
1873
+
1874
+
1875
+ });
1876
+ }
1877
+ }
1878
+
1879
+ player.fullscreenBtn = fullscreenBtn;
1880
+
1881
+ $(document).bind('keydown',function (e) {
1882
+ if (((mejs.MediaFeatures.hasTrueNativeFullScreen && mejs.MediaFeatures.isFullScreen()) || t.isFullScreen) && e.keyCode == 27) {
1883
+ player.exitFullScreen();
1884
+ }
1885
+ });
1886
+
1887
+ },
1888
+ enterFullScreen: function() {
1889
+
1890
+ var t = this;
1891
+
1892
+ // firefox+flash can't adjust plugin sizes without resetting :(
1893
+ if (t.media.pluginType !== 'native' && (mejs.MediaFeatures.isFirefox || t.options.usePluginFullScreen)) {
1894
+ //t.media.setFullscreen(true);
1895
+ //player.isFullScreen = true;
1896
+ return;
1897
+ }
1898
+
1899
+ // store overflow
1900
+ docStyleOverflow = document.documentElement.style.overflow;
1901
+ // set it to not show scroll bars so 100% will work
1902
+ document.documentElement.style.overflow = 'hidden';
1903
+
1904
+ // store sizing
1905
+ normalHeight = t.container.height();
1906
+ normalWidth = t.container.width();
1907
+
1908
+ // attempt to do true fullscreen (Safari 5.1 and Firefox Nightly only for now)
1909
+ if (t.media.pluginType === 'native') {
1910
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1911
+
1912
+ mejs.MediaFeatures.requestFullScreen(t.container[0]);
1913
+ //return;
1914
+
1915
+ if (t.isInIframe) {
1916
+ // sometimes exiting from fullscreen doesn't work
1917
+ // notably in Chrome <iframe>. Fixed in version 17
1918
+ setTimeout(function checkFullscreen() {
1919
+
1920
+ if (t.isNativeFullScreen) {
1921
+
1922
+ // check if the video is suddenly not really fullscreen
1923
+ if ($(window).width() !== screen.width) {
1924
+ // manually exit
1925
+ t.exitFullScreen();
1926
+ } else {
1927
+ // test again
1928
+ setTimeout(checkFullscreen, 500);
1929
+ }
1930
+ }
1931
+
1932
+
1933
+ }, 500);
1934
+ }
1935
+
1936
+ } else if (mejs.MediaFeatures.hasSemiNativeFullScreen) {
1937
+ t.media.webkitEnterFullscreen();
1938
+ return;
1939
+ }
1940
+ }
1941
+
1942
+ // check for iframe launch
1943
+ if (t.isInIframe) {
1944
+ var url = t.options.newWindowCallback(this);
1945
+
1946
+
1947
+ if (url !== '') {
1948
+
1949
+ // launch immediately
1950
+ if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
1951
+ t.pause();
1952
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
1953
+ return;
1954
+ } else {
1955
+ setTimeout(function() {
1956
+ if (!t.isNativeFullScreen) {
1957
+ t.pause();
1958
+ window.open(url, t.id, 'top=0,left=0,width=' + screen.availWidth + ',height=' + screen.availHeight + ',resizable=yes,scrollbars=no,status=no,toolbar=no');
1959
+ }
1960
+ }, 250);
1961
+ }
1962
+ }
1963
+
1964
+ }
1965
+
1966
+ // full window code
1967
+
1968
+
1969
+
1970
+ // make full size
1971
+ t.container
1972
+ .addClass('mejs-container-fullscreen')
1973
+ .width('100%')
1974
+ .height('100%');
1975
+ //.css({position: 'fixed', left: 0, top: 0, right: 0, bottom: 0, overflow: 'hidden', width: '100%', height: '100%', 'z-index': 1000});
1976
+
1977
+ // Only needed for safari 5.1 native full screen, can cause display issues elsewhere
1978
+ // Actually, it seems to be needed for IE8, too
1979
+ //if (mejs.MediaFeatures.hasTrueNativeFullScreen) {
1980
+ setTimeout(function() {
1981
+ t.container.css({width: '100%', height: '100%'});
1982
+ t.setControlsSize();
1983
+ }, 500);
1984
+ //}
1985
+
1986
+ if (t.pluginType === 'native') {
1987
+ t.$media
1988
+ .width('100%')
1989
+ .height('100%');
1990
+ } else {
1991
+ t.container.find('object, embed, iframe')
1992
+ .width('100%')
1993
+ .height('100%');
1994
+
1995
+ //if (!mejs.MediaFeatures.hasTrueNativeFullScreen) {
1996
+ t.media.setVideoSize($(window).width(),$(window).height());
1997
+ //}
1998
+ }
1999
+
2000
+ t.layers.children('div')
2001
+ .width('100%')
2002
+ .height('100%');
2003
+
2004
+ if (t.fullscreenBtn) {
2005
+ t.fullscreenBtn
2006
+ .removeClass('mejs-fullscreen')
2007
+ .addClass('mejs-unfullscreen');
2008
+ }
2009
+
2010
+ t.setControlsSize();
2011
+ t.isFullScreen = true;
2012
+ },
2013
+
2014
+ exitFullScreen: function() {
2015
+
2016
+ var t = this;
2017
+
2018
+ // firefox can't adjust plugins
2019
+ if (t.media.pluginType !== 'native' && mejs.MediaFeatures.isFirefox) {
2020
+ t.media.setFullscreen(false);
2021
+ //player.isFullScreen = false;
2022
+ return;
2023
+ }
2024
+
2025
+ // come outo of native fullscreen
2026
+ if (mejs.MediaFeatures.hasTrueNativeFullScreen && (mejs.MediaFeatures.isFullScreen() || t.isFullScreen)) {
2027
+ mejs.MediaFeatures.cancelFullScreen();
2028
+ }
2029
+
2030
+ // restore scroll bars to document
2031
+ document.documentElement.style.overflow = docStyleOverflow;
2032
+
2033
+ t.container
2034
+ .removeClass('mejs-container-fullscreen')
2035
+ .width(normalWidth)
2036
+ .height(normalHeight);
2037
+ //.css({position: '', left: '', top: '', right: '', bottom: '', overflow: 'inherit', width: normalWidth + 'px', height: normalHeight + 'px', 'z-index': 1});
2038
+
2039
+ if (t.pluginType === 'native') {
2040
+ t.$media
2041
+ .width(normalWidth)
2042
+ .height(normalHeight);
2043
+ } else {
2044
+ t.container.find('object embed')
2045
+ .width(normalWidth)
2046
+ .height(normalHeight);
2047
+
2048
+ t.media.setVideoSize(normalWidth, normalHeight);
2049
+ }
2050
+
2051
+ t.layers.children('div')
2052
+ .width(normalWidth)
2053
+ .height(normalHeight);
2054
+
2055
+ t.fullscreenBtn
2056
+ .removeClass('mejs-unfullscreen')
2057
+ .addClass('mejs-fullscreen');
2058
+
2059
+ t.setControlsSize();
2060
+ t.isFullScreen = false;
2061
+ }
2062
+ });
2063
+
2064
+ })(mejs.$);
2065
+
2066
+ (function($) {
2067
+
2068
+ // add extra default options
2069
+ $.extend(mejs.MepDefaults, {
2070
+ // this will automatically turn on a <track>
2071
+ startLanguage: '',
2072
+
2073
+ tracksText: 'Captions/Subtitles'
2074
+ });
2075
+
2076
+ $.extend(MediaElementPlayer.prototype, {
2077
+
2078
+ hasChapters: false,
2079
+
2080
+ buildtracks: function(player, controls, layers, media) {
2081
+ if (!player.isVideo)
2082
+ return;
2083
+
2084
+ if (player.tracks.length == 0)
2085
+ return;
2086
+
2087
+ var t= this, i, options = '';
2088
+
2089
+ player.chapters =
2090
+ $('<div class="mejs-chapters mejs-layer"></div>')
2091
+ .prependTo(layers).hide();
2092
+ player.captions =
2093
+ $('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>')
2094
+ .prependTo(layers).hide();
2095
+ player.captionsText = player.captions.find('.mejs-captions-text');
2096
+ player.captionsButton =
2097
+ $('<div class="mejs-button mejs-captions-button">'+
2098
+ '<button type="button" aria-controls="' + t.id + '" title="' + t.options.tracksText + '"></button>'+
2099
+ '<div class="mejs-captions-selector">'+
2100
+ '<ul>'+
2101
+ '<li>'+
2102
+ '<input type="radio" name="' + player.id + '_captions" id="' + player.id + '_captions_none" value="none" checked="checked" />' +
2103
+ '<label for="' + player.id + '_captions_none">None</label>'+
2104
+ '</li>' +
2105
+ '</ul>'+
2106
+ '</div>'+
2107
+ '</div>')
2108
+ .appendTo(controls)
2109
+
2110
+ // hover
2111
+ .hover(function() {
2112
+ $(this).find('.mejs-captions-selector').css('visibility','visible');
2113
+ }, function() {
2114
+ $(this).find('.mejs-captions-selector').css('visibility','hidden');
2115
+ })
2116
+
2117
+ // handle clicks to the language radio buttons
2118
+ .delegate('input[type=radio]','click',function() {
2119
+ lang = this.value;
2120
+
2121
+ if (lang == 'none') {
2122
+ player.selectedTrack = null;
2123
+ } else {
2124
+ for (i=0; i<player.tracks.length; i++) {
2125
+ if (player.tracks[i].srclang == lang) {
2126
+ player.selectedTrack = player.tracks[i];
2127
+ player.captions.attr('lang', player.selectedTrack.srclang);
2128
+ player.displayCaptions();
2129
+ break;
2130
+ }
2131
+ }
2132
+ }
2133
+ });
2134
+ //.bind('mouseenter', function() {
2135
+ // player.captionsButton.find('.mejs-captions-selector').css('visibility','visible')
2136
+ //});
2137
+
2138
+ if (!player.options.alwaysShowControls) {
2139
+ // move with controls
2140
+ player.container
2141
+ .bind('mouseenter', function () {
2142
+ // push captions above controls
2143
+ player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
2144
+
2145
+ })
2146
+ .bind('mouseleave', function () {
2147
+ if (!media.paused) {
2148
+ // move back to normal place
2149
+ player.container.find('.mejs-captions-position').removeClass('mejs-captions-position-hover');
2150
+ }
2151
+ });
2152
+ } else {
2153
+ player.container.find('.mejs-captions-position').addClass('mejs-captions-position-hover');
2154
+ }
2155
+
2156
+ player.trackToLoad = -1;
2157
+ player.selectedTrack = null;
2158
+ player.isLoadingTrack = false;
2159
+
2160
+
2161
+
2162
+ // add to list
2163
+ for (i=0; i<player.tracks.length; i++) {
2164
+ if (player.tracks[i].kind == 'subtitles') {
2165
+ player.addTrackButton(player.tracks[i].srclang, player.tracks[i].label);
2166
+ }
2167
+ }
2168
+
2169
+ player.loadNextTrack();
2170
+
2171
+
2172
+ media.addEventListener('timeupdate',function(e) {
2173
+ player.displayCaptions();
2174
+ }, false);
2175
+
2176
+ media.addEventListener('loadedmetadata', function(e) {
2177
+ player.displayChapters();
2178
+ }, false);
2179
+
2180
+ player.container.hover(
2181
+ function () {
2182
+ // chapters
2183
+ if (player.hasChapters) {
2184
+ player.chapters.css('visibility','visible');
2185
+ player.chapters.fadeIn(200).height(player.chapters.find('.mejs-chapter').outerHeight());
2186
+ }
2187
+ },
2188
+ function () {
2189
+ if (player.hasChapters && !media.paused) {
2190
+ player.chapters.fadeOut(200, function() {
2191
+ $(this).css('visibility','hidden');
2192
+ $(this).css('display','block');
2193
+ });
2194
+ }
2195
+ });
2196
+
2197
+ // check for autoplay
2198
+ if (player.node.getAttribute('autoplay') !== null) {
2199
+ player.chapters.css('visibility','hidden');
2200
+ }
2201
+ },
2202
+
2203
+ loadNextTrack: function() {
2204
+ var t = this;
2205
+
2206
+ t.trackToLoad++;
2207
+ if (t.trackToLoad < t.tracks.length) {
2208
+ t.isLoadingTrack = true;
2209
+ t.loadTrack(t.trackToLoad);
2210
+ } else {
2211
+ // add done?
2212
+ t.isLoadingTrack = false;
2213
+ }
2214
+ },
2215
+
2216
+ loadTrack: function(index){
2217
+ var
2218
+ t = this,
2219
+ track = t.tracks[index],
2220
+ after = function() {
2221
+
2222
+ track.isLoaded = true;
2223
+
2224
+ // create button
2225
+ //t.addTrackButton(track.srclang);
2226
+ t.enableTrackButton(track.srclang, track.label);
2227
+
2228
+ t.loadNextTrack();
2229
+
2230
+ };
2231
+
2232
+ if (track.isTranslation) {
2233
+
2234
+ // translate the first track
2235
+ mejs.TrackFormatParser.translateTrackText(t.tracks[0].entries, t.tracks[0].srclang, track.srclang, t.options.googleApiKey, function(newOne) {
2236
+
2237
+ // store the new translation
2238
+ track.entries = newOne;
2239
+
2240
+ after();
2241
+ });
2242
+
2243
+ } else {
2244
+ $.ajax({
2245
+ url: track.src,
2246
+ success: function(d) {
2247
+
2248
+ // parse the loaded file
2249
+ track.entries = mejs.TrackFormatParser.parse(d);
2250
+ after();
2251
+
2252
+ if (track.kind == 'chapters' && t.media.duration > 0) {
2253
+ t.drawChapters(track);
2254
+ }
2255
+ },
2256
+ error: function() {
2257
+ t.loadNextTrack();
2258
+ }
2259
+ });
2260
+ }
2261
+ },
2262
+
2263
+ enableTrackButton: function(lang, label) {
2264
+ var t = this;
2265
+
2266
+ if (label === '') {
2267
+ label = mejs.language.codes[lang] || lang;
2268
+ }
2269
+
2270
+ t.captionsButton
2271
+ .find('input[value=' + lang + ']')
2272
+ .prop('disabled',false)
2273
+ .siblings('label')
2274
+ .html( label );
2275
+
2276
+ // auto select
2277
+ if (t.options.startLanguage == lang) {
2278
+ $('#' + t.id + '_captions_' + lang).click();
2279
+ }
2280
+
2281
+ t.adjustLanguageBox();
2282
+ },
2283
+
2284
+ addTrackButton: function(lang, label) {
2285
+ var t = this;
2286
+ if (label === '') {
2287
+ label = mejs.language.codes[lang] || lang;
2288
+ }
2289
+
2290
+ t.captionsButton.find('ul').append(
2291
+ $('<li>'+
2292
+ '<input type="radio" name="' + t.id + '_captions" id="' + t.id + '_captions_' + lang + '" value="' + lang + '" disabled="disabled" />' +
2293
+ '<label for="' + t.id + '_captions_' + lang + '">' + label + ' (loading)' + '</label>'+
2294
+ '</li>')
2295
+ );
2296
+
2297
+ t.adjustLanguageBox();
2298
+
2299
+ // remove this from the dropdownlist (if it exists)
2300
+ t.container.find('.mejs-captions-translations option[value=' + lang + ']').remove();
2301
+ },
2302
+
2303
+ adjustLanguageBox:function() {
2304
+ var t = this;
2305
+ // adjust the size of the outer box
2306
+ t.captionsButton.find('.mejs-captions-selector').height(
2307
+ t.captionsButton.find('.mejs-captions-selector ul').outerHeight(true) +
2308
+ t.captionsButton.find('.mejs-captions-translations').outerHeight(true)
2309
+ );
2310
+ },
2311
+
2312
+ displayCaptions: function() {
2313
+
2314
+ if (typeof this.tracks == 'undefined')
2315
+ return;
2316
+
2317
+ var
2318
+ t = this,
2319
+ i,
2320
+ track = t.selectedTrack;
2321
+
2322
+ if (track != null && track.isLoaded) {
2323
+ for (i=0; i<track.entries.times.length; i++) {
2324
+ if (t.media.currentTime >= track.entries.times[i].start && t.media.currentTime <= track.entries.times[i].stop){
2325
+ t.captionsText.html(track.entries.text[i]);
2326
+ t.captions.show().height(0);
2327
+ return; // exit out if one is visible;
2328
+ }
2329
+ }
2330
+ t.captions.hide();
2331
+ } else {
2332
+ t.captions.hide();
2333
+ }
2334
+ },
2335
+
2336
+ displayChapters: function() {
2337
+ var
2338
+ t = this,
2339
+ i;
2340
+
2341
+ for (i=0; i<t.tracks.length; i++) {
2342
+ if (t.tracks[i].kind == 'chapters' && t.tracks[i].isLoaded) {
2343
+ t.drawChapters(t.tracks[i]);
2344
+ t.hasChapters = true;
2345
+ break;
2346
+ }
2347
+ }
2348
+ },
2349
+
2350
+ drawChapters: function(chapters) {
2351
+ var
2352
+ t = this,
2353
+ i,
2354
+ dur,
2355
+ //width,
2356
+ //left,
2357
+ percent = 0,
2358
+ usedPercent = 0;
2359
+
2360
+ t.chapters.empty();
2361
+
2362
+ for (i=0; i<chapters.entries.times.length; i++) {
2363
+ dur = chapters.entries.times[i].stop - chapters.entries.times[i].start;
2364
+ percent = Math.floor(dur / t.media.duration * 100);
2365
+ if (percent + usedPercent > 100 || // too large
2366
+ i == chapters.entries.times.length-1 && percent + usedPercent < 100) // not going to fill it in
2367
+ {
2368
+ percent = 100 - usedPercent;
2369
+ }
2370
+ //width = Math.floor(t.width * dur / t.media.duration);
2371
+ //left = Math.floor(t.width * chapters.entries.times[i].start / t.media.duration);
2372
+ //if (left + width > t.width) {
2373
+ // width = t.width - left;
2374
+ //}
2375
+
2376
+ t.chapters.append( $(
2377
+ '<div class="mejs-chapter" rel="' + chapters.entries.times[i].start + '" style="left: ' + usedPercent.toString() + '%;width: ' + percent.toString() + '%;">' +
2378
+ '<div class="mejs-chapter-block' + ((i==chapters.entries.times.length-1) ? ' mejs-chapter-block-last' : '') + '">' +
2379
+ '<span class="ch-title">' + chapters.entries.text[i] + '</span>' +
2380
+ '<span class="ch-time">' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].start) + '&ndash;' + mejs.Utility.secondsToTimeCode(chapters.entries.times[i].stop) + '</span>' +
2381
+ '</div>' +
2382
+ '</div>'));
2383
+ usedPercent += percent;
2384
+ }
2385
+
2386
+ t.chapters.find('div.mejs-chapter').click(function() {
2387
+ t.media.setCurrentTime( parseFloat( $(this).attr('rel') ) );
2388
+ if (t.media.paused) {
2389
+ t.media.play();
2390
+ }
2391
+ });
2392
+
2393
+ t.chapters.show();
2394
+ }
2395
+ });
2396
+
2397
+
2398
+
2399
+ mejs.language = {
2400
+ codes: {
2401
+ af:'Afrikaans',
2402
+ sq:'Albanian',
2403
+ ar:'Arabic',
2404
+ be:'Belarusian',
2405
+ bg:'Bulgarian',
2406
+ ca:'Catalan',
2407
+ zh:'Chinese',
2408
+ 'zh-cn':'Chinese Simplified',
2409
+ 'zh-tw':'Chinese Traditional',
2410
+ hr:'Croatian',
2411
+ cs:'Czech',
2412
+ da:'Danish',
2413
+ nl:'Dutch',
2414
+ en:'English',
2415
+ et:'Estonian',
2416
+ tl:'Filipino',
2417
+ fi:'Finnish',
2418
+ fr:'French',
2419
+ gl:'Galician',
2420
+ de:'German',
2421
+ el:'Greek',
2422
+ ht:'Haitian Creole',
2423
+ iw:'Hebrew',
2424
+ hi:'Hindi',
2425
+ hu:'Hungarian',
2426
+ is:'Icelandic',
2427
+ id:'Indonesian',
2428
+ ga:'Irish',
2429
+ it:'Italian',
2430
+ ja:'Japanese',
2431
+ ko:'Korean',
2432
+ lv:'Latvian',
2433
+ lt:'Lithuanian',
2434
+ mk:'Macedonian',
2435
+ ms:'Malay',
2436
+ mt:'Maltese',
2437
+ no:'Norwegian',
2438
+ fa:'Persian',
2439
+ pl:'Polish',
2440
+ pt:'Portuguese',
2441
+ //'pt-pt':'Portuguese (Portugal)',
2442
+ ro:'Romanian',
2443
+ ru:'Russian',
2444
+ sr:'Serbian',
2445
+ sk:'Slovak',
2446
+ sl:'Slovenian',
2447
+ es:'Spanish',
2448
+ sw:'Swahili',
2449
+ sv:'Swedish',
2450
+ tl:'Tagalog',
2451
+ th:'Thai',
2452
+ tr:'Turkish',
2453
+ uk:'Ukrainian',
2454
+ vi:'Vietnamese',
2455
+ cy:'Welsh',
2456
+ yi:'Yiddish'
2457
+ }
2458
+ };
2459
+
2460
+ /*
2461
+ Parses WebVVT format which should be formatted as
2462
+ ================================
2463
+ WEBVTT
2464
+
2465
+ 1
2466
+ 00:00:01,1 --> 00:00:05,000
2467
+ A line of text
2468
+
2469
+ 2
2470
+ 00:01:15,1 --> 00:02:05,000
2471
+ A second line of text
2472
+
2473
+ ===============================
2474
+
2475
+ Adapted from: http://www.delphiki.com/html5/playr
2476
+ */
2477
+ mejs.TrackFormatParser = {
2478
+ // match start "chapter-" (or anythingelse)
2479
+ pattern_identifier: /^([a-zA-z]+-)?[0-9]+$/,
2480
+ pattern_timecode: /^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,
2481
+
2482
+ split2: function (text, regex) {
2483
+ // normal version for compliant browsers
2484
+ // see below for IE fix
2485
+ return text.split(regex);
2486
+ },
2487
+ parse: function(trackText) {
2488
+ var
2489
+ i = 0,
2490
+ lines = this.split2(trackText, /\r?\n/),
2491
+ entries = {text:[], times:[]},
2492
+ timecode,
2493
+ text;
2494
+
2495
+ for(; i<lines.length; i++) {
2496
+ // check for the line number
2497
+ if (this.pattern_identifier.exec(lines[i])){
2498
+ // skip to the next line where the start --> end time code should be
2499
+ i++;
2500
+ timecode = this.pattern_timecode.exec(lines[i]);
2501
+
2502
+ if (timecode && i<lines.length){
2503
+ i++;
2504
+ // grab all the (possibly multi-line) text that follows
2505
+ text = lines[i];
2506
+ i++;
2507
+ while(lines[i] !== '' && i<lines.length){
2508
+ text = text + '\n' + lines[i];
2509
+ i++;
2510
+ }
2511
+
2512
+ // Text is in a different array so I can use .join
2513
+ entries.text.push(text);
2514
+ entries.times.push(
2515
+ {
2516
+ start: mejs.Utility.timeCodeToSeconds(timecode[1]),
2517
+ stop: mejs.Utility.timeCodeToSeconds(timecode[3]),
2518
+ settings: timecode[5]
2519
+ });
2520
+ }
2521
+ }
2522
+ }
2523
+
2524
+ return entries;
2525
+ }
2526
+ };
2527
+
2528
+ // test for browsers with bad String.split method.
2529
+ if ('x\n\ny'.split(/\n/gi).length != 3) {
2530
+ // add super slow IE8 and below version
2531
+ mejs.TrackFormatParser.split2 = function(text, regex) {
2532
+ var
2533
+ parts = [],
2534
+ chunk = '',
2535
+ i;
2536
+
2537
+ for (i=0; i<text.length; i++) {
2538
+ chunk += text.substring(i,i+1);
2539
+ if (regex.test(chunk)) {
2540
+ parts.push(chunk.replace(regex, ''));
2541
+ chunk = '';
2542
+ }
2543
+ }
2544
+ parts.push(chunk);
2545
+ return parts;
2546
+ }
2547
+ }
2548
+
2549
+ })(mejs.$);
2550
+
2551
+ /*
2552
+ * ContextMenu Plugin
2553
+ *
2554
+ *
2555
+ */
2556
+
2557
+ (function($) {
2558
+
2559
+ $.extend(mejs.MepDefaults,
2560
+ { 'contextMenuItems': [
2561
+ // demo of a fullscreen option
2562
+ {
2563
+ render: function(player) {
2564
+
2565
+ // check for fullscreen plugin
2566
+ if (typeof player.enterFullScreen == 'undefined')
2567
+ return null;
2568
+
2569
+ if (player.isFullScreen) {
2570
+ return "Turn off Fullscreen";
2571
+ } else {
2572
+ return "Go Fullscreen";
2573
+ }
2574
+ },
2575
+ click: function(player) {
2576
+ if (player.isFullScreen) {
2577
+ player.exitFullScreen();
2578
+ } else {
2579
+ player.enterFullScreen();
2580
+ }
2581
+ }
2582
+ }
2583
+ ,
2584
+ // demo of a mute/unmute button
2585
+ {
2586
+ render: function(player) {
2587
+ if (player.media.muted) {
2588
+ return "Unmute";
2589
+ } else {
2590
+ return "Mute";
2591
+ }
2592
+ },
2593
+ click: function(player) {
2594
+ if (player.media.muted) {
2595
+ player.setMuted(false);
2596
+ } else {
2597
+ player.setMuted(true);
2598
+ }
2599
+ }
2600
+ },
2601
+ // separator
2602
+ {
2603
+ isSeparator: true
2604
+ }
2605
+ ,
2606
+ // demo of simple download video
2607
+ {
2608
+ render: function(player) {
2609
+ return "Download Video";
2610
+ },
2611
+ click: function(player) {
2612
+ window.location.href = player.media.currentSrc;
2613
+ }
2614
+ }
2615
+ ]}
2616
+ );
2617
+
2618
+
2619
+ $.extend(MediaElementPlayer.prototype, {
2620
+ buildcontextmenu: function(player, controls, layers, media) {
2621
+
2622
+ // create context menu
2623
+ player.contextMenu = $('<div class="mejs-contextmenu"></div>')
2624
+ .appendTo($('body'))
2625
+ .hide();
2626
+
2627
+ // create events for showing context menu
2628
+ player.container.bind('contextmenu', function(e) {
2629
+ if (player.isContextMenuEnabled) {
2630
+ e.preventDefault();
2631
+ player.renderContextMenu(e.clientX-1, e.clientY-1);
2632
+ return false;
2633
+ }
2634
+ });
2635
+ player.container.bind('click', function() {
2636
+ player.contextMenu.hide();
2637
+ });
2638
+ player.contextMenu.bind('mouseleave', function() {
2639
+
2640
+ //console.log('context hover out');
2641
+ player.startContextMenuTimer();
2642
+
2643
+ });
2644
+ },
2645
+
2646
+ isContextMenuEnabled: true,
2647
+ enableContextMenu: function() {
2648
+ this.isContextMenuEnabled = true;
2649
+ },
2650
+ disableContextMenu: function() {
2651
+ this.isContextMenuEnabled = false;
2652
+ },
2653
+
2654
+ contextMenuTimeout: null,
2655
+ startContextMenuTimer: function() {
2656
+ //console.log('startContextMenuTimer');
2657
+
2658
+ var t = this;
2659
+
2660
+ t.killContextMenuTimer();
2661
+
2662
+ t.contextMenuTimer = setTimeout(function() {
2663
+ t.hideContextMenu();
2664
+ t.killContextMenuTimer();
2665
+ }, 750);
2666
+ },
2667
+ killContextMenuTimer: function() {
2668
+ var timer = this.contextMenuTimer;
2669
+
2670
+ //console.log('killContextMenuTimer', timer);
2671
+
2672
+ if (timer != null) {
2673
+ clearTimeout(timer);
2674
+ delete timer;
2675
+ timer = null;
2676
+ }
2677
+ },
2678
+
2679
+ hideContextMenu: function() {
2680
+ this.contextMenu.hide();
2681
+ },
2682
+
2683
+ renderContextMenu: function(x,y) {
2684
+
2685
+ // alway re-render the items so that things like "turn fullscreen on" and "turn fullscreen off" are always written correctly
2686
+ var t = this,
2687
+ html = '',
2688
+ items = t.options.contextMenuItems;
2689
+
2690
+ for (var i=0, il=items.length; i<il; i++) {
2691
+
2692
+ if (items[i].isSeparator) {
2693
+ html += '<div class="mejs-contextmenu-separator"></div>';
2694
+ } else {
2695
+
2696
+ var rendered = items[i].render(t);
2697
+
2698
+ // render can return null if the item doesn't need to be used at the moment
2699
+ if (rendered != null) {
2700
+ html += '<div class="mejs-contextmenu-item" data-itemindex="' + i + '" id="element-' + (Math.random()*1000000) + '">' + rendered + '</div>';
2701
+ }
2702
+ }
2703
+ }
2704
+
2705
+ // position and show the context menu
2706
+ t.contextMenu
2707
+ .empty()
2708
+ .append($(html))
2709
+ .css({top:y, left:x})
2710
+ .show();
2711
+
2712
+ // bind events
2713
+ t.contextMenu.find('.mejs-contextmenu-item').each(function() {
2714
+
2715
+ // which one is this?
2716
+ var $dom = $(this),
2717
+ itemIndex = parseInt( $dom.data('itemindex'), 10 ),
2718
+ item = t.options.contextMenuItems[itemIndex];
2719
+
2720
+ // bind extra functionality?
2721
+ if (typeof item.show != 'undefined')
2722
+ item.show( $dom , t);
2723
+
2724
+ // bind click action
2725
+ $dom.click(function() {
2726
+ // perform click action
2727
+ if (typeof item.click != 'undefined')
2728
+ item.click(t);
2729
+
2730
+ // close
2731
+ t.contextMenu.hide();
2732
+ });
2733
+ });
2734
+
2735
+ // stop the controls from hiding
2736
+ setTimeout(function() {
2737
+ t.killControlsTimer('rev3');
2738
+ }, 100);
2739
+
2740
+ }
2741
+ });
2742
+
2743
+ })(mejs.$);
includes/media-element/mediaelementplayer.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .mejs-container{position:relative;background:#000;font-family:Helvetica,Arial;text-align:left;vertical-align:top;}.me-plugin{position:absolute;}.mejs-embed,.mejs-embed body{width:100%;height:100%;margin:0;padding:0;background:#000;overflow:hidden;}.mejs-container-fullscreen{position:fixed;left:0;top:0;right:0;bottom:0;overflow:hidden;z-index:1000;}.mejs-container-fullscreen .mejs-mediaelement,.mejs-container-fullscreen video{width:100%;height:100%;}.mejs-background{position:absolute;top:0;left:0;}.mejs-mediaelement{position:absolute;top:0;left:0;width:100%;height:100%;}.mejs-poster{position:absolute;top:0;left:0;}.mejs-poster img{border:0;padding:0;border:0;display:block;}.mejs-overlay{position:absolute;top:0;left:0;}.mejs-overlay-play{cursor:pointer;}.mejs-overlay-button{position:absolute;top:50%;left:50%;width:100px;height:100px;margin:-50px 0 0 -50px;background:url(bigplay.png) no-repeat;}.mejs-overlay:hover .mejs-overlay-button{background-position:0 -100px;}.mejs-overlay-loading{position:absolute;top:50%;left:50%;width:80px;height:80px;margin:-40px 0 0 -40px;background:#333;background:url(background.png);background:rgba(0,0,0,0.9);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(50,50,50,0.9)),to(rgba(0,0,0,0.9)));background:-webkit-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:-moz-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:-o-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:-ms-linear-gradient(top,rgba(50,50,50,0.9),rgba(0,0,0,0.9));background:linear-gradient(rgba(50,50,50,0.9),rgba(0,0,0,0.9));}.mejs-overlay-loading span{display:block;width:80px;height:80px;background:transparent url(loading.gif) 50% 50% no-repeat;}.mejs-container .mejs-controls{position:absolute;background:none;list-style-type:none;margin:0;padding:0;bottom:0;left:0;background:url(background.png);background:rgba(0,0,0,0.7);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(50,50,50,0.7)),to(rgba(0,0,0,0.7)));background:-webkit-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-moz-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-o-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-ms-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:linear-gradient(rgba(50,50,50,0.7),rgba(0,0,0,0.7));height:30px;width:100%;}.mejs-container .mejs-controls div{list-style-type:none;background-image:none;display:block;float:left;margin:0;padding:0;width:26px;height:26px;font-size:11px;line-height:11px;background:0;font-family:Helvetica,Arial;border:0;}.mejs-controls .mejs-button button{cursor:pointer;display:block;font-size:0;line-height:0;text-decoration:none;margin:7px 5px;padding:0;position:absolute;height:16px;width:16px;border:0;background:transparent url(controls.png) no-repeat;}.mejs-controls .mejs-button button:focus{outline:solid 1px yellow;}.mejs-container .mejs-controls .mejs-time{color:#fff;display:block;height:17px;width:auto;padding:8px 3px 0 3px;overflow:hidden;text-align:center;padding:auto 4px;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;}.mejs-container .mejs-controls .mejs-time span{font-size:11px;color:#fff;line-height:12px;display:block;float:left;margin:1px 2px 0 0;width:auto;}.mejs-controls .mejs-play button{background-position:0 0;}.mejs-controls .mejs-pause button{background-position:0 -16px;}.mejs-controls .mejs-stop button{background-position:-112px 0;}.mejs-controls div.mejs-time-rail{width:200px;padding-top:5px;}.mejs-controls .mejs-time-rail span{display:block;position:absolute;width:180px;height:10px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;cursor:pointer;}.mejs-controls .mejs-time-rail .mejs-time-total{margin:5px;background:#333;background:rgba(50,50,50,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(30,30,30,0.8)),to(rgba(60,60,60,0.8)));background:-webkit-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-moz-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-o-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-ms-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:linear-gradient(rgba(30,30,30,0.8),rgba(60,60,60,0.8));}.mejs-controls .mejs-time-rail .mejs-time-buffering{width:100%;background-image:-o-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-ms-linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(-45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:15px 15px;-moz-background-size:15px 15px;-o-background-size:15px 15px;background-size:15px 15px;-webkit-animation:buffering-stripes 2s linear infinite;-moz-animation:buffering-stripes 2s linear infinite;-ms-animation:buffering-stripes 2s linear infinite;-o-animation:buffering-stripes 2s linear infinite;animation:buffering-stripes 2s linear infinite;}@-webkit-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@-moz-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@-ms-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@-o-keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}@keyframes buffering-stripes{from{background-position:0 0;}to{background-position:30px 0;}}.mejs-controls .mejs-time-rail .mejs-time-loaded{background:#3caac8;background:rgba(60,170,200,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(44,124,145,0.8)),to(rgba(78,183,212,0.8)));background:-webkit-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:-moz-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:-o-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:-ms-linear-gradient(top,rgba(44,124,145,0.8),rgba(78,183,212,0.8));background:linear-gradient(rgba(44,124,145,0.8),rgba(78,183,212,0.8));width:0;}.mejs-controls .mejs-time-rail .mejs-time-current{width:0;background:#fff;background:rgba(255,255,255,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(255,255,255,0.9)),to(rgba(200,200,200,0.8)));background:-webkit-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-moz-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-o-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-ms-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:linear-gradient(rgba(255,255,255,0.9),rgba(200,200,200,0.8));}.mejs-controls .mejs-time-rail .mejs-time-handle{display:none;position:absolute;margin:0;width:10px;background:#fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;cursor:pointer;border:solid 2px #333;top:-2px;text-align:center;}.mejs-controls .mejs-time-rail .mejs-time-float{position:absolute;display:none;background:#eee;width:36px;height:17px;border:solid 1px #333;top:-26px;margin-left:-18px;text-align:center;color:#111;}.mejs-controls .mejs-time-rail .mejs-time-float-current{margin:2px;width:30px;display:block;text-align:center;left:0;}.mejs-controls .mejs-time-rail .mejs-time-float-corner{position:absolute;display:block;width:0;height:0;line-height:0;border:solid 5px #eee;border-color:#eee transparent transparent transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;top:15px;left:13px;}.mejs-controls .mejs-fullscreen-button button{background-position:-32px 0;}.mejs-controls .mejs-unfullscreen button{background-position:-32px -16px;}.mejs-controls .mejs-mute button{background-position:-16px -16px;}.mejs-controls .mejs-unmute button{background-position:-16px 0;}.mejs-controls .mejs-volume-button{position:relative;}.mejs-controls .mejs-volume-button .mejs-volume-slider{display:none;height:115px;width:25px;background:url(background.png);background:rgba(50,50,50,0.7);-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;top:-115px;left:0;z-index:1;position:absolute;margin:0;}.mejs-controls .mejs-volume-button:hover{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-total{position:absolute;left:11px;top:8px;width:2px;height:100px;background:#ddd;background:rgba(255,255,255,0.5);margin:0;}.mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-current{position:absolute;left:11px;top:8px;width:2px;height:100px;background:#ddd;background:rgba(255,255,255,0.9);margin:0;}.mejs-controls .mejs-volume-button .mejs-volume-slider .mejs-volume-handle{position:absolute;left:4px;top:-3px;width:16px;height:6px;background:#ddd;background:rgba(255,255,255,0.9);cursor:N-resize;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;margin:0;}.mejs-controls div.mejs-horizontal-volume-slider{height:26px;width:60px;position:relative;}.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total{position:absolute;left:0;top:11px;width:50px;height:8px;margin:0;padding:0;font-size:1px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background:#333;background:rgba(50,50,50,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(30,30,30,0.8)),to(rgba(60,60,60,0.8)));background:-webkit-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-moz-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-o-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:-ms-linear-gradient(top,rgba(30,30,30,0.8),rgba(60,60,60,0.8));background:linear-gradient(rgba(30,30,30,0.8),rgba(60,60,60,0.8));}.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current{position:absolute;left:0;top:11px;width:50px;height:8px;margin:0;padding:0;font-size:1px;-webkit-border-radius:2px;-moz-border-radius:2px;border-radius:2px;background:#fff;background:rgba(255,255,255,0.8);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(255,255,255,0.9)),to(rgba(200,200,200,0.8)));background:-webkit-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-moz-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-o-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:-ms-linear-gradient(top,rgba(255,255,255,0.9),rgba(200,200,200,0.8));background:linear-gradient(rgba(255,255,255,0.9),rgba(200,200,200,0.8));}.mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-handle{display:none;}.mejs-controls .mejs-captions-button{position:relative;}.mejs-controls .mejs-captions-button button{background-position:-48px 0;}.mejs-controls .mejs-captions-button .mejs-captions-selector{visibility:hidden;position:absolute;bottom:26px;right:-10px;width:130px;height:100px;background:url(background.png);background:rgba(50,50,50,0.7);border:solid 1px transparent;padding:10px;overflow:hidden;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul{margin:0;padding:0;display:block;list-style-type:none!important;overflow:hidden;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul li{margin:0 0 6px 0;padding:0;list-style-type:none!important;display:block;color:#fff;overflow:hidden;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul li input{clear:both;float:left;margin:3px 3px 0 5px;}.mejs-controls .mejs-captions-button .mejs-captions-selector ul li label{width:100px;float:left;padding:4px 0 0 0;line-height:15px;font-family:helvetica,arial;font-size:10px;}.mejs-controls .mejs-captions-button .mejs-captions-translations{font-size:10px;margin:0 0 5px 0;}.mejs-chapters{position:absolute;top:0;left:0;-xborder-right:solid 1px #fff;width:10000px;z-index:1;}.mejs-chapters .mejs-chapter{position:absolute;float:left;background:#222;background:rgba(0,0,0,0.7);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(50,50,50,0.7)),to(rgba(0,0,0,0.7)));background:-webkit-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-moz-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-o-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:-ms-linear-gradient(top,rgba(50,50,50,0.7),rgba(0,0,0,0.7));background:linear-gradient(rgba(50,50,50,0.7),rgba(0,0,0,0.7));filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,startColorstr=#323232,endColorstr=#000000);overflow:hidden;border:0;}.mejs-chapters .mejs-chapter .mejs-chapter-block{font-size:11px;color:#fff;padding:5px;display:block;border-right:solid 1px #333;border-bottom:solid 1px #333;cursor:pointer;}.mejs-chapters .mejs-chapter .mejs-chapter-block-last{border-right:none;}.mejs-chapters .mejs-chapter .mejs-chapter-block:hover{background:#666;background:rgba(102,102,102,0.7);background:-webkit-gradient(linear,0% 0,0% 100%,from(rgba(102,102,102,0.7)),to(rgba(50,50,50,0.6)));background:-webkit-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:-moz-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:-o-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:-ms-linear-gradient(top,rgba(102,102,102,0.7),rgba(50,50,50,0.6));background:linear-gradient(rgba(102,102,102,0.7),rgba(50,50,50,0.6));filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,startColorstr=#666666,endColorstr=#323232);}.mejs-chapters .mejs-chapter .mejs-chapter-block .ch-title{font-size:12px;font-weight:bold;display:block;white-space:nowrap;text-overflow:ellipsis;margin:0 0 3px 0;line-height:12px;}.mejs-chapters .mejs-chapter .mejs-chapter-block .ch-timespan{font-size:12px;line-height:12px;margin:3px 0 4px 0;display:block;white-space:nowrap;text-overflow:ellipsis;}.mejs-captions-layer{position:absolute;bottom:0;left:0;text-align:center;line-height:22px;font-size:12px;color:#fff;}.mejs-captions-layer a{color:#fff;text-decoration:underline;}.mejs-captions-layer[lang=ar]{font-size:20px;font-weight:normal;}.mejs-captions-position{position:absolute;width:100%;bottom:15px;left:0;}.mejs-captions-position-hover{bottom:45px;}.mejs-captions-text{padding:3px 5px;background:url(background.png);background:rgba(20,20,20,0.8);}.mejs-clear{clear:both;}.me-cannotplay a{color:#fff;font-weight:bold;}.me-cannotplay span{padding:15px;display:block;}.mejs-controls .mejs-loop-off button{background-position:-64px -16px;}.mejs-controls .mejs-loop-on button{background-position:-64px 0;}.mejs-controls .mejs-backlight-off button{background-position:-80px -16px;}.mejs-controls .mejs-backlight-on button{background-position:-80px 0;}.mejs-controls .mejs-picturecontrols-button{background-position:-96px 0;}.mejs-contextmenu{position:absolute;width:150px;padding:10px;border-radius:4px;top:0;left:0;background:#fff;border:solid 1px #999;z-index:1001;}.mejs-contextmenu .mejs-contextmenu-separator{height:1px;font-size:0;margin:5px 6px;background:#333;}.mejs-contextmenu .mejs-contextmenu-item{font-family:Helvetica,Arial;font-size:12px;padding:4px 6px;cursor:pointer;color:#333;}.mejs-contextmenu .mejs-contextmenu-item:hover{background:#2C7C91;color:#fff;}.mejs-controls .mejs-sourcechooser-button{position:relative;}.mejs-controls .mejs-sourcechooser-button button{background-position:-128px 0;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector{visibility:hidden;position:absolute;bottom:26px;right:-10px;width:130px;height:100px;background:url(background.png);background:rgba(50,50,50,0.7);border:solid 1px transparent;padding:10px;overflow:hidden;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul{margin:0;padding:0;display:block;list-style-type:none!important;overflow:hidden;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li{margin:0 0 6px 0;padding:0;list-style-type:none!important;display:block;color:#fff;overflow:hidden;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li input{clear:both;float:left;margin:3px 3px 0 5px;}.mejs-controls .mejs-sourcechooser-button .mejs-sourcechooser-selector ul li label{width:100px;float:left;padding:4px 0 0 0;line-height:15px;font-family:helvetica,arial;font-size:10px;}
includes/media-element/mediaelementplayer.min.js ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * MediaElementPlayer
3
+ * http://mediaelementjs.com/
4
+ *
5
+ * Creates a controller bar for HTML5 <video> add <audio> tags
6
+ * using jQuery and MediaElement.js (HTML5 Flash/Silverlight wrapper)
7
+ *
8
+ * Copyright 2010-2012, John Dyer (http://j.hn/)
9
+ * Dual licensed under the MIT or GPL Version 2 licenses.
10
+ *
11
+ */if(typeof jQuery!="undefined")mejs.$=jQuery;else if(typeof ender!="undefined")mejs.$=ender;
12
+ (function(f){mejs.MepDefaults={poster:"",defaultVideoWidth:480,defaultVideoHeight:270,videoWidth:-1,videoHeight:-1,defaultAudioWidth:400,defaultAudioHeight:30,audioWidth:-1,audioHeight:-1,startVolume:0.8,loop:false,enableAutosize:true,alwaysShowHours:false,showTimecodeFrameCount:false,framesPerSecond:25,autosizeProgress:true,alwaysShowControls:false,iPadUseNativeControls:false,iPhoneUseNativeControls:false,AndroidUseNativeControls:false,features:["playpause","current","progress","duration","tracks",
13
+ "volume","fullscreen"],isVideo:true,enableKeyboard:true,pauseOtherPlayers:true,keyActions:[{keys:[32,179],action:function(a,b){b.paused||b.ended?b.play():b.pause()}},{keys:[38],action:function(a,b){b.setVolume(Math.min(b.volume+0.1,1))}},{keys:[40],action:function(a,b){b.setVolume(Math.max(b.volume-0.1,0))}},{keys:[37,227],action:function(a,b){if(!isNaN(b.duration)&&b.duration>0){if(a.isVideo){a.showControls();a.startControlsTimer()}b.setCurrentTime(Math.max(b.currentTime-b.duration*0.05,0))}}},{keys:[39,
14
+ 228],action:function(a,b){if(!isNaN(b.duration)&&b.duration>0){if(a.isVideo){a.showControls();a.startControlsTimer()}b.setCurrentTime(Math.min(b.currentTime+b.duration*0.05,b.duration))}}},{keys:[70],action:function(a){if(typeof a.enterFullScreen!="undefined")a.isFullScreen?a.exitFullScreen():a.enterFullScreen()}}]};mejs.mepIndex=0;mejs.players=[];mejs.MediaElementPlayer=function(a,b){if(!(this instanceof mejs.MediaElementPlayer))return new mejs.MediaElementPlayer(a,b);this.$media=this.$node=f(a);
15
+ this.node=this.media=this.$media[0];if(typeof this.node.player!="undefined")return this.node.player;else this.node.player=this;if(typeof b=="undefined")b=this.$node.data("mejsoptions");this.options=f.extend({},mejs.MepDefaults,b);mejs.players.push(this);this.init();return this};mejs.MediaElementPlayer.prototype={hasFocus:false,controlsAreVisible:true,init:function(){var a=this,b=mejs.MediaFeatures,c=f.extend(true,{},a.options,{success:function(e,g){a.meReady(e,g)},error:function(e){a.handleError(e)}}),
16
+ d=a.media.tagName.toLowerCase();a.isDynamic=d!=="audio"&&d!=="video";a.isVideo=a.isDynamic?a.options.isVideo:d!=="audio"&&a.options.isVideo;if(b.isiPad&&a.options.iPadUseNativeControls||b.isiPhone&&a.options.iPhoneUseNativeControls){a.$media.attr("controls","controls");if(b.isiPad&&a.media.getAttribute("autoplay")!==null){a.media.load();a.media.play()}}else if(!(b.isAndroid&&a.AndroidUseNativeControls)){a.$media.removeAttr("controls");a.id="mep_"+mejs.mepIndex++;a.container=f('<div id="'+a.id+'" class="mejs-container"><div class="mejs-inner"><div class="mejs-mediaelement"></div><div class="mejs-layers"></div><div class="mejs-controls"></div><div class="mejs-clear"></div></div></div>').addClass(a.$media[0].className).insertBefore(a.$media);
17
+ a.container.addClass((b.isAndroid?"mejs-android ":"")+(b.isiOS?"mejs-ios ":"")+(b.isiPad?"mejs-ipad ":"")+(b.isiPhone?"mejs-iphone ":"")+(a.isVideo?"mejs-video ":"mejs-audio "));if(b.isiOS){b=a.$media.clone();a.container.find(".mejs-mediaelement").append(b);a.$media.remove();a.$node=a.$media=b;a.node=a.media=b[0]}else a.container.find(".mejs-mediaelement").append(a.$media);a.controls=a.container.find(".mejs-controls");a.layers=a.container.find(".mejs-layers");b=d.substring(0,1).toUpperCase()+d.substring(1);
18
+ a.width=a.options[d+"Width"]>0||a.options[d+"Width"].toString().indexOf("%")>-1?a.options[d+"Width"]:a.media.style.width!==""&&a.media.style.width!==null?a.media.style.width:a.media.getAttribute("width")!==null?a.$media.attr("width"):a.options["default"+b+"Width"];a.height=a.options[d+"Height"]>0||a.options[d+"Height"].toString().indexOf("%")>-1?a.options[d+"Height"]:a.media.style.height!==""&&a.media.style.height!==null?a.media.style.height:a.$media[0].getAttribute("height")!==null?a.$media.attr("height"):
19
+ a.options["default"+b+"Height"];a.setPlayerSize(a.width,a.height);c.pluginWidth=a.height;c.pluginHeight=a.width}mejs.MediaElement(a.$media[0],c)},showControls:function(a){var b=this;a=typeof a=="undefined"||a;if(!b.controlsAreVisible){if(a){b.controls.css("visibility","visible").stop(true,true).fadeIn(200,function(){b.controlsAreVisible=true});b.container.find(".mejs-control").css("visibility","visible").stop(true,true).fadeIn(200,function(){b.controlsAreVisible=true})}else{b.controls.css("visibility",
20
+ "visible").css("display","block");b.container.find(".mejs-control").css("visibility","visible").css("display","block");b.controlsAreVisible=true}b.setControlsSize()}},hideControls:function(a){var b=this;a=typeof a=="undefined"||a;if(b.controlsAreVisible)if(a){b.controls.stop(true,true).fadeOut(200,function(){f(this).css("visibility","hidden").css("display","block");b.controlsAreVisible=false});b.container.find(".mejs-control").stop(true,true).fadeOut(200,function(){f(this).css("visibility","hidden").css("display",
21
+ "block")})}else{b.controls.css("visibility","hidden").css("display","block");b.container.find(".mejs-control").css("visibility","hidden").css("display","block");b.controlsAreVisible=false}},controlsTimer:null,startControlsTimer:function(a){var b=this;a=typeof a!="undefined"?a:1500;b.killControlsTimer("start");b.controlsTimer=setTimeout(function(){b.hideControls();b.killControlsTimer("hide")},a)},killControlsTimer:function(){if(this.controlsTimer!==null){clearTimeout(this.controlsTimer);delete this.controlsTimer;
22
+ this.controlsTimer=null}},controlsEnabled:true,disableControls:function(){this.killControlsTimer();this.hideControls(false);this.controlsEnabled=false},enableControls:function(){this.showControls(false);this.controlsEnabled=true},meReady:function(a,b){var c=this,d=mejs.MediaFeatures,e=b.getAttribute("autoplay");e=!(typeof e=="undefined"||e===null||e==="false");var g;if(!c.created){c.created=true;c.media=a;c.domNode=b;if(!(d.isAndroid&&c.options.AndroidUseNativeControls)&&!(d.isiPad&&c.options.iPadUseNativeControls)&&
23
+ !(d.isiPhone&&c.options.iPhoneUseNativeControls)){c.buildposter(c,c.controls,c.layers,c.media);c.buildkeyboard(c,c.controls,c.layers,c.media);c.buildoverlays(c,c.controls,c.layers,c.media);c.findTracks();for(g in c.options.features){d=c.options.features[g];if(c["build"+d])try{c["build"+d](c,c.controls,c.layers,c.media)}catch(k){}}c.container.trigger("controlsready");c.setPlayerSize(c.width,c.height);c.setControlsSize();if(c.isVideo){if(mejs.MediaFeatures.hasTouch)c.$media.bind("touchstart",function(){if(c.controlsAreVisible)c.hideControls(false);
24
+ else c.controlsEnabled&&c.showControls(false)});else{(c.media.pluginType=="native"?c.$media:f(c.media.pluginElement)).click(function(){a.paused?a.play():a.pause()});c.container.bind("mouseenter mouseover",function(){if(c.controlsEnabled)if(!c.options.alwaysShowControls){c.killControlsTimer("enter");c.showControls();c.startControlsTimer(2500)}}).bind("mousemove",function(){if(c.controlsEnabled){c.controlsAreVisible||c.showControls();c.options.alwaysShowControls||c.startControlsTimer(2500)}}).bind("mouseleave",
25
+ function(){c.controlsEnabled&&!c.media.paused&&!c.options.alwaysShowControls&&c.startControlsTimer(1E3)})}e&&!c.options.alwaysShowControls&&c.hideControls();c.options.enableAutosize&&c.media.addEventListener("loadedmetadata",function(h){if(c.options.videoHeight<=0&&c.domNode.getAttribute("height")===null&&!isNaN(h.target.videoHeight)){c.setPlayerSize(h.target.videoWidth,h.target.videoHeight);c.setControlsSize();c.media.setVideoSize(h.target.videoWidth,h.target.videoHeight)}},false)}a.addEventListener("play",
26
+ function(){for(var h=0,o=mejs.players.length;h<o;h++){var n=mejs.players[h];n.id!=c.id&&c.options.pauseOtherPlayers&&!n.paused&&!n.ended&&n.pause();n.hasFocus=false}c.hasFocus=true},false);c.media.addEventListener("ended",function(){try{c.media.setCurrentTime(0)}catch(h){}c.media.pause();c.setProgressRail&&c.setProgressRail();c.setCurrentRail&&c.setCurrentRail();if(c.options.loop)c.media.play();else!c.options.alwaysShowControls&&c.controlsEnabled&&c.showControls()},false);c.media.addEventListener("loadedmetadata",
27
+ function(){c.updateDuration&&c.updateDuration();c.updateCurrent&&c.updateCurrent();if(!c.isFullScreen){c.setPlayerSize(c.width,c.height);c.setControlsSize()}},false);setTimeout(function(){c.setPlayerSize(c.width,c.height);c.setControlsSize()},50);f(window).resize(function(){c.isFullScreen||mejs.MediaFeatures.hasTrueNativeFullScreen&&document.webkitIsFullScreen||c.setPlayerSize(c.width,c.height);c.setControlsSize()});c.media.pluginType=="youtube"&&c.container.find(".mejs-overlay-play").hide()}if(e&&
28
+ a.pluginType=="native"){a.load();a.play()}if(c.options.success)typeof c.options.success=="string"?window[c.options.success](c.media,c.domNode,c):c.options.success(c.media,c.domNode,c)}},handleError:function(a){this.controls.hide();this.options.error&&this.options.error(a)},setPlayerSize:function(a,b){if(typeof a!="undefined")this.width=a;if(typeof b!="undefined")this.height=b;if(this.height.toString().indexOf("%")>0){var c=this.media.videoWidth&&this.media.videoWidth>0?this.media.videoWidth:this.options.defaultVideoWidth,
29
+ d=this.media.videoHeight&&this.media.videoHeight>0?this.media.videoHeight:this.options.defaultVideoHeight,e=this.container.parent().width();c=parseInt(e*d/c,10);if(this.container.parent()[0].tagName.toLowerCase()==="body"){e=f(window).width();c=f(window).height()}this.container.width(e).height(c);this.$media.width("100%").height("100%");this.container.find("object, embed, iframe").width("100%").height("100%");this.media.setVideoSize&&this.media.setVideoSize(e,c);this.layers.children(".mejs-layer").width("100%").height("100%")}else{this.container.width(this.width).height(this.height);
30
+ this.layers.children(".mejs-layer").width(this.width).height(this.height)}},setControlsSize:function(){var a=0,b=0,c=this.controls.find(".mejs-time-rail"),d=this.controls.find(".mejs-time-total");this.controls.find(".mejs-time-current");this.controls.find(".mejs-time-loaded");var e=c.siblings();if(this.options&&!this.options.autosizeProgress)b=parseInt(c.css("width"));if(b===0||!b){e.each(function(){if(f(this).css("position")!="absolute")a+=f(this).outerWidth(true)});b=this.controls.width()-a-(c.outerWidth(true)-
31
+ c.width())}c.width(b);d.width(b-(d.outerWidth(true)-d.width()));this.setProgressRail&&this.setProgressRail();this.setCurrentRail&&this.setCurrentRail()},buildposter:function(a,b,c,d){var e=f('<div class="mejs-poster mejs-layer"></div>').appendTo(c);b=a.$media.attr("poster");if(a.options.poster!=="")b=a.options.poster;b!==""&&b!=null?this.setPoster(b):e.hide();d.addEventListener("play",function(){e.hide()},false)},setPoster:function(a){var b=this.container.find(".mejs-poster"),c=b.find("img");if(c.length==
32
+ 0)c=f('<img width="100%" height="100%" />').appendTo(b);c.attr("src",a)},buildoverlays:function(a,b,c,d){if(a.isVideo){var e=f('<div class="mejs-overlay mejs-layer"><div class="mejs-overlay-loading"><span></span></div></div>').hide().appendTo(c),g=f('<div class="mejs-overlay mejs-layer"><div class="mejs-overlay-error"></div></div>').hide().appendTo(c),k=f('<div class="mejs-overlay mejs-layer mejs-overlay-play"><div class="mejs-overlay-button"></div></div>').appendTo(c).click(function(){d.paused?d.play():
33
+ d.pause()});d.addEventListener("play",function(){k.hide();e.hide();b.find(".mejs-time-buffering").hide();g.hide()},false);d.addEventListener("playing",function(){k.hide();e.hide();b.find(".mejs-time-buffering").hide();g.hide()},false);d.addEventListener("seeking",function(){e.show();b.find(".mejs-time-buffering").show()},false);d.addEventListener("seeked",function(){e.hide();b.find(".mejs-time-buffering").hide()},false);d.addEventListener("pause",function(){mejs.MediaFeatures.isiPhone||k.show()},
34
+ false);d.addEventListener("waiting",function(){e.show();b.find(".mejs-time-buffering").show()},false);d.addEventListener("loadeddata",function(){e.show();b.find(".mejs-time-buffering").show()},false);d.addEventListener("canplay",function(){e.hide();b.find(".mejs-time-buffering").hide()},false);d.addEventListener("error",function(){e.hide();b.find(".mejs-time-buffering").hide();g.show();g.find("mejs-overlay-error").html("Error loading this resource")},false)}},buildkeyboard:function(a,b,c,d){f(document).keydown(function(e){if(a.hasFocus&&
35
+ a.options.enableKeyboard)for(var g=0,k=a.options.keyActions.length;g<k;g++)for(var h=a.options.keyActions[g],o=0,n=h.keys.length;o<n;o++)if(e.keyCode==h.keys[o]){e.preventDefault();h.action(a,d);return false}return true});f(document).click(function(e){if(f(e.target).closest(".mejs-container").length==0)a.hasFocus=false})},findTracks:function(){var a=this,b=a.$media.find("track");a.tracks=[];b.each(function(c,d){d=f(d);a.tracks.push({srclang:d.attr("srclang").toLowerCase(),src:d.attr("src"),kind:d.attr("kind"),
36
+ label:d.attr("label")||"",entries:[],isLoaded:false})})},changeSkin:function(a){this.container[0].className="mejs-container "+a;this.setPlayerSize(this.width,this.height);this.setControlsSize()},play:function(){this.media.play()},pause:function(){this.media.pause()},load:function(){this.media.load()},setMuted:function(a){this.media.setMuted(a)},setCurrentTime:function(a){this.media.setCurrentTime(a)},getCurrentTime:function(){return this.media.currentTime},setVolume:function(a){this.media.setVolume(a)},
37
+ getVolume:function(){return this.media.volume},setSrc:function(a){this.media.setSrc(a)},remove:function(){if(this.media.pluginType=="flash")this.media.remove();else this.media.pluginType=="native"&&this.media.prop("controls",true);this.isDynamic||this.$node.insertBefore(this.container);this.container.remove()}};if(typeof jQuery!="undefined")jQuery.fn.mediaelementplayer=function(a){return this.each(function(){new mejs.MediaElementPlayer(this,a)})};f(document).ready(function(){f(".mejs-player").mediaelementplayer()});
38
+ window.MediaElementPlayer=mejs.MediaElementPlayer})(mejs.$);
39
+ (function(f){f.extend(mejs.MepDefaults,{playpauseText:"Play/Pause"});f.extend(MediaElementPlayer.prototype,{buildplaypause:function(a,b,c,d){var e=f('<div class="mejs-button mejs-playpause-button mejs-play" ><button type="button" aria-controls="'+this.id+'" title="'+this.options.playpauseText+'"></button></div>').appendTo(b).click(function(g){g.preventDefault();d.paused?d.play():d.pause();return false});d.addEventListener("play",function(){e.removeClass("mejs-play").addClass("mejs-pause")},false);
40
+ d.addEventListener("playing",function(){e.removeClass("mejs-play").addClass("mejs-pause")},false);d.addEventListener("pause",function(){e.removeClass("mejs-pause").addClass("mejs-play")},false);d.addEventListener("paused",function(){e.removeClass("mejs-pause").addClass("mejs-play")},false)}})})(mejs.$);
41
+ (function(f){f.extend(mejs.MepDefaults,{stopText:"Stop"});f.extend(MediaElementPlayer.prototype,{buildstop:function(a,b,c,d){f('<div class="mejs-button mejs-stop-button mejs-stop"><button type="button" aria-controls="'+this.id+'" title="'+this.options.stopText+'"></button></div>').appendTo(b).click(function(){d.paused||d.pause();if(d.currentTime>0){d.setCurrentTime(0);b.find(".mejs-time-current").width("0px");b.find(".mejs-time-handle").css("left","0px");b.find(".mejs-time-float-current").html(mejs.Utility.secondsToTimeCode(0));
42
+ b.find(".mejs-currenttime").html(mejs.Utility.secondsToTimeCode(0));c.find(".mejs-poster").show()}})}})})(mejs.$);
43
+ (function(f){f.extend(MediaElementPlayer.prototype,{buildprogress:function(a,b,c,d){f('<div class="mejs-time-rail"><span class="mejs-time-total"><span class="mejs-time-buffering"></span><span class="mejs-time-loaded"></span><span class="mejs-time-current"></span><span class="mejs-time-handle"></span><span class="mejs-time-float"><span class="mejs-time-float-current">00:00</span><span class="mejs-time-float-corner"></span></span></span></div>').appendTo(b);b.find(".mejs-time-buffering").hide();var e=
44
+ b.find(".mejs-time-total");c=b.find(".mejs-time-loaded");var g=b.find(".mejs-time-current"),k=b.find(".mejs-time-handle"),h=b.find(".mejs-time-float"),o=b.find(".mejs-time-float-current"),n=function(l){l=l.pageX;var q=e.offset(),i=e.outerWidth(),j=0;j=0;var m=l-q.left;if(l>q.left&&l<=i+q.left&&d.duration){j=(l-q.left)/i;j=j<=0.02?0:j*d.duration;p&&d.setCurrentTime(j);if(!mejs.MediaFeatures.hasTouch){h.css("left",m);o.html(mejs.Utility.secondsToTimeCode(j));h.show()}}},p=false;e.bind("mousedown",function(l){if(l.which===
45
+ 1){p=true;n(l);f(document).bind("mousemove.dur",function(q){n(q)}).bind("mouseup.dur",function(){p=false;h.hide();f(document).unbind(".dur")});return false}}).bind("mouseenter",function(){f(document).bind("mousemove.dur",function(l){n(l)});mejs.MediaFeatures.hasTouch||h.show()}).bind("mouseleave",function(){if(!p){f(document).unbind(".dur");h.hide()}});d.addEventListener("progress",function(l){a.setProgressRail(l);a.setCurrentRail(l)},false);d.addEventListener("timeupdate",function(l){a.setProgressRail(l);
46
+ a.setCurrentRail(l)},false);this.loaded=c;this.total=e;this.current=g;this.handle=k},setProgressRail:function(a){var b=a!=undefined?a.target:this.media,c=null;if(b&&b.buffered&&b.buffered.length>0&&b.buffered.end&&b.duration)c=b.buffered.end(0)/b.duration;else if(b&&b.bytesTotal!=undefined&&b.bytesTotal>0&&b.bufferedBytes!=undefined)c=b.bufferedBytes/b.bytesTotal;else if(a&&a.lengthComputable&&a.total!=0)c=a.loaded/a.total;if(c!==null){c=Math.min(1,Math.max(0,c));this.loaded&&this.total&&this.loaded.width(this.total.width()*
47
+ c)}},setCurrentRail:function(){if(this.media.currentTime!=undefined&&this.media.duration)if(this.total&&this.handle){var a=this.total.width()*this.media.currentTime/this.media.duration,b=a-this.handle.outerWidth(true)/2;this.current.width(a);this.handle.css("left",b)}}})})(mejs.$);
48
+ (function(f){f.extend(mejs.MepDefaults,{duration:-1,timeAndDurationSeparator:" <span> | </span> "});f.extend(MediaElementPlayer.prototype,{buildcurrent:function(a,b,c,d){f('<div class="mejs-time"><span class="mejs-currenttime">'+(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00")+"</span></div>").appendTo(b);this.currenttime=this.controls.find(".mejs-currenttime");d.addEventListener("timeupdate",function(){a.updateCurrent()},false)},buildduration:function(a,
49
+ b,c,d){if(b.children().last().find(".mejs-currenttime").length>0)f(this.options.timeAndDurationSeparator+'<span class="mejs-duration">'+(this.options.duration>0?mejs.Utility.secondsToTimeCode(this.options.duration,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25):(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00"))+"</span>").appendTo(b.find(".mejs-time"));else{b.find(".mejs-currenttime").parent().addClass("mejs-currenttime-container");
50
+ f('<div class="mejs-time mejs-duration-container"><span class="mejs-duration">'+(this.options.duration>0?mejs.Utility.secondsToTimeCode(this.options.duration,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25):(a.options.alwaysShowHours?"00:":"")+(a.options.showTimecodeFrameCount?"00:00:00":"00:00"))+"</span></div>").appendTo(b)}this.durationD=this.controls.find(".mejs-duration");d.addEventListener("timeupdate",function(){a.updateDuration()},
51
+ false)},updateCurrent:function(){if(this.currenttime)this.currenttime.html(mejs.Utility.secondsToTimeCode(this.media.currentTime,this.options.alwaysShowHours||this.media.duration>3600,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25))},updateDuration:function(){if(this.media.duration&&this.durationD)this.durationD.html(mejs.Utility.secondsToTimeCode(this.media.duration,this.options.alwaysShowHours,this.options.showTimecodeFrameCount,this.options.framesPerSecond||25))}})})(mejs.$);
52
+ (function(f){f.extend(mejs.MepDefaults,{muteText:"Mute Toggle",hideVolumeOnTouchDevices:true,audioVolume:"horizontal",videoVolume:"vertical"});f.extend(MediaElementPlayer.prototype,{buildvolume:function(a,b,c,d){if(!(mejs.MediaFeatures.hasTouch&&this.options.hideVolumeOnTouchDevices)){var e=this.isVideo?this.options.videoVolume:this.options.audioVolume,g=e=="horizontal"?f('<div class="mejs-button mejs-volume-button mejs-mute"><button type="button" aria-controls="'+this.id+'" title="'+this.options.muteText+
53
+ '"></button></div><div class="mejs-horizontal-volume-slider"><div class="mejs-horizontal-volume-total"></div><div class="mejs-horizontal-volume-current"></div><div class="mejs-horizontal-volume-handle"></div></div>').appendTo(b):f('<div class="mejs-button mejs-volume-button mejs-mute"><button type="button" aria-controls="'+this.id+'" title="'+this.options.muteText+'"></button><div class="mejs-volume-slider"><div class="mejs-volume-total"></div><div class="mejs-volume-current"></div><div class="mejs-volume-handle"></div></div></div>').appendTo(b),
54
+ k=this.container.find(".mejs-volume-slider, .mejs-horizontal-volume-slider"),h=this.container.find(".mejs-volume-total, .mejs-horizontal-volume-total"),o=this.container.find(".mejs-volume-current, .mejs-horizontal-volume-current"),n=this.container.find(".mejs-volume-handle, .mejs-horizontal-volume-handle"),p=function(j,m){if(!k.is(":visible")&&typeof m!="undefined"){k.show();p(j,true);k.hide()}else{j=Math.max(0,j);j=Math.min(j,1);j==0?g.removeClass("mejs-mute").addClass("mejs-unmute"):g.removeClass("mejs-unmute").addClass("mejs-mute");
55
+ if(e=="vertical"){var r=h.height(),s=h.position(),t=r-r*j;n.css("top",s.top+t-n.height()/2);o.height(r-t);o.css("top",s.top+t)}else{r=h.width();s=h.position();r=r*j;n.css("left",s.left+r-n.width()/2);o.width(r)}}},l=function(j){var m=null,r=h.offset();if(e=="vertical"){m=h.height();parseInt(h.css("top").replace(/px/,""),10);m=(m-(j.pageY-r.top))/m;if(r.top==0||r.left==0)return}else{m=h.width();m=(j.pageX-r.left)/m}m=Math.max(0,m);m=Math.min(m,1);p(m);m==0?d.setMuted(true):d.setMuted(false);d.setVolume(m)},
56
+ q=false,i=false;g.hover(function(){k.show();i=true},function(){i=false;!q&&e=="vertical"&&k.hide()});k.bind("mouseover",function(){i=true}).bind("mousedown",function(j){l(j);f(document).bind("mousemove.vol",function(m){l(m)}).bind("mouseup.vol",function(){q=false;f(document).unbind(".vol");!i&&e=="vertical"&&k.hide()});q=true;return false});g.find("button").click(function(){d.setMuted(!d.muted)});d.addEventListener("volumechange",function(){if(!q)if(d.muted){p(0);g.removeClass("mejs-mute").addClass("mejs-unmute")}else{p(d.volume);
57
+ g.removeClass("mejs-unmute").addClass("mejs-mute")}},false);if(this.container.is(":visible")){p(a.options.startVolume);d.pluginType==="native"&&d.setVolume(a.options.startVolume)}}}})})(mejs.$);
58
+ (function(f){f.extend(mejs.MepDefaults,{usePluginFullScreen:true,newWindowCallback:function(){return""},fullscreenText:"Fullscreen"});f.extend(MediaElementPlayer.prototype,{isFullScreen:false,isNativeFullScreen:false,docStyleOverflow:null,isInIframe:false,buildfullscreen:function(a,b,c,d){if(a.isVideo){a.isInIframe=window.location!=window.parent.location;if(mejs.MediaFeatures.hasTrueNativeFullScreen){c=null;c=mejs.MediaFeatures.hasMozNativeFullScreen?f(document):a.container;c.bind(mejs.MediaFeatures.fullScreenEventName,
59
+ function(){if(mejs.MediaFeatures.isFullScreen()){a.isNativeFullScreen=true;a.setControlsSize()}else{a.isNativeFullScreen=false;a.exitFullScreen()}})}var e=this,g=f('<div class="mejs-button mejs-fullscreen-button"><button type="button" aria-controls="'+e.id+'" title="'+e.options.fullscreenText+'"></button></div>').appendTo(b);if(e.media.pluginType==="native"||!e.options.usePluginFullScreen&&!mejs.MediaFeatures.isFirefox)g.click(function(){mejs.MediaFeatures.hasTrueNativeFullScreen&&mejs.MediaFeatures.isFullScreen()||
60
+ a.isFullScreen?a.exitFullScreen():a.enterFullScreen()});else{var k=null;b=function(){var i=document.createElement("x"),j=document.documentElement,m=window.getComputedStyle;if(!("pointerEvents"in i.style))return false;i.style.pointerEvents="auto";i.style.pointerEvents="x";j.appendChild(i);m=m&&m(i,"").pointerEvents==="auto";j.removeChild(i);return!!m}();console.log("supportsPointerEvents",b);if(b&&!mejs.MediaFeatures.isOpera){var h=false,o=function(){if(h){n.hide();p.hide();l.hide();g.css("pointer-events",
61
+ "");e.controls.css("pointer-events","");h=false}},n=f('<div class="mejs-fullscreen-hover" />').appendTo(e.container).mouseover(o),p=f('<div class="mejs-fullscreen-hover" />').appendTo(e.container).mouseover(o),l=f('<div class="mejs-fullscreen-hover" />').appendTo(e.container).mouseover(o),q=function(){var i={position:"absolute",top:0,left:0};n.css(i);p.css(i);l.css(i);n.width(e.container.width()).height(e.container.height()-e.controls.height());i=g.offset().left-e.container.offset().left;fullScreenBtnWidth=
62
+ g.outerWidth(true);p.width(i).height(e.controls.height()).css({top:e.container.height()-e.controls.height()});l.width(e.container.width()-i-fullScreenBtnWidth).height(e.controls.height()).css({top:e.container.height()-e.controls.height(),left:i+fullScreenBtnWidth})};f(document).resize(function(){q()});g.mouseover(function(){if(!e.isFullScreen){var i=g.offset(),j=a.container.offset();d.positionFullscreenButton(i.left-j.left,i.top-j.top,false);g.css("pointer-events","none");e.controls.css("pointer-events",
63
+ "none");n.show();l.show();p.show();q();h=true}});d.addEventListener("fullscreenchange",function(){o()})}else g.mouseover(function(){if(k!==null){clearTimeout(k);delete k}var i=g.offset(),j=a.container.offset();d.positionFullscreenButton(i.left-j.left,i.top-j.top,true)}).mouseout(function(){if(k!==null){clearTimeout(k);delete k}k=setTimeout(function(){d.hideFullscreenButton()},1500)})}a.fullscreenBtn=g;f(document).bind("keydown",function(i){if((mejs.MediaFeatures.hasTrueNativeFullScreen&&mejs.MediaFeatures.isFullScreen()||
64
+ e.isFullScreen)&&i.keyCode==27)a.exitFullScreen()})}},enterFullScreen:function(){var a=this;if(!(a.media.pluginType!=="native"&&(mejs.MediaFeatures.isFirefox||a.options.usePluginFullScreen))){docStyleOverflow=document.documentElement.style.overflow;document.documentElement.style.overflow="hidden";normalHeight=a.container.height();normalWidth=a.container.width();if(a.media.pluginType==="native")if(mejs.MediaFeatures.hasTrueNativeFullScreen){mejs.MediaFeatures.requestFullScreen(a.container[0]);a.isInIframe&&
65
+ setTimeout(function c(){if(a.isNativeFullScreen)f(window).width()!==screen.width?a.exitFullScreen():setTimeout(c,500)},500)}else if(mejs.MediaFeatures.hasSemiNativeFullScreen){a.media.webkitEnterFullscreen();return}if(a.isInIframe){var b=a.options.newWindowCallback(this);if(b!=="")if(mejs.MediaFeatures.hasTrueNativeFullScreen)setTimeout(function(){if(!a.isNativeFullScreen){a.pause();window.open(b,a.id,"top=0,left=0,width="+screen.availWidth+",height="+screen.availHeight+",resizable=yes,scrollbars=no,status=no,toolbar=no")}},
66
+ 250);else{a.pause();window.open(b,a.id,"top=0,left=0,width="+screen.availWidth+",height="+screen.availHeight+",resizable=yes,scrollbars=no,status=no,toolbar=no");return}}a.container.addClass("mejs-container-fullscreen").width("100%").height("100%");setTimeout(function(){a.container.css({width:"100%",height:"100%"});a.setControlsSize()},500);if(a.pluginType==="native")a.$media.width("100%").height("100%");else{a.container.find("object, embed, iframe").width("100%").height("100%");a.media.setVideoSize(f(window).width(),
67
+ f(window).height())}a.layers.children("div").width("100%").height("100%");a.fullscreenBtn&&a.fullscreenBtn.removeClass("mejs-fullscreen").addClass("mejs-unfullscreen");a.setControlsSize();a.isFullScreen=true}},exitFullScreen:function(){if(this.media.pluginType!=="native"&&mejs.MediaFeatures.isFirefox)this.media.setFullscreen(false);else{if(mejs.MediaFeatures.hasTrueNativeFullScreen&&(mejs.MediaFeatures.isFullScreen()||this.isFullScreen))mejs.MediaFeatures.cancelFullScreen();document.documentElement.style.overflow=
68
+ docStyleOverflow;this.container.removeClass("mejs-container-fullscreen").width(normalWidth).height(normalHeight);if(this.pluginType==="native")this.$media.width(normalWidth).height(normalHeight);else{this.container.find("object embed").width(normalWidth).height(normalHeight);this.media.setVideoSize(normalWidth,normalHeight)}this.layers.children("div").width(normalWidth).height(normalHeight);this.fullscreenBtn.removeClass("mejs-unfullscreen").addClass("mejs-fullscreen");this.setControlsSize();this.isFullScreen=
69
+ false}}})})(mejs.$);
70
+ (function(f){f.extend(mejs.MepDefaults,{startLanguage:"",tracksText:"Captions/Subtitles"});f.extend(MediaElementPlayer.prototype,{hasChapters:false,buildtracks:function(a,b,c,d){if(a.isVideo)if(a.tracks.length!=0){var e;a.chapters=f('<div class="mejs-chapters mejs-layer"></div>').prependTo(c).hide();a.captions=f('<div class="mejs-captions-layer mejs-layer"><div class="mejs-captions-position"><span class="mejs-captions-text"></span></div></div>').prependTo(c).hide();a.captionsText=a.captions.find(".mejs-captions-text");
71
+ a.captionsButton=f('<div class="mejs-button mejs-captions-button"><button type="button" aria-controls="'+this.id+'" title="'+this.options.tracksText+'"></button><div class="mejs-captions-selector"><ul><li><input type="radio" name="'+a.id+'_captions" id="'+a.id+'_captions_none" value="none" checked="checked" /><label for="'+a.id+'_captions_none">None</label></li></ul></div></div>').appendTo(b).hover(function(){f(this).find(".mejs-captions-selector").css("visibility","visible")},function(){f(this).find(".mejs-captions-selector").css("visibility",
72
+ "hidden")}).delegate("input[type=radio]","click",function(){lang=this.value;if(lang=="none")a.selectedTrack=null;else for(e=0;e<a.tracks.length;e++)if(a.tracks[e].srclang==lang){a.selectedTrack=a.tracks[e];a.captions.attr("lang",a.selectedTrack.srclang);a.displayCaptions();break}});a.options.alwaysShowControls?a.container.find(".mejs-captions-position").addClass("mejs-captions-position-hover"):a.container.bind("mouseenter",function(){a.container.find(".mejs-captions-position").addClass("mejs-captions-position-hover")}).bind("mouseleave",
73
+ function(){d.paused||a.container.find(".mejs-captions-position").removeClass("mejs-captions-position-hover")});a.trackToLoad=-1;a.selectedTrack=null;a.isLoadingTrack=false;for(e=0;e<a.tracks.length;e++)a.tracks[e].kind=="subtitles"&&a.addTrackButton(a.tracks[e].srclang,a.tracks[e].label);a.loadNextTrack();d.addEventListener("timeupdate",function(){a.displayCaptions()},false);d.addEventListener("loadedmetadata",function(){a.displayChapters()},false);a.container.hover(function(){if(a.hasChapters){a.chapters.css("visibility",
74
+ "visible");a.chapters.fadeIn(200).height(a.chapters.find(".mejs-chapter").outerHeight())}},function(){a.hasChapters&&!d.paused&&a.chapters.fadeOut(200,function(){f(this).css("visibility","hidden");f(this).css("display","block")})});a.node.getAttribute("autoplay")!==null&&a.chapters.css("visibility","hidden")}},loadNextTrack:function(){this.trackToLoad++;if(this.trackToLoad<this.tracks.length){this.isLoadingTrack=true;this.loadTrack(this.trackToLoad)}else this.isLoadingTrack=false},loadTrack:function(a){var b=
75
+ this,c=b.tracks[a],d=function(){c.isLoaded=true;b.enableTrackButton(c.srclang,c.label);b.loadNextTrack()};c.isTranslation?mejs.TrackFormatParser.translateTrackText(b.tracks[0].entries,b.tracks[0].srclang,c.srclang,b.options.googleApiKey,function(e){c.entries=e;d()}):f.ajax({url:c.src,success:function(e){c.entries=mejs.TrackFormatParser.parse(e);d();c.kind=="chapters"&&b.media.duration>0&&b.drawChapters(c)},error:function(){b.loadNextTrack()}})},enableTrackButton:function(a,b){if(b==="")b=mejs.language.codes[a]||
76
+ a;this.captionsButton.find("input[value="+a+"]").prop("disabled",false).siblings("label").html(b);this.options.startLanguage==a&&f("#"+this.id+"_captions_"+a).click();this.adjustLanguageBox()},addTrackButton:function(a,b){if(b==="")b=mejs.language.codes[a]||a;this.captionsButton.find("ul").append(f('<li><input type="radio" name="'+this.id+'_captions" id="'+this.id+"_captions_"+a+'" value="'+a+'" disabled="disabled" /><label for="'+this.id+"_captions_"+a+'">'+b+" (loading)</label></li>"));this.adjustLanguageBox();
77
+ this.container.find(".mejs-captions-translations option[value="+a+"]").remove()},adjustLanguageBox:function(){this.captionsButton.find(".mejs-captions-selector").height(this.captionsButton.find(".mejs-captions-selector ul").outerHeight(true)+this.captionsButton.find(".mejs-captions-translations").outerHeight(true))},displayCaptions:function(){if(typeof this.tracks!="undefined"){var a,b=this.selectedTrack;if(b!=null&&b.isLoaded)for(a=0;a<b.entries.times.length;a++)if(this.media.currentTime>=b.entries.times[a].start&&
78
+ this.media.currentTime<=b.entries.times[a].stop){this.captionsText.html(b.entries.text[a]);this.captions.show().height(0);return}this.captions.hide()}},displayChapters:function(){var a;for(a=0;a<this.tracks.length;a++)if(this.tracks[a].kind=="chapters"&&this.tracks[a].isLoaded){this.drawChapters(this.tracks[a]);this.hasChapters=true;break}},drawChapters:function(a){var b=this,c,d,e=d=0;b.chapters.empty();for(c=0;c<a.entries.times.length;c++){d=a.entries.times[c].stop-a.entries.times[c].start;d=Math.floor(d/
79
+ b.media.duration*100);if(d+e>100||c==a.entries.times.length-1&&d+e<100)d=100-e;b.chapters.append(f('<div class="mejs-chapter" rel="'+a.entries.times[c].start+'" style="left: '+e.toString()+"%;width: "+d.toString()+'%;"><div class="mejs-chapter-block'+(c==a.entries.times.length-1?" mejs-chapter-block-last":"")+'"><span class="ch-title">'+a.entries.text[c]+'</span><span class="ch-time">'+mejs.Utility.secondsToTimeCode(a.entries.times[c].start)+"&ndash;"+mejs.Utility.secondsToTimeCode(a.entries.times[c].stop)+
80
+ "</span></div></div>"));e+=d}b.chapters.find("div.mejs-chapter").click(function(){b.media.setCurrentTime(parseFloat(f(this).attr("rel")));b.media.paused&&b.media.play()});b.chapters.show()}});mejs.language={codes:{af:"Afrikaans",sq:"Albanian",ar:"Arabic",be:"Belarusian",bg:"Bulgarian",ca:"Catalan",zh:"Chinese","zh-cn":"Chinese Simplified","zh-tw":"Chinese Traditional",hr:"Croatian",cs:"Czech",da:"Danish",nl:"Dutch",en:"English",et:"Estonian",tl:"Filipino",fi:"Finnish",fr:"French",gl:"Galician",de:"German",
81
+ el:"Greek",ht:"Haitian Creole",iw:"Hebrew",hi:"Hindi",hu:"Hungarian",is:"Icelandic",id:"Indonesian",ga:"Irish",it:"Italian",ja:"Japanese",ko:"Korean",lv:"Latvian",lt:"Lithuanian",mk:"Macedonian",ms:"Malay",mt:"Maltese",no:"Norwegian",fa:"Persian",pl:"Polish",pt:"Portuguese",ro:"Romanian",ru:"Russian",sr:"Serbian",sk:"Slovak",sl:"Slovenian",es:"Spanish",sw:"Swahili",sv:"Swedish",tl:"Tagalog",th:"Thai",tr:"Turkish",uk:"Ukrainian",vi:"Vietnamese",cy:"Welsh",yi:"Yiddish"}};mejs.TrackFormatParser={pattern_identifier:/^([a-zA-z]+-)?[0-9]+$/,
82
+ pattern_timecode:/^([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{1,3})?) --\> ([0-9]{2}:[0-9]{2}:[0-9]{2}([,.][0-9]{3})?)(.*)$/,split2:function(a,b){return a.split(b)},parse:function(a){var b=0;a=this.split2(a,/\r?\n/);for(var c={text:[],times:[]},d,e;b<a.length;b++)if(this.pattern_identifier.exec(a[b])){b++;if((d=this.pattern_timecode.exec(a[b]))&&b<a.length){b++;e=a[b];for(b++;a[b]!==""&&b<a.length;){e=e+"\n"+a[b];b++}c.text.push(e);c.times.push({start:mejs.Utility.timeCodeToSeconds(d[1]),stop:mejs.Utility.timeCodeToSeconds(d[3]),
83
+ settings:d[5]})}}return c}};if("x\n\ny".split(/\n/gi).length!=3)mejs.TrackFormatParser.split2=function(a,b){var c=[],d="",e;for(e=0;e<a.length;e++){d+=a.substring(e,e+1);if(b.test(d)){c.push(d.replace(b,""));d=""}}c.push(d);return c}})(mejs.$);
84
+ (function(f){f.extend(mejs.MepDefaults,{contextMenuItems:[{render:function(a){if(typeof a.enterFullScreen=="undefined")return null;return a.isFullScreen?"Turn off Fullscreen":"Go Fullscreen"},click:function(a){a.isFullScreen?a.exitFullScreen():a.enterFullScreen()}},{render:function(a){return a.media.muted?"Unmute":"Mute"},click:function(a){a.media.muted?a.setMuted(false):a.setMuted(true)}},{isSeparator:true},{render:function(){return"Download Video"},click:function(a){window.location.href=a.media.currentSrc}}]});
85
+ f.extend(MediaElementPlayer.prototype,{buildcontextmenu:function(a){a.contextMenu=f('<div class="mejs-contextmenu"></div>').appendTo(f("body")).hide();a.container.bind("contextmenu",function(b){if(a.isContextMenuEnabled){b.preventDefault();a.renderContextMenu(b.clientX-1,b.clientY-1);return false}});a.container.bind("click",function(){a.contextMenu.hide()});a.contextMenu.bind("mouseleave",function(){a.startContextMenuTimer()})},isContextMenuEnabled:true,enableContextMenu:function(){this.isContextMenuEnabled=
86
+ true},disableContextMenu:function(){this.isContextMenuEnabled=false},contextMenuTimeout:null,startContextMenuTimer:function(){var a=this;a.killContextMenuTimer();a.contextMenuTimer=setTimeout(function(){a.hideContextMenu();a.killContextMenuTimer()},750)},killContextMenuTimer:function(){var a=this.contextMenuTimer;if(a!=null){clearTimeout(a);delete a}},hideContextMenu:function(){this.contextMenu.hide()},renderContextMenu:function(a,b){for(var c=this,d="",e=c.options.contextMenuItems,g=0,k=e.length;g<
87
+ k;g++)if(e[g].isSeparator)d+='<div class="mejs-contextmenu-separator"></div>';else{var h=e[g].render(c);if(h!=null)d+='<div class="mejs-contextmenu-item" data-itemindex="'+g+'" id="element-'+Math.random()*1E6+'">'+h+"</div>"}c.contextMenu.empty().append(f(d)).css({top:b,left:a}).show();c.contextMenu.find(".mejs-contextmenu-item").each(function(){var o=f(this),n=parseInt(o.data("itemindex"),10),p=c.options.contextMenuItems[n];typeof p.show!="undefined"&&p.show(o,c);o.click(function(){typeof p.click!=
88
+ "undefined"&&p.click(c);c.contextMenu.hide()})});setTimeout(function(){c.killControlsTimer("rev3")},100)}})})(mejs.$);
includes/media-element/mejs-skins.css ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* TED player */
2
+ .mejs-container.mejs-ted {
3
+
4
+ }
5
+ .mejs-ted .mejs-controls {
6
+ background: #eee;
7
+ height: 65px;
8
+ }
9
+
10
+ .mejs-ted .mejs-button,
11
+ .mejs-ted .mejs-time {
12
+ position: absolute;
13
+ background: #ddd;
14
+ }
15
+ .mejs-ted .mejs-controls .mejs-time-rail .mejs-time-total {
16
+ background-color: none;
17
+ background: url(controls-ted.png) repeat-x 0 -52px;
18
+ height: 6px;
19
+ }
20
+ .mejs-ted .mejs-controls .mejs-time-rail .mejs-time-loaded {
21
+ background-color: none;
22
+ background: url(controls-ted.png) repeat-x 0 -52px;
23
+ width: 0;
24
+ height: 6px;
25
+ }
26
+ .mejs-ted .mejs-controls .mejs-time-rail .mejs-time-current {
27
+ width: 0;
28
+ height: 6px;
29
+ background-color: none;
30
+ background: url(controls-ted.png) repeat-x 0 -59px;
31
+ }
32
+ .mejs-ted .mejs-controls .mejs-time-rail .mejs-time-handle {
33
+ display: block;
34
+ margin: 0;
35
+ width: 14px;
36
+ height: 21px;
37
+ top: -7px;
38
+ border: 0;
39
+ background: url(controls-ted.png) no-repeat 0 0;
40
+ }
41
+ .mejs-ted .mejs-controls .mejs-time-rail .mejs-time-float {
42
+ display: none;
43
+ }
44
+ .mejs-ted .mejs-controls .mejs-playpause-button {
45
+ top: 29px;
46
+ left: 9px;
47
+ width: 49px;
48
+ height: 28px;
49
+ }
50
+ .mejs-ted .mejs-controls .mejs-playpause-button button {
51
+ width: 49px;
52
+ height: 28px;
53
+ background: url(controls-ted.png) no-repeat -50px -23px;
54
+ margin: 0;
55
+ padding: 0;
56
+ }
57
+ .mejs-ted .mejs-controls .mejs-pause button {
58
+ background-position: 0 -23px;
59
+ }
60
+
61
+ .mejs-ted .mejs-controls .mejs-fullscreen-button {
62
+ top: 34px;
63
+ right: 9px;
64
+ width: 17px;
65
+ height: 15px;
66
+ background : none;
67
+ }
68
+ .mejs-ted .mejs-controls .mejs-fullscreen-button button {
69
+ width: 19px;
70
+ height: 17px;
71
+ background: transparent url(controls-ted.png) no-repeat 0 -66px;
72
+ margin: 0;
73
+ padding: 0;
74
+ }
75
+ .mejs-ted .mejs-controls .mejs-unfullscreen button {
76
+ background: transparent url(controls-ted.png) no-repeat -21px -66px;
77
+ margin: 0;
78
+ padding: 0;
79
+ }
80
+ .mejs-ted .mejs-controls .mejs-volume-button {
81
+ top: 30px;
82
+ right: 35px;
83
+ width: 24px;
84
+ height: 22px;
85
+ }
86
+ .mejs-ted .mejs-controls .mejs-mute button {
87
+ background: url(controls-ted.png) no-repeat -15px 0;
88
+ width: 24px;
89
+ height: 22px;
90
+ margin: 0;
91
+ padding: 0;
92
+ }
93
+ .mejs-ted .mejs-controls .mejs-unmute button {
94
+ background: url(controls-ted.png) no-repeat -40px 0;
95
+ width: 24px;
96
+ height: 22px;
97
+ margin: 0;
98
+ padding: 0;
99
+ }
100
+ .mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-slider {
101
+ background: #fff;
102
+ border: solid 1px #aaa;
103
+ border-width: 1px 1px 0 1px;
104
+ width: 22px;
105
+ height: 65px;
106
+ top: -65px;
107
+ }
108
+ .mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-total {
109
+ background: url(controls-ted.png) repeat-y -41px -66px;
110
+ left: 8px;
111
+ width: 6px;
112
+ height: 50px;
113
+ }
114
+ .mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-current {
115
+ left: 8px;
116
+ width: 6px;
117
+ background: url(controls-ted.png) repeat-y -48px -66px;
118
+ height: 50px;
119
+ }
120
+
121
+ .mejs-ted .mejs-controls .mejs-volume-button .mejs-volume-handle {
122
+ display: none;
123
+ }
124
+
125
+ .mejs-ted .mejs-controls .mejs-time span {
126
+ color: #333;
127
+ }
128
+ .mejs-ted .mejs-controls .mejs-currenttime-container {
129
+ position: absolute;
130
+ top: 32px;
131
+ right: 100px;
132
+ border: solid 1px #999;
133
+ background: #fff;
134
+ color: #333;
135
+ padding-top: 2px;
136
+ border-radius: 3px;
137
+ color: #333;
138
+ }
139
+ .mejs-ted .mejs-controls .mejs-duration-container {
140
+
141
+ position: absolute;
142
+ top: 32px;
143
+ right: 65px;
144
+ border: solid 1px #999;
145
+ background: #fff;
146
+ color: #333;
147
+ padding-top: 2px;
148
+ border-radius: 3px;
149
+ color: #333;
150
+ }
151
+
152
+ .mejs-ted .mejs-controls .mejs-time button{
153
+ color: #333;
154
+ }
155
+ .mejs-ted .mejs-controls .mejs-captions-button {
156
+ display: none;
157
+ }
158
+ /* END: TED player */
159
+
160
+
161
+ /* WMP player */
162
+ .mejs-container.mejs-wmp {
163
+
164
+ }
165
+ .mejs-wmp .mejs-controls {
166
+ background: transparent url(controls-wmp-bg.png) center 16px no-repeat;
167
+ height: 65px;
168
+ }
169
+
170
+ .mejs-wmp .mejs-button,
171
+ .mejs-wmp .mejs-time {
172
+ position: absolute;
173
+ background: transparent;
174
+ }
175
+ .mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-total {
176
+ background-color: transparent;
177
+ border: solid 1px #ccc;
178
+ height: 3px;
179
+ }
180
+ .mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-loaded {
181
+ background-color: rgba(255,255,255,0.3);
182
+ width: 0;
183
+ height: 3px;
184
+ }
185
+ .mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-current {
186
+ width: 0;
187
+ height: 1px;
188
+ background-color: #014CB6;
189
+ border: solid 1px #7FC9FA;
190
+ border-width: 1px 0;
191
+ border-color: #7FC9FA #fff #619FF2 #fff;
192
+ }
193
+ .mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-handle {
194
+ display: block;
195
+ margin: 0;
196
+ width: 16px;
197
+ height: 9px;
198
+ top: -3px;
199
+ border: 0;
200
+ background: url(controls-wmp.png) no-repeat 0 -80px;
201
+ }
202
+ .mejs-wmp .mejs-controls .mejs-time-rail .mejs-time-float {
203
+ display: none;
204
+ }
205
+ .mejs-wmp .mejs-controls .mejs-playpause-button {
206
+ top: 10px;
207
+ left: 50%;
208
+ margin: 10px 0 0 -20px;
209
+ width: 40px;
210
+ height: 40px;
211
+
212
+ }
213
+ .mejs-wmp .mejs-controls .mejs-playpause-button button {
214
+ width: 40px;
215
+ height: 40px;
216
+ background: url(controls-wmp.png) no-repeat 0 0;
217
+ margin: 0;
218
+ padding: 0;
219
+ }
220
+ .mejs-wmp .mejs-controls .mejs-pause button {
221
+ background-position: 0 -40px;
222
+ }
223
+
224
+ .mejs-wmp .mejs-controls .mejs-currenttime-container {
225
+ position: absolute;
226
+ top: 25px;
227
+ left: 50%;
228
+ margin-left: -93px;
229
+ }
230
+ .mejs-wmp .mejs-controls .mejs-duration-container {
231
+ position: absolute;
232
+ top: 25px;
233
+ left: 50%;
234
+ margin-left: -58px;
235
+ }
236
+
237
+
238
+ .mejs-wmp .mejs-controls .mejs-volume-button {
239
+ top: 32px;
240
+ right: 50%;
241
+ margin-right: -55px;
242
+ width: 20px;
243
+ height: 15px;
244
+ }
245
+ .mejs-wmp .mejs-controls .mejs-volume-button button {
246
+ margin: 0;
247
+ padding: 0;
248
+ background: url(controls-wmp.png) no-repeat -42px -17px;
249
+ width: 20px;
250
+ height: 15px;
251
+ }
252
+ .mejs-wmp .mejs-controls .mejs-unmute button {
253
+ margin: 0;
254
+ padding: 0;
255
+ background: url(controls-wmp.png) no-repeat -42px 0;
256
+ width: 20px;
257
+ height: 15px;
258
+ }
259
+ .mejs-wmp .mejs-controls .mejs-volume-button .mejs-volume-slider {
260
+ background: rgba(102,102,102,0.6);
261
+ }
262
+
263
+ .mejs-wmp .mejs-controls .mejs-fullscreen-button {
264
+ top: 32px;
265
+ right: 50%;
266
+ margin-right: -82px;
267
+ width: 15px;
268
+ height: 14px;
269
+ }
270
+ .mejs-wmp .mejs-controls .mejs-fullscreen-button button {
271
+ margin: 0;
272
+ padding: 0;
273
+ background: url(controls-wmp.png) no-repeat -63px 0;
274
+ width: 15px;
275
+ height: 14px;
276
+ }
277
+ .mejs-wmp .mejs-controls .mejs-captions-button {
278
+ display: none;
279
+ }
280
+ /* END: WMP player */
281
+
282
+
283
+
includes/media-element/silverlightmediaelement.xap ADDED
Binary file
loader.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: BuddyPress Media
4
+ Plugin URI: http://rtcamp.com/buddypress-media/
5
+ Description: This component adds missing media rich features like photos, videos and audios uploading to BuddyPress which are essential if you are building social network, seriously!
6
+ Version: 2.0
7
+ Author: rtCamp
8
+ Author URI: http://rtcamp.com
9
+ */
10
+
11
+ /* A constant that can be checked to see if the BP Media is installed or not. */
12
+ define('BP_MEDIA_IS_INSTALLED', 1);
13
+
14
+ /* Constant to store the current version of the BP Media Plugin. */
15
+ define('BP_MEDIA_VERSION', '2.0');
16
+
17
+ /* A constant to be used as base for other URLs throughout the plugin */
18
+ define('BP_MEDIA_PLUGIN_DIR', dirname(__FILE__));
19
+
20
+ /* A constant to store the Database Version of the BP Media Plugin */
21
+ define('BP_MEDIA_DB_VERSION', '1');
22
+
23
+ /**
24
+ * Function to initialize the BP Media Plugin
25
+ *
26
+ * It checks for the version minimum required version of buddypress before initializing.
27
+ *
28
+ * @uses BP_VERSION to check if the plugin supports the BuddyPress version.
29
+ *
30
+ * @since BP Media 2.0
31
+ */
32
+ function bp_media_init() {
33
+ if (version_compare(BP_VERSION, '1.5.5', '>')) {
34
+ require( BP_MEDIA_PLUGIN_DIR . '/includes/bp-media-loader.php' );
35
+ }
36
+ }
37
+ add_action('bp_include', 'bp_media_init');
38
+
39
+ /**
40
+ * Function to do the tasks required to be done while activating the plugin
41
+ */
42
+ function bp_media_activate() {
43
+ //todo
44
+ }
45
+ register_activation_hook(__FILE__, 'bp_media_activate');
46
+
47
+ /**
48
+ * Function to do the tasks during deactivation.
49
+ *
50
+ * Will Make this function to do the db deletion and other things that might have been created with the plugin.
51
+ */
52
+ function bp_media_deactivate() {
53
+ //todo
54
+ }
55
+ register_deactivation_hook(__FILE__, 'bp_media_deactivate');
56
+ ?>
readme.txt ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === BuddyPress Media Component ===
2
+ Contributors: rtcamp
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=9488824
4
+ Tags: BuddyPress, media, multimedia, audio, video, photo, images, upload, share, MediaElement.js
5
+ License: GPLv2 or later
6
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
7
+ Requires at least: 3.3.2
8
+ Tested up to: 3.4.1
9
+ Stable tag: 2.0
10
+
11
+ BuddyPress Media Component adds multimedia features to your BuddyPress based social network.
12
+
13
+ == Description ==
14
+ [BuddyPress Media Component](http://rtcamp.com/buddypress-media/) adds multimedia features to your BuddyPress based social network, so that your members can upload and share photos, audio and videos with their friends.
15
+
16
+ = Features =
17
+ * Images, Audio and Video Support
18
+ * Superior Performance
19
+ * HTML5 player with fall back
20
+ * Highly Scalable
21
+
22
+ == Installation ==
23
+ Install the plugin from the 'Plugins' section in your dashboard (Plugins > Add New > Search for BuddyPress Media).
24
+
25
+ Alternatively you can [download lastest version](http://downloads.wordpress.org/plugin/buddypress-media.2.0.zip) of BuddyPress Media Component plugin from the repository. Unzip it and upload it to the plugins folder of your WordPress installation (wp-content/plugins/ directory of your WordPress installation).
26
+
27
+ Activate it through the 'Plugins' section.
28
+
29
+ == Frequently Asked Questions ==
30
+ Please visit [BuddyPress Media Component's FAQ page](http://rtcamp.com/buddypress-media/faq/)
31
+
32
+ == Screenshots ==
33
+ Please visit [BuddyPress Media Component's Features page](http://rtcamp.com/buddypress-media/features/)
34
+
35
+ == Changelog ==
36
+
37
+ = 2.0 =
38
+ * Integration into BuddyPress Activities
39
+ * HTML5 Audio Tag Support (with fallback)
40
+ * HTML5 Video Tag Support (with fallback)