Subscribed unsubscribe Subscribe Subscribe

Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

Update: LDR で最速動画ウォッチング + YouTube Anywhere

LDR YouTube greasemonkey

"どこでも YouTube" を実現する Greasemonkey スクリプト YouTube Anywhere」で公開したスクリプトを、せっかくなので、LDR にも対応してみました。「livedoor Reader + YouTube + はてなブックマークで最速動画ウォッチング」と「"どこでも YouTube" を実現する Greasemonkey スクリプト YouTube Anywhere」を足して 2 で割らない感じ。つってもまぁ、最低限 LDR 上で動くようにしただけなのがアレ。それなりに動くので、まぁいいや。あと、ついでにnirvashの日記に触発されて、Qooqle Video Clippers!HATENA-TUBE のフィードにも対応。
使いかたを再度説明。
LDR 上では、YouTube, Qooqle, HATENA-TUBE の動画エントリを見てる時に、ショートカットキー "y" を押すとプレイヤ表示、さらに "y" を押すとプレイヤを隠します。その他のサイト(デフォルトでは del.icio.usはてなブックマーク)では、YouTube の動画ページのリンクの脇にアイコンが表示されるので、クリックするとプレイヤが表示されます。
プレイヤに表示されているアイコンをあれこれ押してみればわかりますが、動画ダウンロードや、各種クリッピングサービスへのリンク等が配置されています。
インストールは以下に示すリンクから。このスクリプトをインストールしたら、以前「livedoor Reader + YouTube + はてなブックマークで最速動画ウォッチング」で公開した YouTube Player on LDR は必要ありませんので、そっはアンインストールしちゃってください。
インストール: youtube_anywhere.user.js

// ==UserScript==
//
// @name          YouTube Anywhere
// @namespace     http://antipop.gs/ns/greasemonkey/youtube_anywhere
// @include       http://reader.livedoor.com/reader*
// @include       http://b.hatena.ne.jp/*
// @include       http://del.icio.us/*
//
// ==/UserScript==
//
// ==Configuration==
//
// add other domains to @include for more use
//
// - include YouTube.
// @include       *youtube.com/*
//
// - include whole the web
// @include       *
//
//==/Configuration==
//
//==Acknowledgments==
//
// Bitcons >> SOME RANDOM DUDE
//  - http://somerandomdude.net/srd-projects/bitcons/
//
//==/Acknowledgments==
//
// ==Copyright==
//
// Copyright (C) 2006 by Kentaro Kuribayashi
//
// This script is distributed under the CCPL by-sa
//  - See: http://creativecommons.org/licenses/by-sa/2.5/
//

(function(){
    var playerContainerId = 'GM_youtube_player';
    var playerWidth  = 425;
    var playerHeight = 350;
    var overlayId    = 'GM_overlay';
    var regexp = [
        new RegExp('^http://(?:www\\.)?youtube\\.com/(?:watch)?\\?.*v=([^&]+).*$', 'i'),
        new RegExp('^http://clippers\\.qooqle\\.jp/video/([^/]+).*$', 'i'),
        new RegExp('^http://www\\.fladdict\\.net/app/hatenatube/#v=([^&]+).*$', 'i'),
    ];

    if (location.href.match('^http://reader\\.livedoor\\.com/reader.*$', 'i')) {
        var w = unsafeWindow;
        var _onload = w.onload;
        var onload  = function(){with (w) {
            Keybind.add('y', function () {
                if ($(playerContainerId)) {
                    hidePlayer();
                }
                else {
                    var item = get_active_item(true);
                    if (item) {
                        regexp.forEach(function (r) {
                            if (item.link.match(r)) {
                                showPlayer(RegExp.$1, item.title);
                            }
                        });
                    }
                }
            });
        }};


        w.onload = function(){
            _onload();
            onload();
        };
    }
    else {
        $A(document.links).forEach(function (link) {
            if (link.href.match(regexp[0])) {
                var videoId    = RegExp.$1;
                var videoTitle = link.innerHTML.replace(/<.+?>/g, '');
                var icon = $C('img', {
                    'src'   : 'http://www.youtube.com/favicon.ico',
                    'alt'   : 'YouTube',
                    'title' : 'watch this movie',
                    'style' : {
                        'marginRight' : '0.5em',
                        'cursor'      : 'pointer',
                    },
                    'event' : [{
                        'name'     : 'click',
                        'callback' : function () { showPlayer(videoId, videoTitle); },
                        'flag'     : false,
                    }],
                });
                link.parentNode.insertBefore(icon, link);
            }
        });
    }

    function $ (id) { return document.getElementById(id); };

    function $A (arg) {
        var array = [];
        for (var i = 0; i < arg.length; i++) {
            array.push(arg[i]);
        }
        return array;
    }

    function $C (tag, prop) {
        var element = document.createElement(tag);
        for (var i in prop) {
            if (i == 'style') {
                for (var p in prop[i]) {
                    element.style[p] = prop[i][p];
                }
            }
            else if (i == 'event') {
                prop[i].forEach(function (e) {
                    element.addEventListener(e.name, e.callback, e.flag);
                });
            }
            else {
                element[i] = prop[i];
            }
        }
        return element;
    };

    function createPlayerContainer (videoId, videoTitle) {
        var playerContainer = $C('div', {
            'id'     : playerContainerId,
            'style'  : {
                'position'        : 'fixed',
                'zIndex'          : '100',
                'backgroundColor' : '#ffffff',
                'padding'         : '0.5em 1.5em',
            },
        });

        var playerHeader = createPlayerHeader(videoTitle);
        var player       = createPlayer(videoId);
        var playerFooter = createPlayerFooter(videoId, videoTitle, player);

        [playerHeader, player, playerFooter].forEach(function (e) {
             playerContainer.appendChild(e);
        });

        return playerContainer;
    }

    function createPlayerHeader (videoTitle) {
        var playerHeader = $C('p', {
            'style' : {
                'fontWeight' : 'bold',
                'margin'     : '0.5em 2em 0.5em 0',
            }
        });

        var closeButton = $C('img', {
            'id'    : 'GM_close_utton',
            'src'   : getImageUrl('close'), 
            'title' : 'Hide this player',
            'style' : {
                'display'         : 'block',
                'position'        : 'absolute',
                'top'             : '5px',
                'right'           : '5px',
                'cursor'          : 'pointer',
                'backgroundColor' : '#00cc00',
            },
            'event' : [
                {
                    'name'     : 'click',
                    'callback' : function () { hidePlayer(); },
                    'flag'     : false,
                },
                {
                    'name'     : 'mouseover',
                    'callback' : function () { $('GM_close_utton').style.backgroundColor = '#ffd700'; },
                    'flag'     : false,
                },
                {
                    'name'     : 'mouseout',
                    'callback' : function () { $('GM_close_utton').style.backgroundColor = '#00cc00'; },
                    'flag'     : false,
                },
            ],
        });

        [document.createTextNode(videoTitle), closeButton,].forEach(function (e) {
            playerHeader.appendChild(e);
        });

        return playerHeader;
    }

    function createPlayerFooter (videoId, videoTitle, player) {
        var playerFooter = $C('div', {
            'style' : {
                'padding' : '0.5em 0',
            }
        });

        var linkContainer = $C('p', {style : { 'textAlign' : 'center', 'margin' : '0', }});
        var youtubeUri    = ['http://www.youtube.com/watch?v=', videoId].join('');
        [
            {
                'id'       : 'GM_download',
                'title'    : 'download this video',
                'getUri'   : ['http://youtubech.com/test/read.cgi?dl=', videoId].join(''),
                'label'    : 'Download',
                'image'    : 'download',
            },
            {
                'id'       : 'GM_post_to_hatena',
                'title'    : 'post to Hatena::Bookmark',
                'getUri'   : ['http://b.hatena.ne.jp/add?mode=confirm&url=', encodeURIComponent(youtubeUri)].join(''),
                'label'    : 'Hatena',
                'image'    : 'arrow',
            },
            {
                'id'       : 'GM_post_to_delicious',
                'title'    : 'post to del.icio.us',
                'getUri'   : ['http://del.icio.us/post?v=4;url=', encodeURIComponent(youtubeUri), ';title=', encodeURIComponent(videoTitle)].join(''),
                'label'    : 'del.icio.us',
                'image'    : 'arrow',
            },
            {
                'id'       : 'GM_post_to_qooqle',
                'title'    : 'post to qooqle',
                'getUri'   : ['http://clippers.qooqle.jp/post?url=', encodeURIComponent(youtubeUri)].join(''),
                'label'    : 'Qooqle',
                'image'    : 'arrow',
            },
        ].forEach(function (i) {
            var link = $C('span', {
                'id'    : i.id,
                'title' : i.title,
                'style' : {
                    'color'         : '#00cc00',
                    'textIndent'    : '20px',
                    'verticalAlign' : 'middle',
                    'marginRight'   : '0.5em',
                    'cursor'        : 'pointer',
                },
                'event' : [
                    {
                        'name'     : 'click',
                        'callback' : function () { window.open(i.getUri); },
                        'flag'     : false,
                    },
                    {
                        'name'     : 'mouseover',
                        'callback' : function () { $(i.id).style.color = '#ffc125'; },
                        'flag'     : false,
                    },
                    {
                        'name'     : 'mouseout',
                        'callback' : function () { $(i.id).style.color = '#00cc00'; },
                        'flag'     : false,
                    },
                ],
            });

            var icon = $C('img', {
                'src'   : getImageUrl(i.image),
                'style' : {
                    'marginRight'     : '0.5em',
                    'backgroundColor' : '#00cc00',
                },
            });

            [icon, document.createTextNode(i.label)].forEach(function (e) {
                link.appendChild(e);
            });
            linkContainer.appendChild(link);
        });

        playerFooter.appendChild(linkContainer);

        [
            {
                'label' : 'URI:',
                'id'    : 'youtube_uri',
                'value' : ['http://www.youtube.com/watch?v=', videoId].join(''),
            },
            {
                'label' : 'Player:',
                'id'    : 'youtube_embed',
                'value' : player.innerHTML,
            },
            {
                'label' : 'Hatena:',
                'id'    : 'hatena_notation',
                'value' : ['[http://youtubech.com/test/read.cgi', encodeURIComponent(['?dl=', videoId, '&.flv'].join('')), ':movie]'].join(''),
            },
        ].forEach(function (i) {
            var inputContainer = $C('p', { 'style' : { 'margin': '0.2em 0 0 0'} });
            var label = $C('label', {
                'for'   : i.id,
            });
            label.innerHTML = i.label;
            var input = $C('input', {
                'id'    : i.id,
                'style' : {
                    'border'   : 'solid 1px #333333',
                    'width'    : '80%',
                    'position' : 'absolute',
                    'right'    : '1.5em',
                },
                'event'   : [
                    {
                        'name'     : 'focus',
                        'callback' : function () { $(i.id).select(); },
                        'flag'     : false,
                    },
                    {
                        'name'     : 'click',
                        'callback' : function () { $(i.id).select(); },
                        'flag'     : false,
                    },
                ]
            });
            input.value = i.value;

            [label, input].forEach(function (e) {
               inputContainer.appendChild(e);
            });
            playerFooter.appendChild(inputContainer);
        });

        return playerFooter;
    }

    function createPlayer (videoId) {
        var videoSrc = ['http://www.youtube.com/v/', videoId].join('');

        var div    = $C('div', {});
        var object = $C('object', {
            'width'  : playerWidth,
            'height' : playerHeight,
        });
        var param  = $C('param',  {
            'name'   : 'movie',
            'value'  : videoSrc,
        });
        var embed  = $C('embed',  {
            'width'  : playerWidth,
            'height' : playerHeight,
            'type'   : 'application/x-shockwave-flash',
            'src'    : videoSrc,
        });

        [param, embed].forEach(function (e) { object.appendChild(e); });
        div.appendChild(object);

        return div;
    }

    function showPlayer (videoId, videoTitle) {
        var playerContainer  = createPlayerContainer(videoId, videoTitle);
        var overlay = $C('div', {
            id     : overlayId,
            style  : {
                'position'        : 'fixed',
                'top'             : '0%',
                'left'            : '0%',
                'width'           : '100%',
                'height'          : '100%',
                'zIndex'          : '99',
                'backgroundImage' : ['url("', getImageUrl('overlay'), '")'].join(''),
            },
            event  : [{
                'name'     : 'click',
                'callback' : function () { hidePlayer(); },
                'flag'     : false,
            }]
        });

        [overlay, playerContainer].forEach(function (e) {
            document.body.appendChild(e);
        });

        centering($(playerContainerId), 0, 0);
    }

    function hidePlayer () {
        [$(playerContainerId), $(overlayId)].forEach(function (e) {
            e.parentNode.removeChild(e);
        });
    }

    function centering (element, x, y) {
        with (element.style) { 
            left = ((window.innerWidth  - element.offsetWidth)  / 2 + (x)) + 'px';
            top  = ((window.innerHeight - element.offsetHeight) / 2 + (y)) + 'px';
        }
    }

    function getImageUrl (name) {
        var images = {
            'close'    : "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%01%03%00%00%00%25%3Dm%22%00%00%00%03sBIT%08%08%08%DB%E1O%E0%00%00%00%06PLTE%FF%FF%FF%FF%FF%FFU%7C%F5l%00%00%00%02tRNS%FF%00%E5%B70J%00%00%00%09pHYs%00%00%0B%12%00%00%0B%12%01%D2%DD~%FC%00%00%00!tEXtSoftware%00Macromedia%20Fireworks%204.0%EA%26'u%00%00%00%16tEXtCreation%20Time%0006%2F02%2F06%3Eg%BF%E4%00%00%00%22IDATx%9Cc%F8%FF%9F%01%8E%3E%9Fg%F8%D8%CF%F0C%9E%E1%8F%3D%08%01%19%40.P%10I%0D%00%8C%AA%1B%19%A3%7D%C5%A0%00%00%00%00IEND%AEB%60%82",
            'download' : "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%01%03%00%00%00%25%3Dm%22%00%00%00%03sBIT%08%08%08%DB%E1O%E0%00%00%00%06PLTE%FF%FF%FF%FF%FF%FFU%7C%F5l%00%00%00%02tRNS%FF%00%E5%B70J%00%00%00%09pHYs%00%00%0B%12%00%00%0B%12%01%D2%DD~%FC%00%00%00!tEXtSoftware%00Macromedia%20Fireworks%204.0%EA%26'u%00%00%00%16tEXtCreation%20Time%0006%2F02%2F06%3Eg%BF%E4%00%00%00'IDATx%9Cc%F8%FF%9F%01%82%FE%D5C%D1%07~%86%1F%F2%0C%7F%EC%19%BE%E53%FC%BE%CF%F0w%3FH%10%A6%0C%00p%88%1A5%81%FD%3F%D0%00%00%00%00IEND%AEB%60%82",
            'arrow'    : "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%01%03%00%00%00%25%3Dm%22%00%00%00%03sBIT%08%08%08%DB%E1O%E0%00%00%00%06PLTE%FF%FF%FF%FF%FF%FFU%7C%F5l%00%00%00%02tRNS%FF%00%E5%B70J%00%00%00%09pHYs%00%00%0B%12%00%00%0B%12%01%D2%DD~%FC%00%00%00!tEXtSoftware%00Macromedia%20Fireworks%204.0%EA%26'u%00%00%00%16tEXtCreation%20Time%0006%2F02%2F06%3Eg%BF%E4%00%00%00%26IDATx%9Cc%F8%FF%9F%01%8E%3E%F0%83%D0%7F~%86%7F%FC%0C%7F%FC%19~%9Cg%F8x%9E%E1%F3y%06%245%00p%20%1A%9E%26%CAE%0A%00%00%00%00IEND%AEB%60%82",
            'overlay'  : "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%01%00%00%00%01%01%03%00%00%00%25%DBV%CA%00%00%00%03sBIT%08%08%08%DB%E1O%E0%00%00%00%06PLTE%FF%FF%FF%00%00%00U%C2%D3~%00%00%00%02tRNS%00%BB*%20%A7%3C%00%00%00%09pHYs%00%00%1B%BC%00%00%1B%BC%01%BA%B7%A0%BB%00%00%00!tEXtSoftware%00Macromedia%20Fireworks%204.0%EA%26'u%00%00%00%0AIDATx%9Cch%00%00%00%82%00%81w%CDr%B6%00%00%00%00IEND%AEB%60%82",
        };

        return images[name];
    }
})();