Twitt tube - ソースコード
説明
「Twitt tube」は、「Web AI」を使ったWebアプリです。「Twitt tube」では、Twitterで検索したyoutubeのURLを連続再生させることができます。このページでは、この「Twitt tube」を作るために書いたプログラムを掲載します。
「Web AI」は、クロノス・クラウンの柳井政和が開発しているJavaScirptのライブラリです。「Web AI」を使うと、Web上からデータを取得して構築するWebページを、とても簡単に構築することができます。
「Web AI」は、Webからの検索結果やフィードの取得、短縮URLへのURLの変換、日本語文章からのキーワードや文章抽出、日本語文章のマルコフ連鎖、クエリーの管理などの機能を備えています。
コアとなる「WebSrch」オブジェクトでは、非同期で行われる通信処理に対して、その結果を待ちながら順番に処理していくプログラムを簡単に書くことができます。また、本ライブラリでは「Google AJAX Search API」を抽象化して、検索データを手軽にプログラムに読み込んで利用できるようにしています。
「Twitt tube」は、この「Web AI」のサンプルとして作成しました。このWebアプリを作成したソースコードを見れば、その簡単さがよく分かると思います。それでは以下に、ソースコードを掲載します。
ソースコード
まずは、HTMLのヘッダー部分のソースコードです。
<!-- Google API --> <script src="http://www.google.com/jsapi" type="text/javascript"></script> <!-- Web AI API --> <script src="crocro.webAi.min.js" type="text/javascript" charset="UTF-8"></script> <!-- ScriptThis --> <script src="app.js" type="text/javascript" charset="UTF-8"></script>
次に、Webアプリ本体部分になる「app.js」のソースコードを掲載します。
/** * 【変数の初期化】 */ // Googleからスクリプトをロード google.load("search", "1"); google.load("feeds", "1"); google.load("jquery", "1.4.3"); google.load("swfobject", "2.2"); // Web AIの初期化 var $WA = crocro.webAi; // 短縮表記 var cQ = new $WA.Query(); // クエリー var cWSrch = new $WA.WebSrch(); // Web検索用 var qKeyQckSrch = "qckSrch"; // 急速検索 var appNm = "Twitt tube"; var tagNm = "#twitt_tube_tags"; // リスト取得用タグ var tagArr = ["#jazz", "#anison", "#80sMusic", "#90sMusic", // タグ配列 "#piano", "#blues", "#soul", "RockAndMetal", "LOKITO70", "MusicPortal"]; var tagNG = ["sex", "nude"]; // URL配列 var urlArr = []; // 取得したURL配列 var urlArrPos = -1; // 現在の配列位置 var urlArrDir = 1; // 現在の再生方向 // 再生フラグ var flgPlay = true; // yutubeプレイヤー var ytplayer; /* *-------------------------------------------------- */ /** * 【初期化処理】 */ cWSrch.ready(function(){ // デフォルトの固定URLを作成 $("#fix_url_raw").val(getUrlBs()); $("#fix_url_min").val(getUrlBs()); setTimeout(loadDelay, 1000); // 遅延読み込み // Web検索用WebSrchを初期化 cWSrch .brand("gglBrnd") .addCallback({ // コールバック処理を追加 // Twitterはよく落ちるのでGoogle経由で使いたいけど // 反映が遅いのでとりあえずこちらで exec: function() { $.getJSON( "http://search.twitter.com/search.json?rpp=100&q=" + encodeURIComponent(tagNm) + "&callback=?", function(res){ if (! res.results) return; // 無効→次へ // 文字列の収集 outer: for (var i = 0; i < res.results.length; i++) { // 変数の初期化 var ln = res.results[i].text; // 文字列の取得 if (! ln.match(/{{(.+?)}}/)) continue; var tag = RegExp.; tag = tag.replace(/><"'\r\n/g, ""); if (tag == "") continue; // NGワードの判定 for (var j = 0; j < tagNG.length; j ++) { if (tag.indexOf(tagNG[j]) >= 0) continue outer; } tagArr.push(tag); } tagArr = $WA.Tools.unq(tagArr); // 配列をユニークに // コールバックの終了を通知 cWSrch.endCallback(); } ) } }) .add(function(){ // 配列リンクの作成 var lnkStrs = []; for (var i = 0; i < tagArr.length; i++) { var lnkStr = '<a href="#" ' + 'onClick="$(\'#q\').val(\'' + tagArr[i] + '\'); return false;">' + tagArr[i] + '</a>'; lnkStrs.push(lnkStr); } // 配列リンクの表示 $("#tagLst").html(lnkStrs.join(" ")); }) .add(function(){ cWSrch.cmndsBreak(); // 終了 setTimeout(function(){ // クエリーの初期化 cQ = new $WA.Query() cQ.prsFrmLocation({useH: true}); if (cQ.get("q") != "") { $("#q").val(cQ.get("q")); // 開始キーワード setTimeout(function(){ strtSrchBtn(); }, 500); } }, 1500); }) .start(); // youtubeプレイヤーの初期化 var params = { allowScriptAccess: "always" }; var atts = { id: "myytplayer" }; var videoID = "dH3GSrCmzC8"; swfobject.embedSWF( "http://www.youtube.com/v/" + videoID // デフォルトURL + "&enablejsapi=1&playerapiid=ytplayer", "ytApiPlayer", "425", "356", "8", null, null, params, atts); }); // yutubeコールバック用メソッド function onYouTubePlayerReady(playerId) { ytplayer = document.getElementById("myytplayer"); ytplayer.addEventListener("onStateChange", "onYouTubePlayerStateChange"); ytplayer.addEventListener("onError", "onYouTubePlayerError"); //videoId = "RSlFrlTqQzg"; // デバッグ用2秒動画 //ytplayer.loadVideoById(videoId); } // yutubeプレイヤーの状態が変化 function onYouTubePlayerStateChange(prm) { if (prm == 0 && flgPlay) { // 停止かつプレイフラグが有効 cntrlPlayer(1); // 次の動画を表示 } } // yutubeプレイヤーでエラーが発生 function onYouTubePlayerError(prm) { if (flgPlay) { // プレイフラグが有効 delNowUrlAndPlayNext(); // 現在のURLの削除&次を再生 } } /* *-------------------------------------------------- */ /** * @title 【検索開始】 * @description * * 検索を実行する。ボタンから呼び出す。 */ function strtSrchBtn() { // 実行中回避処理 if (cWSrch.isExec) { alert("現在、検索中です。\n\n少々お待ち下さい。"); return; } // 検索実行 cWSrch.reset(); strtSrch(); cWSrch.start(); } function strtSrch() { // 変数の初期化 var kwStrt = $("#q").val(); // 開始キーワード kwStrt = kwStrt.replace(/^[ ]+|[ ]$/g, ""); // トリム kwStrt += " youtube"; // youtube動画を検索 // URL配列の初期化 urlArr = []; // 取得したURL配列 urlArrPos = -1; // 現在の配列位置 // 検索処理 cWSrch .feed({ url : function() { return "http://search.twitter.com/search.rss?rpp=100&q=" + encodeURIComponent(kwStrt); }, res : function(res) { if (res.error) return; // 無効→次へ // URLの収集 for (var i = 0; i < res.feed.entries.length; i++) { // 変数の初期化 var e = res.feed.entries[i]; var twitArr = getUrl(e.title); if (twitArr.length == 0) continue; // 空なので飛ばす urlArr = urlArr.concat(twitArr); } urlArr = $WA.Tools.unq(urlArr); // 配列をユニークに } }) .add(function(){ // リストの出力 outLst(); // ソーシャル系URL設定 cQ = new $WA.Query(); cQ.prsFrmLocation({useH: true}); cQ.set("q", $("#q").val()); setSclUrl(cQ.getUrl()); // プレイヤー操作 cntrlPlayer(1); }); } /* *-------------------------------------------------- */ /** * @title 【プレイヤー操作】 * @description * * プレイヤーを操作する。 */ function cntrlPlayer(tgt) { if (tgt != 1 && tgt != -1) return; if (urlArr.length == 0) return; // 対象位置の移動 urlArrDir = tgt; // 現在の再生方向 urlArrPos += urlArrDir; if (urlArrPos >= urlArr.length) urlArrPos = 0; if (urlArrPos < 0) urlArrPos = urlArr.length - 1; $("#ytNowPos").text(urlArrPos); // プレイヤー開始 setTimeout(strtPlayer, 500); } /** * @title 【プレイヤー開始】 * @description * * プレイヤーを開始する。 */ function strtPlayer() { // 実行中回避処理 if (cWSrch.isExec) { return null; // 実行中はnullを戻す } // 変数の初期化 var orgUrl = urlArr[urlArrPos]; // 「jsonpify」が、上手く動作しなくなってので… //var srchUrl = "http://jsonpify.com/api?url=" // JSON→JSONP // + encodeURIComponent( // "http://untiny.me/api/1.0/extract/?format=json&url=" // 短縮URLの展開 // + orgUrl) // 対象の短縮URL // + "&format=json&jsonp=?"; // 「Yahoo Pipes」に変更 //var srchUrl = "http://pipes.yahoo.com/pipes/pipe.run?u=" // + encodeURIComponent( // "http://untiny.me/api/1.0/extract/?format=json&url=" // 短縮URLの展開 // + orgUrl) // 対象の短縮URL // + "&_id=332d9216d8910ba39e6c2577fd321a6a&_render=json&_callback=?"; // 「Yahoo Pipes」も上手くいかなくなったので… // 「ux.nu」に変更 var srchUrl = "http://ux.nu/hugeurl?format=jsonp&url=" + orgUrl // 対象の短縮URL + "&callback=?"; // 検索実行 cWSrch .reset() .addCallback({ exec: function() { if (orgUrl.indexOf("http://www.youtube.com") != 0 && orgUrl.indexOf("http://youtu.be") != 0 ) { $.getJSON( srchUrl, function(data){ // 「jsonpify」の場合 //if (data["org_url"]) { // var tmp_url = data["org_url"].split("\\/").join("/"); // if (tmp_url && tmp_url != "") orgUrl = tmp_url; //} // 「Yahoo Pipes」の場合 //try { // orgUrl = data["value"]["items"][0]["org_url"].replace(/\/g, ""); //} catch(e) {} // 「ux.nu」の場合 try { orgUrl = data["exp"]; } catch(e) {} cWSrch.endCallback(); // コールバックの終了を通知 } ); } else { cWSrch.endCallback(); // コールバックの終了を通知 } } }) .add(function(){ // 有効なURLか確認 if (orgUrl.indexOf("http://www.youtube.com") != 0 && orgUrl.indexOf("http://youtu.be") != 0 ) { cWSrch.cmndsBreak(); // 終了 delNowUrlAndPlayNext(); // 現在のURLの削除&次を再生 return; } // URLからIDを取り出し var videoId = ""; if (orgUrl.indexOf("http://www.youtube.com") == 0) { cQ = new $WA.Query() cQ.prsFrmUrl({url: orgUrl}); videoId = cQ.get("v"); } else if (orgUrl.indexOf("http://youtu.be") == 0) { videoId = orgUrl.substr("http://youtu.be/".length); } if (videoId.length >= 12) { videoId = videoId.substr(0, 11); } // 有効IDの確認 if (videoId.length < 11) { // 次を実行 // urlArrPos += urlArrDir * -1; // cntrlPlayer(urlArrDir); cWSrch.cmndsBreak(); // 終了 delNowUrlAndPlayNext(); // 現在のURLの削除&次を再生 return; } // 有効URLの格納(同一形式に整理) urlArr[urlArrPos] = "http://www.youtube.com/watch?v=" + videoId; // リストの整理 var bfrSz = urlArr.length; urlArr = $WA.Tools.unq(urlArr); // 配列をユニークに var aftrSz = urlArr.length; if (aftrSz < bfrSz) { // 前に同じURLがあった // 次を実行 urlArrPos += urlArrDir * -1; cntrlPlayer(urlArrDir); return; } // リストの出力 outLst(); // 再生 $("#ytApiPlayerWrp").show(); setTimeout(function(){ ytplayer.loadVideoById(videoId); }, 500); }) .start(); } /** * @title 【プレイフラグの変更】 * @description * * プレイフラグを変更する。 */ function chngFlgPlay() { if (flgPlay) { flgPlay = false; $("#btnFlgPlay").val("連続再生"); ytplayer.stopVideo(); } else { flgPlay = true; $("#btnFlgPlay").val("停止"); ytplayer.playVideo(); } } /** * @title 【リストの出力】 * @description * * リストを変更する。 */ function outLst() { // リストの出力 var tmpArr = []; for (var i = 0; i < urlArr.length; i ++) { tmpArr[i] = i + " : " + urlArr[i]; if (i == urlArrPos) { tmpArr[i] += " ← Now Play" $("#ytLstNow").val(urlArr[i]); } } $("#ytLst").val(tmpArr.join("\n")); // パラメータの表示 $("#ytUrlSum").text(urlArr.length); } /** * @title 【現在のURLの削除&次を再生】 * @description * * 現在のURLを削除して次を再生する。 */ function delNowUrlAndPlayNext() { if (urlArr.length <= 0) return; // 配列がない // リストの更新 urlArr = urlArr.slice(0, urlArrPos).concat(urlArr.slice(urlArrPos + 1)); // リストの出力 outLst(); // 次を実行 urlArrPos += urlArrDir * -1; if (flgPlay) cntrlPlayer(urlArrDir); // プレイ中なら再生 } /* *-------------------------------------------------- */ /** * @title 【URLの取得】 * @description * * Twitterの文字列からURLを取得する。 * * @param srcStr 元文字列 * @return URLの配列 */ function getUrl(srcStr) { var chkStr = srcStr; var resArr = []; // URLの取得 resArr = chkStr.match(/http(:\/\/[-_.!~*\'()a-zA-Z0-9;\/?:\@&=+$,%#]+)/ig, ""); // URL if (! resArr) resArr = []; return resArr; } /** * @title 【URL基本部分取得】 * @description * * URLの本体を取得。 * * @return URLの本体部分 */ function getUrlBs() { var urlStr = "http://www.google.com/"; // ダミー if (! $WA.Tools.isLocal()) { // ネット上なので、URLをそのまま利用 urlStr = location.href.replace(/\?.*$|#.*$/g, ""); // 本体部分のみ取得 } return urlStr; } /** * @title 【ソーシャル系URL設定】 * @description * * ソーシャル系のサービスのウィジットにURLを指定する。 * * @param urlStr URL文字列 * @return なし */ function setSclUrl(urlStr) { // ローカル時は無効 if ($WA.Tools.isLocal()) return; // 固定URLの変更 $("#fix_url_raw").val(urlStr); $("#fix_url_min").val(urlStr); // 引数を解析 var cQSrc = new $WA.Query(); cQSrc.prsFrmUrl({url: urlStr}); // 変数の初期化 var cQTmp; var urlTmp; // AddClip ブックマーク用URL AddClipsUrl = urlStr; // Twitter用URL cQTmp = new $WA.Query(); // クエリ解析用 cQTmp.prsFrmUrl({url: $(".twitter-share-button").attr("src")}); cQTmp.set("url", urlStr); cQTmp.set("text", appNm + " - 「" + cQSrc.get("q") + "」の自動再生"); $(".twitter-share-button").attr("src", cQTmp.getUrl()); // Facebookシェア用URL cQTmp = new $WA.Query(); // クエリ解析用 cQTmp.prsFrmUrl({url: $("#fcbkShare").attr("href")}); cQTmp.set("u", urlStr); $("#fcbkShare").attr("href", cQTmp.getUrl()); // Facebookいいね用URL cQTmp = new $WA.Query(); // クエリ解析用 cQTmp.prsFrmUrl({url: $("#fcbkLike").attr("src")}); cQTmp.set("href", urlStr); $("#fcbkLike").attr("src", cQTmp.getUrl()); // はてブ用URL var htbEntryAdd = "http://b.hatena.ne.jp/entry/add/" + urlStr; var htbEntryUrl = "http://b.hatena.ne.jp/entry/" + urlStr; var htbEntryImg = "http://b.hatena.ne.jp/entry/image/" + urlStr; $("#htbEntryAdd").attr("href", htbEntryAdd); $("#htbEntryUrl").attr("href", htbEntryUrl); $("#htbEntryImg").attr("src", htbEntryImg); } /* *-------------------------------------------------- */ /** * @title 【短縮URL取得】 * @description * * 短縮URLを取得する。 * * @return なし */ function getShrtUrl() { cWSrch .reset() .shrtUrl({ // 固定URLを作成して、短縮URLに変換 url : $("#fix_url_raw").val(), res : function(res) { $("#fix_url_min").val(res); } }) .start(); } /** * @title 【遅延読み込み】 * @description * * HTMLの一部を遅延読み込みする。 * * 以下、遅延領域のサンプル。 * * <span class="delay"> * <noscript>No JavaScript</noscript> * <span class="delayBefore">Now Loading...</span> * <span class="delayAfter"><!-- * hoge hoge * --></span> * </span> * * @return なし */ function loadDelay() { $(".delay").each(function () { // 遅延前の表示を消す $(this).children(".delayBefore").html(""); // 遅延後の表示を出す var repStr = $(this).children(".delayAfter").html(); repStr = repStr.replace(/^<!--|-->$/g, ""); $(this).children(".delayAfter").html(repStr); }); } /* *-------------------------------------------------- */ /** * @title 【タグの送信】 * @description * * タグをTwitterに投稿する。 * * @return なし */ function sendTag() { // リンク用のURL var cQLnk = new $WA.Query(); cQLnk.prsFrmUrl({url: "http://crocro.com/write/web_ai/app/twitt_tube/index.html"}); cQLnk.set("q", $("#q").val()); // 投稿文字列 var cQTmp = new $WA.Query(); cQTmp.prsFrmUrl({url: "http://twitter.com/home/"}); var sttsStr = "{{" + $("#q").val() + "}} - " + cQLnk.getUrl() + " " + tagNm + " via @ruten"; cQTmp.set("status", sttsStr); // ウィンドウを開く var urlStr = cQTmp.getUrl(); window.open(urlStr); } /* *-------------------------------------------------- */ /** * @title 【テスト用】 * @description * * テスト用コードを記述する。 */ function test() { }