twistage_stats_reports 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/stats/breakdown_report.rb +139 -0
- data/lib/stats/disk_usage_report.rb +71 -0
- data/lib/stats/event_report.rb +351 -0
- data/lib/stats/image_report.rb +5 -0
- data/lib/stats/latin_1_to_utf.rb +10 -0
- data/lib/stats/percent_watched_report.rb +48 -0
- data/lib/stats/publish_report.rb +168 -0
- data/lib/stats/report.rb +122 -0
- data/lib/stats/source_report.rb +106 -0
- data/lib/stats/tzinfo_extensions.rb +13 -0
- data/lib/twistage_stats_reports.rb +12 -0
- metadata +74 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'stats/tzinfo_extensions'
|
2
|
+
|
3
|
+
class Stats::BreakdownReport < Stats::EventReport
|
4
|
+
set_attributes [ :id, :date, :start_date, :end_date, :title, :label, :name, :query_time, :bytes_uploaded, :bytes_encoded, :bytes_uploaded_gb, :bytes_encoded_gb, :container ]
|
5
|
+
set_numeric_attributes [ :assets_uploaded, :assets_encoded, :duration_uploaded, :duration_encoded, :duration_uploaded_min, :duration_encoded_min ]
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@label = options[:label]
|
9
|
+
|
10
|
+
@container = options[:container]
|
11
|
+
|
12
|
+
@assets_uploaded = options[:assets_uploaded] || 0
|
13
|
+
@assets_encoded = options[:assets_encoded] || 0
|
14
|
+
|
15
|
+
@query_time = nil
|
16
|
+
|
17
|
+
@duration_uploaded = options[:duration_uploaded].to_f || 0
|
18
|
+
@duration_uploaded_min = ('%.2f' % (@duration_uploaded / 60.seconds.to_f)).to_f
|
19
|
+
|
20
|
+
@duration_encoded = options[:duration_encoded].to_f || 0
|
21
|
+
@duration_encoded_min = ('%.2f' % (@duration_encoded / 60.seconds.to_f)).to_f
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.csv_keys
|
25
|
+
[ :container, :assets_encoded, :assets_uploaded, :duration_uploaded, :duration_encoded ]
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_csv(options = {})
|
29
|
+
the_csv_keys = strip_keys_by_label(self.class.csv_keys, @label)
|
30
|
+
the_csv_keys.map do |k|
|
31
|
+
self.class.format_csv_value(send(k))
|
32
|
+
end.join(',')
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_xml options = {}
|
36
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
37
|
+
xml.instruct! unless options[:skip_instruct]
|
38
|
+
|
39
|
+
xml.__send__(@label) do
|
40
|
+
xml.container @container
|
41
|
+
xml.assets_encoded @assets_encoded
|
42
|
+
xml.assets_uploaded @assets_uploaded
|
43
|
+
xml.duration_encoded @duration_encoded
|
44
|
+
xml.duration_uploaded @duration_uploaded
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_json(options = {})
|
49
|
+
report = HashWithIndifferentAccess.new
|
50
|
+
report['container'] = @container
|
51
|
+
report['assets_encoded'] = @assets_encoded
|
52
|
+
report['assets_uploaded'] = @assets_uploaded
|
53
|
+
report['duration_encoded'] = @duration_encoded
|
54
|
+
report['duration_uploaded'] = @duration_uploaded
|
55
|
+
|
56
|
+
report.to_json
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.to_amcharts(reports, show_date, show_date_range, options = {})
|
60
|
+
assets_encoded = []
|
61
|
+
assets_uploaded = []
|
62
|
+
complete_labels = []
|
63
|
+
duration_encoded = []
|
64
|
+
duration_uploaded = []
|
65
|
+
guids = []
|
66
|
+
labels = []
|
67
|
+
reports = pad_reports(reports, options) if options["pad"]
|
68
|
+
reports = reports.reverse if options[:reverse]
|
69
|
+
|
70
|
+
reports.each do |report|
|
71
|
+
label = report.container
|
72
|
+
label = '<blank>' if 'null' == label
|
73
|
+
|
74
|
+
complete_labels << label
|
75
|
+
labels << label.previewize((options[:max_label_length] || 15).to_i)
|
76
|
+
assets_uploaded << report.assets_uploaded
|
77
|
+
duration_uploaded << report.duration_uploaded_min
|
78
|
+
assets_encoded << report.assets_encoded
|
79
|
+
duration_encoded << report.duration_encoded_min
|
80
|
+
guids << report.id
|
81
|
+
end
|
82
|
+
|
83
|
+
show_screenshots = reports.length <= 10
|
84
|
+
|
85
|
+
max_labels = 20
|
86
|
+
# frequency == 1 if we can display all labels, or a number greater
|
87
|
+
# than 1 if we can't
|
88
|
+
frequency = (labels.length / max_labels.to_f).ceil
|
89
|
+
|
90
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => 2)
|
91
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
92
|
+
xml.chart do
|
93
|
+
xml.series do
|
94
|
+
labels.each_with_index do |value, index|
|
95
|
+
# only display every nth value where n depends the total
|
96
|
+
# number of labels and the max labels we are allowed to
|
97
|
+
# display, otherwise clear out the value
|
98
|
+
value = "" if index % frequency != 0
|
99
|
+
xml.value value, :xid => index
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
xml.graphs do
|
104
|
+
#the gid is used in the settings file to set different settings just for this graph
|
105
|
+
unless options[:show_uploads] == 'false'
|
106
|
+
xml.graph :gid => 'assets_uploaded' do
|
107
|
+
assets_uploaded.each_with_index do |value, index|
|
108
|
+
xml.value value, :xid => index
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
unless options[:show_duration_uploaded] == 'false'
|
114
|
+
xml.graph :gid => 'duration_uploaded' do
|
115
|
+
duration_uploaded.each_with_index do |value, index|
|
116
|
+
xml.value value, :xid => index
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
unless options[:show_encodes] == 'false'
|
122
|
+
xml.graph :gid => 'assets_encoded' do
|
123
|
+
assets_encoded.each_with_index do |value, index|
|
124
|
+
xml.value value, :xid => index
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
unless options[:show_duration_encoded] == 'false'
|
130
|
+
xml.graph :gid => 'duration_encoded' do
|
131
|
+
duration_encoded.each_with_index do |value, index|
|
132
|
+
xml.value value, :xid => index
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'stats/tzinfo_extensions'
|
2
|
+
|
3
|
+
class Stats::DiskUsageReport < Stats::EventReport
|
4
|
+
set_attributes [ :id, :obj_id, :group, :name, :nickname, :title, :label, :name, :query_time, :start_date, :end_date ]
|
5
|
+
set_numeric_attributes [ :actual_bytes, :actual_average_bytes, :bytes, :average_bytes, :objects, :average_objects ]
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@label = "stats" # video unless date
|
9
|
+
@obj_id = options[:obj_id ] unless options[:obj_id ].blank?
|
10
|
+
@nickname = options[:nickname ] unless options[:nickname ].blank?
|
11
|
+
@name = options[:name ] unless options[:name ].blank?
|
12
|
+
@group = options[:group ] unless options[:group ].blank?
|
13
|
+
@start_date = options[:start_date] unless options[:start_date].blank?
|
14
|
+
@end_date = options[:end_date ] unless options[:end_date ].blank?
|
15
|
+
@actual_bytes = options[:storage_bytes].to_i
|
16
|
+
@actual_average_bytes = options[:average_storage_bytes].to_i
|
17
|
+
if options[:storage_bytes]
|
18
|
+
@bytes = sprintf("%0.3f", options[:storage_bytes] / 1.gigabyte)
|
19
|
+
end
|
20
|
+
if options[:average_storage_bytes]
|
21
|
+
@average_bytes = sprintf("%0.3f", options[:average_storage_bytes] / 1.gigabyte)
|
22
|
+
end
|
23
|
+
@objects = options[:objects].to_i
|
24
|
+
@average_objects = options[:average_objects].to_i
|
25
|
+
@id = @nickname
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.csv_keys
|
29
|
+
keys = @nickname.nil? ? [ :id ] : []
|
30
|
+
keys += [ :start_date, :end_date, :actual_bytes, :actual_average_bytes, :objects, :average_objects ]
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_csv(options = {})
|
34
|
+
the_csv_keys = strip_keys_by_label(self.class.csv_keys, @label)
|
35
|
+
the_csv_keys.map do |k|
|
36
|
+
self.class.format_csv_value(send(k))
|
37
|
+
end.join(',')
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_xml options = {}
|
41
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
42
|
+
xml.instruct! unless options[:skip_instruct]
|
43
|
+
|
44
|
+
xml.__send__(@label) do
|
45
|
+
xml.id @nickname unless @nickname.nil?
|
46
|
+
xml.start_date @start_date.strftime("%Y/%m/%d") unless @start_date.nil?
|
47
|
+
xml.end_date @end_date.strftime("%Y/%m/%d") unless @end_date.nil?
|
48
|
+
xml.bytes @actual_bytes
|
49
|
+
xml.average_bytes @actual_average_bytes if @group =~ /daily|weekly|monthly/
|
50
|
+
xml.objects @objects
|
51
|
+
xml.average_objects @average_objects if @group =~ /daily|weekly|monthly/
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_json(options = {})
|
56
|
+
report = HashWithIndifferentAccess.new
|
57
|
+
report['id'] = @nickname unless @nickname.nil?
|
58
|
+
report['start_date'] = @start_date.strftime("%Y/%m/%d") unless @start_date.nil?
|
59
|
+
report['end_date'] = @end_date.strftime("%Y/%m/%d") unless @end_date.nil?
|
60
|
+
report['bytes'] = @actual_bytes
|
61
|
+
report['average_bytes'] = @actual_average_bytes if @group =~ /daily|weekly|monthly/
|
62
|
+
report['objects'] = @objects
|
63
|
+
report['average_objects'] = @average_objects if @group =~ /daily|weekly|monthly/
|
64
|
+
|
65
|
+
report.to_json
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.to_amcharts(reports, show_date, show_date_range, options = {})
|
69
|
+
UsageSample.to_amcharts(reports, options)
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,351 @@
|
|
1
|
+
require 'stats/tzinfo_extensions'
|
2
|
+
|
3
|
+
class Stats::EventReport < Stats::Report
|
4
|
+
extend ActiveSupport::Inflector
|
5
|
+
extend ActionView::Helpers::TextHelper
|
6
|
+
extend ActionView::Helpers::NumberHelper
|
7
|
+
|
8
|
+
class Pluralizer
|
9
|
+
include Singleton
|
10
|
+
extend ActionView::Helpers::TextHelper
|
11
|
+
end
|
12
|
+
|
13
|
+
SUPPRESSED_LABELS = {
|
14
|
+
:id => %w[domain metropolitan-area],
|
15
|
+
:title => %w[country domain metropolitan-area tag browser device profile],
|
16
|
+
:hits => %w[],
|
17
|
+
:plays => %w[profile],
|
18
|
+
:downloads => %w[domain profile],
|
19
|
+
:bytes_transferred => %w[profile],
|
20
|
+
}
|
21
|
+
|
22
|
+
set_attributes [ :id, :date, :start_date, :end_date, :title, :label, :name, :query_time, :stats_type ]
|
23
|
+
set_numeric_attributes [ :hits, :plays, :downloads, :bytes_transferred]
|
24
|
+
|
25
|
+
def set_date(time, scope = nil)
|
26
|
+
t = Time.parse time.to_s
|
27
|
+
case scope
|
28
|
+
when nil
|
29
|
+
@date = t
|
30
|
+
when :daily
|
31
|
+
@date = t.beginning_of_day
|
32
|
+
when :monthly
|
33
|
+
@start_date = t.beginning_of_month
|
34
|
+
@end_date = t.end_of_month
|
35
|
+
when :weekly
|
36
|
+
@start_date = t.beginning_of_week
|
37
|
+
@end_date = @start_date.next_week.yesterday
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_start_date(scope)
|
42
|
+
case scope
|
43
|
+
when nil, :daily
|
44
|
+
@date
|
45
|
+
when :monthly, :weekly
|
46
|
+
@start_date
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_xml options = {}
|
51
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
52
|
+
xml.instruct! unless options[:skip_instruct]
|
53
|
+
|
54
|
+
xml.__send__(@label) do
|
55
|
+
xml.id @id if @id and not SUPPRESSED_LABELS[:id].include?(@label)
|
56
|
+
xml.name @name if @name
|
57
|
+
xml.title @title unless SUPPRESSED_LABELS[:title].include?(@label)
|
58
|
+
xml.hits @hits
|
59
|
+
if @stats_type != 'image'
|
60
|
+
[ :plays, :downloads ].each do |key|
|
61
|
+
xml.tag!(key, self[key]) unless SUPPRESSED_LABELS[key].include?(@label)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
xml.date(pretty_time(@date)) if @date
|
65
|
+
xml.start_date(pretty_time(@start_date)) if @start_date
|
66
|
+
xml.end_date(pretty_time(@end_date)) if @end_date
|
67
|
+
unless SUPPRESSED_LABELS[:bytes_transferred].include?(@label)
|
68
|
+
xml.bytes_transferred @bytes_transferred.to_i
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_csv(options = {})
|
74
|
+
klass_keys = options[:images] ? Stats::ImageReport.csv_keys : self.class.csv_keys
|
75
|
+
the_csv_keys = strip_keys_by_label(klass_keys, @label)
|
76
|
+
|
77
|
+
the_csv_keys.map do |k|
|
78
|
+
self.class.format_csv_value(send(k))
|
79
|
+
end.join(',')
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_json(options = {})
|
83
|
+
report = HashWithIndifferentAccess.new
|
84
|
+
report['id'] = @id if @id and not SUPPRESSED_LABELS[:id].include?(@label)
|
85
|
+
report['name'] = @name if @name
|
86
|
+
report['title'] = @title unless SUPPRESSED_LABELS[:title].include?(@label)
|
87
|
+
|
88
|
+
report['hits'] = @hits
|
89
|
+
if @stats_type != 'image'
|
90
|
+
[ :plays, :downloads ].each do |key|
|
91
|
+
report[key.to_s] = self[key.to_s] unless SUPPRESSED_LABELS[key].include?(@label)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
report['date'] = pretty_time(@date) if @date
|
96
|
+
report['start_date'] = pretty_time(@start_date) if @start_date
|
97
|
+
report['end_date'] = pretty_time(@end_date) if @end_date
|
98
|
+
|
99
|
+
unless SUPPRESSED_LABELS[:bytes_transferred].include?(@label)
|
100
|
+
report['bytes_transferred'] = @bytes_transferred.to_i
|
101
|
+
end
|
102
|
+
|
103
|
+
report.to_json
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.get_url(r)
|
107
|
+
if 'image' == r.stats_type
|
108
|
+
prepend = 'image_'
|
109
|
+
type = 'albums'
|
110
|
+
elsif 'track' == r.stats_type
|
111
|
+
prepend = ''
|
112
|
+
type = 'tracks'
|
113
|
+
else
|
114
|
+
prepend = ''
|
115
|
+
type = 'videos'
|
116
|
+
end
|
117
|
+
|
118
|
+
url = if r.id.nil?
|
119
|
+
nil
|
120
|
+
else
|
121
|
+
case r.label
|
122
|
+
when "company" then "/companies/#{r.id}/#{prepend}statistics"
|
123
|
+
when "video" then "/videos/#{r.id}/statistics"
|
124
|
+
when "track" then "/tracks/#{r.id}/statistics"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
url ||= (r.title.blank? ? nil : "/#{type}/#{r.id}/statistics")
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.csv_keys
|
132
|
+
[ :id, :name, :title, :hits, :plays, :downloads, :bytes_transferred, :date, :start_date, :end_date ]
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.to_amcharts(reports, show_date, show_date_range, options = {})
|
136
|
+
options["fields"] ||= [ :hits, :plays, :downloads ].reject { |field| SUPPRESSED_LABELS[field].include?(options["group"]) }.map(&:to_s)
|
137
|
+
complete_labels = []
|
138
|
+
labels = []
|
139
|
+
hits = []
|
140
|
+
plays = []
|
141
|
+
downloads = []
|
142
|
+
urls = []
|
143
|
+
guids = []
|
144
|
+
reports = pad_reports(reports, options) if options["pad"]
|
145
|
+
reports = reports.reverse if options[:reverse]
|
146
|
+
|
147
|
+
reports.each do |r|
|
148
|
+
if show_date and !r.date.blank?
|
149
|
+
label = "#{r.date.month}/#{r.date.day}"
|
150
|
+
elsif show_date_range and !r.start_date.blank? and !r.end_date.blank?
|
151
|
+
label = if r.start_date.month == r.end_date.month && r.start_date.day == r.start_date.beginning_of_month.day && r.end_date.day == r.end_date.end_of_month.day
|
152
|
+
"#{r.start_date.strftime("%b \'%y")}"
|
153
|
+
else
|
154
|
+
"#{r.start_date.month}/#{r.start_date.day}-#{r.end_date.month}/#{r.end_date.day}"
|
155
|
+
end
|
156
|
+
elsif !r.title.blank?
|
157
|
+
label = r.title
|
158
|
+
elsif !r.name.blank?
|
159
|
+
label = r.name
|
160
|
+
else
|
161
|
+
label = r.id.to_s
|
162
|
+
end
|
163
|
+
|
164
|
+
complete_labels << label
|
165
|
+
labels << label.previewize((options[:max_label_length] || 15).to_i)
|
166
|
+
hits << r.hits
|
167
|
+
if r.stats_type != 'image'
|
168
|
+
plays << r.plays
|
169
|
+
downloads << r.downloads
|
170
|
+
end
|
171
|
+
|
172
|
+
guids << r.id
|
173
|
+
if !options.has_key?(:video_id) && !options.has_key?(:track_id)
|
174
|
+
urls << get_url(r)
|
175
|
+
else
|
176
|
+
urls << nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
show_screenshots = false # && reports.length <= 10
|
181
|
+
|
182
|
+
max_labels = 40
|
183
|
+
# frequency == 1 if we can display all labels, or a number greater
|
184
|
+
# than 1 if we can't
|
185
|
+
if show_date || show_date_range
|
186
|
+
frequency = 1
|
187
|
+
else
|
188
|
+
frequency = (labels.length / max_labels.to_f).ceil
|
189
|
+
end
|
190
|
+
|
191
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => 2)
|
192
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
193
|
+
xml.chart do
|
194
|
+
xml.series do
|
195
|
+
labels.each_with_index do |value, index|
|
196
|
+
# only display every nth value where n depends the total
|
197
|
+
# number of labels and the max labels we are allowed to
|
198
|
+
# display, otherwise clear out the value
|
199
|
+
value = "" if index % frequency != 0
|
200
|
+
xml.value value, :xid => index
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
xml.graphs do
|
205
|
+
#the gid is used in the settings file to set different settings just for this graph
|
206
|
+
level = "Hits"
|
207
|
+
if options[:fields].include?("hits")
|
208
|
+
xml.graph :gid => 'hits' do
|
209
|
+
hits.each_with_index do |value, index|
|
210
|
+
if value != 0 || complete_labels[index].blank? || show_date || show_date_range
|
211
|
+
opts = { :xid => index, :description => complete_labels[index] }
|
212
|
+
opts[:url] = urls[index] unless urls[index].blank?
|
213
|
+
xml.value value, opts
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
if options[:fields].include?("plays")
|
220
|
+
xml.graph :gid => 'plays' do
|
221
|
+
plays.each_with_index do |value, index|
|
222
|
+
if value != 0 || complete_labels[index].blank? || show_date || show_date_range
|
223
|
+
opts = { :xid => index, :description => complete_labels[index] }
|
224
|
+
opts[:url] = urls[index] unless urls[index].blank?
|
225
|
+
opts[:bullet] = "../videos/#{guids[index]}/screenshots/32w.jpg" if !guids[index].blank? && show_screenshots
|
226
|
+
xml.value value, opts
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
if options[:fields].include?("downloads")
|
233
|
+
xml.graph :gid => 'downloads' do
|
234
|
+
downloads.each_with_index do |value, index|
|
235
|
+
if value != 0 || complete_labels[index].blank? || show_date || show_date_range
|
236
|
+
opts = { :xid => index, :description => complete_labels[index] }
|
237
|
+
opts[:url] = urls[index] unless urls[index].blank?
|
238
|
+
xml.value value, opts
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
AMMAP_COUNTRIES = [ "AF", "AX", "AL", "DZ", "AD", "AO", "AI", "AG",
|
248
|
+
"AR", "AM", "AW", "AU", "AT", "AZ", "BS", "BH", "BD", "BB", "BY",
|
249
|
+
"BE", "BZ", "BJ", "BM", "BT", "BO", "BA", "BW", "BR", "BN", "BG",
|
250
|
+
"BF", "BI", "KH", "CM", "CA", "CV", "CF", "TD", "CL", "CN", "CO",
|
251
|
+
"KM", "CG", "CD", "CR", "CI", "HR", "CU", "CY", "CZ", "DK", "DJ",
|
252
|
+
"DM", "DO", "EC", "EG", "SV", "GQ", "ER", "EE", "ET", "FO", "FK",
|
253
|
+
"FJ", "FI", "FR", "GF", "GA", "GM", "GE", "DE", "GH", "GR", "GL",
|
254
|
+
"GD", "GP", "GT", "GN", "GW", "GY", "HT", "HN", "HK", "HU", "IS",
|
255
|
+
"IN", "ID", "IR", "IQ", "IE", "IL", "IT", "JM", "JP", "JO", "KZ",
|
256
|
+
"KE", "KP", "KR", "KW", "KG", "LA", "LV", "LB", "LS", "LR", "LY",
|
257
|
+
"LI", "LT", "LU", "MK", "MG", "MW", "MY", "ML", "MT", "MQ", "MR",
|
258
|
+
"MU", "MX", "MD", "MN", "ME", "MS", "MA", "MZ", "MM", "NA", "NP",
|
259
|
+
"NL", "NC", "NZ", "NI", "NE", "NG", "NO", "OM", "PK", "PW", "PS",
|
260
|
+
"PA", "PG", "PY", "PE", "PH", "PL", "PT", "PR", "QA", "RE", "RO",
|
261
|
+
"RU", "RW", "KN", "LC", "WS", "ST", "SA", "SN", "RS", "SL", "SG",
|
262
|
+
"SK", "SI", "SB", "SO", "ZA", "GS", "ES", "LK", "SD", "SR", "SJ",
|
263
|
+
"SZ", "SE", "CH", "SY", "TW", "TJ", "TZ", "TH", "TL", "TG", "TO",
|
264
|
+
"TT", "TN", "TR", "TM", "TC", "UG", "UA", "AE", "GB", "US", "UY",
|
265
|
+
"UZ", "VU", "VE", "VN", "VG", "EH", "YE", "ZM", "ZW", ]
|
266
|
+
|
267
|
+
def self.to_ammap_country_data(reports, metric)
|
268
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
269
|
+
zoom, zoom_x, zoom_y = zoom_levels
|
270
|
+
xml.map :map_file => 'maps/world.swf', :zoom_x => zoom_x, :zoom_y => zoom_y, :zoom => zoom do
|
271
|
+
xml.areas do
|
272
|
+
AMMAP_COUNTRIES.each do |country_code|
|
273
|
+
report = reports.find { |report| report.id == country_code }
|
274
|
+
value = report && report.send(metric) || 0
|
275
|
+
title_value = make_title_value(metric, value)
|
276
|
+
|
277
|
+
attributes = {
|
278
|
+
:title => "#{TZInfo::Country.code_to_name(country_code)}: #{title_value}",
|
279
|
+
:mc_name => country_code,
|
280
|
+
:value => value == 0 ? 0 : sprintf('%.8f', Math.log(value + 1))
|
281
|
+
}
|
282
|
+
xml.area attributes
|
283
|
+
end
|
284
|
+
xml.area :mc_name => "borders", :color => "#AAAAAA"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
xml.target!
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.zoom_levels
|
291
|
+
return "115%", "-0%", "-20%"
|
292
|
+
end
|
293
|
+
|
294
|
+
def self.to_ammap_metro_data(reports, metric)
|
295
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
296
|
+
zoom, zoom_x, zoom_y = zoom_levels
|
297
|
+
color = "Graphs::#{metric.to_s.capitalize}".constantize.new.color1 rescue '85E006'
|
298
|
+
xml.map :map_file => 'maps/world.swf', :tl_long => "-168.49", :tl_lat => "83.63", :br_long => "190.3", :br_lat => "-55.58", :zoom_x => zoom_x, :zoom_y => zoom_y, :zoom => zoom do
|
299
|
+
xml.movies do
|
300
|
+
reports.select { |report| not report.id.blank? }.each do |report|
|
301
|
+
latitude, longitude = report.id.split(';')
|
302
|
+
bubble_size = calculate_bubble_size(report.send(metric))
|
303
|
+
title_value = make_title_value metric, report.send(metric)
|
304
|
+
xml.movie(:title => "#{report.name}: #{title_value}",
|
305
|
+
:lat => latitude,
|
306
|
+
:long => longitude,
|
307
|
+
:file => 'target',
|
308
|
+
:width => bubble_size,
|
309
|
+
:height => bubble_size,
|
310
|
+
:color => color,
|
311
|
+
:alpha => 65,
|
312
|
+
:fixed_size => true)
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
xml.areas do
|
317
|
+
AMMAP_COUNTRIES.each do |country_code|
|
318
|
+
xml.area :mc_name => country_code, :value => 0
|
319
|
+
end
|
320
|
+
xml.area :mc_name => "borders", :color => "#AAAAAA"
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
xml.target!
|
325
|
+
end
|
326
|
+
|
327
|
+
MinimumMapBubbleSize = 7
|
328
|
+
|
329
|
+
def self.calculate_bubble_size value
|
330
|
+
return 0 if value == 0
|
331
|
+
(MinimumMapBubbleSize + 5.0 * Math.log10(value)).to_i
|
332
|
+
end
|
333
|
+
|
334
|
+
def self.make_title_value metric, value
|
335
|
+
if [:bytes_transferred].include? metric
|
336
|
+
title_value = number_with_delimiter(number_to_human_size(value)) + ' transferred'
|
337
|
+
else
|
338
|
+
title_value = Pluralizer.pluralize(number_with_delimiter(value), singularize(metric))
|
339
|
+
end
|
340
|
+
title_value
|
341
|
+
end
|
342
|
+
|
343
|
+
private
|
344
|
+
|
345
|
+
def strip_keys_by_label(the_keys, label)
|
346
|
+
SUPPRESSED_LABELS.each do |key, labels|
|
347
|
+
the_keys = (the_keys - [ key ]) if labels.include?(label)
|
348
|
+
end
|
349
|
+
the_keys
|
350
|
+
end
|
351
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class Stats::PercentWatchedReport < Stats::Report
|
2
|
+
set_attributes [ :label, :start_date, :end_date, :query_time ]
|
3
|
+
set_numeric_attributes [ :percent_watched, :percent_of_watches, :fall_off, :watch_count ]
|
4
|
+
|
5
|
+
def to_xml options = {}
|
6
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
7
|
+
xml.instruct! unless options[:skip_instruct]
|
8
|
+
|
9
|
+
xml.__send__(@label) do
|
10
|
+
xml.percent_watched @percent_watched
|
11
|
+
xml.percent_of_watches @percent_of_watches
|
12
|
+
xml.fall_off @fall_off
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_json(options = {})
|
17
|
+
report = HashWithIndifferentAccess.new
|
18
|
+
report['percent_watched'] = percent_watched
|
19
|
+
report['percent_of_watches'] = percent_of_watches
|
20
|
+
report['fall_off'] = fall_off
|
21
|
+
report.to_json
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.csv_keys
|
25
|
+
[ :percent_watched, :percent_of_watches, :fall_off ]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.to_amcharts(reports, show_date, show_date_range, options = {})
|
29
|
+
xml = Builder::XmlMarkup.new
|
30
|
+
xml.instruct! :xml, :version => "1.0", :encoding => "UTF-8"
|
31
|
+
xml.chart do
|
32
|
+
xml.series do
|
33
|
+
reports.each_with_index do |report, index|
|
34
|
+
xml.value "#{report.percent_watched.to_i}%", :xid => report.percent_watched
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
xml.graphs do
|
39
|
+
xml.graph :gid => 'percent_watched' do
|
40
|
+
reports.each_with_index do |report, index|
|
41
|
+
xml.value sprintf('%.1f', report.percent_of_watches), :xid => report.percent_watched
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'stats/tzinfo_extensions'
|
2
|
+
|
3
|
+
class Stats::PublishReport < Stats::EventReport
|
4
|
+
set_attributes [ :id, :date, :start_date, :end_date, :title, :label, :name, :query_time, :bytes_uploaded, :bytes_encoded, :bytes_uploaded_gb, :bytes_encoded_gb ]
|
5
|
+
set_numeric_attributes [ :assets_uploaded, :assets_encoded, :duration_uploaded, :duration_encoded, :duration_uploaded_min, :duration_encoded_min ]
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@start_date = options[:date]
|
9
|
+
|
10
|
+
if 'day' == options[:group]
|
11
|
+
@date = options[:date]
|
12
|
+
else
|
13
|
+
@end_date = options[:date].advance(options[:advance_by] => 1).advance(:days => -1)
|
14
|
+
end
|
15
|
+
|
16
|
+
@label = options[:label]
|
17
|
+
|
18
|
+
@assets_uploaded = options[:assets_uploaded]
|
19
|
+
@assets_encoded = options[:assets_encoded]
|
20
|
+
|
21
|
+
@query_time = nil
|
22
|
+
|
23
|
+
@bytes_uploaded = options[:bytes_uploaded]
|
24
|
+
@bytes_uploaded_gb = ('%.2f' % (options[:bytes_uploaded] / 1.gigabyte.to_f)).to_f
|
25
|
+
|
26
|
+
@bytes_encoded = options[:bytes_encoded]
|
27
|
+
@bytes_encoded_gb = ('%.2f' % (options[:bytes_encoded] / 1.gigabyte.to_f)).to_f
|
28
|
+
|
29
|
+
@duration_uploaded = options[:duration_uploaded]
|
30
|
+
@duration_uploaded_min = ('%.2f' % (options[:duration_uploaded] / 60.seconds.to_f)).to_f
|
31
|
+
|
32
|
+
@duration_encoded = options[:duration_encoded]
|
33
|
+
@duration_encoded_min = ('%.2f' % (options[:duration_encoded] / 60.seconds.to_f)).to_f
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.csv_keys
|
37
|
+
[ :assets_encoded, :assets_uploaded, :bytes_encoded, :bytes_uploaded, :duration_uploaded, :duration_encoded, :date, :start_date, :end_date ]
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_xml options = {}
|
41
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
42
|
+
xml.instruct! unless options[:skip_instruct]
|
43
|
+
|
44
|
+
xml.__send__(@label) do
|
45
|
+
xml.assets_encoded @assets_encoded
|
46
|
+
xml.assets_uploaded @assets_uploaded
|
47
|
+
xml.bytes_encoded @bytes_encoded
|
48
|
+
xml.bytes_uploaded @bytes_uploaded
|
49
|
+
xml.date(pretty_time(@date)) if @date
|
50
|
+
xml.duration_encoded @duration_encoded
|
51
|
+
xml.duration_uploaded @duration_uploaded
|
52
|
+
xml.end_date(pretty_time(@end_date)) if @end_date
|
53
|
+
xml.start_date(pretty_time(@start_date)) if @start_date
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_json(options = {})
|
58
|
+
report = HashWithIndifferentAccess.new
|
59
|
+
report['assets_encoded'] = @assets_encoded
|
60
|
+
report['assets_uploaded'] = @assets_uploaded
|
61
|
+
report['bytes_encoded'] = @bytes_encoded
|
62
|
+
report['bytes_uploaded'] = @bytes_uploaded
|
63
|
+
report['date'] = pretty_time(@date) if @date
|
64
|
+
report['duration_encoded'] = @duration_encoded
|
65
|
+
report['duration_uploaded'] = @duration_uploaded
|
66
|
+
report['end_date'] = pretty_time(@end_date) if @end_date
|
67
|
+
report['start_date'] = pretty_time(@start_date) if @start_date
|
68
|
+
|
69
|
+
report.to_json
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.to_amcharts(reports, show_date, show_date_range, options = {})
|
73
|
+
assets_encoded = []
|
74
|
+
assets_uploaded = []
|
75
|
+
bytes_encoded = []
|
76
|
+
bytes_uploaded = []
|
77
|
+
complete_labels = []
|
78
|
+
duration_encoded = []
|
79
|
+
duration_uploaded = []
|
80
|
+
guids = []
|
81
|
+
labels = []
|
82
|
+
urls = []
|
83
|
+
reports = reports.reverse if options[:reverse]
|
84
|
+
|
85
|
+
reports.each do |report|
|
86
|
+
label = case options[:group]
|
87
|
+
when 'daily' ; "#{report.date.month}/#{report.date.day}"
|
88
|
+
when 'weekly' ; "#{report.start_date.month}/#{report.start_date.day}-#{report.end_date.month}/#{report.end_date.day}"
|
89
|
+
when 'monthly' ; "#{report.start_date.strftime("%b \'%y")}"
|
90
|
+
else raise "invalid group: #{options[:group]}"
|
91
|
+
end
|
92
|
+
|
93
|
+
complete_labels << label
|
94
|
+
labels << label.previewize((options[:max_label_length] || 15).to_i)
|
95
|
+
assets_uploaded << report.assets_uploaded
|
96
|
+
duration_uploaded << report.duration_uploaded_min
|
97
|
+
bytes_uploaded << report.bytes_uploaded_gb
|
98
|
+
assets_encoded << report.assets_encoded
|
99
|
+
duration_encoded << report.duration_encoded_min
|
100
|
+
bytes_encoded << report.bytes_encoded_gb
|
101
|
+
guids << report.id
|
102
|
+
end
|
103
|
+
|
104
|
+
show_screenshots = reports.length <= 10
|
105
|
+
|
106
|
+
max_labels = 40
|
107
|
+
# frequency == 1 if we can display all labels, or a number greater
|
108
|
+
# than 1 if we can't
|
109
|
+
frequency = (show_date || show_date_range) ? 1 : (labels.length / max_labels.to_f).ceil
|
110
|
+
|
111
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => 2)
|
112
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
113
|
+
xml.chart do
|
114
|
+
xml.series do
|
115
|
+
labels.each_with_index do |value, index|
|
116
|
+
# only display every nth value where n depends the total
|
117
|
+
# number of labels and the max labels we are allowed to
|
118
|
+
# display, otherwise clear out the value
|
119
|
+
value = "" if index % frequency != 0
|
120
|
+
xml.value value, :xid => index
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
xml.graphs do
|
125
|
+
#the gid is used in the settings file to set different settings just for this graph
|
126
|
+
unless options[:show_uploads] == 'false'
|
127
|
+
xml.graph :gid => 'assets_uploaded' do
|
128
|
+
assets_uploaded.each_with_index do |value, index|
|
129
|
+
if value != 0 || show_date || show_date_range
|
130
|
+
xml.value value, :xid => index
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
unless options[:show_duration_uploaded] == 'false'
|
137
|
+
xml.graph :gid => 'duration_uploaded' do
|
138
|
+
duration_uploaded.each_with_index do |value, index|
|
139
|
+
if value != 0 || show_date || show_date_range
|
140
|
+
xml.value value, :xid => index
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
unless options[:show_encodes] == 'false'
|
147
|
+
xml.graph :gid => 'assets_encoded' do
|
148
|
+
assets_encoded.each_with_index do |value, index|
|
149
|
+
if value != 0 || show_date || show_date_range
|
150
|
+
xml.value value, :xid => index
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
unless options[:show_duration_encoded] == 'false'
|
157
|
+
xml.graph :gid => 'duration_encoded' do
|
158
|
+
duration_encoded.each_with_index do |value, index|
|
159
|
+
if value != 0 || show_date || show_date_range
|
160
|
+
xml.value value, :xid => index
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
data/lib/stats/report.rb
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
class Stats::Report
|
2
|
+
def initialize options = {}
|
3
|
+
options.assert_valid_keys self.class.attributes
|
4
|
+
|
5
|
+
self.class.attributes.each { |a| instance_variable_set "@#{a}", nil }
|
6
|
+
options.each { |k, v| instance_variable_set "@#{k}", v }
|
7
|
+
self.class.numeric_attributes.each do |a|
|
8
|
+
attribute_name = "@#{a}"
|
9
|
+
instance_variable_set(attribute_name, 0) if instance_variable_get(attribute_name).blank?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def == other
|
14
|
+
self.class.attributes.all? do |e|
|
15
|
+
attribute_name = "@#{e}"
|
16
|
+
instance_variable_get(attribute_name) == other.instance_variable_get(attribute_name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def [] method_name
|
21
|
+
send method_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.array_to_xml(report_array, options = {})
|
25
|
+
report_array.to_xml options.merge({:root => 'statistics-reports'})
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.array_to_csv(report_array, options = {})
|
29
|
+
buf = ""
|
30
|
+
|
31
|
+
unless report_array.first.nil?
|
32
|
+
label = report_array.first.label
|
33
|
+
new_options = options.merge( { :label => label } )
|
34
|
+
the_csv_labels = options[:images] ? Stats::ImageReport.csv_labels : report_array[0].class.csv_labels
|
35
|
+
Stats::EventReport::SUPPRESSED_LABELS.each do |key, labels|
|
36
|
+
the_csv_labels = strip_label(key, the_csv_labels) if labels.include?(label)
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
buf << the_csv_labels + "\n" unless report_array.empty?
|
41
|
+
|
42
|
+
report_array.each do |report|
|
43
|
+
buf << report.to_csv(new_options) + "\n"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
buf
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.strip_label(label_sym, labels_as_str)
|
51
|
+
labels = labels_as_str.split(/,/)
|
52
|
+
(labels - [ label_sym.to_s ]).join(',')
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.csv_keys
|
56
|
+
[]
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_csv(options = {})
|
60
|
+
klass_keys = options[:images] ? Stats::ImageReport.csv_keys : self.class.csv_keys
|
61
|
+
klass_keys.map { |k| self.class.format_csv_value(send(k)) }.join(',')
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.csv_labels
|
65
|
+
csv_keys.map { |k| format_csv_value(k.to_s) }.join(',')
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.format_csv_value(value)
|
69
|
+
return "\"#{value}\"" if value =~ /,/
|
70
|
+
value
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.to_amcharts reports, *options
|
74
|
+
return reports.first.class.to_amcharts(reports, *options) unless reports.empty?
|
75
|
+
xml = Builder::XmlMarkup.new(:indent => 2)
|
76
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
77
|
+
xml.chart
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.pad_reports(reports, options)
|
81
|
+
limit = options["limit"].to_i
|
82
|
+
return reports if limit < 1 || reports.length < 1
|
83
|
+
|
84
|
+
# make a copy of the first report
|
85
|
+
clone = reports[0].clone
|
86
|
+
# blank out all text fields
|
87
|
+
clone.class.send(:attributes).each { |key| clone.send("#{key}=", "") }
|
88
|
+
# zero out all numeric fields
|
89
|
+
clone.class.send(:numeric_attributes).each { |key| clone.send("#{key}=", 0) }
|
90
|
+
# add empty reports at the end
|
91
|
+
(limit - reports.length).times { reports << clone }
|
92
|
+
reports
|
93
|
+
end
|
94
|
+
|
95
|
+
# class instance variables (@attributes and @numeric_attributes) are used to make
|
96
|
+
# validation, initialization, assignment, comparison, and accessor generation generic
|
97
|
+
def self.set_attributes attrs
|
98
|
+
attr_accessor *attrs
|
99
|
+
@attributes ||= []
|
100
|
+
@attributes.concat attrs
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.set_numeric_attributes attrs
|
104
|
+
@numeric_attributes ||= []
|
105
|
+
@numeric_attributes.concat attrs
|
106
|
+
set_attributes attrs
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def self.numeric_attributes
|
112
|
+
@numeric_attributes
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.attributes
|
116
|
+
@attributes
|
117
|
+
end
|
118
|
+
|
119
|
+
def pretty_time(t)
|
120
|
+
t.strftime "%Y/%m/%d"
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'stats/tzinfo_extensions'
|
2
|
+
|
3
|
+
class Stats::SourceReport < Stats::EventReport
|
4
|
+
set_attributes [ :id, :date, :start_date, :end_date, :title, :label, :name, :query_time, :bytes_uploaded, :bytes_encoded, :bytes_uploaded_gb, :bytes_encoded_gb, :publish_type ]
|
5
|
+
set_numeric_attributes [ :publishes, :duration, :duration_min, :webcam_duration_min ]
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@label = options[:label]
|
9
|
+
@publish_type = options[:publish_type]
|
10
|
+
@publishes = options[:publishes] || 0
|
11
|
+
@query_time = nil
|
12
|
+
@duration = options[:duration].to_f || 0
|
13
|
+
@duration_min = ('%.2f' % (@duration / 60.seconds.to_f)).to_f
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.csv_keys
|
17
|
+
[ :publish_type, :publishes, :duration ]
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_csv(options = {})
|
21
|
+
the_csv_keys = strip_keys_by_label(self.class.csv_keys, @label)
|
22
|
+
the_csv_keys.map do |k|
|
23
|
+
self.class.format_csv_value(send(k))
|
24
|
+
end.join(',')
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_xml options = {}
|
28
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
29
|
+
xml.instruct! unless options[:skip_instruct]
|
30
|
+
|
31
|
+
xml.__send__(@label) do
|
32
|
+
xml.publish_type @publish_type
|
33
|
+
xml.publishes @publishes
|
34
|
+
xml.duration @duration
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_json(options = {})
|
39
|
+
report = HashWithIndifferentAccess.new
|
40
|
+
report['publish_type'] = @publish_type
|
41
|
+
report['publishes'] = @publishes
|
42
|
+
report['duration'] = @duration
|
43
|
+
|
44
|
+
report.to_json
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.to_amcharts(reports, show_date, show_date_range, options = {})
|
48
|
+
complete_labels = []
|
49
|
+
durations = []
|
50
|
+
guids = []
|
51
|
+
labels = []
|
52
|
+
publishes = []
|
53
|
+
reports = pad_reports(reports, options) if options["pad"]
|
54
|
+
reports = reports.reverse if options[:reverse]
|
55
|
+
|
56
|
+
reports.each do |report|
|
57
|
+
label = report.publish_type
|
58
|
+
label = '<blank>' if 'blank' == label
|
59
|
+
|
60
|
+
complete_labels << label
|
61
|
+
labels << label.previewize((options[:max_label_length] || 15).to_i)
|
62
|
+
durations << report.duration_min
|
63
|
+
publishes << report.publishes
|
64
|
+
guids << report.id
|
65
|
+
end
|
66
|
+
|
67
|
+
show_screenshots = reports.length <= 10
|
68
|
+
|
69
|
+
max_labels = 20
|
70
|
+
# frequency == 1 if we can display all labels, or a number greater than 1 if we can't
|
71
|
+
frequency = (labels.length / max_labels.to_f).ceil
|
72
|
+
|
73
|
+
xml = options[:builder] ||= Builder::XmlMarkup.new(:indent => 2)
|
74
|
+
xml.instruct! :xml, :version=>"1.0", :encoding=>"UTF-8"
|
75
|
+
xml.chart do
|
76
|
+
xml.series do
|
77
|
+
labels.each_with_index do |value, index|
|
78
|
+
# only display every nth value where n depends the total
|
79
|
+
# number of labels and the max labels we are allowed to
|
80
|
+
# display, otherwise clear out the value
|
81
|
+
value = "" if index % frequency != 0
|
82
|
+
xml.value value, :xid => index
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
xml.graphs do
|
87
|
+
#the gid is used in the settings file to set different settings just for this graph
|
88
|
+
unless options[:show_uploads] == 'false'
|
89
|
+
xml.graph :gid => 'uploads' do
|
90
|
+
publishes.each_with_index do |value, index|
|
91
|
+
xml.value value, :xid => index
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
unless options[:show_duration_uploaded] == 'false'
|
97
|
+
xml.graph :gid => 'duration_uploaded' do
|
98
|
+
durations.each_with_index do |value, index|
|
99
|
+
xml.value value, :xid => index
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Stats; end
|
2
|
+
|
3
|
+
require 'stats/report'
|
4
|
+
require 'stats/event_report'
|
5
|
+
require 'stats/breakdown_report'
|
6
|
+
require 'stats/disk_usage_report'
|
7
|
+
require 'stats/image_report'
|
8
|
+
require 'stats/latin_1_to_utf'
|
9
|
+
require 'stats/percent_watched_report'
|
10
|
+
require 'stats/publish_report'
|
11
|
+
require 'stats/source_report'
|
12
|
+
require 'stats/tzinfo_extensions'
|
metadata
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: twistage_stats_reports
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- David Wegman
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-11-05 00:00:00 -08:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Shared data structures and logic for interacting with the Twistage Stats service
|
22
|
+
email: dwegman@twistage.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/twistage_stats_reports.rb
|
31
|
+
- lib/stats/breakdown_report.rb
|
32
|
+
- lib/stats/disk_usage_report.rb
|
33
|
+
- lib/stats/event_report.rb
|
34
|
+
- lib/stats/image_report.rb
|
35
|
+
- lib/stats/latin_1_to_utf.rb
|
36
|
+
- lib/stats/percent_watched_report.rb
|
37
|
+
- lib/stats/publish_report.rb
|
38
|
+
- lib/stats/report.rb
|
39
|
+
- lib/stats/source_report.rb
|
40
|
+
- lib/stats/tzinfo_extensions.rb
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://rubygems.org/gems/twistage_stats_reports
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options: []
|
47
|
+
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
segments:
|
64
|
+
- 0
|
65
|
+
version: "0"
|
66
|
+
requirements: []
|
67
|
+
|
68
|
+
rubyforge_project:
|
69
|
+
rubygems_version: 1.3.7
|
70
|
+
signing_key:
|
71
|
+
specification_version: 3
|
72
|
+
summary: Twistage Stats Reports
|
73
|
+
test_files: []
|
74
|
+
|