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