PageSourceSearch

https://www.pourquoidocteur.fr/themes/theme_pqd_2018/js/RYPP.js

js pourquoidocteur.fr collected 2026-10-01 10:44:51 UTC 9,626 bytes, 324 lines download raw bytes

1/*
2  Youtube Player with Playlist (v2.18)
3  https://github.com/carloscabo/responsive-youtube-player-with-playlist
4  by Carlos Cabo (@putuko)
5*/
6
7var RYPP = (function($, undefined) {
8  'use strict';
9
10  function Rypp(el, api_key, options) {
11
12    if (typeof api_key === 'undefined') {
13      console.log("Youtube API V3 requires a valid API KEY.\nFollow the instructions at: https://developers.google.com/youtube/v3/getting-started");
14      return false;
15    }
16
17    // DOM Elements container
18    this.DOM = {};
19
20    // Default settings container
21    this.options = {};
22
23    // Data / urls
24    this.data = {
25      // Playlist url
26      ytapi: {
27        playlist_info: 'https://www.googleapis.com/youtube/v3/playlists?part=snippet&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
28        playlist: 'https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId={{RESOURCES_ID}}&key={{YOUR_API_KEY}}',
29        videolist: 'https://www.googleapis.com/youtube/v3/videos?part=snippet,status&maxResults=50&id={{RESOURCES_ID}}&key={{YOUR_API_KEY}}'
30      },
31      firsttime: true,
32      ismobile: (typeof window.orientation !== 'undefined')
33    };
34
35    // Initialize
36    this.init(el, api_key, options);
37  }
38
39  // Prototype for the instance
40  Rypp.prototype = {
41
42    init: function(el, api_key, options) {
43
44      // Api key
45      this.api_key = api_key;
46
47      // Default options
48      this.options = {
49        update_title_desc: false,
50        autoplay: true,
51        autonext: true,
52        loop: true,
53        mute: false
54      };
55
56      // Merge initial options
57      if (typeof options !== 'undefined') {
58        $.extend(this.options, options);
59      }
60
61      // YT Player object
62      this.ytplayer = null;
63
64      // DOM elements
65      this.DOM = {};
66      this.DOM.$el = $(el);
67      this.DOM.$playlc = this.DOM.$el.find('.RYPP-playlist');
68      this.DOM.$items =  this.DOM.$el.find('.RYPP-items');
69      this.DOM.$videoc = this.DOM.$el.find('.RYPP-video');
70      this.DOM.$title  = this.DOM.$el.find('.RYPP-title');
71      this.DOM.$desc   = this.DOM.$el.find('.RYPP-desc');
72
73      // Unique player ID
74      this.data.player_uid = (Math.random().toString(16).substr(2,8));
75      this.DOM.$el.attr('data-rypp',this.data.player_uid).find('.RYPP-video-player').attr('id','RYPP-vp-'+this.data.player_uid);
76
77      // Link JS only once
78      if (typeof YT === 'undefined') {
79        var
80          tag = document.createElement('script'),
81          hID = document.getElementsByTagName('head')[0];
82        // Add youtube API in HEAD
83        // tag.src = "https://www.youtube.com/iframe_api";
84        tag.src = 'https://www.youtube.com/player_api';
85        hID.appendChild(tag);
86      }
87
88    },
89
90    onYouTubeIframeAPIReady: function() {
91      if( this.options.update_title_desc ) {
92        this.updateTitleDesc();
93      }
94      this.populatePlaylist();
95    },
96
97    updateTitleDesc: function() {
98      var
99        that = this,
100        resources_id = this.DOM.$el.attr('data-playlist'),
101        url  = this.data.ytapi.playlist_info.replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);
102
103      $.ajaxSetup ({cache: false});
104      $.ajax(url, {
105        context: this,
106        dataType: 'json',
107        crossDomain: true,
108        error: function(){
109          // Not successful
110        },
111        success: function(data){
112          // console.log(data);
113          this.DOM.$title.html( data.items[0].snippet.title );
114          this.DOM.$desc.html( data.items[0].snippet.description );
115        }
116      });
117    },
118
119    populatePlaylist: function() {
120      // Empty playlist
121      this.DOM.$items.html('').append($('<ol>'));
122
123      // Now we read the video list from playlist data or from IDs...
124      if (this.DOM.$el.attr('data-playlist')) {
125        this.getVideosFrom(
126          'playlist',
127          this.DOM.$el.attr('data-playlist')
128        );
129      } else if (this.DOM.$el.attr('data-ids')) {
130        var vl = this.DOM.$el.attr('data-ids');
131        // Clean spaces
132        vl = ($.map(vl.split(','),$.trim)).join(',');
133        this.getVideosFrom(
134          'videolist',
135          vl
136        );
137      }
138    },
139
140    addAPIPlayer: function() {
141      var that = this;
142
143      this.ytplayer = new YT.Player('RYPP-vp-'+this.data.player_uid, {
144        // height: '390',
145        // width: '640',
146        playerVars: {
147          // controls: 0,
148          // showinfo: 0 ,
149          // autoplay: 0,
150          enablejsapi: 1,
151          rel: 0,
152          modestbranding: 1,
153          wmode: 'transparent'
154        },
155        events: {
156          'onReady': function(){
157            that.onPlayerReady();
158          },
159          'onStateChange': function(e){
160            that.onPlayerStateChange(e);
161          },
162          'onError': function(e) {
163            console.log(e);
164          }
165        }
166      });
167    },
168
169    // Ready to play
170    onPlayerReady: function() {
171      this.startPlayList();
172    },
173
174    // When video finish
175    onPlayerStateChange: function(e){
176      var
177        that = this;
178
179      if (typeof e !== 'undefined') {
180
181        // On video loaded?
182        if(e.data === -1 && this.data.firsttime) {
183          if(!this.options.autoplay && !this.data.ismobile) { // Is desktop
184            this.ytplayer.stopVideo();
185            this.data.firsttime = false;
186          }
187          if(this.options.mute) {
188            this.ytplayer.mute();
189          }
190        }
191
192        // If mobile and stored in buffer we STOP the video in mobile devices
193        if(e.data === 3 && this.data.ismobile && this.data.firsttime) {
194          setTimeout(function(){
195            that.ytplayer.stopVideo();
196            that.data.firsttime = false;
197          }, 500);
198        }
199
200        // Play next only if not mobile
201        var next = null;
202        if(e.data === 0 && !this.data.ismobile && this.options.autonext) {
203          next = this.DOM.$items.find('li.selected').next();
204          if (next.length === 0 && this.options.loop) {
205            next = this.DOM.$items.find('li').first();
206          }
207          next.click();
208        }
209
210      }
211
212    },
213
214
215    // Get video from data-ids or playlist
216    // It's impossible to know if a video in a playlist its available or currently deleted. So we do 2 request, first we get all the video IDs an then we ask for info about them.
217    getVideosFrom: function(kind, resources_id) {
218      var
219        that = this,
220        url  = this.data.ytapi[kind].replace('{{RESOURCES_ID}}', resources_id).replace('{{YOUR_API_KEY}}', this.api_key);
221
222      $.ajaxSetup ({cache: false});
223      $.ajax(url, {
224        context: this,
225        dataType: 'json',
226        crossDomain: true,
227        error: function(){
228          // Not successful
229        },
230        success: function(data){
231
232          // We queried for a playlist
233          if (data.kind === 'youtube#playlistItemListResponse') {
234
235            // We get the video IDs and query gain, its the only way to be sure that all the videos are available, and not were deleted :(
236            var vl = $.map(data.items, function(val,idx) {
237              if (typeof val.snippet.resourceId.videoId !== 'undefined') {
238                return val.snippet.resourceId.videoId;
239              }
240            }).join(',');
241
242            that.getVideosFrom('videolist',vl);
243
244          } else if (data.kind === 'youtube#videoListResponse') {
245
246            // Videos froma  Videolist
247            for (var i = 0, len = data.items.length; i < len; i++) {
248              var item = data.items[i];
249
250              // Videos without thumbnail, deleted or rejected are not included in the player!
251              if (
252                $.inArray(item.status.uploadStatus, ['rejected', 'deleted', 'failed']) === -1 &&
253                typeof item.snippet.thumbnails !== 'undefined'
254              ) {
255                var
256                  vid = item.id,
257                  tit = item.snippet.title,
258                  aut = item.snippet.channelTitle,
259                  thu = item.snippet.thumbnails.default.url;
260                that.addVideo2Playlist(vid, tit, aut, thu);
261              }
262            }
263            that.addAPIPlayer();
264          }
265        }
266      });
267    },
268
269    // All videos are supossed to be loaded
270    // lets start the playlist
271    startPlayList: function() {
272
273      var
274        D = this.DOM,
275        vid = null,
276        that = this;
277
278      // Click on playlist elemnts
279      D.$items.on('click', 'li', function(e) {
280        e.preventDefault();
281        D.$items.find('li').removeClass('selected');
282        $(this).addClass('selected');
283        vid = $(this).data('video-id');
284        // Call YT API function
285        that.ytplayer.loadVideoById(vid);
286        // If we are in mobile we must stop
287        if (that.data.ismobile) {
288          that.data.firsttime = true;
289        }
290      });
291
292      // Select first if none
293      if (D.$items.find('li.selected').length === 0) {
294        D.$items.find('li').first().click();
295      }
296    },
297
298    // Add video block to playlist
299    addVideo2Playlist: function(vid, tit, aut, thu) {
300      var
301        D  = this.DOM;
302      $('<li data-video-id="'+vid+'"><p class="title">'+tit+'<small class="author"><br>'+aut+'</small></p><img src="'+thu+'" class="thumb"></li>').appendTo(D.$items.find('ol'));
303    },
304
305  }; // prototypes
306
307  return Rypp;
308
309}(jQuery));
310
311// YOUTUBE API CALLBACK
312function onYouTubeIframeAPIReady() {
313  $('[data-rypp]').each(function(idx, el) {
314    $(el)[0].rypp_data_obj.onYouTubeIframeAPIReady();
315  });
316}
317
318// JQuery hook
319$.fn.rypp = function(api_key, options) {
320  return this.each(function() {
321    // Store object in DOM element
322    this.rypp_data_obj = new RYPP(this, api_key, options);
323  });
324};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.