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.$1;
                            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() {
    }
Cronus Crown(クロノス・クラウン)のトップページに戻る
(c)2002-2017 Cronus Crown (c)1997-2017 Masakazu Yanai
このWebPageに関するご意見・お問い合わせは
サイト情報 弊社への連絡
までお願いします。