integration/js/contentplayer.js
changeset 50 9cc1b66d0880
child 64 458cc4576415
equal deleted inserted replaced
49:cb8403125d4d 50:9cc1b66d0880
       
     1 IriSP.contentplayer = function(opts) {
       
     2     var directory = new IriSP.Model.Directory(),
       
     3         project = directory.remoteSource({
       
     4             url: opts.project_url,
       
     5             serializer: IriSP.serializers.ldt
       
     6         }),
       
     7         apidirectory = new IriSP.Model.Directory(),
       
     8         currentIndex = 0,
       
     9         currentSegment,
       
    10         currentMedia,
       
    11         globalTags = {},
       
    12         seqCount;
       
    13         
       
    14     var ratio = 2.37;
       
    15 
       
    16     function resizeVideo() {
       
    17         var currentwidth = $(window).width(),
       
    18             maxheight = $(window).height() - 220,
       
    19             height = Math.min(maxheight, currentwidth / ratio),
       
    20             width = ratio * height;
       
    21         $("#video_sequence").css({
       
    22             width: Math.floor(width),
       
    23             height: Math.floor(height)
       
    24         });
       
    25     }
       
    26     
       
    27     $(window).on("resize", resizeVideo);
       
    28     resizeVideo();
       
    29     
       
    30     var timeSlider = $("#progressBar"),
       
    31         slidersRange = 1000,
       
    32         wasPaused = true,
       
    33         lastVal = 0,
       
    34         isClicking = false;
       
    35     timeSlider.slider({
       
    36         range: "min",
       
    37         value: 0,
       
    38         min: 0,
       
    39         max: slidersRange,
       
    40         slide: function(event, ui) {
       
    41             if (isClicking && Math.abs(lastVal - ui.value) > 10) {
       
    42                 isClicking = false;
       
    43             }
       
    44             if (!isClicking && currentMedia) {
       
    45                 currentMedia.setCurrentTime(currentMedia.duration * ui.value / slidersRange);
       
    46             }
       
    47         },
       
    48         start: function(event, ui) {
       
    49             isClicking = true;
       
    50             lastVal = ui.value;
       
    51         },
       
    52         stop: function(event, ui) {
       
    53             if (isClicking && currentMedia) {
       
    54                 timeSlider.slider("value", slidersRange * currentMedia.getCurrentTime() / currentMedia.duration);
       
    55                 playOrPause();
       
    56             }
       
    57             isClicking = false;
       
    58         }
       
    59     });
       
    60     
       
    61     function playOrPause() {
       
    62         if (currentMedia) {
       
    63             if (currentMedia.paused) {
       
    64                 currentMedia.play();
       
    65             } else {
       
    66                 currentMedia.pause();
       
    67             }
       
    68         }
       
    69     }
       
    70     
       
    71     $(".video-wait, #btnPlayPause").click(function() {
       
    72         playOrPause();
       
    73         return false;
       
    74     });
       
    75     
       
    76     var segmentdragout = $("#title_sequence"),
       
    77         segmentdragin = segmentdragout.find("ul")
       
    78         segmentdragging = false;
       
    79     
       
    80     function resizeSegmentDrag() {
       
    81         var segmentdelta = segmentdragout.width() - segmentdragin.width();
       
    82         segmentdragin.draggable("option","containment",segmentdelta < 0 ? [ segmentdelta - 20, 0, 20, 0 ] : "parent")
       
    83     }
       
    84     
       
    85     segmentdragin.draggable({
       
    86         axis: "x",
       
    87         start: function() {
       
    88             segmentdragging = true;
       
    89         },
       
    90         stop: function() {
       
    91             segmentdragging = false;
       
    92         }
       
    93     });
       
    94     
       
    95     $(window).on("resize", resizeSegmentDrag);
       
    96     resizeSegmentDrag();   
       
    97     
       
    98     segmentdragin.on("mouseup", "li", function() {
       
    99         if (!segmentdragging) {
       
   100             var s = project.getElement($(this).attr("data-segment-id"));
       
   101             if (s) {
       
   102                 currentMedia.setCurrentTime(s.begin);
       
   103             }
       
   104         }
       
   105     }).click(function() {
       
   106         return false;
       
   107     });
       
   108      
       
   109     var tagsdragout = $("#tag_sequence"),
       
   110         tagsdragin = tagsdragout.find("ul")
       
   111         tagsdragging = false;
       
   112     
       
   113     function resizeTagsDrag() {
       
   114         var tagsdelta = tagsdragout.width() - tagsdragin.width();
       
   115         tagsdragin.draggable("option","containment",tagsdelta < 0 ? [ tagsdelta - 20, 0, 20, 0 ] : "parent");
       
   116         tagsdragin.css("left",Math.floor(tagsdelta/2));
       
   117     }
       
   118     
       
   119     tagsdragin.draggable({
       
   120         axis: "x",
       
   121         start: function() {
       
   122             tagsdragging = true;
       
   123         },
       
   124         stop: function() {
       
   125             tagsdragging = false;
       
   126         }
       
   127     });
       
   128     
       
   129     $(window).on("resize", resizeTagsDrag);
       
   130     resizeTagsDrag();
       
   131     
       
   132     var taginput = $("#form_tag input[type=text]");
       
   133     taginput.autocomplete({
       
   134         source: function(params, response) {
       
   135             var rx = new RegExp(params.term,"gi");
       
   136             response(
       
   137                 _(globalTags)
       
   138                     .chain()
       
   139                     .keys()
       
   140                     .filter(function(tag) {
       
   141                         return rx.test(tag)
       
   142                     })
       
   143                     .shuffle()
       
   144                     .first(5)
       
   145                     .value()
       
   146                 );
       
   147         }
       
   148     });
       
   149     taginput.on("keyup input paste", function() {
       
   150         taginput.val(taginput.val().toUpperCase());
       
   151     });
       
   152     $("#form_tag").on("submit", function() {
       
   153         var _tagvalue = taginput.val().toUpperCase();
       
   154         if (_tagvalue && currentSegment) {
       
   155             /* Création d'une liste d'annotations contenant une annotation afin de l'envoyer au serveur */
       
   156             var _exportedAnnotations = new IriSP.Model.List(directory),
       
   157                 /* Création d'un objet source utilisant un sérialiseur spécifique pour l'export */
       
   158                 _export = directory.newLocalSource({
       
   159                     serializer: IriSP.serializers.ldt_annotate
       
   160                 }),
       
   161                 /* Création d'une annotation dans cette source avec un ID généré à la volée (param. false) */
       
   162                 _annotation = new IriSP.Model.Annotation(false, _export),
       
   163                 /* Si le Type d'Annotation n'existe pas, il est créé à la volée */
       
   164                 _annotationType = new IriSP.Model.AnnotationType(false, _export),
       
   165                 /* L'objet Tag qui sera envoyé */
       
   166                 _tag = new IriSP.Model.Tag(false, _export);
       
   167             /* L'objet Tag doit avoir pour titre le texte du tag envoyé */
       
   168             _tag.title = _tagvalue;
       
   169             /* Si nous avons dû générer un ID d'annotationType à la volée... */
       
   170             _annotationType.dont_send_id = true;
       
   171             /* Il faut inclure le titre dans le type d'annotation */
       
   172             _annotationType.title = "Contribution";
       
   173 
       
   174             _annotation.setMedia(currentSegment.getMedia().id);
       
   175             _annotation.setBegin(currentSegment.begin);
       
   176             _annotation.setEnd(currentSegment.end);
       
   177             
       
   178             _annotation.setAnnotationType(_annotationType.id); 
       
   179             
       
   180             _annotation.title = _tagvalue;
       
   181             _annotation.created = new Date(); /* Date de création de l'annotation */
       
   182             _annotation.description = _tagvalue;
       
   183             
       
   184             _annotation.setTags([_tag.id]); /*Liste des ids de tags */
       
   185             
       
   186             /* Les données créateur/date de création sont envoyées non pas dans l'annotation, mais dans le projet */
       
   187             _export.creator = "theend";
       
   188             _export.created = new Date();
       
   189             /* Ajout de l'annotation à la liste à exporter */
       
   190             _exportedAnnotations.push(_annotation);
       
   191             /* Ajout de la liste à exporter à l'objet Source */
       
   192             _export.addList("annotation",_exportedAnnotations);
       
   193             
       
   194             var segmentAtPost = currentSegment;
       
   195             
       
   196             IriSP.jQuery.ajax({
       
   197                 url: IriSP.endpoints.post_annotation,
       
   198                 type: "POST",
       
   199                 contentType: 'application/json',
       
   200                 data: _export.serialize(), /* L'objet Source est sérialisé */
       
   201                 success: function(_data) {
       
   202                     var n = 1 + (segmentAtPost.__tags[_tagvalue] || 0)
       
   203                     segmentAtPost.__tags[_tagvalue] = n;
       
   204                     showCurrentTags();
       
   205                 },
       
   206                 error: function(_xhr, _error, _thrown) {
       
   207                     console.log("Error when sending annotation", _thrown);
       
   208                 }
       
   209             });
       
   210         }
       
   211         return false;
       
   212     });
       
   213     
       
   214     project.onLoad(function() {
       
   215         
       
   216         currentMedia = project.currentMedia;
       
   217         
       
   218         addMedia(currentMedia);
       
   219         
       
   220         $("#duration").text(currentMedia.duration.toString());
       
   221         $("h1").text(currentMedia.title); //TODO: Remove when on platform
       
   222         var segmentsHtml = "";
       
   223         
       
   224         project.getAnnotations().forEach(function(s) {
       
   225             segmentsHtml += '<li data-segment-id="' + s.id + '"><a href="#">' + s.title + ' </a> </li>';
       
   226             var url = IriSP.endpoints.annotations_by_timecode
       
   227                 .replace('__CONTENT_ID__', s.getMedia().id)
       
   228                 .replace('__BEGIN__', s.begin.valueOf())
       
   229                 .replace('__END__', s.end.valueOf());
       
   230             var proj = apidirectory.remoteSource({
       
   231                 url: url,
       
   232                 serializer: IriSP.serializers.ldt
       
   233             });
       
   234             proj.__segment = s;
       
   235             proj.onLoad(function() {
       
   236                 proj.__segment.__tags = {};
       
   237                 proj.getAnnotations().forEach(function(a) {
       
   238                     var tags = a.getTagTexts();
       
   239                     _(tags).each(function(t) {
       
   240                         var upt = t.toUpperCase(),
       
   241                             nl = 1 + (proj.__segment.__tags[upt] || 0),
       
   242                             ng = 1 + (globalTags[upt] || 0);
       
   243                         proj.__segment.__tags[upt] = nl;
       
   244                         globalTags[upt] = ng;
       
   245                     });
       
   246                     if (proj.__segment === currentSegment) {
       
   247                         showCurrentTags();
       
   248                     }
       
   249                 });
       
   250             });
       
   251             s.on("enter", function() {
       
   252                 currentSegment = s;
       
   253                 showCurrentTags();
       
   254                 $("#title_sequence li").removeClass("here");
       
   255                 $("#title_sequence li[data-segment-id='" + s.id + "']").addClass("here");
       
   256             });
       
   257         });
       
   258         
       
   259         segmentdragin.html(segmentsHtml);
       
   260         resizeSegmentDrag();
       
   261         
       
   262         currentMedia.play();
       
   263     });
       
   264     
       
   265     function showCurrentTags() {
       
   266         var vals = _(currentSegment.__tags).values(),
       
   267             max = Math.max.apply(Math, vals),
       
   268             min = Math.min(max - 1, Math.min.apply(Math, vals)),
       
   269             b = 160 / (max - min);
       
   270         var html = _(currentSegment.__tags)
       
   271             .chain()
       
   272             .map(function(v, k) {
       
   273                 var c = Math.floor( 95 + (v - min) * b );
       
   274                 return '<li><a href="'
       
   275                     + IriSP.endpoints.tag_page.replace("__TAG__",encodeURIComponent(k))
       
   276                     + '" style="color: rgb('
       
   277                     + [c,c,c].join(",")
       
   278                     + ')">'
       
   279                     + k
       
   280                     + ' </a> </li>'
       
   281             })
       
   282             .shuffle()
       
   283             .value()
       
   284             .join("");
       
   285         tagsdragin.html(html);
       
   286         resizeTagsDrag();
       
   287     }
       
   288     
       
   289     function addMedia(media) {
       
   290         if (media.has_player) {
       
   291             return;
       
   292         }
       
   293         media.has_player = true;
       
   294         media.loaded = false;
       
   295         media.paused = true;
       
   296         var videourl = media.video;
       
   297         if (typeof IriSP.video_url_transform === "function") {
       
   298             videourl = IriSP.video_url_transform(media.video);
       
   299         }
       
   300         var videoid = "video_" + media.id,
       
   301             videoEl = $('<video>'),
       
   302             seekCache = undefined,
       
   303             mp4_file = videourl.replace(/\.webm$/i,'.mp4'),
       
   304             webm_file = videourl.replace(/\.mp4$/i,'.webm'),
       
   305             mp4_src = $('<source>'),
       
   306             webm_src = $('<source>');
       
   307             
       
   308         mp4_src.attr({
       
   309             src: mp4_file,
       
   310             type: "video/mp4"
       
   311         })
       
   312         webm_src.attr({
       
   313             src: webm_file,
       
   314             type: "video/webm"
       
   315         });
       
   316 
       
   317         videoEl.attr({
       
   318             id : videoid
       
   319         }).css({
       
   320             position : "absolute",
       
   321             left: 0,
       
   322             top: 0,
       
   323             width : "100%",
       
   324             height : "100%"
       
   325         });
       
   326         videoEl.append(mp4_src).append(webm_src);
       
   327         $("#video_sequence").append(videoEl);
       
   328         var mediaEl = videoEl[0];
       
   329         
       
   330         media.show = function() {
       
   331             videoEl.show();
       
   332         }
       
   333         media.hide = function() {
       
   334             videoEl.hide();
       
   335         }
       
   336         
       
   337         // Binding functions to Media Element Functions
       
   338         
       
   339         media.on("setcurrenttime", function(_milliseconds) {
       
   340             try {
       
   341                 mediaEl.currentTime = (_milliseconds / 1000);
       
   342             }
       
   343             catch (err) {}
       
   344         });
       
   345         
       
   346         media.on("setvolume", function(_vol) {
       
   347             try {
       
   348                 media.volume = _vol;
       
   349                 mediaEl.volume = _vol;
       
   350             }
       
   351             catch (err) {}
       
   352         });
       
   353         
       
   354         media.on("setmuted", function(_muted) {
       
   355             try {
       
   356                 media.muted = _muted;
       
   357                 mediaEl.muted = _muted;
       
   358             }
       
   359             catch (err) {}
       
   360         });
       
   361         
       
   362         media.on("setplay", function() {
       
   363             try {
       
   364                 mediaEl.play();
       
   365             }
       
   366             catch (err) {}
       
   367         });
       
   368         
       
   369         media.on("setpause", function() {
       
   370             try {
       
   371                 mediaEl.pause();
       
   372             }
       
   373             catch (err) {}
       
   374         });
       
   375         
       
   376         // Binding DOM events to media
       
   377         
       
   378         function getVolume() {
       
   379             media.muted = mediaEl.muted;
       
   380             media.volume = mediaEl.volume;
       
   381         }
       
   382         
       
   383         videoEl.on("loadedmetadata", function() {
       
   384             getVolume();
       
   385             media.loaded = true;
       
   386             media.trigger("loadedmetadata");
       
   387             media.trigger("volumechange");
       
   388         })
       
   389         
       
   390         videoEl.on("timeupdate", function() {
       
   391             media.trigger("timeupdate", new IriSP.Model.Time(1000*mediaEl.currentTime));
       
   392         });
       
   393         
       
   394         videoEl.on("volumechange", function() {
       
   395             getVolume();
       
   396             media.trigger("volumechange");
       
   397         })
       
   398         
       
   399         videoEl.on("play", function() {
       
   400             media.trigger("play");
       
   401         });
       
   402         
       
   403         videoEl.on("pause", function() {
       
   404             media.trigger("pause");
       
   405         });
       
   406         
       
   407         videoEl.on("seeking", function() {
       
   408             media.trigger("seeking");
       
   409         });
       
   410         
       
   411         videoEl.on("seeked", function() {
       
   412             media.trigger("seeked");
       
   413         });
       
   414         
       
   415         // Binding UI Events and Mashup Playing to Media
       
   416         
       
   417         media.on("play", function() {
       
   418             $("#btnPlayPause, .video-wait, #progressBar .ui-slider-handle").addClass("pause");
       
   419         });
       
   420         
       
   421         media.on("pause", function() {
       
   422             $("#btnPlayPause, .video-wait, #progressBar .ui-slider-handle").removeClass("pause");
       
   423         });
       
   424         
       
   425         media.on("timeupdate", function(_time) {
       
   426             $("#current").text(_time.toString());
       
   427             if (!isClicking) {
       
   428                 timeSlider.slider("value", slidersRange * _time / media.duration);
       
   429             }
       
   430         });
       
   431             
       
   432     }
       
   433     
       
   434 }