PluginProbe
WpStream – Live Streaming, Video on Demand, Pay Per View / 3.7
WpStream – Live Streaming, Video on Demand, Pay Per View v3.7
4.14.1 4.14.0 4.13.2 4.13.1 4.13 4.12.5 4.12.4 4.12.3 4.12.2 4.12.1 4.12 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 4.5 4.5.1 4.5.11 4.5.11.1 4.5.11.2 4.5.11.4 4.5.11.5 4.5.11.6 All 181 releases
← All changes | includes/class-wpstream-player.php +715 -525 4.14.1 → 3.7 View file →
@@ -1,310 +1,219 @@
1 1 <?php
2 2
3 +/*
4 + * To change this license header, choose License Headers in Project Properties.
5 + * To change this template file, choose Tools | Templates
6 + * and open the template in the editor.
7 + */
8 +
9 +
3 10 /**
4 - * Front-end video player for WpStream live channels and video-on-demand.
11 + * Description of class-wpstream-player
5 12 *
6 - * This class is the WordPress and backwards-compatibility facade: it hooks
7 - * the_content, decides whether the current user is entitled to watch, preserves
8 - * the established public renderer methods, and exposes the status-poll AJAX
9 - * endpoint. Wpstream_Playback_Presentation owns source resolution, engine
10 - * selection, assets, and viewer-facing player markup.
11 - *
12 - * Live status is fetched from the WpStream cloud API and cached in a 45-second
13 - * transient so repeated polls do not hammer the remote service.
14 - *
15 - * @package Wpstream
16 - * @subpackage Wpstream/includes
17 - * @author cretu
13 + * @author cretu
18 14 */
19 -
20 -// Exit if accessed directly.
21 -if ( ! defined( 'ABSPATH' ) ) {
22 - exit;
23 -}
24 -
25 15 class Wpstream_Player{
26 - /** @var object Main plugin instance; exposes shared services (live connection, quota manager). */
27 - public $main;
28 -
29 - /**
30 - * @var Wpstream_Playback_Session Helper that issues/validates playback sessions for encrypted streams.
31 - */
32 - public $playback_session;
33 -
34 - /**
35 - * Wire up the player: keep a handle on the plugin, load the playback-session
36 - * helper, and register the content filter, purchase check, and status-poll
37 - * AJAX endpoints (both logged-in and nopriv).
38 - *
39 - * @param object $plugin_main Main plugin instance passed in by the loader.
40 - */
41 16 public function __construct($plugin_main) {
42 - // Keep a reference to the main plugin so we can reach its services later.
43 17 $this->main = $plugin_main;
44 -
45 - // Instantiate the playback-session helper (used for encrypted streams).
46 - $this->playback_session = new Wpstream_Playback_Session();
47 -
48 - // Inject the player markup into single wpstream product/VOD pages.
18 +
49 19 add_filter( 'the_content',array($this, 'wpstream_filter_the_title') );
50 - // On a WooCommerce single product, render the player only if the visitor already bought it.
51 20 add_action( 'woocommerce_before_single_product', array($this,'wpstream_user_logged_in_product_already_bought') );
52 -
53 - // Front-end status poll endpoint for logged-in users.
54 - add_action( 'wp_ajax_wpstream_player_check_status', array($this,'wpstream_player_check_status') );
55 - // Same endpoint for logged-out visitors (nopriv) so public streams can poll too.
21 +
22 + add_action( 'wp_ajax_wpstream_player_check_status', array($this,'wpstream_player_check_status') );
56 23 add_action('wp_ajax_nopriv_wpstream_player_check_status', array($this,'wpstream_player_check_status'));
57 -
24 +
25 +
26 + add_action( 'wp_ajax_wpstream_force_clear_transient', array($this,'wpstream_force_clear_transient') );
27 + add_action('wp_ajax_nopriv_wpstream_force_clear_transient', array($this,'wpstream_force_clear_transient'));
28 +
29 +
58 30 }
59 31
60 32
61 33
62 -
34 + /**
35 + * clear status transients
36 + *
37 + * @author cretu
38 + */
63 39
40 +
41 + public function wpstream_force_clear_transient($event_id){
42 +
43 + $transient_name = 'event_data_to_return_'.$event_id;
44 + delete_transient($transient_name);
45 + update_post_meta($event_id,'statsUrl','');
46 + update_post_meta($event_id,'chatUrl','');
64 47
48 + }
49 +
50 +
51 +
65 52 /**
66 - * AJAX endpoint: report whether a channel is currently live and, if so, its
67 - * playback/stats/chat URLs. Called repeatedly by the front-end player JS.
68 - *
69 - * The posted id must be a published streaming channel or it is rejected
70 - * before any work. Reads the channel status from a 45-second transient; on
71 - * a cache miss it calls the WpStream cloud API and refreshes the transient.
72 - * Liveness is public, but the playback/stats/chat URLs are returned only to
73 - * callers who pass the player-render entitlement check; the response always
74 - * carries exactly the five keys the player JS reads. Echoes a JSON payload
75 - * and dies. No nonce check on purpose (see inline note) because the hosting
76 - * page may be cached, which would invalidate the nonce.
77 - *
78 - * edited 4.0
79 - *
80 - * @return void Outputs JSON and terminates the request.
81 - * @author cretu
82 - */
53 + * check player status
54 + *
55 + * @author cretu
56 + */
57 +
83 58 public function wpstream_player_check_status(){
84 - // did not add a nonce check here because this is a call done from the frontend
85 - // and the page might be cached, so the nonce would not be valid
86 - // Which channel/post the caller is asking about.
87 - $channel_id = intval($_POST['channel_id']);
59 + $event_id = intval($_POST['event_id']);
60 + $show_id=$event_id;
61 + $transient_name = 'event_data_to_return_'.$event_id;
62 + $event_data_for_transient = get_transient( $transient_name );
63 +
88 64
89 - // Reject anything that is not a published streaming channel BEFORE any
90 - // cache read, remote API call or meta write: the id must be a wpstream
91 - // live/VOD post, or a WooCommerce product carrying one of the wpstream
92 - // product types. This stops arbitrary-id probing from reaching the API
93 - // or touching unrelated posts' meta.
94 - $channel_post = get_post( $channel_id );
95 - $is_valid_channel = false;
96 - if ( $channel_post instanceof WP_Post && 'publish' === $channel_post->post_status ) {
97 - if ( in_array( $channel_post->post_type, array( 'wpstream_product', 'wpstream_product_vod' ), true ) ) {
98 - $is_valid_channel = true;
99 - } elseif ( 'product' === $channel_post->post_type
100 - && has_term( array( 'live_stream', 'video_on_demand', 'subscription' ), 'product_type', $channel_post ) ) {
101 - $is_valid_channel = true;
65 +
66 + if ( false === $event_data_for_transient || $event_data_for_transient=='' ) { //ws || $hls_to_return==''
67 +
68 + $server_id = ''; // server id IS blank - need to retrive it
69 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
70 +
71 + if($server_id==''){
72 + update_post_meta($show_id,'server_id', '' );
73 +
74 + $server_id =$this->main->wpstream_live_connection->retrive_server_id_based_on_show_id($show_id);
75 +
102 76 }
103 - }
104 - if ( ! $is_valid_channel ) {
105 - ob_end_clean();
106 - wp_send_json_error( array( 'message' => esc_html__( 'Invalid channel.', 'wpstream' ) ), 400 );
107 - }
77 +
78 +
79 +
80 + update_post_meta($show_id,'server_id', $server_id );
81 + $values_array=array(
82 + "server_id" => esc_html($server_id),
83 + 'from_where' => 'wpstream_check_event_status_front_player'
84 + );
85 +
86 + if($server_id==''){
87 + $this->main->wpstream_live_connection->wpstream_reset_event_data($show_id);
88 + //print 'failed connection';
89 + return;
90 + }
91 +
92 +
93 +
94 + $url=WPSTREAM_CLUBLINKSSL."://www.".WPSTREAM_CLUBLINK."/wp-json/rcapi/v1/api20-livestrem/event_status/?access_token=".$token;
95 + $arguments = array(
96 + 'method' => 'GET',
97 + 'timeout' => 45,
98 + 'redirection' => 5,
99 + 'httpversion' => '1.0',
100 + 'blocking' => true,
101 + 'headers' => array(),
102 + 'body' => $values_array,
103 + 'cookies' => array()
104 + );
108 105
109 - // Channel state (cache, Baker fetch on miss, fresh-data meta sync) is
110 - // owned by Wpstream_Channel_State — the poll only asks questions of it.
111 - $state = Wpstream_Channel_State::for_channel( $channel_id, 'wpstream_player_check_status_note_from_js' );
106 + $response = wp_remote_post($url,$arguments);
107 + $received_data = wp_remote_retrieve_body($response);
112 108
113 - // Live means playable: upstream status active AND a playback URL present.
114 - if ( $state->is_live() ) {
109 + if( isset($response['response']['code']) && $response['response']['code']=='200'){
110 + $received_data_encoded=json_decode($received_data,true);
111 +
112 + if( isset($received_data_encoded['success']) && intval( $received_data_encoded['success'] ) ==1 ){
113 +
114 + /*
115 + * we set transient and return the array saved
116 + * false if no data
117 + *
118 + * */
119 + $event_data_for_transient= $this->main->wpstream_live_connection->api20_wpstream_update_event($received_data_encoded,$show_id,$server_id);
120 + }else{
121 + $this->main->wpstream_live_connection->wpstream_reset_event_data($show_id);
122 + }
123 +
124 + }else{
125 + $this->main->wpstream_live_connection->wpstream_reset_event_data($show_id);
126 + }
127 +
128 +
115 129
116 - // Entitlement gate: playback/stats/chat URLs go only to
117 - // callers who pass the same check that decides whether the player
118 - // renders at all (free wpstream post types for anyone; WooCommerce
119 - // products only for buyers / active subscribers / bundle owners).
120 - // Liveness itself stays visible so a paywall page can reflect it.
121 - $viewer_is_entitled = wpstream_user_entitled_for_product( $channel_id );
122 -
123 - // cleanup any previous echo before sending json
124 - ob_end_clean();
125 - // Both branches return exactly the keys the player JS reads —
126 - // never the raw upstream payload or any debug field.
127 - if ( $viewer_is_entitled ) {
128 - echo json_encode( array(
129 - 'started' => 'yes',
130 - 'channel_id' => $channel_id,
131 - 'event_uri' => $state->playback_url(),
132 - 'live_conect_views' => $state->stats_url(),
133 - 'chat_url' => $state->chat_url(),
134 - ));
135 - } else {
136 - // Unentitled caller: same JSON shape, real liveness, but every
137 - // URL field empty.
138 - echo json_encode( array(
139 - 'started' => 'yes',
140 - 'channel_id' => $channel_id,
141 - 'event_uri' => '',
142 - 'live_conect_views' => '',
143 - 'chat_url' => '',
144 - ));
130 +
131 + if ( false === $event_data_for_transient || $event_data_for_transient=='' ){
132 + //we are not live
133 + $event_data_for_transient=array();
134 + $event_data_for_transient['hlsPlaybackUrl']='';
135 +
145 136 }
146 -
137 + }
138 +
139 +
140 +
141 + // 1==2 &&
142 +
143 + if( $event_data_for_transient['hlsPlaybackUrl']!=''){
144 + echo json_encode( array(
145 +
146 + 'started' => 'yes',
147 + 'server_id' => $event_data_for_transient['server_id'],
148 + 'event_id' => $event_id,
149 + 'event_uri' => $event_data_for_transient['hlsPlaybackUrl'],
150 + 'live_conect_views' => $event_data_for_transient['statsUrl'],
151 + 'chat_url' => $event_data_for_transient['chatUrl'],
152 +
153 + ));
147 154 }else{
148 - // Channel is not live: return a "started: no" payload with empty
149 - // URLs, in the same five-key shape as the live branch.
150 - // cleanup any previous echo before sending json
151 - ob_end_clean();
152 155 echo json_encode( array(
153 156 'started' => 'no',
154 - 'channel_id' => $channel_id,
157 + 'server_id' => $server_id,
158 + 'event_id' => $event_id,
155 159 'event_uri' => '',
156 160 'live_conect_views' => '',
157 161 'chat_url' => '',
162 +
158 163 ));
159 -
164 + $this->wpstream_force_clear_transient($event_id);
160 165 }
161 -
162 - // AJAX response is complete; stop execution so nothing else is appended.
163 166 die();
164 167 }
165 -
166 -
167 -
168 +
169 +
170 +
168 171 /**
169 - * the_content filter: prepend the player markup to single live/VOD product pages.
172 + * Insert player in page
170 173 *
171 - * @param string $content The post content WordPress is about to render.
172 - * @return string Content with the player div prepended, or unchanged.
173 174 * @author cretu
174 175 */
175 176 public function wpstream_filter_the_title( $content ) {
176 - // Only inject on single WpStream live-product or VOD-product pages.
177 - if( is_singular('wpstream_product') || is_singular('wpstream_product_vod') ){
177 + if( is_singular('wpstream_product')){
178 178 global $post;
179 - // The theme may own the player placement and switch the injection off.
180 - if ( ! $this->auto_insert_enabled( intval( $post->ID ), 'the_content' ) ) {
181 - return $content;
182 - }
183 - // Build the player HTML for the current post and prepend it to the content.
184 179 $args=array('id'=>$post->ID);
185 180 $custom_content = $this->wpstream_insert_player_inpage($args);
186 181 $content = '<div class="wpestream_inserted_player">'.$custom_content.'</div>'.$content;
187 182 return $content;
188 183 }else{
189 - // Not a player page: return content untouched.
190 184 return $content;
191 185 }
192 186 }
193 187
194 188 /**
195 - * Decide whether the plugin injects its player automatically into a page.
196 - *
197 - * Themes that render the player in their own templates switch this off.
198 - * Replaces the `wpstream_remove_wpstream_filter()` function-name sniff,
199 - * which is honoured as the default for one more release.
200 - *
201 - * @param int $post_id Post the page is about.
202 - * @param string $context `the_content` or `woocommerce_before_single_product`.
203 - * @return bool
204 - */
205 - private function auto_insert_enabled( $post_id, $context ) {
206 - // One-release shim: a theme defining the legacy opt-out function still opts out.
207 - $enabled = ! function_exists( 'wpstream_remove_wpstream_filter' );
208 -
209 - /**
210 - * Filter whether the plugin inserts its player into the page automatically.
211 - *
212 - * Only the automatic placements (post content, WooCommerce single product)
213 - * are affected; shortcodes and builder widgets always render.
214 - *
215 - * @since 4.14.0
216 - *
217 - * @param bool $enabled Whether to insert the player.
218 - * @param int $post_id Post the page is about.
219 - * @param string $context `the_content` or `woocommerce_before_single_product`.
220 - */
221 - return (bool) apply_filters( 'wpstream_player_auto_insert', $enabled, $post_id, $context );
222 - }
223 -
224 - /**
225 - * Build the access notice shown in place of the player.
226 - *
227 - * @param string $reason `nobuy`, `nolog` or `sub_active`.
228 - * @param int $product_id Product the notice is about.
229 - * @param string $message Configured wording for the reason.
230 - * @param string $wrapper_class Extra class on the outer wrapper (shortcode placement).
231 - * @param string $notice_style Inline style kept by the shortcode placement.
232 - * @return string Notice markup.
233 - */
234 - private function not_entitled_notice( $reason, $product_id, $message, $wrapper_class = '', $notice_style = '' ) {
235 - /**
236 - * Filter the wording of the access notice shown in place of the player.
237 - *
238 - * @since 4.14.0
239 - *
240 - * @param string $message Plain-text message (not yet escaped).
241 - * @param int $product_id Product the notice is about.
242 - * @param string $reason `nobuy`, `nolog` or `sub_active` — the entitlement path,
243 - * not the wording (global-subscription sites show the
244 - * "not subscribed" text under `nobuy`).
245 - */
246 - $message = (string) apply_filters( 'wpstream_player_not_entitled_message', $message, $product_id, $reason );
247 -
248 - // Assemble the block with the message escaped; the style is a plugin constant.
249 - $style = '' !== $notice_style ? ' style="' . esc_attr( $notice_style ) . '"' : '';
250 - $html = '<div class="wpstream_player_wrapper ' . esc_attr( trim( $wrapper_class . ' no_buy' ) ) . '"><div class="wpstream_player_container">'
251 - . '<div class="wpstream_notice"' . $style . '>' . esc_html( $message ) . '</div>'
252 - . '</div></div>';
253 -
254 - /**
255 - * Filter the whole access notice block shown in place of the player.
256 - *
257 - * The default markup is already escaped; callbacks own the escaping of
258 - * anything they add. This decides presentation only — entitlement was
259 - * refused before this point and is not revisited.
260 - *
261 - * @since 4.14.0
262 - *
263 - * @param string $html Notice markup.
264 - * @param int $product_id Product the notice is about.
265 - * @param string $reason `nobuy`, `nolog` or `sub_active` (the entitlement path).
266 - */
267 - return (string) apply_filters( 'wpstream_player_not_entitled_html', $html, $product_id, $reason );
268 - }
269 -
270 - /**
271 - * Build the player HTML for a shortcode/embed and return it as a string.
189 + * Insert player in page
272 190 *
273 - * Buffers the echoed player markup so it can be returned instead of printed.
274 - *
275 - * @param array $attributes Shortcode attributes; 'id' selects the product.
276 - * @param string|null $content Unused enclosed shortcode content.
277 - * @return string The captured player markup.
278 191 * @author cretu
279 192 */
193 +
280 194 public function wpstream_insert_player_inpage($attributes, $content = null){
281 195 $product_id = '';
282 196 $return_string = '';
283 - // Normalise the incoming attributes against the supported defaults.
284 - $attributes = shortcode_atts(
197 + $attributes = shortcode_atts(
285 198 array(
286 199 'id' => 0,
287 200 ), $attributes) ;
288 201
289 202
290 - // Take the product id from the attributes when present.
291 203 if ( isset($attributes['id']) ){
292 204 $product_id=$attributes['id'];
293 205 }
294 -
295 - // No explicit id: fall back to the first available product id. The
296 - // lookup lives on the main plugin class, not on this player service.
206 +
297 207 if(intval($product_id)==0){
298 - $product_id= $this->main->wpstream_player_retrieve_first_id();
208 + $product_id= $this->wpstream_player_retrive_first_id();
299 209 }
300 210
301 - // Capture everything the shortcode renderer echoes into a string.
302 211 ob_start();
303 -
212 +
304 213 $this->wpstream_video_player_shortcode($product_id);
305 214 $return_string= ob_get_contents();
306 - ob_end_clean();
215 + ob_end_clean();
307 216
308 217 return $return_string;
309 218 }
310 219
@@ -311,71 +220,70 @@
311 220
312 221
313 222
314 223 /**
315 - * Render the player for a product, gated by login and purchase entitlement.
224 + * Video Player shortcode
316 225 *
317 - * Picks the live or VOD renderer based on product type / taxonomy term, and
318 - * shows a "not purchased" / "must log in" notice when the visitor is not
319 - * entitled to watch.
320 - *
321 - * @param string|int $from_sh_id Product/post id to render.
322 - * @return void Echoes the player markup or an access notice.
323 226 * @author cretu
324 227 */
228 +
325 229 public function wpstream_video_player_shortcode($from_sh_id='') {
326 - // disable cache in order to be able to check the nonce
327 - if ( !defined( 'DONOTCACHEPAGE' ) ) {
328 - define( 'DONOTCACHEPAGE', true );
329 - }
330 230
331 - $product_id = intval( $from_sh_id );
332 - $product_post = get_post( $product_id );
333 - if ( ! $product_post instanceof WP_Post
334 - || ( 'publish' !== $product_post->post_status && ! current_user_can( 'read_post', $product_id ) ) ) {
335 - return;
336 - }
231 + if ( is_user_logged_in() ) {
232 + global $product;
233 + $current_user = wp_get_current_user();
234 + $product_id = intval($from_sh_id);
337 235
338 - // Player depends on Video.js plus the WpStream player glue script (+styles).
339 - wpstream_enqueue_player_assets();
340 236
341 - if ( is_user_logged_in() ) {
342 - // Logged-in branch: gather the identifier needed to check entitlement.
343 - // Entitlement gate: the single shared rule (free type / purchase /
344 - // active subscription / bundle / Netflix mode).
345 - if ( wpstream_user_entitled_for_product( $product_id ) ){
346 - // Open the player wrapper markup.
237 + if ( ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) && wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product_id) ) || get_post_type($product_id)=='wpstream_product' ){
238 + global $product;
347 239 echo '<div class="wpstream_player_wrapper wpstream_player_shortcode"><div class="wpstream_player_container">';
348 - echo $this->main->playback_presentation->render( $product_id, 'auto' );
349 - // Close the player wrapper markup.
240 +
241 +
242 + if( get_post_type($product_id) == 'wpstream_product' ){
243 +
244 + $wpstream_product_type = esc_html(get_post_meta($product_id, 'wpstream_product_type', true));
245 + if($wpstream_product_type==1){
246 + $this->wpstream_live_event_player($product_id);
247 + } else if($wpstream_product_type==2 || $wpstream_product_type==3){
248 + $this->wpstream_video_on_demand_player($product_id);
249 + }
250 +
251 + }else{
252 + $term_list = wp_get_post_terms($product_id, 'product_type');
253 + $is_subscription_live_event = esc_html(get_post_meta($product_id,'_subscript_live_event',true));
254 +
255 + if( $term_list[0]->name=='live_stream' || ( $term_list[0]->name=='subscription' && $is_subscription_live_event=='yes' ) ){
256 + $this->wpstream_live_event_player($product_id);
257 + }else if( $term_list[0]->name=='video_on_demand' || ($term_list[0]->name=='subscription' && $is_subscription_live_event=='no' ) ){
258 + $this->wpstream_video_on_demand_player($product_id);
259 + }
260 + }
261 +
262 +
350 263 echo '</div></div>';
351 264 }else{
352 - // Logged in but not entitled: show a "not purchased" notice for paid products.
265 +
353 266 if( get_post_type($product_id) == 'product' ){
354 - $message = (string) get_option( 'wpstream_product_not_bought', 'You did not yet purchase this item.' );
355 - echo $this->not_entitled_notice( 'nobuy', $product_id, $message, 'wpstream_player_shortcode', 'background:#e16767;' );
267 + echo '<div class="wpstream_player_wrapper wpstream_player_shortcode no_buy"><div class="wpstream_player_container">';
268 + echo '<div class="wpstream_notice" style="background:#e16767;">'.esc_html__('You did not buy this product!','wpstream').'</div>';
269 + echo '</div></div>';
356 270 }
357 271 }
358 272
273 +
274 + }else{
275 +
276 + $product_id = intval($from_sh_id);
277 + if( get_post_type($product_id) == 'wpstream_product' ){
359 278
360 - }else{
361 - // Logged-out branch. Stable type slug is '' when the product has no term.
362 - $product_type_slug = wpstream_get_product_type_slug($product_id);
279 + $wpstream_product_type = esc_html(get_post_meta($product_id, 'wpstream_product_type', true));
280 + if($wpstream_product_type==1){
281 + $this->wpstream_live_event_player($product_id);
282 + } else if($wpstream_product_type==2 || $wpstream_product_type==3){
283 + $this->wpstream_video_on_demand_player($product_id);
284 + }
363 285
364 - if( get_post_type($product_id) == 'product' && ($product_type_slug=='live_stream' || $product_type_slug=='video_on_demand') ){
365 - // Paid live/VOD product requires login: show a "must log in" notice.
366 - $message = (string) get_option( 'wpstream_product_not_login', 'You must be logged in to watch this video.' );
367 - echo $this->not_entitled_notice( 'nolog', $product_id, $message, 'wpstream_player_shortcode', 'background:#e16767;' );
368 - }elseif( get_post_type($product_id) == 'wpstream_product' ){
369 - // Free live product is watchable without login.
370 - echo '<div class="wpstream_player_wrapper wpstream_player_shortcode"><div class="wpstream_player_container">';
371 - echo $this->main->playback_presentation->render( $product_id, 'auto' );
372 - echo '</div></div>';
373 - } else if( get_post_type($product_id) == 'wpstream_product_vod' ){
374 - // Free VOD product is watchable without login.
375 - echo '<div class="wpstream_player_wrapper wpstream_player_shortcode"><div class="wpstream_player_container">';
376 - echo $this->main->playback_presentation->render( $product_id, 'auto' );
377 - echo '</div></div>';
378 286 }
379 287 }
380 288 }
381 289
@@ -381,107 +289,439 @@
381 289
382 290
383 291
384 292 /**
385 - * Strip a leading http:// or https:// scheme from a URL.
293 + * Video Player shortcode - low latency
386 294 *
387 - * @param string $url URL to normalise.
388 - * @return string URL without its leading scheme, or unchanged if none matched.
389 295 * @author cretu
390 296 */
391 - function remove_http($url) { return $this->main->playback_presentation->remove_http( $url ); }
392 297
298 + public function wpstream_video_player_shortcode_low_latency($from_sh_id='') {
299 +
300 + if ( is_user_logged_in() ) {
301 + global $product;
302 + $current_user = wp_get_current_user();
303 + $product_id = intval($from_sh_id);
304 +
305 +
306 + if ( ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) && wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product_id) ) || get_post_type($product_id)=='wpstream_product' ){
307 + global $product;
308 + echo '<div class="wpstream_player_wrapper wpstream_player_shortcode"><div class="wpstream_player_container">';
309 +
310 +
311 + if( get_post_type($product_id) == 'wpstream_product' ){
312 +
313 + $wpstream_product_type = esc_html(get_post_meta($product_id, 'wpstream_product_type', true));
314 + if($wpstream_product_type==1){
315 + $this->wpstream_live_event_player_low_latency($product_id);
316 + }
317 +
318 + }else{
319 + $term_list = wp_get_post_terms($product_id, 'product_type');
320 + $is_subscription_live_event = esc_html(get_post_meta($product_id,'_subscript_live_event',true));
321 +
322 + if( $term_list[0]->name=='live_stream' || ( $term_list[0]->name=='subscription' && $is_subscription_live_event=='yes' ) ){
323 + $this->wpstream_live_event_player_low_latency($product_id);
324 + }
325 + }
326 +
327 +
328 + echo '</div></div>';
329 + }else{
330 +
331 + if( get_post_type($product_id) == 'product' ){
332 + echo '<div class="wpstream_player_wrapper wpstream_player_shortcode no_buy"><div class="wpstream_player_container">';
333 + echo '<div class="wpstream_notice" style="background:#e16767;">'.esc_html__('You did not buy this product!','wpstream').'</div>';
334 + echo '</div></div>';
335 + }
336 + }
337 +
338 +
339 + }else{
340 + $product_id = intval($from_sh_id);
341 + if( get_post_type($product_id) == 'wpstream_product' ){
342 +
343 + $wpstream_product_type = esc_html(get_post_meta($product_id, 'wpstream_product_type', true));
344 + if($wpstream_product_type==1){
345 + $this->wpstream_live_event_player_low_latency($product_id);
346 + }
347 + }
348 + }
349 + }
350 +
351 +
352 +
353 +
354 +
393 355 /**
394 - * Derive the "live connect" stats URI from an event-status payload.
356 + * Live Event Player
395 357 *
396 - * @deprecated Kept because separately-installed themes may call it; the
397 - * derivation now lives in Wpstream_Channel_State.
398 - * @param array $event_status Status data from the cloud API.
399 - * @return string The stats URL, a host derived from the playback URL, or ''.
358 + * @author cretu
400 359 */
401 - function wpstream_get_live_connect_uri($event_status) {
402 - return Wpstream_Channel_State::derive_stats_url( $event_status );
360 + function remove_http($url) {
361 + $disallowed = array('http://', 'https://');
362 + foreach($disallowed as $d) {
363 + if(strpos($url, $d) === 0) {
364 + return str_replace($d, '', $url);
365 + }
366 + }
367 + return $url;
403 368 }
404 -
369 +
370 +
405 371 /**
406 - * Resolve the effective event settings for a product: per-event options when
407 - * enabled, otherwise the site-wide global channel options.
372 + * Live Event Player
408 373 *
409 - * @param int $product_id Product/channel id.
410 - * @return mixed The per-event options array, or the global options.
411 374 * @author cretu
412 375 */
413 - function wpstream_return_event_settings($product_id){ return $this->main->playback_presentation->wpstream_return_event_settings( $product_id ); }
376 +
377 + function wpstream_live_event_player($product_id,$poster_show='',$use_chat=''){
378 + $live_event_uri = get_post_meta($product_id,'live_event_uri',true);
379 + $api20_event_id = get_post_meta($product_id,'server_id',true);
380 +
381 + $thumb_id = get_post_thumbnail_id($product_id);
382 + $thumb = wp_get_attachment_image_src($thumb_id,'small');
414 383
415 - /**
416 - * Deprecated misspelled alias of wpstream_return_event_settings().
417 - *
418 - * Kept because the method is public and may be called by external code.
419 - *
420 - * @deprecated 4.13.4 Use wpstream_return_event_settings() instead.
421 - */
422 - function wpestream_return_event_settings($product_id){ return $this->wpstream_return_event_settings( $product_id ); }
384 + $chatUrl= get_post_meta($product_id,'statsUrl',true);
385 +
386 +
387 + $live_event_uri_final = $this->wpstream_request_hls_player_dynamic('',$product_id);// buleala lu Gabi
388 + $now = time().rand(0,10);
389 + $live_conect_array = explode('live.streamer.wpstream.net',$live_event_uri_final);
390 + $live_conect_views = $live_conect_array[0].'live.streamer.wpstream.net';
391 + $live_conect_views = $this->remove_http($live_conect_views);
392 + $usernamestream = esc_html ( get_option('wpstream_api_username','') );
393 +
394 + echo '<div class="wpstream_live_player_wrapper" data-now="'.$now.'" data-me="'.esc_attr($usernamestream).'" data-product-id="'.$product_id.'" id="wpstream_live_player_wrapper'.$now.'" > '
395 + . '<div id="wpestream_live_counting" class="wpestream_live_counting"></div>';
396 +
397 + $show_wpstream_not_live_mess=' style="display:none;" ';
398 + if(trim($live_event_uri_final) ==''){
399 + $show_wpstream_not_live_mess='';
400 + }
401 +
402 +
403 + print '<div class="wpstream_not_live_mess " '.$show_wpstream_not_live_mess.' ><div class="wpstream_not_live_mess_back"></div><div class="wpstream_not_live_mess_mess">'.esc_html__('We are not live at this moment. Please check back later.','wpstream').'</div></div>';
404 +
405 +
406 + $poster_data=' poster="'.$thumb[0].'" ';
407 + if($poster_show=='no'){
408 + $poster_data='';
409 + }
410 +
411 + echo'
412 + <video id="wpstream-video'.$now.'" '.$poster_data.' class="video-js vjs-default-skin vjs-16-9" playsinline="true" controls>
413 + <source
414 + src="'.$live_event_uri_final.'"
415 + type="application/x-mpegURL">
416 + </video>';
423 417
418 + print '<script type="text/javascript">
419 + //<![CDATA[
420 + jQuery(document).ready(function(){
421 + wpstream_player_initialize("'.$now.'","'.$live_event_uri_final.'","'.$live_conect_views.'");';
422 + print'});
423 + //]]>
424 + </script>';
425 + print '</div>';
426 +
427 +
428 + if(trim($live_event_uri_final) ==''){
429 + // $show_wpstream_not_live_mess='';
430 + }else{
431 + print '<script type="text/javascript">
432 + //<![CDATA[
433 + jQuery(document).ready(function(){
434 + var player_wrapper = jQuery(".wpstream_live_player_wrapper");
435 + wpstream_read_websocket_info("'.$product_id.'","wpstream_live_player_wrapper'.$now.'", player_wrapper ,"'.$chatUrl.'", "'.$live_event_uri_final.'");
436 + });
437 + //]]>
438 + </script>';
439 + }
440 +
441 +
442 + if($use_chat=="yes"){
443 + $this->wpstream_connect_to_chat($product_id);
444 + }
445 +
446 + usleep (10000);
447 +
448 + }
449 +
450 +
451 +
424 452 /**
425 - * Render the live event player for a channel.
453 + * Live Event Player
426 454 *
427 - * Fetches channel status from the cloud API (cached 45s in a transient),
428 - * then renders either the legacy Video.js markup or, when the channel has an
429 - * embedUrl, the newer iframe-based player with a minted embed key.
430 - *
431 - * edited in 4.0
432 - *
433 - * @param int $channel_id Channel/post id.
434 - * @param string $poster_show Pass 'no' to suppress the poster image.
435 - * @return void Echoes the player markup.
436 455 * @author cretu
437 456 */
438 - function wpstream_live_event_player($channel_id,$poster_show=''){ $this->main->playback_presentation->wpstream_live_event_player( $channel_id, $poster_show ); }
457 +
458 + function wpstream_live_event_player_low_latency($product_id,$poster_show='',$use_chat=''){
459 + $live_event_uri = get_post_meta($product_id,'live_event_uri',true);
460 + $api20_event_id = get_post_meta($product_id,'server_id',true);
461 +
462 + $thumb_id = get_post_thumbnail_id($product_id);
463 + $thumb = wp_get_attachment_image_src($thumb_id,'small');
439 464
465 + $chatUrl= get_post_meta($product_id,'statsUrl',true);
466 +
467 +
468 + //$live_event_uri_final = $this->wpstream_request_hls_player_dynamic('',$product_id);// buleala lu Gabi
469 +
470 +
471 + $live_event_uri_final= get_post_meta($product_id,'sldpPlaybackUrl',true);
472 + $now = time().rand(0,10);
473 +
474 + $usernamestream = esc_html ( get_option('wpstream_api_username','') );
475 +
476 +
477 +
478 +
479 + echo '<div class="wpstream_live_player_wrapper wpstream_low_latency" data-now="'.$now.'" data-me="'.esc_attr($usernamestream).'" data-product-id="'.$product_id.'" id="wpstream_live_player_wrapper'.$now.'" > '
480 + . '<div id="wpestream_live_counting" class="wpestream_live_counting"></div>';
481 +
482 + $show_wpstream_not_live_mess=' style="display:none;" ';
483 + if(trim($live_event_uri_final) ==''){
484 + $show_wpstream_not_live_mess='';
485 + }
486 +
487 +
488 + print '<div class="wpstream_not_live_mess " '.$show_wpstream_not_live_mess.' ><div class="wpstream_not_live_mess_back"></div><div class="wpstream_not_live_mess_mess">'.esc_html__('We are not live at this moment. Please check back later.','wpstream').'</div></div>';
489 +
490 +
491 + $poster_data=' poster="'.$thumb[0].'" ';
492 + if($poster_show=='no'){
493 + $poster_data='';
494 + }
495 +
496 +
497 + echo'
498 + <div iccd="player" id="wpstream-video'.$now.'" '.$poster_data.' class="" >
499 + </div>';
500 +
501 + print '<script type="text/javascript">
502 + //<![CDATA[
503 + jQuery(document).ready(function(){
504 + var low_latencyid="wpstream-video'.$now.'";
505 + document.addEventListener("DOMContentLoaded", initPlayer(low_latencyid,"'.$live_event_uri_final.'") ); ';
506 + print'});
507 + //]]>
508 + </script>';
509 +
510 +
511 +
512 + if(trim($live_event_uri_final) ==''){
513 + // $show_wpstream_not_live_mess='';
514 + }else{
515 + print '<script type="text/javascript">
516 + //<![CDATA[
517 + jQuery(document).ready(function(){
518 + var player_wrapper = jQuery(".wpstream_live_player_wrapper");
519 + wpstream_read_websocket_info("'.$product_id.'","wpstream_live_player_wrapper'.$now.'", player_wrapper ,"'.$chatUrl.'", "'.$live_event_uri_final.'");
520 + });
521 + //]]>
522 + </script>';
523 + }
524 +
525 +
526 + if($use_chat=="yes"){
527 + $this->wpstream_connect_to_chat($product_id);
528 + }
529 +
530 + usleep (10000);
531 +
532 + }
533 +
534 +
440 535
441 - /*
442 - * Ask the cloud API for a VOD's HLS manifest URL (and DRM keys/embed data).
536 + /**
537 + * HLS PLAYER
443 538 *
444 - * Persists a 5-minute transient of the HLS URL and stores decryption keys /
445 - * embed metadata as post meta. Note: the transient read is immediately
446 - * overwritten with false below, so the API is currently queried every call.
447 - *
448 - * @param string $video_name Remote video name/identifier.
449 - * @param int $product_id Product/post to store the resulting meta on.
450 - * @return string HLS URL on success, '' on failure.
539 + * @author cretu
451 540 */
452 - public function wpstream_request_video_on_demand_hls_player($video_name,$product_id){ return $this->main->playback_presentation->wpstream_request_video_on_demand_hls_player( $video_name, $product_id ); }
541 + public function wpstream_request_hls_player_dynamic($server_id,$product_id){
542 +
543 + $transient_name = 'hls_to_return_'.$product_id;
544 + $hls_to_return = get_transient( $transient_name );
453 545
546 + if ( false === $hls_to_return || $hls_to_return=='' ) { //ws || $hls_to_return==''
547 +
548 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
549 + $values_array = array();
550 + $values_array['server_id'] = $server_id;
551 +
552 + if($server_id==''){
553 + $this->main->wpstream_live_connection->wpstream_check_event_status_front_player($product_id,$server_id);
554 + $server_id = get_post_meta($product_id,'server_id', true );
555 + $values_array['server_id'] = $server_id;
556 + }
557 +
558 +
559 + if($server_id==''){
560 + delete_transient($transient_name);
561 + return '';exit();
562 + }
563 +
564 + $url = WPSTREAM_CLUBLINKSSL."://www.".WPSTREAM_CLUBLINK."/wp-json/rcapi/v1/api20-livestrem/ap20_get_player_hls_dynamic/?access_token=".$token;
565 +
566 +
567 + $arguments = array(
568 + 'method' => 'GET',
569 + 'timeout' => 45,
570 + 'redirection' => 5,
571 + 'httpversion' => '1.0',
572 + 'blocking' => true,
573 + 'headers' => array(),
574 + 'body' => $values_array,
575 + 'cookies' => array()
576 + );
577 + $response = wp_remote_post($url,$arguments);
578 +
579 + $received_data = json_decode( wp_remote_retrieve_body($response) ,true);
580 +
581 +
582 +
583 +
584 + if( isset($response['response']['code']) && $response['response']['code']=='200'){
585 + $hls_to_return = trim($received_data);
586 +
587 +
588 + set_transient( $transient_name, $hls_to_return, 60 );
589 + return $hls_to_return;
590 + }else{
591 + return 'failed connection';
592 + }
593 + exit();
594 + }else{
595 + return $hls_to_return;
596 + }
597 +
598 + }
599 +
600 +
601 +
454 602 /**
455 - * Resolve the CSS class for the configured Video.js theme/skin.
603 + * HLS PLAYER
456 604 *
457 - * Enqueues the theme stylesheet as a side effect. Streamify users get no theme.
458 - *
459 - * @param int|null $channel_id Channel/product id (used for the streamify check).
460 - * @return string A 'vjs-theme-*' class, or '' when no theme applies.
605 + * @author cretu
461 606 */
462 - function wpstream_get_player_theme( $channel_id = null ) { return $this->main->playback_presentation->wpstream_get_player_theme( $channel_id ); }
607 +
463 608
464 - /**
465 - * Enqueue the bundled Video.js theme stylesheet for the selected skin.
466 - *
467 - * @param string $player_theme Theme slug (skips the built-in 'default').
468 - * @return void
469 - */
470 - function wpstream_enqueue_player_theme_style( $player_theme ) { $this->main->playback_presentation->wpstream_enqueue_player_theme_style( $player_theme ); }
609 + public function wpstream_request_hls_player($product_id){
610 +
611 + $transient_name = 'hls_to_return_'.$product_id;
612 + $hls_to_return = get_transient( $transient_name );
471 613
614 + if ( false === $hls_to_return || $hls_to_return=='' ) {
615 +
616 + $show_id = intval($product_id);
617 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
618 + $values_array = array();
619 + $values_array['show_id'] = $show_id;
620 +
621 + $url = WPSTREAM_CLUBLINKSSL."://www.".WPSTREAM_CLUBLINK."/wp-json/rcapi/v1/videos/ap20_get_player_hls/?access_token=".$token;
622 +
623 +
624 + $arguments = array(
625 + 'method' => 'GET',
626 + 'timeout' => 45,
627 + 'redirection' => 5,
628 + 'httpversion' => '1.0',
629 + 'blocking' => true,
630 + 'headers' => array(),
631 + 'body' => $values_array,
632 + 'cookies' => array()
633 + );
634 + $response = wp_remote_post($url,$arguments);
635 +
636 + $received_data = json_decode( wp_remote_retrieve_body($response) ,true);
637 +
638 +
639 +
640 + if( isset($response['response']['code']) && $response['response']['code']=='200'){
641 + $hls_to_return = trim($received_data);
642 + set_transient( $transient_name, $hls_to_return, 60 );
643 + return $hls_to_return = trim($received_data);
644 + }else{
645 + return 'failed connection';
646 + }
647 + exit();
648 + }else{
649 + return $hls_to_return;
650 + }
651 +
652 + }
653 +
654 +
655 +
472 656 /**
473 - * Resolve the VOD source URL and type for a product.
657 + * VODPlayer uri details
474 658 *
475 - * Encrypted VODs (and WooCommerce products) get an HLS manifest fetched
476 - * from the cloud API; unencrypted VODs use the stored external/local URL.
477 - *
478 - * @param int $product_id Product/post id.
479 - * @return array Keys: video_path_final, wpstream_data_setup, video_type,
480 - * free_video_type, post_type.
481 659 * @author cretu
482 660 */
483 - public function wpstream_video_on_demand_player_uri_request($product_id){ return $this->main->playback_presentation->resolve_vod_source( $product_id ); }
661 + public function wpstream_video_on_demand_player_uri_request($product_id){
662 +
663 + $wpstream_data_setup = ' data-setup="{}" ';
664 +
665 + /* free_video_type
666 + * 1 - free live channel
667 + * 2 - free video encrypted
668 + * 3 - free video -not encrypted
669 + */
670 + $free_video_type = intval( get_post_meta($product_id, 'wpstream_product_type', true));
671 +
672 +
673 + if($free_video_type==2 || get_post_type($product_id)=='product' ){
674 +
675 + /* IF vide is encrypted- readed from vod,streaner
676 + */
677 +
678 + $video_type = 'application/x-mpegURL';
679 + $video_path = get_post_meta($product_id,'_movie_url',true);
680 + if(get_post_type($product_id)=='wpstream_product'){
681 + $video_path = esc_html(get_post_meta($product_id, 'wpstream_free_video', true));
682 + }
683 +
684 + $username = esc_html ( get_option('wpstream_api_username','') );
685 + if (filter_var($username, FILTER_VALIDATE_EMAIL)) {
686 + $username = $this->wpstream_retrive_username();
687 + }
688 +
689 + if(strpos($username,'@')!=false){
690 + $username_array= explode('@', $username);
691 + $username=$username_array[0];
692 + }
693 +
694 + $video_path_final = 'https://vod.streamer.wpstream.net/'.$username.'/'.$video_path.'/index.m3u8?'.get_site_url();
695 + if(!is_ssl()){
696 + $video_path_final = 'http://vod.streamer.wpstream.net/'.$username.'/'.$video_path.'/index.m3u8?'.get_site_url();
697 + }
698 +
699 + }else if($free_video_type==3){
700 +
701 + /* Video is unecrypted - read from local or youtube / vimeo
702 + */
703 +
704 + $video_type = 'video/mp4';
705 + $video_path_final=esc_html(get_post_meta($product_id, 'wpstream_free_video_external', true));
706 +
707 + if (strpos($video_path_final, 'www.youtube') !== false) {
708 + $wpstream_data_setup= ' data-setup=\'{ "techOrder": ["youtube"], "sources": [{ "type": "video/youtube", "src": "'.$video_path_final.'"}] }\' ';
709 + $video_path_final='';
710 + }
711 + if (strpos($video_path_final, 'vimeo.com') !== false) {
712 + $wpstream_data_setup= ' data-setup=\'{"techOrder": ["vimeo"], "sources": [{ "type": "video/vimeo", "src": "'.$video_path_final.'"}], "vimeo": { "color": "#fbc51b"} }\' ';
713 + $video_path_final='';
714 + }
715 +
716 + }
717 +
718 + $return_array=array();
719 + $return_array['video_path_final'] = $video_path_final;
720 + $return_array['wpstream_data_setup']= $wpstream_data_setup;
721 + $return_array['video_type'] = $video_type;
722 + return $return_array;
723 + }
484 724
485 725
486 726
487 727 /**
@@ -489,219 +729,169 @@
489 729 *
490 730 * @author cretu
491 731 */
492 732
493 - public function wpstream_video_on_demand_player($product_id){ $this->main->playback_presentation->wpstream_video_on_demand_player( $product_id ); }
733 + public function wpstream_video_on_demand_player($product_id){
734 +
735 + $uri_details = $this->wpstream_video_on_demand_player_uri_request($product_id);
736 + $video_path_final = $uri_details['video_path_final'];
737 + $wpstream_data_setup = $uri_details['wpstream_data_setup'];
738 + $video_type = $uri_details['video_type'];
739 +
740 + $thumb_id = get_post_thumbnail_id($product_id);
741 + $thumb = wp_get_attachment_image_src($thumb_id,'small');
742 + $usernamestream = esc_html ( get_option('wpstream_api_username','') );
743 +
744 + $pack = $this->main->wpstream_live_connection->wpstream_request_pack_data_per_user();
745 +
746 + if($pack['band']>0){
747 + echo '<video id="wpstream-video'.time().'" class="video-js vjs-default-skin vjs-16-9 kuk wpstream_video_on_demand" data-me="'.esc_attr($usernamestream).'" data-product-id="'.$product_id.'" controls preload="auto"
748 + poster="'.$thumb[0].'" '.$wpstream_data_setup.'>
494 749
750 + <source src="'.trim($video_path_final).'" type="'.$video_type.'">
751 + <p class="vjs-no-js">
752 + To view this video please enable JavaScript, and consider upgrading to a web browser that
753 + <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
754 + </p>
755 + </video>';
756 + }else{
757 + print esc_html_e('Insufficient resources to stream this title','wpstream');
758 + }
495 759
760 + }
761 +
762 +
496 763
764 +
765 +
766 +
497 767 /**
498 - * Render a VOD player that shows only the trailer (used by the theme).
768 + * Retreive username for vod path
499 769 *
500 - * No main video source is set; playback is limited to the trailer plus
501 - * its play/mute/unmute controls.
502 - *
503 - * @param int $product_id Product/post id.
504 - * @return void Echoes the trailer-only player markup.
505 770 * @author cretu
506 771 */
507 - public function wpstream_video_on_demand_player_only_trailer($product_id){ $this->main->playback_presentation->wpstream_video_on_demand_player_only_trailer( $product_id ); }
772 + private function wpstream_retrive_username(){
773 + $token = $this->main->wpstream_live_connection->wpstream_get_token();
508 774
509 - /**
510 - * Decide whether the current user may watch the given product.
511 - *
512 - * @deprecated Kept as a compatibility shim for separately-installed themes
513 - * that call it; the rule itself lives in wpstream_user_entitled_for_product()
514 - * (includes/Helpers/wpstream-entitlement.php). New code calls the helper.
515 - *
516 - * @param int $product_id Product id.
517 - * @return bool True when the user is entitled to watch.
518 - * @since 3.12
519 - */
520 - public function wpstream_check_if_player_can_dsplay($product_id){
521 - // Delegate to the single entitlement rule.
522 - return wpstream_user_entitled_for_product( $product_id );
523 - }
524 -
525 -
526 -
527 - /**
528 - * Theme variant of the entitlement check.
529 - *
530 - * @deprecated Kept as a compatibility shim for separately-installed themes
531 - * that call it; the rule itself lives in wpstream_user_entitled_for_product()
532 - * (includes/Helpers/wpstream-entitlement.php). New code calls the helper.
533 - *
534 - * @param int $product_id Product/post id.
535 - * @return bool True when the player may be displayed.
536 - * @since 3.12
537 - */
538 - public function wpstream_check_if_player_can_dsplay_theme($product_id){
539 - // Delegate to the single entitlement rule.
540 - return wpstream_user_entitled_for_product( $product_id );
775 + $url=WPSTREAM_CLUBLINKSSL."://www.".WPSTREAM_CLUBLINK."/wp-json/rcapi/v1/return_login/?access_token=".$token;
776 + $arguments = array(
777 + 'method' => 'GET',
778 + 'timeout' => 45,
779 + 'redirection' => 5,
780 + 'httpversion' => '1.0',
781 + 'blocking' => true,
782 + 'headers' => array(),
783 + 'cookies' => array()
784 + );
785 + $response = wp_remote_post($url,$arguments);
786 + $received_data = json_decode( wp_remote_retrieve_body($response) ,true);
787 + if( isset($response['response']['code']) && $response['response']['code']=='200'){
788 + return ($received_data); die();
789 + }else{
790 + print 'Failed to conbect media server';
791 + die();
792 + }
541 793 }
542 -
543 -
544 - /**
545 - * Check the global-subscription entitlement for a product (Netflix mode).
546 - *
547 - * @deprecated Logic moved to wpstream_user_has_qualifying_global_subscription()
548 - * (includes/Helpers/wpstream-entitlement.php); kept as a compatibility shim
549 - * for external callers.
550 - *
551 - * @param int $product_id Product id.
552 - * @return bool True when the user has a qualifying active subscription.
553 - * @since 3.12
554 - */
555 - public function wpstream_in_plugin_check_global_subscription_model($product_id) {
556 - // Delegate to the moved Netflix-mode leg of the entitlement rule.
557 - return wpstream_user_has_qualifying_global_subscription( $product_id );
558 - }
559 794
560 795
561 796
562 797
563 798
564 -
565 -
566 -
567 -
568 799 /**
569 - *
570 - *
571 - *
572 - *
573 - * check if the user bought the product and display the player - TO REDo
574 - *
575 - * @since 3.0.1
800 + * check if the user bought the product and display the player - TO REDo
801 + *
802 + * @since 3.0.1
576 803 * returns html of the player
577 - *
578 - *
579 - *
580 - *
581 - *
582 - */
583 - public function wpstream_user_logged_in_product_already_bought($from_sh_id='') {
584 - // Work against the current WooCommerce product on the page.
585 - global $product;
586 - if ( ! $product instanceof WC_Product ) {
587 - return;
588 - }
589 - $product_id = $product->get_id();
590 - $current_user = wp_get_current_user();
591 - // The theme may own the player placement and switch the injection off.
592 - if ( ! $this->auto_insert_enabled( intval( $product_id ), 'woocommerce_before_single_product' ) ) {
593 - return;
594 - }
595 - // Stable type slug is '' when the product has no term (never a crash).
596 - $product_type_slug = wpstream_get_product_type_slug($product_id);
804 + */
805 + public function wpstream_user_logged_in_product_already_bought($from_sh_id='') {
597 806
598 - // A "simple subscription" (neither live nor VOD) has no player here.
599 - $is_simple_subscription = get_post_meta($product_id, '_subscript_live_event');
600 - if ( $product_type_slug == 'subscription' && ! empty( $is_simple_subscription ) && $is_simple_subscription[0] == 'none' ) {
601 - return;
602 - }
807 + if ( is_user_logged_in() ) {
808 + global $product;
809 + $current_user = wp_get_current_user();
810 + $product_id = $product->get_id();
603 811
604 - if ( is_user_logged_in() ) {
605 - if( wpstream_user_entitled_for_product($product_id) ){
606 - // Entitled: the presentation module classifies live vs VOD
607 - // (product term or subscription flag) and renders.
608 - echo '<div class="wpstream_player_wrapper "><div class="wpstream_player_container">';
609 - echo $this->main->playback_presentation->render( $product_id, 'auto' );
610 - echo '</div></div>';
611 - } else {
612 - // Not entitled: show the appropriate "no buy" message.
613 - if( $product_type_slug=='subscription' ){
614 - // For subscriptions, only prompt when there is no active subscription.
615 - if( !wcs_user_has_subscription( $current_user->ID, $product_id ,'active') ) {
616 - $this->wpstream_display_no_buy_message('nobuy',$product_id);
617 - }
618 812
619 - }else{
620 - $this->wpstream_display_no_buy_message('nobuy',$product_id);
621 - }
813 + if ( wc_customer_bought_product( $current_user->user_email, $current_user->ID, $product_id) || ( function_exists('wcs_user_has_subscription') && wcs_user_has_subscription( $current_user->ID, $product_id ,'active') ) ){
622 814
623 815
816 + echo '<div class="wpstream_player_wrapper"><div class="wpstream_player_container">';
817 +
818 + $is_subscription_live_event = esc_html(get_post_meta($product_id,'_subscript_live_event',true));
819 + $term_list = wp_get_post_terms($product_id, 'product_type');
820 +
821 +
822 + if( $term_list[0]->name=='live_stream' || ($term_list[0]->name=='subscription' && $is_subscription_live_event=='yes' ) ){
823 + $this->wpstream_live_event_player($product_id);
824 + }else if( $term_list[0]->name=='video_on_demand' || ($term_list[0]->name=='subscription' && $is_subscription_live_event=='no' ) ){
825 + $this->wpstream_video_on_demand_player($product_id);
826 + }
827 + echo '</div></div>';
828 + }else{
829 + if( get_post_type($product_id) == 'wpstream_product' ){
830 + echo '<div class="wpstream_player_wrapper no_buy"><div class="wpstream_player_container">';
831 + echo '<div class="wpstream_notice">'.__('You did not buy this product!','wpstream').'</div>';
832 + echo '</div></div>';
833 + }
624 834 }
625 835
626 -
627 - }else{
628 - // Logged out: prompt the visitor to log in.
629 - $this->wpstream_display_no_buy_message('nolog',$product_id);
836 +
630 837 }
631 838 }
632 839
840 + /**
841 + * check if the user bought the product and display the player - TO REDo
842 + *
843 + * @since 3.0.1
844 + * returns html of the player
845 + */
633 846
847 + public function wpstream_chat_wrapper($product_id){
848 + require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/templates/wpstream_chat_template.php';
849 + }
850 +
634 851
635 852
636 -
637 - /**
638 - * display no buy Message
639 - * Render the appropriate access notice ("must log in" / "not purchased" /
640 - * "not subscribed" / "subscription active") for a product.
641 - *
642 - * @param string $log Which case to show: 'sub_active', 'nolog', or other (nobuy).
643 - * @param int $product_id Product/post id.
644 - * @return void Echoes the notice markup.
645 - * @since 3.12.2
646 - */
647 - public function wpstream_display_no_buy_message($log,$product_id) {
648 - // Special case: subscription already active -> confirmation notice and return early.
649 - if($log=='sub_active'){
650 - $message = (string) get_option( 'wpstream_subscription_active', 'Your Subscription is Active.' );
651 - echo $this->not_entitled_notice( 'sub_active', $product_id, $message );
652 - return;
853 + public function wpstream_connect_to_chat($product_id){
854 + $current_user = wp_get_current_user();
855 + $userID = $current_user->ID;
856 + $user_login = $current_user->user_login;
653 857
654 - }else if($log=='nolog'){
655 - // Visitor is logged out.
656 - $reason = 'nolog';
657 - $message = (string) get_option( 'wpstream_product_not_login', 'You must be logged in to watch this video.' );
658 - }else{
659 - // Default: logged in but has not purchased.
660 - $reason = 'nobuy';
661 - $message = (string) get_option( 'wpstream_product_not_bought', 'You did not yet purchase this item.' );
662 - }
663 - // In subscription mode, swap in the "not subscribed" wording.
664 - $subscription_model = intval( get_option('wpstream_global_sub','')) ;
665 - if($subscription_model==1){
666 - $message = (string) get_option( 'wpstream_product_not_subscribe', 'You did not yet subscribe to this item.' );
667 - }
858 + $key='';
668 859
860 + $chatUrl = get_post_meta($product_id,'chatUrl',true);
861 +
669 862
670 - if( get_post_type($product_id) == 'product' && $subscription_model==0 ){
671 - // PPV mode: only show the notice for live/VOD/subscription product types.
672 - $product = wc_get_product($product_id);
673 - $product_type_slug = wpstream_get_product_type_slug($product_id);
674 - $product_type = $product->get_type();
675 - $is_subscription_live_event = esc_html(get_post_meta($product_id,'_subscript_live_event',true));
863 + wp_enqueue_script( 'sockjs-0.3.min' );
864 + wp_enqueue_script( 'emojione.min.js' );
865 + wp_enqueue_script( "jquery-effects-core");
866 + wp_enqueue_script( 'jquery.linkify.min.js');
867 + wp_enqueue_script( 'ripples.min.js');
868 + wp_enqueue_script( 'material.min.js');
869 + wp_enqueue_script( 'chat.js');
676 870
677 871
678 872
679 - if( $product_type_slug=='video_on_demand' || $product_type_slug=='live_stream' || $product_type=='subscription'){
680 - echo $this->not_entitled_notice( $reason, $product_id, $message );
681 - }
873 + wp_enqueue_style( 'chat.css');
874 + wp_enqueue_style( 'ripples.css');
875 + wp_enqueue_style( 'emojione.min.css');
682 876
683 - }else if( get_post_type($product_id) == 'product' && $subscription_model==1 ){
684 - // Subscription mode: show the notice for any non-simple product.
685 - // '' (no term) counts as non-simple, matching the pre-guard intent.
686 - if( wpstream_get_product_type_slug($product_id)!=='simple'){
687 - echo $this->not_entitled_notice( $reason, $product_id, $message );
688 - }
689 - }
690 - }
691 877
692 - /**
693 - * Get the video player logo URL.
694 - *
695 - * @param int $product_id Product ID.
696 - * @return mixed|string Logo URL, the WpStream symbol for streamify users, or ''.
697 - */
698 - public function wpstream_get_video_player_logo( $product_id ) { return $this->main->playback_presentation->wpstream_get_video_player_logo( $product_id ); }
878 +
879 +
880 + if(!is_user_logged_in()){
881 + $user_login='';
882 + $chatUrl='';
883 + }
699 884
700 - /*
701 - * Check whether a channel/product is on a basic (streamify) subscription.
702 - *
703 - * @param int $channel_id Channel ID
704 - * @return bool True when the 'basicStreaming' meta equals '1'.
705 - */
706 - public function wpstream_is_streamify_user( $channel_id ) { return $this->main->playback_presentation->wpstream_is_streamify_user( $channel_id ); }
885 +
886 + print '<script type="text/javascript">
887 + //<![CDATA[
888 + jQuery(document).ready(function(){
889 + username = "'.$user_login.'";
890 + key="'.$key.'";
891 +
892 + });
893 + //]]>
894 + </script>';
895 +
896 + }
707 897 }