integration/js/tagplayer.js
changeset 50 9cc1b66d0880
child 64 458cc4576415
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/integration/js/tagplayer.js	Fri Dec 14 13:07:58 2012 +0100
@@ -0,0 +1,487 @@
+IriSP.tagplayer = function(opts) {
+    var directory = new IriSP.Model.Directory(),
+        project = directory.remoteSource({
+            url: IriSP.endpoints.mashup_by_tag,
+            url_params: {
+                tag: opts.tag
+            },
+            serializer: IriSP.serializers.ldt
+        }),
+        apidirectory = new IriSP.Model.Directory(),
+        mashup,
+        currentIndex = 0,
+        currentSegment,
+        currentMedia,
+        globalTags = {},
+        seqCount;
+        
+    var ratio = 2.37;
+
+    function resizeVideo() {
+        var currentwidth = $(window).width(),
+            maxheight = $(window).height() - 220,
+            height = Math.min(maxheight, currentwidth / ratio),
+            width = ratio * height;
+        $("#video_sequence").css({
+            width: Math.floor(width),
+            height: Math.floor(height)
+        });
+    }
+    
+    $(window).on("resize", resizeVideo);
+    resizeVideo();
+    
+    var timeSlider = $("#progressBar"),
+        slidersRange = 1000,
+        wasPaused = true,
+        lastVal = 0,
+        isClicking = false;
+    timeSlider.slider({
+        range: "min",
+        value: 0,
+        min: 0,
+        max: slidersRange,
+        slide: function(event, ui) {
+            if (isClicking && Math.abs(lastVal - ui.value) > 10) {
+                isClicking = false;
+            }
+            if (!isClicking && currentSegment && currentMedia) {
+                var t = currentSegment.begin + ( currentSegment.getDuration() * ui.value / slidersRange );
+                currentMedia.setCurrentTime(t);
+            }
+        },
+        start: function(event, ui) {
+            isClicking = true;
+            lastVal = ui.value;
+        },
+        stop: function(event, ui) {
+            if (isClicking && currentMedia && currentSegment) {
+                var t = currentMedia.getCurrentTime() - currentSegment.begin;
+                timeSlider.slider("value", slidersRange * t / currentSegment.getDuration());
+                playOrPause();
+            }
+            isClicking = false;
+        }
+    });
+    
+    $("#btnBck").click(function() {
+        var newn = currentIndex ? ( currentIndex - 1 ) : ( seqCount - 1 );
+        goToPart(newn);
+        return false;
+    });
+    $("#btnFwd").click(function() {
+        var newn = ( 1 + currentIndex ) % seqCount;
+        goToPart(newn);
+        return false;
+    });
+    
+    function playOrPause() {
+        if (currentMedia) {
+            if (currentMedia.paused) {
+                currentMedia.play();
+            } else {
+                currentMedia.pause();
+            }
+        }
+    }
+    
+    $(".video-wait, #btnPlayPause").click(function() {
+        playOrPause();
+        return false;
+    });
+    
+    var segmentdragout = $("#title_sequence"),
+        segmentdragin = segmentdragout.find("ul")
+        segmentdragging = false;
+    
+    function resizeSegmentDrag() {
+        var segmentdelta = segmentdragout.width() - segmentdragin.width();
+        segmentdragin.draggable("option","containment",segmentdelta < 0 ? [ segmentdelta - 20, 0, 20, 0 ] : "parent")
+    }
+    
+    segmentdragin.draggable({
+        axis: "x",
+        start: function() {
+            segmentdragging = true;
+        },
+        stop: function() {
+            segmentdragging = false;
+        }
+    });
+    
+    $(window).on("resize", resizeSegmentDrag);
+    resizeSegmentDrag();   
+    
+    segmentdragin.on("mouseup", "li", function() {
+        if (!segmentdragging) {
+            goToPart(parseInt($(this).attr("data-segment-index")));
+        }
+    }).click(function() {
+        return false;
+    });
+     
+    var tagsdragout = $("#tag_sequence"),
+        tagsdragin = tagsdragout.find("ul")
+        tagsdragging = false;
+    
+    function resizeTagsDrag() {
+        var tagsdelta = tagsdragout.width() - tagsdragin.width();
+        tagsdragin.draggable("option","containment",tagsdelta < 0 ? [ tagsdelta - 20, 0, 20, 0 ] : "parent");
+        tagsdragin.css("left",Math.floor(tagsdelta/2));
+    }
+    
+    tagsdragin.draggable({
+        axis: "x",
+        start: function() {
+            tagsdragging = true;
+        },
+        stop: function() {
+            tagsdragging = false;
+        }
+    });
+    
+    $(window).on("resize", resizeTagsDrag);
+    resizeTagsDrag();
+    
+    var taginput = $("#form_tag input[type=text]");
+    taginput.autocomplete({
+        source: function(params, response) {
+            var rx = new RegExp(params.term,"gi");
+            response(
+                _(globalTags)
+                    .chain()
+                    .keys()
+                    .filter(function(tag) {
+                        return rx.test(tag)
+                    })
+                    .shuffle()
+                    .first(5)
+                    .value()
+                );
+        }
+    });
+    taginput.on("keyup input paste", function() {
+        taginput.val(taginput.val().toUpperCase());
+    });
+    $("#form_tag").on("submit", function() {
+        var _tagvalue = taginput.val().toUpperCase();
+        if (_tagvalue && currentSegment) {
+            /* Création d'une liste d'annotations contenant une annotation afin de l'envoyer au serveur */
+            var _exportedAnnotations = new IriSP.Model.List(directory),
+                /* Création d'un objet source utilisant un sérialiseur spécifique pour l'export */
+                _export = directory.newLocalSource({
+                    serializer: IriSP.serializers.ldt_annotate
+                }),
+                /* Création d'une annotation dans cette source avec un ID généré à la volée (param. false) */
+                _annotation = new IriSP.Model.Annotation(false, _export),
+                /* Si le Type d'Annotation n'existe pas, il est créé à la volée */
+                _annotationType = new IriSP.Model.AnnotationType(false, _export),
+                /* L'objet Tag qui sera envoyé */
+                _tag = new IriSP.Model.Tag(false, _export);
+            /* L'objet Tag doit avoir pour titre le texte du tag envoyé */
+            _tag.title = _tagvalue;
+            /* Si nous avons dû générer un ID d'annotationType à la volée... */
+            _annotationType.dont_send_id = true;
+            /* Il faut inclure le titre dans le type d'annotation */
+            _annotationType.title = "Contribution";
+
+            _annotation.setMedia(currentSegment.getMedia().id);
+            _annotation.setBegin(currentSegment.begin);
+            _annotation.setEnd(currentSegment.end);
+            
+            _annotation.setAnnotationType(_annotationType.id); 
+            
+            _annotation.title = _tagvalue;
+            _annotation.created = new Date(); /* Date de création de l'annotation */
+            _annotation.description = _tagvalue;
+            
+            _annotation.setTags([_tag.id]); /*Liste des ids de tags */
+            
+            /* Les données créateur/date de création sont envoyées non pas dans l'annotation, mais dans le projet */
+            _export.creator = "theend";
+            _export.created = new Date();
+            /* Ajout de l'annotation à la liste à exporter */
+            _exportedAnnotations.push(_annotation);
+            /* Ajout de la liste à exporter à l'objet Source */
+            _export.addList("annotation",_exportedAnnotations);
+            
+            var segmentAtPost = currentSegment;
+            
+            IriSP.jQuery.ajax({
+                url: IriSP.endpoints.post_annotation,
+                type: "POST",
+                contentType: 'application/json',
+                data: _export.serialize(), /* L'objet Source est sérialisé */
+                success: function(_data) {
+                    var n = 1 + (segmentAtPost.__tags[_tagvalue] || 0)
+                    segmentAtPost.__tags[_tagvalue] = n;
+                    showCurrentTags();
+                },
+                error: function(_xhr, _error, _thrown) {
+                    console.log("Error when sending annotation", _thrown);
+                }
+            });
+        }
+        return false;
+    });
+    
+    project.onLoad(function() {
+        mashup = project.getMashups()[0];
+        if (!mashup) {
+            return;
+        }
+        mashup.getMedias().forEach(addMedia);
+        seqCount = mashup.segments.length;
+        var html = mashup.segments.map(function(s, i) {
+                return '<li data-segment-index="' + i + '"><a href="#">' + s.title + ' </a> </li>'
+            }).join("");
+        segmentdragin.html(html);
+        resizeSegmentDrag();
+        goToPart(0);
+        mashup.segments.forEach(function(s) {
+            var url = IriSP.endpoints.annotations_by_timecode
+                .replace('__CONTENT_ID__', s.getMedia().id)
+                .replace('__BEGIN__', s.annotation.begin.valueOf())
+                .replace('__END__', s.annotation.end.valueOf());
+            var proj = apidirectory.remoteSource({
+                url: url,
+                serializer: IriSP.serializers.ldt
+            });
+            proj.__segment = s.annotation;
+            proj.onLoad(function() {
+                proj.__segment.__tags = {};
+                proj.getAnnotations().forEach(function(a) {
+                    var tags = a.getTagTexts();
+                    _(tags).each(function(t) {
+                        var upt = t.toUpperCase(),
+                            nl = 1 + (proj.__segment.__tags[upt] || 0),
+                            ng = 1 + (globalTags[upt] || 0);
+                        proj.__segment.__tags[upt] = nl;
+                        globalTags[upt] = ng;
+                    });
+                    if (proj.__segment === currentSegment) {
+                        showCurrentTags();
+                    }
+                });
+            });
+        });
+    });
+    
+    function goToPart(n) {
+        if (currentMedia) {
+            currentMedia.pause();
+        }
+        currentIndex = n;
+        currentSegment = mashup.segments[n].annotation;
+        currentMedia = currentSegment.getMedia();
+        mashup.getMedias().forEach(function(m) {
+            if (m === currentMedia) {
+                m.show();
+            } else {
+                m.hide();
+            }
+        });
+        $("#title_sequence li").removeClass("here");
+        $("#title_sequence li[data-segment-index='" + n + "']").addClass("here");
+        $("#duration").text(currentSegment.getDuration().toString());
+        
+        if (currentSegment.__tags) {
+            showCurrentTags();
+        }
+        timeSlider.slider("value",0);
+        currentMedia.setCurrentTime(currentSegment.begin);
+        if (!currentMedia.loaded) {
+            $(".video-wait").show();
+            $("#btnPlayPause, .video-wait, #progressBar .ui-slider-handle").removeClass("pause");
+        }
+        currentMedia.play();
+    }
+    
+    function showCurrentTags() {
+        var vals = _(currentSegment.__tags).values(),
+            max = Math.max.apply(Math, vals),
+            min = Math.min(max - 1, Math.min.apply(Math, vals)),
+            b = 128 / (max - min);
+        var html = _(currentSegment.__tags)
+            .chain()
+            .map(function(v, k) {
+                var c = Math.floor( 127 + (v - min) * b );
+                return '<li><a href="'
+                    + IriSP.endpoints.tag_page.replace("__TAG__",encodeURIComponent(k))
+                    + '" style="color: rgb('
+                    + [c,c,c].join(",")
+                    + ')">'
+                    + k
+                    + ' </a> </li>'
+            })
+            .shuffle()
+            .value()
+            .join("");
+        tagsdragin.html(html);
+        resizeTagsDrag();
+    }
+    
+    function addMedia(media) {
+        if (media.has_player) {
+            return;
+        }
+        media.has_player = true;
+        media.loaded = false;
+        media.paused = true;
+        var videourl = media.video;
+        if (typeof IriSP.video_url_transform === "function") {
+            videourl = IriSP.video_url_transform(media.video);
+        }
+        var videoid = "video_" + media.id,
+            videoEl = $('<video>'),
+            seekCache = undefined,
+            mp4_file = videourl.replace(/\.webm$/i,'.mp4'),
+            webm_file = videourl.replace(/\.mp4$/i,'.webm'),
+            mp4_src = $('<source>'),
+            webm_src = $('<source>');
+            
+        mp4_src.attr({
+            src: mp4_file,
+            type: "video/mp4"
+        })
+        webm_src.attr({
+            src: webm_file,
+            type: "video/webm"
+        });
+
+        videoEl.attr({
+            id : videoid
+        }).css({
+            position : "absolute",
+            left: 0,
+            top: 0,
+            width : "100%",
+            height : "100%"
+        });
+        videoEl.append(mp4_src).append(webm_src);
+        $("#video_sequence").append(videoEl);
+        var mediaEl = videoEl[0];
+        
+        media.show = function() {
+            videoEl.show();
+        }
+        media.hide = function() {
+            videoEl.hide();
+        }
+        
+        // Binding functions to Media Element Functions
+        
+        media.on("setcurrenttime", function(_milliseconds) {
+            try {
+                mediaEl.currentTime = (_milliseconds / 1000);
+            }
+            catch (err) {}
+        });
+        
+        media.on("setvolume", function(_vol) {
+            try {
+                media.volume = _vol;
+                mediaEl.volume = _vol;
+            }
+            catch (err) {}
+        });
+        
+        media.on("setmuted", function(_muted) {
+            try {
+                media.muted = _muted;
+                mediaEl.muted = _muted;
+            }
+            catch (err) {}
+        });
+        
+        media.on("setplay", function() {
+            try {
+                mediaEl.play();
+            }
+            catch (err) {}
+        });
+        
+        media.on("setpause", function() {
+            try {
+                mediaEl.pause();
+            }
+            catch (err) {}
+        });
+        
+        // Binding DOM events to media
+        
+        function getVolume() {
+            media.muted = mediaEl.muted;
+            media.volume = mediaEl.volume;
+        }
+        
+        videoEl.on("loadedmetadata", function() {
+            getVolume();
+            media.loaded = true;
+            media.trigger("loadedmetadata");
+            media.trigger("volumechange");
+        })
+        
+        videoEl.on("timeupdate", function() {
+            media.trigger("timeupdate", new IriSP.Model.Time(1000*mediaEl.currentTime));
+        });
+        
+        videoEl.on("volumechange", function() {
+            getVolume();
+            media.trigger("volumechange");
+        })
+        
+        videoEl.on("play", function() {
+            media.trigger("play");
+        });
+        
+        videoEl.on("pause", function() {
+            media.trigger("pause");
+        });
+        
+        videoEl.on("seeking", function() {
+            media.trigger("seeking");
+        });
+        
+        videoEl.on("seeked", function() {
+            media.trigger("seeked");
+        });
+        
+        // Binding UI Events and Mashup Playing to Media
+        
+        media.on("play", function() {
+            if (media === currentMedia) {
+                $("#btnPlayPause, .video-wait, #progressBar .ui-slider-handle").addClass("pause");
+            }
+        });
+        
+        media.on("pause", function() {
+            if (media === currentMedia) {
+                $("#btnPlayPause, .video-wait, #progressBar .ui-slider-handle").removeClass("pause");
+            }
+        });
+        
+        media.on("timeupdate", function(_time) {
+            if (media === currentMedia) {
+                if ( _time < currentSegment.end ) {
+                    var t = 0;
+                    if ( _time >= ( currentSegment.begin - 40 ) ) { // Add one frame of tolerance
+                        t = Math.max(0, _time - currentSegment.begin);
+                    } else {
+                        media.setCurrentTime(currentSegment.begin);
+                    }
+                    $("#current").text(new IriSP.Model.Time(t).toString());
+                    if (!isClicking) {
+                        timeSlider.slider("value", slidersRange * t / currentSegment.getDuration());
+                    }
+                } else {
+                    media.pause();
+                    goToPart((currentIndex + 1) % seqCount)
+                }
+            }
+        });
+            
+    }
+    
+    
+}