twistage_stats_reports 1.0.0
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/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
|
+
|