StatsCollect 0.1.0.20101220 → 0.1.1.20101220
Sign up to get free protection for your applications and to get access to all the features.
- data/Credits +5 -0
- data/ReleaseInfo +1 -1
- data/TODO +2 -1
- data/bin/StatsCollect.rb +0 -5
- data/lib/StatsCollect/Backends/MySQL.rb +5 -2
- data/lib/StatsCollect/Locations/Facebook.rb +3 -1
- data/lib/StatsCollect/Locations/Youtube.rb +70 -2
- data/lib/StatsCollect/Stats.rb +19 -3
- metadata +2 -2
data/Credits
CHANGED
@@ -5,6 +5,11 @@
|
|
5
5
|
* http://www.ruby-lang.org/
|
6
6
|
* Thanks a lot Matz for this truly wonderful language !
|
7
7
|
|
8
|
+
== rUtilAnts
|
9
|
+
* Muriel Salvan (http://murielsalvan.users.sourceforge.net)
|
10
|
+
* http://rutilants.sourceforge.net
|
11
|
+
* Used for plugins and logging handling.
|
12
|
+
|
8
13
|
= Projects used by StatsCollect plugins
|
9
14
|
|
10
15
|
== Plugin Backends/MySQL
|
data/ReleaseInfo
CHANGED
data/TODO
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
* MySpace: Get the user ID by parsing the Profile URL and remove :MySpaceName configuration option.
|
1
|
+
* MySpace: Get the user ID by parsing the Profile URL and remove :MySpaceName configuration option.
|
2
|
+
* Get all the orders at once, and merge them to call Locations just once per execution.
|
data/bin/StatsCollect.rb
CHANGED
@@ -4,11 +4,6 @@
|
|
4
4
|
# Licensed under the terms specified in LICENSE file. No warranty is provided.
|
5
5
|
#++
|
6
6
|
|
7
|
-
# Uncomment for PlanetHoster
|
8
|
-
#require 'rubygems'
|
9
|
-
#ENV['GEM_PATH'] = "/home/murieles/ruby/gems:/home/murieles/.gem/ruby/1.8:/usr/lib/ruby/gems/1.8"
|
10
|
-
#Gem.clear_paths
|
11
|
-
|
12
7
|
require 'rUtilAnts/Logging'
|
13
8
|
RUtilAnts::Logging::initializeLogging('','')
|
14
9
|
require 'tmpdir'
|
@@ -36,7 +36,10 @@ module StatsCollect
|
|
36
36
|
rStatus = nil
|
37
37
|
|
38
38
|
if (defined?(@LstStatsOrders) == nil)
|
39
|
-
@LstStatsOrders =
|
39
|
+
@LstStatsOrders = []
|
40
|
+
@MySQLConnection.query('SELECT id, timestamp, objects_list, categories_list, locations_list, status FROM stats_orders WHERE status=0 OR status=1 ORDER BY timestamp DESC').each do |iRow|
|
41
|
+
@LstStatsOrders << iRow.clone
|
42
|
+
end
|
40
43
|
end
|
41
44
|
if (!@LstStatsOrders.empty?)
|
42
45
|
lID, rTimeStamp, lStrLocations, lStrObjects, lStrCategories, rStatus = @LstStatsOrders.pop
|
@@ -115,7 +118,7 @@ module StatsCollect
|
|
115
118
|
# Return:
|
116
119
|
# * _Integer_: Its resulting ID
|
117
120
|
def addCategory(iCategory, iValueType)
|
118
|
-
@MySQLConnection.query("INSERT INTO stats_categories (name, value_type) VALUES ('#{@MySQLConnection.escape_string(
|
121
|
+
@MySQLConnection.query("INSERT INTO stats_categories (name, value_type) VALUES ('#{@MySQLConnection.escape_string(iCategory)}', #{iValueType})")
|
119
122
|
|
120
123
|
return @MySQLConnection.insert_id
|
121
124
|
end
|
@@ -42,7 +42,9 @@ module StatsCollect
|
|
42
42
|
lProfilePage = iMechanizeAgent.get('http://www.facebook.com/profile.php')
|
43
43
|
lNbrFriends = nil
|
44
44
|
lProfilePage.root.css('script').each do |iScriptNode|
|
45
|
-
lMatch = iScriptNode.content.match(/>(\d*)
|
45
|
+
lMatch = iScriptNode.content.match(/>Friends \((\d*)\)<\\\/a><\\\/span>/)
|
46
|
+
# The following line is valid for old profiles only
|
47
|
+
#lMatch = iScriptNode.content.match(/>(\d*) friends<\\\/a><\\\/span>/)
|
46
48
|
if (lMatch != nil)
|
47
49
|
lNbrFriends = Integer(lMatch[1])
|
48
50
|
break
|
@@ -23,8 +23,8 @@ module StatsCollect
|
|
23
23
|
require 'mechanize'
|
24
24
|
lMechanizeAgent = Mechanize.new
|
25
25
|
lLoginForm = lMechanizeAgent.get('http://www.youtube.com').link_with(:text => 'Sign In').click.forms[1]
|
26
|
-
lLoginForm.Email =
|
27
|
-
lLoginForm.Passwd =
|
26
|
+
lLoginForm.Email = iConf[:LoginEMail]
|
27
|
+
lLoginForm.Passwd = iConf[:LoginPassword]
|
28
28
|
lMechanizeAgent.submit(lLoginForm, lLoginForm.buttons.first).meta.first.click
|
29
29
|
if ((oStatsProxy.isCategoryIncluded?('Video plays')) or
|
30
30
|
(oStatsProxy.isCategoryIncluded?('Video likes')) or
|
@@ -33,6 +33,19 @@ module StatsCollect
|
|
33
33
|
(oStatsProxy.isCategoryIncluded?('Video responses')))
|
34
34
|
getVideos(oStatsProxy, lMechanizeAgent)
|
35
35
|
end
|
36
|
+
if ((oStatsProxy.isObjectIncluded?('Global')) and
|
37
|
+
((oStatsProxy.isCategoryIncluded?('Visits')) or
|
38
|
+
(oStatsProxy.isCategoryIncluded?('Followers'))))
|
39
|
+
getOverview(oStatsProxy, lMechanizeAgent)
|
40
|
+
end
|
41
|
+
if ((oStatsProxy.isObjectIncluded?('Global')) and
|
42
|
+
(oStatsProxy.isCategoryIncluded?('Friends')))
|
43
|
+
getFriends(oStatsProxy, lMechanizeAgent)
|
44
|
+
end
|
45
|
+
if ((oStatsProxy.isObjectIncluded?('Global')) and
|
46
|
+
(oStatsProxy.isCategoryIncluded?('Following')))
|
47
|
+
getSubscriptions(oStatsProxy, lMechanizeAgent)
|
48
|
+
end
|
36
49
|
end
|
37
50
|
|
38
51
|
# Get the videos statistics
|
@@ -62,6 +75,61 @@ module StatsCollect
|
|
62
75
|
logDebug "#{lLstVideosRead.size} videos read: #{lLstVideosRead.join(', ')}"
|
63
76
|
end
|
64
77
|
|
78
|
+
# Get the overview statistics
|
79
|
+
#
|
80
|
+
# Parameters:
|
81
|
+
# * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
|
82
|
+
# * *iMechanizeAgent* (_Mechanize_): The agent reading pages
|
83
|
+
def getOverview(oStatsProxy, iMechanizeAgent)
|
84
|
+
lOverviewPage = iMechanizeAgent.get('http://www.youtube.com/account_overview')
|
85
|
+
lNbrVisits = nil
|
86
|
+
lNbrFollowers = nil
|
87
|
+
lOverviewPage.root.css('div.statBlock').each do |iStatsSectionNode|
|
88
|
+
lChildrenNodes = iStatsSectionNode.children
|
89
|
+
lChildrenNodes.each_with_index do |iNode, iIdx|
|
90
|
+
if (iNode.content == 'Channel Views:')
|
91
|
+
lNbrVisits = Integer(lChildrenNodes[iIdx+1].content.strip)
|
92
|
+
elsif (iNode.content == 'Subscribers:')
|
93
|
+
lNbrFollowers = Integer(lChildrenNodes[iIdx+1].content.strip)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
if ((lNbrVisits != nil) and
|
97
|
+
(lNbrFollowers != nil))
|
98
|
+
break
|
99
|
+
end
|
100
|
+
end
|
101
|
+
if (lNbrVisits == nil)
|
102
|
+
logErr "Unable to get number of visits: #{lOverviewPage}"
|
103
|
+
elsif (lNbrFollowers == nil)
|
104
|
+
logErr "Unable to get number of followers: #{lOverviewPage}"
|
105
|
+
else
|
106
|
+
oStatsProxy.addStat('Global', 'Visits', lNbrVisits)
|
107
|
+
oStatsProxy.addStat('Global', 'Followers', lNbrFollowers)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Get the friends statistics
|
112
|
+
#
|
113
|
+
# Parameters:
|
114
|
+
# * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
|
115
|
+
# * *iMechanizeAgent* (_Mechanize_): The agent reading pages
|
116
|
+
def getFriends(oStatsProxy, iMechanizeAgent)
|
117
|
+
lOverviewPage = iMechanizeAgent.get('http://www.youtube.com/profile?view=friends')
|
118
|
+
lNbrFriends = Integer(lOverviewPage.root.xpath('//span[@name="channel-box-item-count"]').first.content)
|
119
|
+
oStatsProxy.addStat('Global', 'Friends', lNbrFriends)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Get the friends statistics
|
123
|
+
#
|
124
|
+
# Parameters:
|
125
|
+
# * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
|
126
|
+
# * *iMechanizeAgent* (_Mechanize_): The agent reading pages
|
127
|
+
def getSubscriptions(oStatsProxy, iMechanizeAgent)
|
128
|
+
lOverviewPage = iMechanizeAgent.get('http://www.youtube.com/profile?view=subscriptions')
|
129
|
+
lNbrFollowing = Integer(lOverviewPage.root.xpath('//span[@name="channel-box-item-count"]').first.content)
|
130
|
+
oStatsProxy.addStat('Global', 'Following', lNbrFollowing)
|
131
|
+
end
|
132
|
+
|
65
133
|
end
|
66
134
|
|
67
135
|
end
|
data/lib/StatsCollect/Stats.rb
CHANGED
@@ -10,12 +10,10 @@ require 'StatsCollect/StatsProxy'
|
|
10
10
|
module StatsCollect
|
11
11
|
|
12
12
|
# Stats orders statuses
|
13
|
-
# !!! Those constants are also defined in the RoR website.
|
14
13
|
STATS_ORDER_STATUS_TOBEPROCESSED = 0
|
15
14
|
STATS_ORDER_STATUS_RECOVERABLE_ERROR = 1
|
16
15
|
STATS_ORDER_STATUS_UNRECOVERABLE_ERROR = 2
|
17
16
|
# Value types
|
18
|
-
# !!! Those constants are also defined in the RoR website.
|
19
17
|
STATS_VALUE_TYPE_INTEGER = 0
|
20
18
|
STATS_VALUE_TYPE_FLOAT = 1
|
21
19
|
STATS_VALUE_TYPE_PERCENTAGE = 2
|
@@ -33,6 +31,7 @@ module StatsCollect
|
|
33
31
|
parsePluginsFromDir('Notifiers', "#{File.expand_path(File.dirname(__FILE__))}/Notifiers", 'StatsCollect::Notifiers')
|
34
32
|
|
35
33
|
@Backend = nil
|
34
|
+
@BackendInit = false
|
36
35
|
@Notifier = nil
|
37
36
|
@ConfigFile = nil
|
38
37
|
@DisplayHelp = false
|
@@ -183,7 +182,10 @@ module StatsCollect
|
|
183
182
|
begin
|
184
183
|
# Collect statistics
|
185
184
|
logInfo "[#{DateTime.now.strftime('%Y-%m-%d %H:%M:%S')}] - Begin collecting stats..."
|
186
|
-
|
185
|
+
if (!@BackendInit)
|
186
|
+
@BackendInstance.initSession(@Conf[:Backends][@Backend])
|
187
|
+
@BackendInit = true
|
188
|
+
end
|
187
189
|
# Get the stats orders to process
|
188
190
|
lFoundOrder = false
|
189
191
|
lTimeStamp, lLstLocations, lLstObjects, lLstCategories, lStatus = @BackendInstance.getNextStatsOrder
|
@@ -245,6 +247,20 @@ module StatsCollect
|
|
245
247
|
end
|
246
248
|
end
|
247
249
|
|
250
|
+
# Enqueue a new stats order
|
251
|
+
#
|
252
|
+
# Parameters:
|
253
|
+
# * *iLstLocations* (<em>list<String></em>): Locations list (can be empty for all locations)
|
254
|
+
# * *iLstObjects* (<em>list<String></em>): Objects list (can be empty for all objects)
|
255
|
+
# * *iLstCategories* (<em>list<String></em>): Categories list (can be empty for all categories)
|
256
|
+
def pushStatsOrder(iLstLocations, iLstObjects, iLstCategories)
|
257
|
+
if (!@BackendInit)
|
258
|
+
@BackendInstance.initSession(@Conf[:Backends][@Backend])
|
259
|
+
@BackendInit = true
|
260
|
+
end
|
261
|
+
@BackendInstance.putNewStatsOrder(DateTime.now, iLstLocations, iLstObjects, iLstCategories, STATS_ORDER_STATUS_TOBEPROCESSED)
|
262
|
+
end
|
263
|
+
|
248
264
|
private
|
249
265
|
|
250
266
|
# Process an order
|