StatsCollect 0.1.1.20101220 → 0.2.0.20110830

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.
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -15,34 +15,26 @@ module StatsCollect
15
15
  # * *iConf* (<em>map<Symbol,Object></em>): Configuration of this backend
16
16
  def initSession(iConf)
17
17
  @IdxID = 0
18
+ logMsg 'Session initialized.'
18
19
  end
19
20
 
20
- # Get the next stats order.
21
- # Code to begin a new transaction can be set in this method too.
21
+ # Get the next stats orders.
22
22
  #
23
- # Return:
24
- # * _DateTime_: The time stamp, or nil if no new stats order
25
- # * <em>list<String></em>: List of locations
26
- # * <em>list<String></em>: List of objects
27
- # * <em>list<String></em>: List of categories
28
- # * _Integer_: The order status
29
- def getNextStatsOrder
30
- rTimeStamp = nil
31
- rLstLocations = nil
32
- rLstObjects = nil
33
- rLstCategories = nil
34
- rStatus = nil
35
-
36
- if (defined?(@LstStatsOrders) == nil)
37
- @LstStatsOrders = [
38
- [ DateTime.now, [], [], [], STATS_ORDER_STATUS_TOBEPROCESSED ]
39
- ]
40
- end
41
- if (!@LstStatsOrders.empty?)
42
- rTimeStamp, rLstLocations, rLstObjects, rLstCategories, rStatus = @LstStatsOrders.pop
43
- end
44
-
45
- return rTimeStamp, rLstLocations, rLstObjects, rLstCategories, rStatus
23
+ # Parameters:
24
+ # * *oStatsOrdersProxy* (_StatsOrdersProxy_): The stats orders proxy to be used to give stats orders
25
+ def getStatsOrders(oStatsOrdersProxy)
26
+ oStatsOrdersProxy.addStatsOrder(0, DateTime.now, [], [], [], STATS_ORDER_STATUS_TOBEPROCESSED)
27
+ # oStatsOrdersProxy.addStatsOrder(0, DateTime.now, ['MySpace'], [], ['Friends list'], STATS_ORDER_STATUS_TOBEPROCESSED)
28
+ logMsg 'Added stats order 0.'
29
+ end
30
+
31
+ # Dequeue the given stat orders IDs.
32
+ # Code to begin a new transaction can be set in this method too. In this case, the dequeue should be part of the transaction, or it will have to be re-enqueued during rollback method call (otherwise orders will be lost).
33
+ #
34
+ # Parameters:
35
+ # * *iLstStatsOrderIDs* (<em>list<Integer></em>): The list of stats order IDs to dequeue
36
+ def dequeueStatsOrders(iLstStatsOrderIDs)
37
+ logMsg "Transaction started and stats orders dequeued: #{iLstStatsOrderIDs.join(', ')}"
46
38
  end
47
39
 
48
40
  # Get the list of known locations
@@ -125,7 +117,23 @@ module StatsCollect
125
117
  # * *iValue* (_Object_): The value to store
126
118
  # * *iValueType* (_Integer_): The value type
127
119
  def addStat(iTimeStamp, iLocationID, iObjectID, iCategoryID, iValue, iValueType)
128
- logMsg "Added stat: #{iTimeStamp} | Location: #{iLocationID} | Object: #{iObjectID} | Category: #{iCategoryID} | Value: #{iValue}"
120
+ logMsg "Added stat: #{iTimeStamp} | Location: #{iLocationID} | Object: #{iObjectID} | Category: #{iCategoryID} (value type: #{iValueType}) | Value: #{iValue}"
121
+ end
122
+
123
+ # Get an existing stat value
124
+ #
125
+ # Parameters:
126
+ # * *iTimeStamp* (_DateTime_): The timestamp
127
+ # * *iLocationID* (_Integer_): The location ID
128
+ # * *iObjectID* (_Integer_): The object ID
129
+ # * *iCategoryID* (_Integer_): The category ID
130
+ # * *iValueType* (_Integer_): The value type
131
+ # Return:
132
+ # * _Object_: The corresponding value, or nil if none
133
+ def getStat(iTimeStamp, iLocationID, iObjectID, iCategoryID, iValueType)
134
+ logMsg "Get stat: #{iTimeStamp} | Location: #{iLocationID} | Object: #{iObjectID} | Category: #{iCategoryID} (value type: #{iValueType})"
135
+
136
+ return nil
129
137
  end
130
138
 
131
139
  # Add a new stats order
@@ -150,6 +158,10 @@ module StatsCollect
150
158
  logMsg 'Transaction rollbacked'
151
159
  end
152
160
 
161
+ # Close a session of this backend
162
+ def closeSession
163
+ end
164
+
153
165
  end
154
166
 
155
167
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -22,7 +22,7 @@ module StatsCollect
22
22
  def execute(oStatsProxy, iConf, iLstObjects, iLstCategories)
23
23
  require 'mechanize'
24
24
  lMechanizeAgent = Mechanize.new
25
- # Get the number of likes from Facebook
25
+ # Get the number of shares
26
26
  if (oStatsProxy.isCategoryIncluded?('Monthly shares'))
27
27
  getDomains(oStatsProxy, lMechanizeAgent, iConf, 'month', 'Monthly shares')
28
28
  end
@@ -0,0 +1,106 @@
1
+ #--
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module StatsCollect
7
+
8
+ module Locations
9
+
10
+ class CSV
11
+
12
+ # Execute the plugin.
13
+ # This method has to add the stats and errors to the proxy.
14
+ # It can filter only objects and categories given.
15
+ # It has access to its configuration.
16
+ #
17
+ # Parameters:
18
+ # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
19
+ # * *iConf* (<em>map<Symbol,Object></em>): The configuration associated to this plugin
20
+ # * *iLstObjects* (<em>list<String></em>): List of objects to filter (can be empty for all)
21
+ # * *iLstCategories* (<em>list<String></em>): List of categories to filter (can be empty for all)
22
+ def execute(oStatsProxy, iConf, iLstObjects, iLstCategories)
23
+ if (!iConf[:Files].empty?)
24
+ # Get the list of categories, locations and objects
25
+ lCategories = oStatsProxy.getCategories
26
+ lObjects = oStatsProxy.getObjects
27
+ lLocations = oStatsProxy.getLocations
28
+ lCSVLocations = []
29
+ lCSVObjects = []
30
+ lCSVCategories = []
31
+ require 'csv'
32
+ iConf[:Files].each do |iFileName|
33
+ lIdxLine = 0
34
+ lMissingIDs = false
35
+ ::CSV::open(iFileName, 'r', :col_sep => iConf[:ColumnSeparator], :quote_char => iConf[:QuoteChar], :row_sep => iConf[:RowSeparator]).each do |iRow|
36
+ case lIdxLine
37
+ when 0
38
+ # We have locations in this line
39
+ iRow[1..-1].each do |iLocationName|
40
+ if (lLocations[iLocationName] == nil)
41
+ logWarn "Unknown location from CSV file #{iFileName}: #{iLocationName}"
42
+ lMissingIDs = true
43
+ end
44
+ lCSVLocations << iLocationName
45
+ end
46
+ when 1
47
+ # We have objects in this line
48
+ iRow[1..-1].each do |iObjectName|
49
+ if (lObjects[iObjectName] == nil)
50
+ logWarn "Unknown object from CSV file #{iFileName}: #{iObjectName}"
51
+ lMissingIDs = true
52
+ end
53
+ lCSVObjects << iObjectName
54
+ end
55
+ when 2
56
+ # We have categories in this line
57
+ iRow[1..-1].each do |iCategoryName|
58
+ if (lCategories[iCategoryName] == nil)
59
+ logWarn "Unknown category from CSV file #{iFileName}: #{iCategoryName}"
60
+ lMissingIDs = true
61
+ end
62
+ lCSVCategories << iCategoryName
63
+ end
64
+ else
65
+ if (lMissingIDs and
66
+ (iConf[:IDsMustExist]))
67
+ raise RuntimeError.new("Missing some IDs from CSV file #{iFileName}.")
68
+ end
69
+ # A line of data
70
+ lTimestamp = DateTime.strptime(iRow[0], iConf[:DateTimeFormat])
71
+ iRow[1..-1].each_with_index do |iStrValue, iIdx|
72
+ if (iStrValue != nil)
73
+ # Interpret the CSV value based on the value type of this column
74
+ lValueType = (lCategories[lCSVCategories[iIdx]] || STATS_VALUE_TYPE_UNKNOWN)
75
+ lValue = nil
76
+ case lValueType
77
+ when STATS_VALUE_TYPE_INTEGER
78
+ lValue = Integer(iStrValue)
79
+ when STATS_VALUE_TYPE_FLOAT
80
+ lValue = Float(iStrValue)
81
+ when STATS_VALUE_TYPE_PERCENTAGE
82
+ lValue = Float(iStrValue)
83
+ when STATS_VALUE_TYPE_UNKNOWN
84
+ lValue = iStrValue
85
+ when STATS_VALUE_TYPE_MAP
86
+ lValue = eval(iStrValue)
87
+ when STATS_VALUE_TYPE_STRING
88
+ lValue = iStrValue
89
+ else
90
+ raise RuntimeError.new("Unknown value type for category #{lCSVCategories[iIdx]}: #{lValueType}")
91
+ end
92
+ oStatsProxy.addStat(lCSVObjects[iIdx], lCSVCategories[iIdx], lValue, :Timestamp => lTimestamp, :Location => lCSVLocations[iIdx])
93
+ end
94
+ end
95
+ end
96
+ lIdxLine += 1
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -22,6 +22,8 @@ module StatsCollect
22
22
  def execute(oStatsProxy, iConf, iLstObjects, iLstCategories)
23
23
  require 'mechanize'
24
24
  lMechanizeAgent = Mechanize.new
25
+ # Set a specific user agent, as Facebook will treat our agent as a mobile one
26
+ lMechanizeAgent.user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'
25
27
  lLoginForm = lMechanizeAgent.get('http://www.facebook.com').forms[0]
26
28
  lLoginForm.email = iConf[:LoginEMail]
27
29
  lLoginForm.pass = iConf[:LoginPassword]
@@ -29,7 +31,7 @@ module StatsCollect
29
31
  lMechanizeAgent.submit(lLoginForm, lLoginForm.buttons.first)
30
32
  if ((oStatsProxy.isObjectIncluded?('Global')) and
31
33
  (oStatsProxy.isCategoryIncluded?('Friends')))
32
- getProfile(oStatsProxy, lMechanizeAgent)
34
+ getProfile(oStatsProxy, lMechanizeAgent, iConf)
33
35
  end
34
36
  end
35
37
 
@@ -38,11 +40,13 @@ module StatsCollect
38
40
  # Parameters:
39
41
  # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
40
42
  # * *iMechanizeAgent* (_Mechanize_): The agent reading pages
41
- def getProfile(oStatsProxy, iMechanizeAgent)
42
- lProfilePage = iMechanizeAgent.get('http://www.facebook.com/profile.php')
43
+ # * *iConf* (<em>map<Symbol,Object></em>): The configuration associated to this plugin
44
+ def getProfile(oStatsProxy, iMechanizeAgent, iConf)
45
+ lProfilePage = iMechanizeAgent.get("http://www.facebook.com/#{iConf[:URLID]}")
43
46
  lNbrFriends = nil
44
47
  lProfilePage.root.css('script').each do |iScriptNode|
45
- lMatch = iScriptNode.content.match(/>Friends \((\d*)\)<\\\/a><\\\/span>/)
48
+ lMatch = iScriptNode.content.match(/sk=friends&amp;v=friends\\">Friends \((\d*)\)/)
49
+ #lMatch = iScriptNode.content.match(/>Friends \((\d*)\)/)
46
50
  # The following line is valid for old profiles only
47
51
  #lMatch = iScriptNode.content.match(/>(\d*) friends<\\\/a><\\\/span>/)
48
52
  if (lMatch != nil)
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -22,6 +22,8 @@ module StatsCollect
22
22
  def execute(oStatsProxy, iConf, iLstObjects, iLstCategories)
23
23
  require 'mechanize'
24
24
  lMechanizeAgent = Mechanize.new
25
+ # Set a specific user agent, as Facebook will treat our agent as a mobile one
26
+ lMechanizeAgent.user_agent = 'Mozilla/5.0 (Windows; U; Windows NT 6.1; fr; rv:1.9.2.13) Gecko/20101203 Firefox/3.6.13'
25
27
  lLoginForm = lMechanizeAgent.get('http://www.facebook.com').forms[0]
26
28
  lLoginForm.email = iConf[:LoginEMail]
27
29
  lLoginForm.pass = iConf[:LoginPassword]
@@ -43,7 +45,7 @@ module StatsCollect
43
45
  lProfilePage = iMechanizeAgent.get("http://www.facebook.com/pages/#{iConf[:PageID]}")
44
46
  lNbrLikes = nil
45
47
  lProfilePage.root.css('script').each do |iScriptNode|
46
- lMatch = iScriptNode.content.match(/>(\d*) People Like This/)
48
+ lMatch = iScriptNode.content.match(/>\\u003cspan class=\\"uiNumberGiant fsxxl fwb\\">(\d*)\\u003c\\\/span>/)
47
49
  if (lMatch != nil)
48
50
  lNbrLikes = Integer(lMatch[1])
49
51
  break
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -0,0 +1,103 @@
1
+ #--
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module StatsCollect
7
+
8
+ module Locations
9
+
10
+ class GoogleGroup
11
+
12
+ MEMBERSTATUS_INVITED = 0
13
+ MEMBERSTATUS_MEMBER = 1
14
+ MEMBERSTATUS_OWNER = 2
15
+
16
+ # Execute the plugin.
17
+ # This method has to add the stats and errors to the proxy.
18
+ # It can filter only objects and categories given.
19
+ # It has access to its configuration.
20
+ #
21
+ # Parameters:
22
+ # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
23
+ # * *iConf* (<em>map<Symbol,Object></em>): The configuration associated to this plugin
24
+ # * *iLstObjects* (<em>list<String></em>): List of objects to filter (can be empty for all)
25
+ # * *iLstCategories* (<em>list<String></em>): List of categories to filter (can be empty for all)
26
+ def execute(oStatsProxy, iConf, iLstObjects, iLstCategories)
27
+ require 'mechanize'
28
+ lMechanizeAgent = Mechanize.new
29
+ lLoginForm = lMechanizeAgent.get('http://groups.google.com/').link_with(:text => 'Sign in').click.forms[0]
30
+ lLoginForm.Email = iConf[:LoginEMail]
31
+ lLoginForm.Passwd = iConf[:LoginPassword]
32
+ if (Mechanize::VERSION > '1.0.0')
33
+ lMechanizeAgent.submit(lLoginForm, lLoginForm.buttons.first).meta_refresh.first.click
34
+ else
35
+ lMechanizeAgent.submit(lLoginForm, lLoginForm.buttons.first).meta.first.click
36
+ end
37
+ iConf[:Objects].each do |iGroupName|
38
+ if (oStatsProxy.isCategoryIncluded?('Friends'))
39
+ getMembers(oStatsProxy, lMechanizeAgent, iGroupName)
40
+ end
41
+ if (oStatsProxy.isCategoryIncluded?('Friends list'))
42
+ getMembersList(oStatsProxy, lMechanizeAgent, iGroupName)
43
+ end
44
+ end
45
+ end
46
+
47
+ # Get the members statistics
48
+ #
49
+ # Parameters:
50
+ # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
51
+ # * *iMechanizeAgent* (_Mechanize_): The agent reading pages
52
+ # * *iGroupName* (_String_): Name of the group to retrieve members from
53
+ def getMembers(oStatsProxy, iMechanizeAgent, iGroupName)
54
+ lMembersPage = iMechanizeAgent.get("http://groups.google.com/group/#{iGroupName}/manage_members?hl=en")
55
+ lNbrFriends = Integer(lMembersPage.root.css('div.mngcontentbox table.membertabs tr td.st b').first.content.match(/All members \((\d*)\)/)[1])
56
+ oStatsProxy.addStat(iGroupName, 'Friends', lNbrFriends)
57
+ end
58
+
59
+ # Get the members list
60
+ #
61
+ # Parameters:
62
+ # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
63
+ # * *iMechanizeAgent* (_Mechanize_): The agent reading pages
64
+ # * *iGroupName* (_String_): Name of the group to retrieve members from
65
+ def getMembersList(oStatsProxy, iMechanizeAgent, iGroupName)
66
+ lExportForm = iMechanizeAgent.get("http://groups.google.com/group/#{iGroupName}/manage_members?hl=en").forms[4]
67
+ lLstMembers = iMechanizeAgent.submit(lExportForm, lExportForm.buttons.first).content.split("\n")[2..-1]
68
+ # The map of members
69
+ # map< Name, [ MemberStatus, JoinDateTime ] >
70
+ lMapMembers = {}
71
+ lLstMembers.each do |iStrMemberInfo|
72
+ lEmail, _, lStrStatus, _, _, _, lStrYear, lStrMonth, lStrDay, lStrHour, lStrMinute, lStrSecond = iStrMemberInfo.split(',')
73
+ lStatus = nil
74
+ case lStrStatus
75
+ when 'invited'
76
+ lStatus = MEMBERSTATUS_INVITED
77
+ when 'member'
78
+ lStatus = MEMBERSTATUS_MEMBER
79
+ when 'owner'
80
+ lStatus = MEMBERSTATUS_OWNER
81
+ else
82
+ logErr "Unknown member status (#{lStrStatus}) for email #{lEmail}. Will be counted as a member."
83
+ lStatus = MEMBERSTATS_MEMBER
84
+ end
85
+ lMapMembers[lEmail] = [
86
+ lStatus,
87
+ DateTime.civil(
88
+ lStrYear.to_i,
89
+ lStrMonth.to_i,
90
+ lStrDay.to_i,
91
+ lStrHour.to_i,
92
+ lStrMinute.to_i,
93
+ lStrSecond.to_i)
94
+ ]
95
+ end
96
+ oStatsProxy.addStat(iGroupName, 'Friends list', lMapMembers)
97
+ end
98
+
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2009-2010 Muriel Salvan (murielsalvan@users.sourceforge.net)
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
3
  # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
4
  #++
5
5
 
@@ -30,14 +30,17 @@ module StatsCollect
30
30
  lLoginForm.Password = iConf[:LoginPassword]
31
31
  # Submit to get to the home page
32
32
  lMechanizeAgent.submit(lLoginForm, lLoginForm.buttons.first)
33
- if ((oStatsProxy.isObjectIncluded?('Global')) and
34
- (oStatsProxy.isCategoryIncluded?('Comments')))
35
- getProfile(oStatsProxy, lMechanizeAgent)
36
- end
37
- if ((oStatsProxy.isObjectIncluded?('Global')) and
38
- ((oStatsProxy.isCategoryIncluded?('Friends')) or
39
- (oStatsProxy.isCategoryIncluded?('Visits'))))
40
- getDashboard(oStatsProxy, lMechanizeAgent)
33
+ if (oStatsProxy.isObjectIncluded?('Global'))
34
+ if (oStatsProxy.isCategoryIncluded?('Comments'))
35
+ getProfile(oStatsProxy, lMechanizeAgent)
36
+ end
37
+ if ((oStatsProxy.isCategoryIncluded?('Friends')) or
38
+ (oStatsProxy.isCategoryIncluded?('Visits')))
39
+ getDashboard(oStatsProxy, lMechanizeAgent)
40
+ end
41
+ if (oStatsProxy.isCategoryIncluded?('Friends list'))
42
+ getFriendsList(oStatsProxy, lMechanizeAgent)
43
+ end
41
44
  end
42
45
  if (oStatsProxy.isCategoryIncluded?('Song plays'))
43
46
  getSongs(oStatsProxy, lMechanizeAgent)
@@ -63,7 +66,8 @@ module StatsCollect
63
66
  # Click on the Profile link from the home page
64
67
  lProfilePage = iMechanizeAgent.get('http://www.myspace.com/home').link_with(:text => 'Profile').click
65
68
  # Screen scrap it
66
- lNbrComments = Integer(lProfilePage.root.css('div.commentsModule > div > div > div > div.moduleBody > div.genericComments > a.moreComments > span.cnt').first.content.match(/of (\d*)/)[1])
69
+ lNbrComments = Integer(lProfilePage.root.css('article#module18 div.wrapper section.content div.commentContainer a.moreComments span.cnt').first.content.match(/of (\d*)/)[1])
70
+
67
71
  oStatsProxy.addStat('Global', 'Comments', lNbrComments)
68
72
  end
69
73
 
@@ -75,8 +79,8 @@ module StatsCollect
75
79
  def getDashboard(oStatsProxy, iMechanizeAgent)
76
80
  # Get the dashboard page
77
81
  lJSonData = eval(iMechanizeAgent.get_file('http://www.myspace.com/stats/fans_json/profile_stats/en-US/x=0').gsub(':','=>'))
78
- lNbrVisits = lJSonData['data'].select { |iItem| next (iItem[0] == 'myspace_views') }.first[-1]
79
- lNbrFriends = lJSonData['data'].select { |iItem| next (iItem[0] == 'myspace_friends') }.first[-1]
82
+ lNbrVisits = Integer(lJSonData['data'].select { |iItem| next (iItem[0] == 'myspace_views') }.first[-1].gsub(',',''))
83
+ lNbrFriends = Integer(lJSonData['data'].select { |iItem| next (iItem[0] == 'myspace_friends') }.first[-1].gsub(',',''))
80
84
  oStatsProxy.addStat('Global', 'Visits', lNbrVisits)
81
85
  oStatsProxy.addStat('Global', 'Friends', lNbrFriends)
82
86
 
@@ -217,6 +221,53 @@ module StatsCollect
217
221
  logDebug "#{lLstBlogsRead.size} blogs read: #{lLstBlogsRead.join(', ')}"
218
222
  end
219
223
 
224
+ # Get the friends list
225
+ #
226
+ # Parameters:
227
+ # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
228
+ # * *iMechanizeAgent* (_Mechanize_): The agent reading pages
229
+ def getFriendsList(oStatsProxy, iMechanizeAgent)
230
+ lFriendsPage = iMechanizeAgent.get('http://www.myspace.com/my/friends/grid/page/1')
231
+ # Keep track of the last first friend of the page, as we will detect ending page thanks to it.
232
+ lLastFirstFriend = nil
233
+ lFriendsMap = {}
234
+ lIdxPage = 2
235
+ while (lFriendsPage != nil)
236
+ lFirstFriend = nil
237
+ lFriendsPage.root.css('ul.myDataList li').each do |iFriendNode|
238
+ if (iFriendNode['data-id'] != nil)
239
+ # We have a friend node
240
+ lFriendID = iFriendNode['data-id']
241
+ lFriendName = nil
242
+ iFriendNode.css('div div.vcard span.hcard a.nickname').each do |iFriendLinkNode|
243
+ lFriendName = iFriendLinkNode['href'][1..-1]
244
+ if (lFriendName == nil)
245
+ logErr "Could not get friend's name for ID #{lFriendID}: #{iFriendLinkNode}"
246
+ end
247
+ lFriendsMap[lFriendID] = lFriendName
248
+ end
249
+ if (lFirstFriend == nil)
250
+ # Check if the page has not changed
251
+ if (lLastFirstFriend == lFriendID)
252
+ # Finished
253
+ break
254
+ end
255
+ lFirstFriend = lFriendID
256
+ end
257
+ end
258
+ end
259
+ lLastFirstFriend = lFirstFriend
260
+ # Get next page if we did not reach the end
261
+ if (lLastFirstFriend == nil)
262
+ lFriendsPage = nil
263
+ else
264
+ lFriendsPage = iMechanizeAgent.get("http://www.myspace.com/my/friends/grid/page/#{lIdxPage}")
265
+ lIdxPage += 1
266
+ end
267
+ end
268
+ oStatsProxy.addStat('Global', 'Friends list', lFriendsMap)
269
+ end
270
+
220
271
  end
221
272
 
222
273
  end
@@ -0,0 +1,64 @@
1
+ #--
2
+ # Copyright (c) 2010 - 2011 Muriel Salvan (murielsalvan@users.sourceforge.net)
3
+ # Licensed under the terms specified in LICENSE file. No warranty is provided.
4
+ #++
5
+
6
+ module StatsCollect
7
+
8
+ module Locations
9
+
10
+ class RB
11
+
12
+ # Execute the plugin.
13
+ # This method has to add the stats and errors to the proxy.
14
+ # It can filter only objects and categories given.
15
+ # It has access to its configuration.
16
+ #
17
+ # Parameters:
18
+ # * *oStatsProxy* (_StatsProxy_): The stats proxy to be used to populate stats
19
+ # * *iConf* (<em>map<Symbol,Object></em>): The configuration associated to this plugin
20
+ # * *iLstObjects* (<em>list<String></em>): List of objects to filter (can be empty for all)
21
+ # * *iLstCategories* (<em>list<String></em>): List of categories to filter (can be empty for all)
22
+ def execute(oStatsProxy, iConf, iLstObjects, iLstCategories)
23
+ if (!iConf[:Files].empty?)
24
+ # Get the list of categories, locations and objects
25
+ lCategories = oStatsProxy.getCategories
26
+ lObjects = oStatsProxy.getObjects
27
+ lLocations = oStatsProxy.getLocations
28
+ iConf[:Files].each do |iFileName|
29
+ lLstStats = nil
30
+ File.open(iFileName, 'r') do |iFile|
31
+ lLstStats = eval(iFile.read)
32
+ end
33
+ lMissingIDs = false
34
+ logInfo "Read #{lLstStats.size} stats from RB file."
35
+ lLstStats.each do |ioStatInfo|
36
+ iCheckExistenceBeforeAdd, iTimeStamp, iLocationName, iObjectName, iCategoryName, iValue = ioStatInfo
37
+ ioStatInfo[1] = DateTime.strptime(iTimeStamp, iConf[:DateTimeFormat])
38
+ if (iConf[:IDsMustExist])
39
+ if (lLocations[iLocationName] == nil)
40
+ logWarn "Unknown location from RB file #{iFileName}: #{iLocationName}"
41
+ lMissingIDs = true
42
+ end
43
+ if (lObjects[iObjectName] == nil)
44
+ logWarn "Unknown object from RB file #{iFileName}: #{iObjectName}"
45
+ lMissingIDs = true
46
+ end
47
+ if (lCategories[iCategoryName] == nil)
48
+ logWarn "Unknown category from RB file #{iFileName}: #{iCategoryName}"
49
+ lMissingIDs = true
50
+ end
51
+ end
52
+ end
53
+ if (!lMissingIDs)
54
+ oStatsProxy.addStatsList(lLstStats)
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+
64
+ end