Modified client side tweet scraping script
authorveltr
Wed, 15 Feb 2012 18:52:07 +0100
changeset 3 82b4715202d1
parent 2 5533075b5f08
child 4 17a9402e2dc3
Modified client side tweet scraping script
client/controlpanel.html
client/css/base-metric.css
client/css/controlpanel.css
client/js/podium.js
client/js/tweetsource.js
client/podium-cp-tweets.html
--- a/client/controlpanel.html	Wed Feb 15 12:34:36 2012 +0100
+++ b/client/controlpanel.html	Wed Feb 15 18:52:07 2012 +0100
@@ -5,6 +5,7 @@
         <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
         <title>controlpanel</title>
         <meta name="description" content="" />
+        <link rel="stylesheet" href="css/base-metric.css" />
         <link rel="stylesheet" href="css/controlpanel.css" />
         <script type="text/javascript">
             $(function() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/css/base-metric.css	Wed Feb 15 18:52:07 2012 +0100
@@ -0,0 +1,28 @@
+@font-face {
+    font-family: "Metric";
+    font-weight: normal;
+    font-style: normal;
+    src: url("../font/MetricF-Regular.otf");
+}
+@font-face {
+    font-family: "Metric";
+    font-weight: bold;
+    font-style: normal;
+    src: url("../font/MetricF-Bold.otf");
+}
+@font-face {
+    font-family: "Metric";
+    font-weight: normal;
+    font-style: italic;
+    src: url("../font/MetricF-Italic.otf");
+}
+a, body, div, h1, h2, h3, h4, h5, h6, li, p, span, ul {
+    font-weight: normal; margin: 0; padding: 0; border: none; font-size: 100%;
+    font: inherit; text-decoration: none; color: inherit;
+}
+ul {
+    list-style: none;
+}
+body {
+    font-family: Metric; background: #000000;
+}
\ No newline at end of file
--- a/client/css/controlpanel.css	Wed Feb 15 12:34:36 2012 +0100
+++ b/client/css/controlpanel.css	Wed Feb 15 18:52:07 2012 +0100
@@ -1,31 +1,4 @@
-@font-face {
-    font-family: "Metric";
-    font-weight: normal;
-    font-style: normal;
-    src: url("../font/MetricF-Regular.otf");
-}
-@font-face {
-    font-family: "Metric";
-    font-weight: bold;
-    font-style: normal;
-    src: url("../font/MetricF-Bold.otf");
-}
-@font-face {
-    font-family: "Metric";
-    font-weight: normal;
-    font-style: italic;
-    src: url("../font/MetricF-Italic.otf");
-}
-a, body, div, h1, h2, h3, h4, h5, h6, li, p, span, ul {
-    font-weight: normal; margin: 0; padding: 0; border: none; font-size: 100%;
-    font: inherit; text-decoration: none; color: inherit;
-}
-ul {
-    list-style: none;
-}
-body {
-    font-family: Metric; background: #000000;
-}
+
 #btv-cp-container {
     position: absolute; top: -65px; width: 100%;
     background-image: linear-gradient(bottom, rgb(224,224,224) 20%, rgb(250,250,250) 80%);
--- a/client/js/podium.js	Wed Feb 15 12:34:36 2012 +0100
+++ b/client/js/podium.js	Wed Feb 15 18:52:07 2012 +0100
@@ -8,7 +8,7 @@
     this.options = opts || {};
     this.options.container = this.options.container || 'podium';
     this.options.spacing = this.options.spacing || 20;
-    this.options.background = '#ffffff';
+    this.options.barBgd = this.options.barBgd || '#ffffff';
     this.options.transitionDuration = this.options.transitionDuration || 200;
     this.$ = this.options.jquery || jQuery;
     this._$ = this.$('#' + this.options.container);
@@ -30,7 +30,7 @@
         var _newCol = document.createElement("div");
         this.$(_newCol).css({
             "float": "left",
-            "background": this.options.background,
+            "background": this.options.barBgd,
             "margin-top": this.options.height,
             "width": 0,
             "height": 0,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/js/tweetsource.js	Wed Feb 15 18:52:07 2012 +0100
@@ -0,0 +1,215 @@
+/* Author: Raphaël Velt, IRI
+ * 
+ * Licence: CeCILL-B - http://www.cecill.info/licences/Licence_CeCILL-B_V1-fr.html
+ * 
+ * */
+
+Btv_TweetArray = function() {
+    this.tweets = [];
+    this.idIndex = [];
+}
+
+Btv_TweetArray.prototype.push = function(_tweet) {
+    this.tweets.push(_tweet);
+    this.idIndex.push(_tweet.id_str);
+}
+
+Btv_TweetArray.prototype.addTweet = function(_tweet, _inhibitCallback) {
+    if (this.idIndex.indexOf(_tweet.id_str) != -1) {
+        return;
+    }
+    if (!_tweet.date_value) {
+        _tweet.date_value = Date.parse(_tweet.created_at.replace(/(\+|-)/,'UTC$1'));
+    }
+    var _pos = this.tweets.length;
+    while (_pos && this.idIndex[_pos - 1] > _tweet.id_str) {
+        _pos--;
+    }
+    this.tweets.splice(_pos,0,_tweet);
+    this.idIndex.splice(_pos,0,_tweet.id_str);
+}
+
+Btv_TweetArray.prototype.addMultipleTweets = function(_multiTweets) {
+    var _l = _multiTweets.length;
+    for (var _i = 0; _i < _l; _i++) {
+        this.addTweet(_multiTweets[_i], true);
+    }
+}
+
+Btv_TweetArray.prototype.count = function() {
+    return this.tweets.length;
+}
+
+Btv_TweetArray.prototype.getTweet = function(_i) {
+    return this.tweets(_i);
+}
+
+Btv_TweetArray.prototype.slice = function(_start, _end) {
+    var _slice = this.tweets.slice(_start, _end),
+        _result = new Btv_TweetArray(),
+        _l = _slice.length;
+    for (var _i = 0; _i < _l; _i++) {
+        _result.push(_slice[_i]);
+    }
+    return _result;
+}
+
+Btv_TweetArray.prototype.reverse = function() {
+    var _result = new Btv_TweetArray(),
+        _l = this.tweets.length;
+    for (var _i = _l-1; _i >= 0; _i--) {
+        _result.push(this.tweets[_i]);
+    }
+    return _result;
+}
+
+Btv_TweetArray.prototype.each = function(_callback) {
+    var _l = this.count();
+    for (var _i = 0; _i < _l; _i++) {
+        _callback(this.tweets[_i]);
+    }
+}
+
+Btv_TweetArray.prototype.map = function(_callback) {
+    var _result = [];
+    this.each(function(_tweet) {
+        _result.push(_callback(_tweet))
+    });
+    return _result;
+}
+
+Btv_TweetArray.prototype.search = function(_filter) {
+    var _filtered = new Btv_TweetArray(),
+        _reFilter = new RegExp(_filter.replace(/\W/gim,'\\$1'),'gim');
+    this.each(function(_tweet) {
+        var _mention = '@' + _tweet.from_user;
+        if (( _tweet.text.search(_reFilter) != -1 ) || ( _mention.search(_reFilter) != -1 )) {
+            _filtered.push(_tweet);
+        }
+    });
+    return _filtered;
+}
+
+Btv_TweetArray.prototype.beforeDate = function(_date) {
+    var _filtered = new Btv_TweetArray();
+    this.each(function(_tweet) {
+        if (_tweet.date_value < _date) {
+            _filtered.push(_tweet);
+        }
+    });
+    return _filtered;
+}
+
+Btv_TweetArray.prototype.afterDate = function(_date) {
+    var _filtered = new Btv_TweetArray();
+    this.each(function(_tweet) {
+        if (_tweet.date_value > _date) {
+            _filtered.push(_tweet);
+        }
+    });
+    return _filtered;
+}
+
+Btv_TweetArray.prototype.tweetById = function(_tweetId) {
+    var _index = this.idIndex.indexOf(_tweetId);
+    return (_index ? this.tweets[_index] : null);
+}
+
+Btv_TweetArray.prototype.lastTweet = function() {
+    return this.tweets[this.tweets.length - 1];
+}
+
+/*
+ * 
+ */
+
+Btv_TweetSource = function(_opts) {
+    Btv_TweetArray.call(this);
+    this.loading = false;
+    if (!_opts || !_opts.keywords || !_opts.keywords.length) {
+        return;
+    }
+    this.options = _opts;
+    var _this = this;
+    this.retrieveInitialTweets()
+    setInterval(function() {
+        _this.retrieveNewTweets();
+    }, 5000);
+}
+
+Btv_TweetSource.prototype = new Btv_TweetArray();
+
+Btv_TweetSource.prototype.retrieveTweets = function(_opts) {
+    
+    function getTwitterUrl(url) {
+        $.getJSON(url, function(data) {
+            _currentPage++;
+            var _isLast = true;
+            if (data.results && data.results.length) {
+                _this.addMultipleTweets(data.results);
+                var _oldestTweetId = data.results[data.results.length - 1].id_str,
+                    _maxId = _oldestTweetId;
+                if (_currentPage < _opts.pages) {
+                    _isLast = false;
+                    getTwitterUrl(_baseurl + _firstparams + '&max_id=' + _maxId + _lastparams);
+                }
+            }
+            
+            if (_isLast) {
+                _this.loading = false;
+                if (_this.tweetsCallback) {
+                    _this.tweetsCallback();
+                }
+            }
+        });
+    }
+    
+    if (this.loading) {
+        return;
+    }
+    this.loading = true;
+    
+    var _baseurl = "http://search.twitter.com/search.json",
+        _currentPage = 0,
+        _firstparams = "?q="
+            + encodeURIComponent(this.options.keywords.join(' OR '))
+            + "&rpp=100"
+            + (this.options.lang ? "&lang=" + this.options.lang : '' ),
+        _lastparams = ( _opts.since_id ? "&since_id=" + _opts.since_id : '' )
+            + "&callback=?",
+        _jsonurl = _baseurl + _firstparams + _lastparams,
+        _this = this;
+    getTwitterUrl(_jsonurl);
+    
+}
+
+Btv_TweetSource.prototype.retrieveInitialTweets = function() {
+    this.retrieveTweets({
+        "pages": 6
+    });
+}
+
+Btv_TweetSource.prototype.retrieveNewTweets = function() {
+    this.retrieveTweets({
+        "pages": 1,
+        "since_id": this.lastTweet().id_str
+    });
+}
+
+Btv_TweetArray.prototype.setTweetsCallback = function(_callback) {
+    this.tweetsCallback = _callback;
+}
+
+/*
+Btv_TweetSubscriber = function(tweetArray) {
+    this.tweetArray = tweetArray;
+    this.position = 0;
+}
+
+Btv_TweetSubscriber.getTweets = function() {
+    var _p = this.position,
+        _l = this.tweetArray.count();
+    this.position = _l;
+    return this.tweetArray.slice(_p,_l);
+}
+*/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/podium-cp-tweets.html	Wed Feb 15 18:52:07 2012 +0100
@@ -0,0 +1,144 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <meta charset="utf-8" />
+        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+        <title>controlpanel</title>
+        <meta name="description" content="" />
+        <link rel="stylesheet" href="css/base-metric.css" />
+        <link rel="stylesheet" href="css/controlpanel.css" />
+        <style type="text/css">
+            #podium-container {
+                width: 800px;
+                margin: 200px auto 0;
+            }
+            #podium {
+                width: 100%;
+                height: 300px;
+                cursor: pointer;
+            }
+            #podium-labels {
+                float: left;
+                width: 100%;
+                clear: both;
+                margin-top: 20px;
+            }
+            #podium-labels li {
+                float: left;
+                width: 200px;
+                color: #ffffff;
+                text-align: center;
+                font-size: 28px;
+                font-weight: bold;
+            }
+        </style>
+        <script type="text/javascript" src="lib/jquery.min.js"></script>
+        <script type="text/javascript" src="js/podium.js"></script>
+        <script type="text/javascript" src="js/tweetsource.js"></script>
+        <script type="text/javascript">
+            var tzero = new Date();
+            $(function() {
+                setInterval(function() {
+                    var _t = Math.floor((new Date() - tzero)/1000),
+                        _s = _t % 60,
+                        _m = Math.floor(_t/60) % 60,
+                        _h = Math.floor(_t/3600);
+                    $("#btv-cp-temps").html(
+                        _h  + ':' + (_m < 10 ? '0' : '') + _m + ':' + (_s < 10 ? '0' : '') + _s
+                    )
+                }, 500);
+                var _keywords = ['Sarkozy', 'Hollande', 'candidat', 'politique']
+                myTweetSource = new Btv_TweetSource({
+                    keywords: _keywords
+                });
+                myPodium = new Btv_Podium([0,0,0,0]);
+                myTweetSource.setTweetsCallback(function() {
+                    $("#btv-cp-nb-tweets").html(this.count());
+                    var _counts = [];
+                    for (var _i = 0; _i < _keywords.length; _i++) {
+                        _counts.push(this.search(_keywords[_i]).count());
+                    }
+                    myPodium.update(_counts);
+                    $('#btv-cp-liste-tweets-tout').html(
+                        this.reverse().slice(0,20).map(function(_t) {
+                            return '<li onclick="addTweet(\''
+                                + _t.id_str
+                                + '\'); return false;"><a title="Ajouter à la sélection" href="#"><span class="btv-cp-tweet-date">'
+                                + _t.created_at.match(/\d+:\d+:\d+/)[0]
+                                + '</span> <span class="btv-cp-tweet-from">@'
+                                + _t.from_user
+                                + '</span> <span class="btv-cp-tweet-text">'
+                                + _t.text
+                                + '</span><div class="btv-cp-tweet-button btv-cp-tweet-add"></div></a></li>'
+                        }).join('')
+                    )
+                });
+            });
+            function addTweet(tweetId) {
+                var _t = myTweetSource.tweetById(tweetId);
+                if (_t) {
+                    $("#btv-cp-liste-tweets-selection").prepend(
+                        '<li onclick="showTweet(\''
+                            + _t.id_str
+                            + '\'); return false;"><a title="Afficher sur l\'écran" href="#"><span class="btv-cp-tweet-date">'
+                            + _t.created_at.match(/\d+:\d+:\d+/)[0]
+                            + '</span> <span class="btv-cp-tweet-from">@'
+                            + _t.from_user
+                            + '</span> <span class="btv-cp-tweet-text">'
+                            + _t.text
+                            + '</span><div class="btv-cp-tweet-button btv-cp-tweet-show"></div></a></li>'
+                    );
+                }
+            }
+        </script>
+    </head>
+    <body>
+        <div id="btv-cp-container">
+            <div class="btv-cp-line">
+                <div class="btv-cp-element">
+                    <h2>Bubble <b>TV</b></h2>
+                </div>
+                <div class="btv-cp-element" id="btv-cp-cont-filtre">
+                    <h3>Rechercher/Filtrer</h3>
+                    <input id="btv-cp-champ-filtre" />
+                    <a href="#" id="btv-cp-clear-filtre">x</a>
+                </div>
+                <div class="btv-cp-element">
+                    <h3>Derniers tweets</h3>
+                    <ul class="btv-cp-liste-tweets" id="btv-cp-liste-tweets-tout">
+                    </ul>
+                </div>
+                <div class="btv-cp-element">
+                    <h3>Tweets sélectionnés</h3>
+                    <ul class="btv-cp-liste-tweets" id="btv-cp-liste-tweets-selection">
+                    </ul>
+                </div>
+                <div class="btv-cp-element btv-cp-cont-pause" id="btv-cp-cont-pause-amont">
+                    <h3>Arrivée des tweets</h3>
+                    <a class="btv-cp-play-pause btv-cp-status-pause" href="#"></a>
+                </div>
+                <div class="btv-cp-element btv-cp-cont-pause" id="btv-cp-cont-pause-aval">
+                    <h3>Purge des colonnes</h3>
+                    <a class="btv-cp-play-pause btv-cp-status-pause" href="#"></a>
+                </div>
+                <div class="btv-cp-element btv-cp-compteur">
+                    <h3>Nombre de tweets</h3>
+                    <h4 id="btv-cp-nb-tweets"></h4>
+                </div>
+                <div class="btv-cp-element btv-cp-compteur">
+                    <h3>Temps écoulé</h3>
+                    <h4 id="btv-cp-temps">0:00:00</h4>
+                </div>
+            </div>
+        </div>
+        <div id="podium-container">
+            <div id="podium"></div>
+            <ul id="podium-labels">
+                <li>Sarkozy</li>
+                <li>Hollande</li>
+                <li>candidat</li>
+                <li>politique</li>
+            </ul>
+        </div>
+    </body>
+</html>