StatsCollect 0.1.0.20101220 → 0.1.1.20101220
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|