2010年5月9日日曜日

とりあえず完成 - YouTubeの自分のチャンネルの動画を再生回数の多い順にリストアップするガジェット

昨日のコードはcssの部分が適当でした。 今日の作業で、一応それなりのcssになったので投稿です。

コードはこんな感じ。 コードがはみ出ているかもしれないけど、気にしない方向でお願いします。 よく見たいときはマウスドラッグとかで選択してテキストエディターに貼り付けてください。

<?xml version="1.0" encoding="UTF-8"?>
<Module>
    <ModulePrefs title="youtube __UP_channel_name__ channel ranking" author="吉日@片鱗懐古のブログ" height="40" description="YouTubeの私のチャンネルにある動画の中で、再生回数が多い方から__UP_list_num__個を表示します。他の人がこのガジェットを使うときは、コードをコピーしてUserPrefの値を書き換え、ご自身のサーバースペースにアップロードして使ってください。">
        <Require feature="dynamic-height"/>
    </ModulePrefs>
    
    <UserPref name="channel_name"     datatype="hidden" default_value="PieceOfNostalgy"/>
    <UserPref name="list_num"         datatype="hidden" default_value="5"/>
    <UserPref name="background_color" datatype="hidden" default_value="#efefef"/>
    
    <Content type="html"><![CDATA[
        <style type="text/css">
            body{
                background-color: __UP_background_color__ !important;
                overflow: hidden;
            }
            #user_gadget_div{
                overflow: hidden;
            }
            .row{
                white-space: nowrap;
                word-break: keep-all;
            }
            ol{
                list-style-type: decimal;
            }
        </style>
        <div id="user_gadget_div" class="main">
            <a target="_top" href="http://www.youtube.com/user/__UP_channel_name__">YouTubeに移動</a>
        </div>
        <script type="text/javascript">
            var prefs = new _IG_Prefs(__MODULE_ID__);
            var channel_name = prefs.getString("channel_name");
            var list_num     = prefs.getInt("list_num");
            
            function makeDOMRequest()
            {
                var params = {};  
                params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.DOM;  
                var url = "http://gdata.youtube.com/feeds/api/videos?author=" + channel_name + "&orderby=viewCount&max-results=" + list_num;  
                gadgets.io.makeRequest(url, response, params);
            };
            
            function response(obj)
            {
                var domdata = obj.data;
                var entryList = domdata.getElementsByTagName("entry");
                
                var text = 'YouTubeのチャンネル<a target="_top" href="http://www.youtube.com/user/' + channel_name + '">' + channel_name + '</a>から再生回数が多いもの' + list_num + 'つを表示しています。<ol>';
                
                for(var i = 0; i < entryList.length; i++)
                {
                    var entryNodeList = entryList.item(i).childNodes;
                    var entry = new Object();
                    entry.title = "タイトル取得失敗";
                    entry.link = "リンク先取得失敗";
                    entry.category = "";
                    entry.viewCount = "再生回数取得失敗";
                    
                    for(var j = 0; j < entryNodeList.length; j++)
                    {
                        var node = entryNodeList.item(j);
                        if(node.nodeName == "title") 
                        {
                            entry.title = node.firstChild.nodeValue;
                        }
                        else if( (node.nodeName == "link") && (node.getAttribute("rel") == "alternate") )
                        {
                            entry.link = node.getAttribute("href");
                        }
                        else if(node.nodeName == "category")
                        {
                            var labelAttr = node.getAttribute("label");
                            if( (labelAttr != null) && (labelAttr != "") )
                            {
                                entry.category += node.getAttribute("term") + "/" + entry.category
                            }
                            else
                            {
                                var keyword = node.getAttribute("term");
                                if(keyword.substring(0, 7) != "http://")
                                {
                                    entry.category += keyword + " ";
                                }
                            }
                        }
                        else if(node.nodeName == "yt:statistics")
                        {
                            entry.viewCount = node.getAttribute("viewCount");
                        }
                    }
                    
                    text += '<li><div class="row"><a target="_top" href="' + entry.link + '" title="' + entry.title + '">' + entry.title + '</a></div><div class="row" title="カテゴリー : ' + entry.category + '">カテゴリー : ' + entry.category + '</div><div class="row" title="再生回数 : ' + entry.viewCount + '">再生回数 : ' + entry.viewCount + '回</div></li>';
                }
                
                text += "</ol>";
                document.getElementById('user_gadget_div').innerHTML = text;
                
                gadgets.window.adjustHeight();
            };
            
            gadgets.util.registerOnLoadHandler(makeDOMRequest);
        </script>
    ]]></Content>
</Module>

サイドバーに表示するのを前提に作っています。 動画のタイトルなどは表示しきれませんが、改行して表示してしまうと間延びしてしまうので、あえてhiddenにしています。 タイトル全文を確認したい人のために、tooltipを付けています。

自分のブログでは幅可変のレイアウトにしているので、ブラウザの幅を変えるとガジェットの幅も変わってしまいます。 そのため、ブラウザの幅を縮めるとガジェット内の改行(「YouTubeのチャンネルPieceOfNostalgyから再生回数が多いもの5つを表示しています。」の部分)が増えて、5番目の動画がhiddenしてしまうこともあります。 面倒なので、それは仕様で。

ガジェット内のcssとbloggerのcssは別物です。 このコードではガジェット用のcssはContentタグの中、先頭に書いてます。 UserPrefのパラメータbackground_colorを使えば、bodyのbackground-colorをブログと揃えられるようにしました。

JavaScriptをoffにしている人にも配慮して、最初にYouTubeチャンネルのトップへのリンクを表示しています。 __UP_UserPrefパラメータ__を使えばJavaScriptがoffの場合でもパラメータを渡せるので、活用。 これは背景色にも使っています。

cssの不具合について、このコードのスタイルシートで

#user_gadget_div{
    overflow: hidden;
}

としている部分、次のようなコードにするとOperaとGoogleChromeでolリストの数字が表示されませんでした。

div{
    overflow: hidden;
}

チョッと検索したところ、ブラウザのバグかもしれません。 リストの中でoverflowを設定するとそうなるとか。

バグといえば、昨日自分で書いたコードがNoScriptに怒られてました。 「xss攻撃の可能性がなんたら」と書いたんですが、正確には「Clickjacking / UI Redressingの可能性があります」でした。 確認不足。 「管理者用の設定アイコンとガジェットの表示が重なっているのが原因」というのは当たりっぽいです。 読む人には無関係でした。

まだガジェットのコードはplalaに置いてます。 完成したことだし、google系のサーバーのどこかに置き場所を探すつもりです。