Clickable “positioning” hyperlinks to A/V (locally

2019-09-04 03:39发布

Meta: This question is a follow-up, or a variant of a similar question about embedded Youtube videos: How to target "hidden" iframes? (application: links to starting positions of a "poster image hidden"-embedded Youtube video)


Definitions:

A "poster" image

A customized image on which you click, to reveal the actual A/V player.

Locally stored

The A/V is stored on your website, as opposed to a streaming service such as Youtube.

Clickable "positioning" hyperlinks

When a certain hyperlink inside an HTML text, a predefined starting (and perhaps ending) position of the A/V is addressed and automatically played.


I have been reading things on the net about function(){something.currentTime=...;});, but I have not been able to implement this.

1条回答
淡お忘
2楼-- · 2019-09-04 04:02

Demo

I'm sorry for the delay, and for it not being exactly the same as the Youtube one, the thing I lack most it's consistency, but here it is.

I've based this example in two songs from Hozier, one in audio and one in video format. (Hope nobody sues me)

As always you can modify the styles later on to fit your design, I just put something quick together to demonstrate.

Below, you will see a basic example of how the code works (for a more in-depth example, please refer to the demo).

HTML

Audio

<div class="mediaAudioFacade"
     id="id"
     data-sources="source1.mp3,source2.wav,source3.ogg"
     data-start="seconds"(optional)
     data-end="seconds"(optional)>
label
</div>

<div class="mediaJumper" data-id="id" data-time="seconds">label</div>

Video

<div class="mediaVideoFacade" (..)>(..)</div>
(..)

The only difference would be the class attribute, this being mediaVideoFacade instead of mediaAudioFacade.

JavaScript

    window.addEventListener("load",function(){
    setUpMediaObjects();
    setUpMediaJumpers();
});
MediaObjects = [];
MediaJumpers = [];

function setUpMediaObjects() {
    var allAudioFacades = document.querySelectorAll(".mediaAudioFacade");
    if (allAudioFacades) {
        for (var i = 0; i < allAudioFacades.length; i++) {
            var facade = allAudioFacades[i];
            var mo = new MediaObject(facade);
            MediaObjects.push(mo);
        }
    }

    var allVideoFacades = document.querySelectorAll(".mediaVideoFacade");
    if (allVideoFacades) {
        for (var i = 0; i < allVideoFacades.length; i++) {
            var facade = allVideoFacades[i];
            var mo = new MediaObject(facade);
            MediaObjects.push(mo);
        }
    }
}

function setUpMediaJumpers(){
    var allMediaJumpers = document.querySelectorAll(".mediaJumper");
    for( var i = 0 ; i < allMediaJumpers.length ; i ++ ){
        var mediaJumper = allMediaJumpers[i];
        var mj = new MediaJumper(mediaJumper);
        MediaJumpers.push(mj);
    }
}


function MediaObject(facade) {
    this.facade = facade;
    this.id = this.facade.id;
    this.sourcesURI = this.facade.dataset.sources.split(",");
    this.sources = this.getSources();
    var isAudio = this.facade.className.match(/mediaAudioFacade/);
    this.type = (isAudio) ? "audio" : "video";
    this.icon = new Image();
        this.icon.src = (isAudio) ? "http://i.imgur.com/HKktAoE.png" : "http://findicons.com/icon/download/566082/video_play/33/png";
        this.setUpFacade();
    this.capType = this.type.substr(0,1).toUpperCase() + this.type.substr(1);
    this.elem = document.createElement(this.type);
    this.elem.controls = "true";
    this.elem.className = "mediaType".replace(/type/i, this.capType);
    this.hasStarted = false;
    this.appendSources();
    this.startTime = this.facade.dataset.start;
    this.endTime = this.facade.dataset.end;
    this.facade.addEventListener("click", this.startUp.bind(this) );
}

MediaObject.prototype.setUpFacade = function () {
    var label = document.createElement("span");
    label.innerHTML = this.facade.innerHTML || "Play audio.";
    this.facade.innerHTML = "";
    this.facade.appendChild(this.icon);
    this.facade.appendChild(label);
}

MediaObject.prototype.getSources = function () {
    var sources = [];
    for (var i = 0; i < this.sourcesURI.length; i++) {
        var sourceURI = this.sourcesURI[i];
        var source = document.createElement("source");
        source.src = sourceURI;
        sources.push(source);
    }
    return sources;
}

MediaObject.prototype.appendSources = function () {
    for (var i = 0; i < this.sources.length; i++) {
        var source = this.sources[i];
        this.elem.appendChild(source);
    }
}

MediaObject.prototype.startUp = function () {
    this.replaceNode(this.facade, this.elem);
    this.hasStarted = true;
    if( this.startTime )
        this.elem.currentTime = this.startTime;
    if( this.endTime )
        this.elem.addEventListener("timeupdate",this.checkForVideoEnd.bind(this));
    this.elem.play();
}

MediaObject.prototype.checkForVideoEnd = function(){
    console.log(this.elem.currentTime);
    if( Math.floor(this.elem.currentTime) == this.endTime )
        this.elem.pause();
}

MediaObject.prototype.replaceNode = function(node1,node2){
    var parent = node1.parentNode;
    var next = node1.nextSibling;
    if( next )
        parent.insertBefore(node2,next);
    else
        parent.appendChild(node2);
    parent.removeChild(node1);
}

function MediaJumper(jumper){
    this.jumper = jumper;
    this.id = this.jumper.dataset.id;
    this.mediaObject = this.getMediaObject();
    this.time = this.jumper.dataset.time;
    this.jumper.addEventListener("click",this.jump.bind(this));
}

MediaJumper.prototype.getMediaObject = function(){
    for( var i = 0 ; i < MediaObjects.length ; i ++ ){
        var mediaObj = MediaObjects[i];
        if( mediaObj.id == this.id )
            return mediaObj;
    }
    return null;
}

MediaJumper.prototype.jump = function(){
    if( this.mediaObject ){
        if( !this.mediaObject.hasStarted )
            this.mediaObject.startUp();
        this.mediaObject.elem.currentTime = this.time;
        this.mediaObject.elem.play();
    }
}

Feel free to ask any question's about the code, or report anything that is not working, good luck and hope it helps! :)

Updates

  • Added a data-start and data-end, note that data-end will only stop the video if the time specified matches the current time of the video floored. Technically:

    if( Math.Floor(MediaCurrentTime) == DataEndTime ) stop();

This means if a jumper is called it will continue to play normally until it hits that number again, and if the jumper calls for a time beyond the data-end, then the video will be played normally.

查看更多
登录 后发表回答