Ustream.tvビューア
UTMCの後輩の間でUstream.tvという動画ストリーミング・サービスでWindowsデスクトップや現実のデスクトップを晒し合うのが流行ってたので,割り込んでjQueryというJavaScriptライブラリを使ったビューアを書いてみた... と言うか,先週末から1週間かけて書いてた.もちろん,平日はほとんど時間が取れなかったけど.
- http://www.ustream.tv/ USTREAM.TV: LIVE VIDEO Streaming, Free Video Chat Rooms. Watch Shows & Broadcast Live TV, stream videos, web podcasts. Live streaming videos and webcam chat
- http://jquery.com/ jQuery: The Write Less, Do More, JavaScript Library
メモ:
- Ajax通信のほぼ全てを縛る「同一ドメイン制限」の回避には,Ajax通信先(別ドメイン)がJSONP形式でデータを送ってくれることが必須.JavaScriptソースの読み込みは同一ドメイン制限に縛られないので,データを「実行するとそのデータを返す関数のJavaScriptソース」という形式で送るのがJSONPのアイディア.
- (少なくともjQueryでは)AjaxでWebDAVが操作できる(←ブラウザ依存?).(ユーザの性善説の下では)サーバ側で記憶したい情報は単にWebDAVにXML(もしくは適当なテキスト・ファイル)をPUTすればよい.
- FirefoxにFireBugをインストールすればprintfデバッグができる(ただしバグ多し): http://getfirebug.com/console.html Firebug Console Object and API
以下,ソース.開発者キーがHTMLソース内に直書きされてるのでサンプルをthe Internetに公開する訳には行かない.開発者キーはhttp://developer.ustream.tv/ に登録すると貰える.jQuery UIではsortableのみを使っており,jQuery UIのダウンロード・ページが提供するカスタマイズ機能でsortable関連部分だけを含むソースを生成して使った.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <!-- vim: set ts=2 sts=2 sw=2 tw=0 fdm=marker: --> <!-- $Id: $ --> <html lang="ja"> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta name="author" content="flatline @ UTMC" /> <title>Ustream Viewer</title> <meta name="keyword" lang="ja" content="ustream.tv jquery ajax" /> <meta name="description" content="複数のUstream Showを一覧で見る" /> <link href="ustream.css" rel="stylesheet" title="default" type="text/css" /> <script type="text/javascript" src="jquery-1.2.6.js"></script> <script type="text/javascript" src="jquery.cookie.js"></script> <script type="text/javascript" src="jquery-ui-personalized-1.6rc2.packed.js"></script> <script type="text/javascript" src="jquery.timers-1.0.0.js"></script> <script type="text/javascript"> <!-- function a(v) { var c = $.cookie("a"); if (c) { var a = unescape(c); if (! a.match(v)) { while (true) { var b = a + "," + v; var e = escape(b); if (e.length > 4094) { a = a.replace(/[^,]*,/, ""); } else { $.cookie("a", b, {expires:365}); break; } } } } else { $.cookie("a", v); } } function d(u) { var x = 0; $("ul#m li").each(function() { if ($(this).attr("id").replace(/_\d+_l$/, "") == u) x += 1; }); if (x == 1) { var c = $.cookie("a"); if (c) { var a = unescape(c).split(/,/); var b = new Array(a.length-1); for (var i=0,j=0; i<a.length; i+=1) { var x = a[i]; if (x != u) { b[j] = x; j += 1; } } $.cookie("a", b.join(","), {expires:365}); } } } function f(e) { e.preventDefault(); var l = e.data; var u = l.attr("id").replace(/_\d+_l$/, ""); d(u); l.fadeOut("slow", function() { l.remove(); }); } function h(e) { e.preventDefault(); var u = $(this).attr("id").replace(/_\d+_r/, ""); var a = $.trim($("#d").html().replace(/<[^>]+>/g, "")).split(/\s+/); var b = false; jQuery.each(a, function(i, v) { b = b || (v == u); } ); if (b) { $(this).remove(); } else { a.push(u); var s = '<?xml version="1.0" encoding="utf-8"?>\n<ul>\n' + $.map(a, function(e) { return "<li>" + e + "</li>"; } ).join("\n") + "\n</ul>\n"; (function(b) { $.ajax({ type:"PUT", url:"default.xml", data:s, dataType:"text", success:function(x, r) { if (r == "success") { b.remove(); $("#d ul").append("<li>" + u + "</li>"); } } }); })($(this)); } } function g(v, b) { var w = v + "_" + c; c += 1; $.getJSON("http://api.ustream.tv/json/user/" + v + "/listAllChannels?key=(開発者キー)&callback=?", function(j) { if (j == null) { alert("そのようなユーザは存在しません."); return; } var s = $.map(j, function(e) { var ed = e.description; return e.title.replace(/(.)/g, "$1​") + // word-wrap:break-word; の代わり (ed != null && ed != "" ? " (" + ed + ")" : "") + (e.status == "live" ? "\n" + e.embedTag.replace(/width="320"/g, 'width="160"') .replace(/height="260"/g, 'height="130"') : " : オフライン") }).join("<br>\n"); $("#m").append('<li id="' + w + '_l">' + s + ' <br><input type="submit" value="削除" id="' + w + '_d">' + (b ? '<input type="submit" value="ワンタッチに登録" id="' + w + '_r">' : "") + '</li>'); var l = $("#" + w + "_l"); $("#" + w + "_d").bind("click", l, f); $("#" + w + "_r").bind("click", h); l.fadeIn("slow"); a(v); }); } $(document).ready(function() { $("#m").sortable({}); $("#a").click(function(e) { e.preventDefault(); var u = $("#u"); var v = u.val(); u.val(""); var b = true; $("#d ul li").each(function() { b = b && ($(this).text() != e); }); g(v, b); }); $("#c").click(function(e) { e.preventDefault(); $.cookie("a", null); }); $("#d").load("default.xml", function() { $("#d ul li").click(function() { g($(this).text()); }); var c = $.cookie("a"); if (c) { var a = unescape(c).split(/,/); var l = $("#d ul li"); for (var i=0; i<a.length; i+=1) { var e = a[i], b = true; l.each(function() { b = b && ($(this).text() != e); }); (function(i, e, b) { $(this).oneTime(100+i*1500, function() { g(e, b); }); })(i, e, b); } } }); }); var c=0; // --> </script> </head> <body> <h1><a href="http://ustream.tv/">Ustream</a> Viewer</h1> <ul id="m"></ul> <hr> <p id="p">ワンタッチID(サイトグローバル)</p> <div id="d"></div> <form action= "#"> <input type="text" id="u" size="15"> <input type="submit" value="メンバーをIDで追加" id="a"> </form> <input type="submit" value="デフォルト表示メンバー(Cookie)の消去" id="c"> <address> flatline @ UTMC </address> </body> </html>
ul { list-style:none; margin:0px; padding:0px; } ul#m li { display:none; float:left; width:160px; border:blue solid thin; padding:0px; word-wrap:break-word; /* IE,CSS3 */ } p#p { display:inline; } div#d { display:inline; } div#d ul { display:inline; } div#d ul li { display:inline; text-decoration:underline; cursor:pointer; margin:0px 0.5ex; } hr { clear:both; }
<?xml version="1.0" encoding="utf-8"?> <ul> <li>SFShiba</li> <li>ObamaForAmerica</li> </ul>