Videojs: plugin download with resolution selector


videojs plugin download

HTML:

<video id="example_video" class="video-js vjs-default-skin" controls preload="none" width="640" height="264" poster="http://video-js.zencoder.com/oceans-clip.png" data-setup='{}'>
    <source data-res="480" src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
    <source data-res="240" src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
    <source data-res="720" src="http://video-js.zencoder.com/oceans-clip.mp4" type='video/mp4' />
    <track kind="captions" src="demo.captions.vtt" srclang="en" label="English"></track>
    <!-- Tracks need an ending tag thanks to IE9 -->
    <track kind="subtitles" src="demo.captions.vtt" srclang="en" label="English"></track>
    <!-- Tracks need an ending tag thanks to IE9 -->
    <p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a>
    </p>
</video>

CSS:

.vjs-dl-button.vjs-menu-button.vjs-control {
    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAAB6JQAAgIMAAPn/AACA6QAAdTAAAOpgAAA6mAAAF2+SX8VGAAAA80lEQVR42rSUsUoDQRCGP+WKCHkFX0AsLewOE9DYp0lnYXtPY+MLpRB7X0BSCDFGBA+L87PZQmFn767wh4FlZ+bbhf1nUcnEVL1Xd+o+xS7tTXM9BKCVsVa5nkPyOiZWNheBugKoGwMarX8HfRV6srnq1/oMOAdaoC6A6lRzBDwAj8Cf56/VD4frU51FPpqr2wGQN/W6z5DzVBjpXV0MdfaF+pqB7NXLaEQmahXAtgMglTpBXavL4GYz9SUBr4KapbomndYERagn6mkh36hWaXbagm+eekzdAl0FbIDbZM6xI/MN3ACbA3UB3PV8HSU9A83PAANeN+uxqxQHAAAAAElFTkSuQmCC);
    background-repeat: no-repeat;
    background-position: 10px 4px;
}

JS:

/*
 * Videojs Plugin for download
 * By: tutorialspots.com
 * Base on Video.js Resolution Selector (https://github.com/dominic-p/videojs-resolution-selector)
 * Thanks for Dominic P
*/

(function (_V_) {

    var methods = {
        res_label: function (res) {
            return (/^\d+$/.test(res)) ? res + 'p' : res;
        }
    };

    _V_.DownloadMenuItem = _V_.MenuItem.extend({
        call_count: 0,
        init: function (player, options) {
            var touchstart = false;
            // Modify options for parent MenuItem class's init.
            options.label = methods.res_label(options.res);
            // Call the parent constructor
            _V_.MenuItem.call(this, player, options);
            // Store the resolution as a property
            this.resolution = options.res;
            // Register our click and tap handlers
            this.on(['click', 'tap'], this.onClick);
        }
    });

    // Handle clicks on the menu items
    _V_.DownloadMenuItem.prototype.onClick = function () {
        // Check if this has already been called
        if (this.call_count > 0) {
            return;
        }
        // Call the player.changeDl method
        this.player().changeDl(this.resolution);
        // Increment the call counter
        this.call_count++;
    };


    _V_.DownloadTitleMenuItem = _V_.MenuItem.extend({
        init: function (player, options) {
            // Call the parent constructor
            _V_.MenuItem.call(this, player, options);
            // No click handler for the menu title
            this.off('click');
        }
    });

    _V_.DownloadSelector = _V_.MenuButton.extend({

        init: function (player, options) {
            // Add our list of available resolutions to the player object
            player.availableRes = options.available_res;
            // Call the parent constructor
            _V_.MenuButton.call(this, player, options);
            // Set the button text based on the option provided
            this.el().firstChild.firstChild.innerHTML = options.buttonText;
        }
    });

    // Set class for resolution selector button
    _V_.DownloadSelector.prototype.className = 'vjs-dl-button';

    // Create a menu item for each available resolution
    _V_.DownloadSelector.prototype.createItems = function () {
        var player = this.player(),
            items = [];
        // Add the menu title item
        items.push(new _V_.DownloadTitleMenuItem(player, {
            el: _V_.Component.prototype.createEl('li', {
                className: 'vjs-menu-title vjs-dl-menu-title',
                innerHTML: player.localize('Quality')
            })
        }));

        // Add an item for each available resolution
        for (current_res in player.availableRes) {
            // Don't add an item for the length attribute
            if ('length' == current_res) {
                continue;
            }
            items.push(new _V_.DownloadMenuItem(player, {
                res: current_res
            }));
        }

        // Sort the available resolutions in descending order
        items.sort(function (a, b) {
            if (typeof a.resolution == 'undefined') {
                return -1;
            } else {
                return parseInt(b.resolution) - parseInt(a.resolution);
            }
        });

        return items;
    };

    _V_.plugin('DownloadSelector', function (options) {
        // Only enable the plugin on HTML5 videos
        if (!this.el().firstChild.canPlayType) {
            return;
        }
        var player = this,
            sources = player.options().sources,
            i = sources.length,
            available_res = {
                length: 0
            },
            current_res,
            DownloadSelector;

        // Get all of the available resolutions
        while (i > 0) {
            i--;
            // Skip sources that don't have data-res attributes
            if (!sources[i]['data-res']) {
                continue;
            }
            current_res = sources[i]['data-res'];
            if (typeof available_res[current_res] !== 'object') {

                available_res[current_res] = [];
                available_res.length++;
            }
            available_res[current_res].unshift(sources[i]);
        }

        if (typeof player.localize !== 'function') {
            player.localize = function (string) {
                return string;
            };
        }

        // Define the change res method
        player.changeDl = function (target_resolution) {
            callback = options.callback || function (a) {
                return a;
            }
            var win = window.open(callback(player.availableRes[target_resolution][0].src), '_blank');
            //var win = window.open(player.availableRes[target_resolution][0].src, '_blank');
            if (win) {
                //Browser has allowed it to be opened
                win.focus();
            } else {
                //Broswer has blocked it
                alert('Please allow popups for this site');
            }
        };

        // Add the resolution selector button
        DownloadSelector = new _V_.DownloadSelector(player, {
            buttonText: 'Download',
            available_res: available_res
        });

        // Add the button to the control bar object and the DOM
        player.controlBar.DownloadSelector = player.controlBar.addChild(DownloadSelector);
    });

})(videojs);
$(document).ready(function () {
    videojs('example_video', {
        "plugins": {
            "DownloadSelector": {
                "callback": function (a) {
                    return a + (a.match(/\?/)?'&':'?')+'forcedownload'
                }
            }
        }
    });
})

Download:
videojs-dowload.js
videojs-dowload.css

Online demo: http://jsfiddle.net/sans_amour/up8vzu4s/4/

The callback function we can leave blank, the download link will same as the play link.

$(document).ready(function () {
    videojs('example_video', {
        "plugins": {
            "DownloadSelector": {}
        }
    });
})

With the callback function, we can modify the download link, like use shorten link (ouo.io, bc.vc, adf.ly…)

In the future, we’ll write a tutorial for make shorten link with PHP.

Note: The example use some external resource:
http://vjs.zencdn.net/4.9.1/video-js.css
http://vjs.zencdn.net/4.9.1/video.js
http://code.jquery.com/jquery-2.1.3.js

Leave a Reply