PageSourceSearch

https://www.laregione.ch/lib/videojs/video-js-youtube.js?fmt=2b2de3a4

js laregione.ch collected 2026-10-01 10:13:43 UTC 22,435 bytes, 798 lines download raw bytes

1
vendor: 22,432 bytes, lines 1-798
1/* The MIT License (MIT)
2
3Copyright (c) 2014-2015 Benoit Tremblay <[email protected]>
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21THE SOFTWARE. */
22/*global define, YT*/
23(function (root, factory) {
24  if(typeof exports==='object' && typeof module!=='undefined') {
25    var videojs = require('video.js');
26    module.exports = factory(videojs.default || videojs);
27  } else if(typeof define === 'function' && define.amd) {
28    define(['videojs'], function(videojs){
29      return (root.Youtube = factory(videojs));
30    });
31  } else {
32    root.Youtube = factory(root.videojs);
33  }
34}(this, function(videojs) {
35  'use strict';
36
37  var _isOnMobile = videojs.browser.IS_IOS || videojs.browser.IS_NATIVE_ANDROID;
38  var Tech = videojs.getTech('Tech');
39
40  class Youtube extends Tech {
41
42    constructor(options, ready) {
43      super(options, ready);
44
45      this.setPoster(options.poster);
46      this.setSrc(this.options_.source, true);
47
48      // Set the vjs-youtube class to the player
49      // Parent is not set yet so we have to wait a tick
50      this.setTimeout(function() {
51        if (this.el_) {
52          this.el_.parentNode.className += ' vjs-youtube';
53
54          if (_isOnMobile) {
55            this.el_.parentNode.className += ' vjs-youtube-mobile';
56          }
57
58          if (Youtube.isApiReady) {
59            this.initYTPlayer();
60          } else {
61            Youtube.apiReadyQueue.push(this);
62          }
63        }
64      }.bind(this));
65    }
66
67    dispose() {
68      if (this.ytPlayer) {
69        //Dispose of the YouTube Player
70        if (this.ytPlayer.stopVideo) {
71          this.ytPlayer.stopVideo();
72        }
73        if (this.ytPlayer.destroy) {
74          this.ytPlayer.destroy();
75        }
76      } else {
77        //YouTube API hasn't finished loading or the player is already disposed
78        var index = Youtube.apiReadyQueue.indexOf(this);
79        if (index !== -1) {
80          Youtube.apiReadyQueue.splice(index, 1);
81        }
82      }
83      this.ytPlayer = null;
84
85      this.el_.parentNode.className = this.el_.parentNode.className
86          .replace(' vjs-youtube', '')
87          .replace(' vjs-youtube-mobile', '');
88      this.el_.parentNode.removeChild(this.el_);
89
90      //Needs to be called after the YouTube player is destroyed, otherwise there will be a null reference exception
91      Tech.prototype.dispose.call(this);
92    }
93
94    createEl() {
95      var div = document.createElement('div');
96      div.setAttribute('id', this.options_.techId);
97      div.setAttribute('style', 'width:100%;height:100%;top:0;left:0;position:absolute');
98      div.setAttribute('class', 'vjs-tech');
99
100      var divWrapper = document.createElement('div');
101      divWrapper.appendChild(div);
102
103      if (!_isOnMobile && !this.options_.ytControls) {
104        var divBlocker = document.createElement('div');
105        divBlocker.setAttribute('class', 'vjs-iframe-blocker');
106        divBlocker.setAttribute('style', 'position:absolute;top:0;left:0;width:100%;height:100%');
107
108        // In case the blocker is still there and we want to pause
109        divBlocker.onclick = function() {
110          this.pause();
111        }.bind(this);
112
113        divWrapper.appendChild(divBlocker);
114      }
115
116      return divWrapper;
117    }
118
119    initYTPlayer() {
120      var playerVars = {
121        controls: 0,
122        modestbranding: 1,
123        rel: 0,
124        showinfo: 0,
125        loop: this.options_.loop ? 1 : 0
126      };
127
128      // Let the user set any YouTube parameter
129      // https://developers.google.com/youtube/player_parameters?playerVersion=HTML5#Parameters
130      // To use YouTube controls, you must use ytControls instead
131      // To use the loop or autoplay, use the video.js settings
132
133      if (typeof this.options_.autohide !== 'undefined') {
134        playerVars.autohide = this.options_.autohide;
135      }
136
137      if (typeof this.options_['cc_load_policy'] !== 'undefined') {
138        playerVars['cc_load_policy'] = this.options_['cc_load_policy'];
139      }
140
141      if (typeof this.options_.ytControls !== 'undefined') {
142        playerVars.controls = this.options_.ytControls;
143      }
144
145      if (typeof this.options_.disablekb !== 'undefined') {
146        playerVars.disablekb = this.options_.disablekb;
147      }
148
149      if (typeof this.options_.color !== 'undefined') {
150        playerVars.color = this.options_.color;
151      }
152
153      if (!playerVars.controls) {
154        // Let video.js handle the fullscreen unless it is the YouTube native controls
155        playerVars.fs = 0;
156      } else if (typeof this.options_.fs !== 'undefined') {
157        playerVars.fs = this.options_.fs;
158      }
159
160      if (this.options_.source.src.indexOf('end=') !== -1) {
161        var srcEndTime = this.options_.source.src.match(/end=([0-9]*)/);
162        this.options_.end = parseInt(srcEndTime[1]);
163      }
164
165      if (typeof this.options_.end !== 'undefined') {
166        playerVars.end = this.options_.end;
167      }
168
169      if (typeof this.options_.hl !== 'undefined') {
170        playerVars.hl = this.options_.hl;
171      } else if (typeof this.options_.language !== 'undefined') {
172        // Set the YouTube player on the same language than video.js
173        playerVars.hl = this.options_.language.substr(0, 2);
174      }
175
176      if (typeof this.options_['iv_load_policy'] !== 'undefined') {
177        playerVars['iv_load_policy'] = this.options_['iv_load_policy'];
178      }
179
180      if (typeof this.options_.list !== 'undefined') {
181        playerVars.list = this.options_.list;
182      } else if (this.url && typeof this.url.listId !== 'undefined') {
183        playerVars.list = this.url.listId;
184      }
185
186      if (typeof this.options_.listType !== 'undefined') {
187        playerVars.listType = this.options_.listType;
188      }
189
190      if (typeof this.options_.modestbranding !== 'undefined') {
191        playerVars.modestbranding = this.options_.modestbranding;
192      }
193
194      if (typeof this.options_.playlist !== 'undefined') {
195        playerVars.playlist = this.options_.playlist;
196      }
197
198      if (typeof this.options_.playsinline !== 'undefined') {
199        playerVars.playsinline = this.options_.playsinline;
200      }
201
202      if (typeof this.options_.rel !== 'undefined') {
203        playerVars.rel = this.options_.rel;
204      }
205
206      if (typeof this.options_.showinfo !== 'undefined') {
207        playerVars.showinfo = this.options_.showinfo;
208      }
209
210      if (this.options_.source.src.indexOf('start=') !== -1) {
211        var srcStartTime = this.options_.source.src.match(/start=([0-9]*)/);
212        this.options_.start = parseInt(srcStartTime[1]);
213      }
214
215      if (typeof this.options_.start !== 'undefined') {
216        playerVars.start = this.options_.start;
217      }
218
219      if (typeof this.options_.theme !== 'undefined') {
220        playerVars.theme = this.options_.theme;
221      }
222
223      // Allow undocumented options to be passed along via customVars
224      if (typeof this.options_.customVars !== 'undefined') {
225        var customVars = this.options_.customVars;
226        Object.keys(customVars).forEach(function(key) {
227          playerVars[key] = customVars[key];
228        });
229      }
230
231      this.activeVideoId = this.url ? this.url.videoId : null;
232      this.activeList = playerVars.list;
233
234      var playerConfig = {
235        videoId: this.activeVideoId,
236        playerVars: playerVars,
237        events: {
238          onReady: this.onPlayerReady.bind(this),
239          onPlaybackQualityChange: this.onPlayerPlaybackQualityChange.bind(this),
240          onPlaybackRateChange: this.onPlayerPlaybackRateChange.bind(this),
241          onStateChange: this.onPlayerStateChange.bind(this),
242          onVolumeChange: this.onPlayerVolumeChange.bind(this),
243          onError: this.onPlayerError.bind(this)
244        }
245      };
246
247      if (typeof this.options_.enablePrivacyEnhancedMode !== 'undefined' && this.options_.enablePrivacyEnhancedMode) {
248        playerConfig.host = 'https://www.youtube-nocookie.com';
249      }
250
251      this.ytPlayer = new YT.Player(this.options_.techId, playerConfig);
252    }
253
254    onPlayerReady() {
255      if (this.options_.muted) {
256        this.ytPlayer.mute();
257      }
258
259      var playbackRates = this.ytPlayer.getAvailablePlaybackRates();
260      if (playbackRates.length > 1) {
261        this.featuresPlaybackRate = true;
262      }
263
264      this.playerReady_ = true;
265      this.triggerReady();
266
267      if (this.playOnReady) {
268        this.play();
269      } else if (this.cueOnReady) {
270        this.cueVideoById_(this.url.videoId);
271        this.activeVideoId = this.url.videoId;
272      }
273    }
274
275    onPlayerPlaybackQualityChange() {
276
277    }
278
279    onPlayerPlaybackRateChange() {
280      this.trigger('ratechange');
281    }
282
283    onPlayerStateChange(e) {
284      var state = e.data;
285
286      if (state === this.lastState || this.errorNumber) {
287        return;
288      }
289
290      this.lastState = state;
291
292      switch (state) {
293        case -1:
294          this.trigger('loadstart');
295          this.trigger('loadedmetadata');
296          this.trigger('durationchange');
297          this.trigger('ratechange');
298          break;
299
300        case YT.PlayerState.ENDED:
301          this.trigger('ended');
302          break;
303
304        case YT.PlayerState.PLAYING:
305          this.trigger('timeupdate');
306          this.trigger('durationchange');
307          this.trigger('playing');
308          this.trigger('play');
309
310          if (this.isSeeking) {
311            this.onSeeked();
312          }
313          break;
314
315        case YT.PlayerState.PAUSED:
316          this.trigger('canplay');
317          if (this.isSeeking) {
318            this.onSeeked();
319          } else {
320            this.trigger('pause');
321          }
322          break;
323
324        case YT.PlayerState.BUFFERING:
325          this.player_.trigger('timeupdate');
326          this.player_.trigger('waiting');
327          break;
328      }
329    }
330
331    onPlayerVolumeChange() {
332      this.trigger('volumechange');
333    }
334
335    onPlayerError(e) {
336      this.errorNumber = e.data;
337      this.trigger('pause');
338      this.trigger('error');
339    }
340
341    error() {
342      var code = 1000 + this.errorNumber; // as smaller codes are reserved
343      switch (this.errorNumber) {
344        case 5:
345          return { code: code, message: 'Error while trying to play the video' };
346
347        case 2:
348        case 100:
349          return { code: code, message: 'Unable to find the video' };
350
351        case 101:
352        case 150:
353          return {
354            code: code,
355            message: 'Playback on other Websites has been disabled by the video owner.'
356          };
357      }
358
359      return { code: code, message: 'YouTube unknown error (' + this.errorNumber + ')' };
360    }
361
362    loadVideoById_(id) {
363      var options = {
364        videoId: id
365      };
366      if (this.options_.start) {
367        options.startSeconds = this.options_.start;
368      }
369      if (this.options_.end) {
370        options.endSeconds = this.options_.end;
371      }
372      this.ytPlayer.loadVideoById(options);
373    }
374
375    cueVideoById_(id) {
376      var options = {
377        videoId: id
378      };
379      if (this.options_.start) {
380        options.startSeconds = this.options_.start;
381      }
382      if (this.options_.end) {
383        options.endSeconds = this.options_.end;
384      }
385      this.ytPlayer.cueVideoById(options);
386    }
387
388    src(src) {
389      if (src) {
390        this.setSrc({ src: src });
391      }
392
393      return this.source;
394    }
395
396    poster() {
397      // You can't start programmaticlly a video with a mobile
398      // through the iframe so we hide the poster and the play button (with CSS)
399      if (_isOnMobile) {
400        return null;
401      }
402
403      return this.poster_;
404    }
405
406    setPoster(poster) {
407      this.poster_ = poster;
408    }
409
410    setSrc(source) {
411      if (!source || !source.src) {
412        return;
413      }
414
415      delete this.errorNumber;
416      this.source = source;
417      this.url = Youtube.parseUrl(source.src);
418
419      if (!this.options_.poster) {
420        if (this.url.videoId) {
421          // Set the low resolution first
422          this.poster_ = 'https://img.youtube.com/vi/' + this.url.videoId + '/0.jpg';
423          this.trigger('posterchange');
424
425          // Check if their is a high res
426          this.checkHighResPoster();
427        }
428      }
429
430      if (this.options_.autoplay && !_isOnMobile) {
431        if (this.isReady_) {
432          this.play();
433        } else {
434          this.playOnReady = true;
435        }
436      } else if (this.activeVideoId !== this.url.videoId) {
437        if (this.isReady_) {
438          this.cueVideoById_(this.url.videoId);
439          this.activeVideoId = this.url.videoId;
440        } else {
441          this.cueOnReady = true;
442        }
443      }
444    }
445
446    autoplay() {
447      return this.options_.autoplay;
448    }
449
450    setAutoplay(val) {
451      this.options_.autoplay = val;
452    }
453
454    loop() {
455      return this.options_.loop;
456    }
457
458    setLoop(val) {
459      this.options_.loop = val;
460    }
461
462    play() {
463      if (!this.url || !this.url.videoId) {
464        return;
465      }
466
467      this.wasPausedBeforeSeek = false;
468
469      if (this.isReady_) {
470        if (this.url.listId) {
471          if (this.activeList === this.url.listId) {
472            this.ytPlayer.playVideo();
473          } else {
474            this.ytPlayer.loadPlaylist(this.url.listId);
475            this.activeList = this.url.listId;
476          }
477        }
478
479        if (this.activeVideoId === this.url.videoId) {
480          this.ytPlayer.playVideo();
481        } else {
482          this.loadVideoById_(this.url.videoId);
483          this.activeVideoId = this.url.videoId;
484        }
485      } else {
486        this.trigger('waiting');
487        this.playOnReady = true;
488      }
489    }
490
491    pause() {
492      if (this.ytPlayer) {
493        this.ytPlayer.pauseVideo();
494      }
495    }
496
497    paused() {
498      return (this.ytPlayer) ?
499          (this.lastState !== YT.PlayerState.PLAYING && this.lastState !== YT.PlayerState.BUFFERING)
500          : true;
501    }
502
503    currentTime() {
504      return this.ytPlayer ? this.ytPlayer.getCurrentTime() : 0;
505    }
506
507    setCurrentTime(seconds) {
508      if (this.lastState === YT.PlayerState.PAUSED) {
509        this.timeBeforeSeek = this.currentTime();
510      }
511
512      if (!this.isSeeking) {
513        this.wasPausedBeforeSeek = this.paused();
514      }
515
516      this.ytPlayer.seekTo(seconds, true);
517      this.trigger('timeupdate');
518      this.trigger('seeking');
519      this.isSeeking = true;
520
521      // A seek event during pause does not return an event to trigger a seeked event,
522      // so run an interval timer to look for the currentTime to change
523      if (this.lastState === YT.PlayerState.PAUSED && this.timeBeforeSeek !== seconds) {
524        clearInterval(this.checkSeekedInPauseInterval);
525        this.checkSeekedInPauseInterval = setInterval(function() {
526          if (this.lastState !== YT.PlayerState.PAUSED || !this.isSeeking) {
527            // If something changed while we were waiting for the currentTime to change,
528            //  clear the interval timer
529            clearInterval(this.checkSeekedInPauseInterval);
530          } else if (this.currentTime() !== this.timeBeforeSeek) {
531            this.trigger('timeupdate');
532            this.onSeeked();
533          }
534        }.bind(this), 250);
535      }
536    }
537
538    seeking() {
539      return this.isSeeking;
540    }
541
542    seekable() {
543      if(!this.ytPlayer) {
544        return videojs.createTimeRange();
545      }
546
547      return videojs.createTimeRange(0, this.ytPlayer.getDuration());
548    }
549
550    onSeeked() {
551      clearInterval(this.checkSeekedInPauseInterval);
552      this.isSeeking = false;
553
554      if (this.wasPausedBeforeSeek) {
555        this.pause();
556      }
557
558      this.trigger('seeked');
559    }
560
561    playbackRate() {
562      return this.ytPlayer ? this.ytPlayer.getPlaybackRate() : 1;
563    }
564
565    setPlaybackRate(suggestedRate) {
566      if (!this.ytPlayer) {
567        return;
568      }
569
570      this.ytPlayer.setPlaybackRate(suggestedRate);
571    }
572
573    duration() {
574      return this.ytPlayer ? this.ytPlayer.getDuration() : 0;
575    }
576
577    currentSrc() {
578      return this.source && this.source.src;
579    }
580
581    ended() {
582      return this.ytPlayer ? (this.lastState === YT.PlayerState.ENDED) : false;
583    }
584
585    volume() {
586      return this.ytPlayer ? this.ytPlayer.getVolume() / 100.0 : 1;
587    }
588
589    setVolume(percentAsDecimal) {
590      if (!this.ytPlayer) {
591        return;
592      }
593
594      this.ytPlayer.setVolume(percentAsDecimal * 100.0);
595    }
596
597    muted() {
598      return this.ytPlayer ? this.ytPlayer.isMuted() : false;
599    }
600
601    setMuted(mute) {
602      if (!this.ytPlayer) {
603        return;
604      }
605      else{
606        this.muted(true);
607      }
608
609      if (mute) {
610        this.ytPlayer.mute();
611      } else {
612        this.ytPlayer.unMute();
613      }
614      this.setTimeout( function(){
615        this.trigger('volumechange');
616      }, 50);
617    }
618
619    buffered() {
620      if(!this.ytPlayer || !this.ytPlayer.getVideoLoadedFraction) {
621        return videojs.createTimeRange();
622      }
623
624      var bufferedEnd = this.ytPlayer.getVideoLoadedFraction() * this.ytPlayer.getDuration();
625
626      return videojs.createTimeRange(0, bufferedEnd);
627    }
628
629    // TODO: Can we really do something with this on YouTUbe?
630    preload() {}
631    load() {}
632    reset() {}
633    networkState() {
634      if (!this.ytPlayer) {
635        return 0; //NETWORK_EMPTY
636      }
637      switch (this.ytPlayer.getPlayerState()) {
638        case -1: //unstarted
639          return 0; //NETWORK_EMPTY
640        case 3: //buffering
641          return 2; //NETWORK_LOADING
642        default:
643          return 1; //NETWORK_IDLE
644      }
645    }
646    readyState() {
647      if (!this.ytPlayer) {
648        return 0; //HAVE_NOTHING
649      }
650      switch (this.ytPlayer.getPlayerState()) {
651        case -1: //unstarted
652          return 0; //HAVE_NOTHING
653        case 5: //video cued
654          return 1; //HAVE_METADATA
655        case 3: //buffering
656          return 2; //HAVE_CURRENT_DATA
657        default:
658          return 4; //HAVE_ENOUGH_DATA
659      }
660    }
661
662    supportsFullScreen() {
663      return document.fullscreenEnabled ||
664          document.webkitFullscreenEnabled ||
665          document.mozFullScreenEnabled ||
666          document.msFullscreenEnabled;
667    }
668
669    // Tries to get the highest resolution thumbnail available for the video
670    checkHighResPoster(){
671      var uri = 'https://img.youtube.com/vi/' + this.url.videoId + '/maxresdefault.jpg';
672
673      try {
674        var image = new Image();
675        image.onload = function(){
676          // Onload may still be called if YouTube returns the 120x90 error thumbnail
677          if('naturalHeight' in image){
678            if (image.naturalHeight <= 90 || image.naturalWidth <= 120) {
679              return;
680            }
681          } else if(image.height <= 90 || image.width <= 120) {
682            return;
683          }
684
685          this.poster_ = uri;
686          this.trigger('posterchange');
687        }.bind(this);
688        image.onerror = function(){};
689        image.src = uri;
690      }
691      catch(e){}
692    }
693  }
694
695  Youtube.isSupported = function() {
696    return true;
697  };
698
699  Youtube.canPlaySource = function(e) {
700    return Youtube.canPlayType(e.type);
701  };
702
703  Youtube.canPlayType = function(e) {
704    return (e === 'video/youtube');
705  };
706
707  Youtube.parseUrl = function(url) {
708    var result = {
709      videoId: null
710    };
711
712    var regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/;
713    var match = url.match(regex);
714
715    if (match && match[2].length === 11) {
716      result.videoId = match[2];
717    }
718
719    var regPlaylist = /[?&]list=([^#\&\?]+)/;
720    match = url.match(regPlaylist);
721
722    if(match && match[1]) {
723      result.listId = match[1];
724    }
725
726    return result;
727  };
728
729  function apiLoaded() {
730    YT.ready(function() {
731      Youtube.isApiReady = true;
732
733      for (var i = 0; i < Youtube.apiReadyQueue.length; ++i) {
734        Youtube.apiReadyQueue[i].initYTPlayer();
735      }
736    });
737  }
738
739  function loadScript(src, callback) {
740    var loaded = false;
741    var tag = document.createElement('script');
742    var firstScriptTag = document.getElementsByTagName('script')[0];
743    if (!firstScriptTag) {
744      // when loaded in jest without jsdom setup it doesn't get any element.
745      // In jest it doesn't really make sense to do anything, because no one is watching youtube in jest
746      return;
747    }
748    firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
749    tag.onload = function () {
750      if (!loaded) {
751        loaded = true;
752        callback();
753      }
754    };
755    tag.onreadystatechange = function () {
756      if (!loaded && (this.readyState === 'complete' || this.readyState === 'loaded')) {
757        loaded = true;
758        callback();
759      }
760    };
761    tag.src = src;
762  }
763
764  function injectCss() {
765    var css = // iframe blocker to catch mouse events
766        '.vjs-youtube .vjs-iframe-blocker { display: none; }' +
767        '.vjs-youtube.vjs-user-inactive .vjs-iframe-blocker { display: block; }' +
768        '.vjs-youtube .vjs-poster { background-size: cover; }' +
769        '.vjs-youtube-mobile .vjs-big-play-button { display: none; }';
770
771    var head = document.head || document.getElementsByTagName('head')[0];
772
773    var style = document.createElement('style');
774    style.type = 'text/css';
775
776    if (style.styleSheet){
777      style.styleSheet.cssText = css;
778    } else {
779      style.appendChild(document.createTextNode(css));
780    }
781
782    head.appendChild(style);
783  }
784
785  Youtube.apiReadyQueue = [];
786
787  if (typeof document !== 'undefined'){
788    loadScript('https://www.youtube.com/iframe_api', apiLoaded);
789    injectCss();
790  }
791
792  // Older versions of VJS5 doesn't have the registerTech function
793  if (typeof videojs.registerTech !== 'undefined') {
794    videojs.registerTech('Youtube', Youtube);
795  } else {
796    videojs.registerComponent('Youtube', Youtube);
797  }
798}));

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.