integration/js/tagplayer.js
author veltr
Tue, 15 Jan 2013 17:16:51 +0100
changeset 76 4bdadca1cd5a
parent 73 fb4d0566ab19
child 81 a2befc2110c1
permissions -rw-r--r--
Now uses sort by weight option and unloads unnecessary video files

IriSP.tagplayer = function(opts) {
    var directory = new IriSP.Model.Directory(),
        project = directory.remoteSource({
            url: IriSP.endpoints.mashup_by_tag,
            url_params: {
                tag: '"' + opts.tag + '"',
                sort: "weight"
            },
            serializer: IriSP.serializers.ldt
        }),
        apidirectory = new IriSP.Model.Directory(),
        mashup,
        currentIndex = 0,
        currentSegment,
        currentMedia,
        globalTags = {},
        seqCount,
        mediasInDom = [],
        MAX_LOADED_VIDEOS = 2;
        
    var ratio = 2.37;

    if (typeof window.localStorage !== "undefined" && window.localStorage.getItem !== "undefined") {
        var resolution = window.localStorage.getItem("resolution") || "SD";
    } else {
        var resolution = "SD";
    }
    var video_url_transform = function(url) {
        return url.replace(/[SH]D(\.[a-z0-9]+)$/,resolution + "$1");
    }
    
    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;
    timeSlider.slider({
        range: "min",
        value: 0,
        min: 0,
        max: slidersRange,
        slide: function(event, ui) {
            var t = currentSegment.begin + ( currentSegment.getDuration() * ui.value / slidersRange );
            currentMedia.setCurrentTime(t);
        }
    });
    
    $("#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");
        if (segmentdelta < 0 && $("#title_sequence li").length) {
            var x = $("#title_sequence li[data-segment-index='" + currentIndex + "']").offset().left - segmentdragin.offset().left;
            segmentdragin.css("left", Math.max(segmentdelta - 20, Math.min( 20, 36 - x)))
        }
    }
    
    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(toRight) {
        var tagsdelta = tagsdragout.width() - tagsdragin.width();
        tagsdragin.draggable("option","containment",tagsdelta < 0 ? [ tagsdelta - 20, 0, 20, 0 ] : "parent");
        tagsdragin.css("left",(toRight && tagsdelta < 0) ? tagsdelta - 20 : 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]"),
        replacerx;
    taginput.autocomplete({
        source: function(params, response) {
            var charsub = [ '[aáàâä]', '[cç]', '[eéèêë]', '[iíìîï]', '[oóòôö]' ],
                term = params.term.replace(/([\\\*\+\?\|\{\[\}\]\(\)\^\$\.\#\/])/gm, '\\$1');
            _(charsub).each(function(chars) {
                var tmprx = new RegExp(chars,"gim");
                term = term.replace(tmprx, chars);
            });
            var searchrx = new RegExp("(^|\\s)" + term, "i");
            replacerx = new RegExp("(^|\\s)(" + term + ")", "gi");
            response(
                _(globalTags)
                    .chain()
                    .keys()
                    .filter(function(tag) {
                        return searchrx.test(tag)
                    })
                    .sortBy(_.identity)
                    .value()
                );
        }
    }).data("autocomplete")._renderItem = function(ul, item) {
        return $( "<li>" )
            .data( "item.autocomplete", item )
            .append( "<a>" + item.label.replace(replacerx, '$1<b>$2</b>') + "</a>" )
            .appendTo( ul );
    };
    taginput.on("keyup input paste", function() {
        taginput.val(taginput.val().toUpperCase());
    });
    $("#form_tag").on("submit", function() {
        var _tagvalue = taginput.val().toUpperCase();
        taginput.val("");
        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 = currentSegment.title;
            _annotation.created = new Date(); /* Date de création de l'annotation */
            _annotation.description = _tagvalue;
            
            _annotation.setTags([_tag.id]); /*Liste des ids de tags */
            
            _annotation.creator = "theend";
            _annotation.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(_tagvalue);
                },
                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(function(m) {
            addMedia(m);
        });
        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();
        var followingMedias = [];
        for (var i = n; i < mashup.segments.length; i++) {
            followingMedias.push(mashup.segments[i].getMedia());
        }
        followingMedias = _(followingMedias).uniq().slice(0, MAX_LOADED_VIDEOS);
        var mediasToRemove = _(mediasInDom).difference(followingMedias);
        _(mediasToRemove).each(function(m) {
            m.removeFromDom();
        });
        followingMedias = _(followingMedias).difference(mediasInDom);
        _(followingMedias).each(function(m) {
            m.addToDom();
        });
        mashup.getMedias().forEach(function(m) {
            if (m === currentMedia) {
                m.show();
            } else {
                m.hide();
            }
        });
        console.log("There are now",mediasInDom.length,'~',$("video").length,"<video>s in DOM");
        $("#title_sequence li").removeClass("here");
        $("#title_sequence li[data-segment-index='" + n + "']").addClass("here");
        resizeSegmentDrag();
        $("#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").removeClass("pause");
        }
        currentMedia.play();
    }
    
    function showCurrentTags(tagToShow) {
        var vals = _(currentSegment.__tags).values(),
            max = Math.max.apply(Math, vals),
            min = Math.min(max - 1, Math.min.apply(Math, vals)),
            b = 160 / (max - min),
            tagList = _(currentSegment.__tags).map(function(v, k) {
                return {
                    label: k,
                    weight: v
                }
            });
        tagList = _(tagList).shuffle();
        if (tagToShow && currentSegment.__tags[tagToShow]) {
            tagList = tagList.filter(function(t) {
                return (t.label !== tagToShow);
            });
            tagList.push({
                label: tagToShow,
                weight: currentSegment.__tags[tagToShow]
            });
        }
        var html = tagList.reduce(
            function(memo, tag) {
                var c = Math.floor( 95 + (tag.weight - min) * b );
                return memo + '<li><a href="'
                    + IriSP.endpoints.tag_page.replace("__TAG__",encodeURIComponent(tag.label))
                    + '" style="color: rgb('
                    + [c,c,c].join(",")
                    + ')">'
                    + tag.label
                    + ' </a> </li>';
            },
            "");
        tagsdragin.html(html);
        resizeTagsDrag(!!tagToShow);
    }
    
    var can_play_mp4 = !!document.createElement('video').canPlayType('video/mp4');
    
    function addMedia(media) {
        if (media.is_added) {
            return;
        }
        media.is_added = true;
        
        var videourl = video_url_transform(media.video),
            videoid = "video_" + media.id,
            mp4_file = videourl.replace(/\.webm$/i,'.mp4'),
            webm_file = videourl.replace(/\.mp4$/i,'.webm'),
            video_file = can_play_mp4 ? mp4_file : webm_file,
            videoEl = undefined,
            mediaEl = undefined;
        
        media.addToDom = function() {
            if (videoEl) {
                return;
            }
            console.log("Adding to DOM",media.title);
            mediasInDom.push(media);
            mediasInDom = _(mediasInDom).uniq();
            media.loaded = false;
            media.paused = true;
            videoEl = $('<video>');
            mediaEl = videoEl[0];
            
            videoEl.attr({
                src : video_file,
                id : videoid
            }).css({
                position : "absolute",
                left: 0,
                top: 0,
                width : "100%",
                height : "100%",
                display: "none"
            });
    
            $("#video_sequence").append(videoEl);
            
            // 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");
            });
        }
        
        media.removeFromDom = function() {
            console.log("Removing from DOM",media.title);
            videoEl.remove();
            videoEl = undefined;
            mediaEl = undefined;
            mediasInDom = _(mediasInDom).without(media);
        }
        media.show = function() {
            if (!videoEl) {
                media.addToDom();
            }
            console.log("Showing media",media.title);
            videoEl.show();
        }
        media.hide = function() {
            if (videoEl) {
                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() {
            if (!mediaEl) {
                return;
            }
            try {
                mediaEl.pause();
            }
            catch (err) {}
        });
        
        // Binding UI Events and Mashup Playing to Media
        
        media.on("play", function() {
            if (media === currentMedia) {
                $("#btnPlayPause, .video-wait").addClass("pause");
            }
        });
        
        media.on("pause", function() {
            if (media === currentMedia) {
                $("#btnPlayPause, .video-wait").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());
                    timeSlider.slider("value", slidersRange * t / currentSegment.getDuration());
                } else {
                    media.pause();
                    if (currentIndex < seqCount - 1) {
                        goToPart(currentIndex + 1)
                    } else {
                        document.location = $(".link_prev").attr("href");
                    }
                }
            }
        });
            
    }
    
    $(".sdhdgroup").addClass(resolution);
    
    $(".sdhdbtn").click(function() {
        var newres = $(this).attr("title");
        if (resolution !== newres) {
            window.localStorage.setItem("resolution", newres);
            document.location.reload();
        }
        return false;
    });
    
    $("#btnInfo, .lightBoxClose").click(function() {
        $(".lightBoxWrap").toggle();
        return false;
    });
    
}