sports_db 0.0.2 → 0.0.3

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.
@@ -0,0 +1,11 @@
1
+ require 'digest/md5'
2
+
3
+ class ScoreNotification < ActiveRecord::Base
4
+ belongs_to :game
5
+
6
+ def set_digest
7
+ str = self["message"] + TimeService.now.to_s
8
+ self["digest"] = Digest::SHA1.hexdigest(str)
9
+ end
10
+
11
+ end
@@ -0,0 +1,47 @@
1
+ module SportsDb
2
+ class NewsBuilder
3
+
4
+ def self.update_player_news
5
+ p "Updating SN Player news ..."
6
+ config = SimpleConfig.for(:feeds)
7
+ require 'open-uri'
8
+
9
+ articles = []
10
+
11
+ unless !config.player_news_url.blank?
12
+ p "No sporting news player new URL given."
13
+ return
14
+ end
15
+
16
+ open( config.player_news_url ) do |file|
17
+ doc = Nokogiri::XML(file.read)
18
+
19
+ doc.xpath('//row').each do |player_element|
20
+ player = Player.find_by_sporting_news_id( player_element['PLAYER_ID'].to_i )
21
+ if player
22
+ content = "#{player_element['COMMENT']}. #{player_element['IMPACT']}."
23
+ content.gsub!("..",".")
24
+
25
+ article = Article.new
26
+ article.title = "News for #{player.first_name} #{player.last_name}"
27
+ article.category = "Player News"
28
+ article.player = player
29
+ article.contents = content
30
+ articles << article
31
+
32
+ p "#{player.first_name} #{player.last_name}"
33
+ end
34
+ end
35
+ end
36
+
37
+ Article.transaction do
38
+ Article.delete_all("player_id is not null")
39
+ articles.each {|article| article.save }
40
+ end
41
+
42
+ rescue Exception => e
43
+ Zumobi::ExceptionHandler.error e
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,530 @@
1
+ module SportsDb
2
+ class SportingNewsFeedBuilder
3
+
4
+ def self.update_news_feed
5
+ config_feeds = SimpleConfig.for(:feeds)
6
+
7
+ Article.transaction do
8
+ # #delete existing articles older than 30 days
9
+ # remove_date = TimeService.now - 30.day
10
+ # sn_articles_old = Article.find(:all, :conditions => ["source = 'Sporting News' and published_at > ?", remove_date])
11
+ # sn_articles_old.each {|article| article.destroy }
12
+
13
+ update_webgen_feeds(config_feeds.news_feeds, "news")
14
+ update_webgen_feeds(config_feeds.breaking_news_feeds, "breaking")
15
+
16
+
17
+ if CONFIG.affiliation_key == 'l.nfl.com'
18
+ update_webgen_feeds(config_feeds.team_feeds, "pro_team_news")
19
+ elsif CONFIG.affiliation_key == 'l.nba.com'
20
+ update_webgen_feeds(config_feeds.team_feeds, "pro_team_news")
21
+ elsif CONFIG.affiliation_key == 'l.mlb.com'
22
+ update_webgen_feeds(config_feeds.team_feeds, "pro_team_news")
23
+ update_webgen_feeds(config_feeds.fantasy_news_feeds, "fantasy")
24
+ elsif CONFIG.affiliation_key.match('l.ncaa.org')
25
+ update_webgen_feeds(ExternalFeed.find(:all, :conditions => ["content_type = ? and provider = ?", "news", "Sporting News"]), "ncaa_team_news")
26
+ end
27
+ end
28
+ end
29
+
30
+ def self.update_webgen_feeds(feed_list, list_type)
31
+ if list_type == "ncaa_team_news"
32
+ feed_list.each do |feed_obj|
33
+ feed_team = Team.find(feed_obj.team_id)
34
+
35
+ if !feed_team.nil?
36
+ feed_url = feed_obj.woven_feed_url
37
+ if CONFIG.woven_feed_server != "woven.zumobi.net"
38
+ feed_url = feed_url.gsub("woven.zumobi.net", CONFIG.woven_feed_server)
39
+ end
40
+ list_type = "team_news"
41
+
42
+ rss = retrieve_feed(feed_url)
43
+ parse_webgen_feeds(rss, feed_team.key, feed_url, list_type, feed_team.city_name)
44
+ end
45
+ end
46
+ else
47
+ feed_list.each do |feed_title, url|
48
+ if list_type == "pro_team_news"
49
+ feed_key = feed_title
50
+ if Team.column_names.include?("tsn_key") && feed_key.to_s.match(CONFIG.affiliation_key)
51
+ feed_key = tsn_keys_to_stats_key(feed_key)
52
+ end
53
+ team = Team.find_by_key(feed_key)
54
+ feed_title = (!team.nil?) ? team.city_name : feed_title
55
+ list_type = "team_news"
56
+ elsif list_type == "breaking"
57
+ feed_key = CONFIG.affiliation_key
58
+ elsif list_type == "news"
59
+ feed_key = CONFIG.affiliation_key
60
+ elsif list_type == "fantasy"
61
+ feed_key = "fantasy"
62
+ end
63
+
64
+ if !feed_key.blank?
65
+ rss = retrieve_feed(url)
66
+ parse_webgen_feeds(rss, feed_key, url, list_type, feed_title)
67
+ end
68
+ end
69
+ end
70
+ rescue Exception => e
71
+ Zumobi::ExceptionHandler.error e
72
+ end
73
+
74
+ def self.parse_webgen_feeds(rss, feed_key, url, list_type, feed_title)
75
+ p "News - #{feed_title} - #{url}"
76
+
77
+ article_count = 0
78
+
79
+ doc = Nokogiri::XML(rss)
80
+ source = "Sporting News"
81
+ if !doc.nil?
82
+
83
+ doc.xpath('//item').each do |node|
84
+ article_count += 1
85
+
86
+ if feed_key == CONFIG.affiliation_key
87
+ article_link = node.xpath('link').text
88
+ if !article_link.match(CONFIG.sn_breaking_news_match)
89
+ next
90
+ end
91
+ end
92
+
93
+ guid = node.xpath('guid').text
94
+ item_title = node.xpath('title').text
95
+
96
+ if Article.find_by_digest(guid).nil? && Article.find_by_title(item_title).nil?
97
+ article_obj = Article.new
98
+
99
+ article_obj.title = node.xpath('title').text
100
+ article_obj.published_at = node.xpath('pubDate').text
101
+ article_obj.link = node.xpath('link').text
102
+ article_obj.digest = guid
103
+ article_obj.source = source
104
+
105
+ if list_type == "team_news" || list_type == "team_news_no_filters"
106
+ article_obj.category = "Team News"
107
+ elsif list_type == "breaking" || list_type == "news"
108
+ article_obj.category = "League News"
109
+ elsif list_type == "fantasy"
110
+ article_obj.category = "Fantasy News"
111
+ else
112
+ article_obj.category = "News"
113
+ end
114
+
115
+ if guid.blank?
116
+ article_obj.set_digest
117
+ end
118
+
119
+ if list_type == "breaking"
120
+ article_obj.author = (!node.xpath('author').nil?) ? node.xpath('author').text : ""
121
+ article_obj.contents = (!node.xpath('description').nil?) ? node.xpath('description').text.strip : ""
122
+ else
123
+ article_obj.author = (!node.xpath('dc:creator').nil?) ? node.xpath('dc:creator').text : ""
124
+ article_obj.contents = (!node.xpath('content:encoded').nil?) ? node.xpath('content:encoded').text.strip : ""
125
+ thumb_image = (!node.xpath('media:thumbnail').nil?) ? node.xpath('media:thumbnail/@url').text : ""
126
+ if !thumb_image.blank?
127
+ if CONFIG.affiliation_key == 'l.nfl.com'
128
+ article_obj.thumb_image_url = CONFIG.image_service + 'crop/w/110/url/' + CGI::escape(CGI::escape(thumb_image))
129
+ article_obj.article_image_url = CONFIG.image_service + 'transform/w/480/h/480/url/' + CGI::escape(CGI::escape(thumb_image))
130
+ else
131
+ article_obj.thumb_image_url = CONFIG.image_service + 'crop/w/55/url/' + CGI::escape(CGI::escape(thumb_image))
132
+ article_obj.article_image_url = CONFIG.image_service + 'transform/w/280/h/280/url/' + CGI::escape(CGI::escape(thumb_image))
133
+ end
134
+ end
135
+ end
136
+
137
+ if article_obj.title.blank? || article_obj.title == "." || article_obj.contents.blank? || article_obj.contents == "."
138
+ next
139
+ end
140
+
141
+ if list_type == "fantasy"
142
+ set_fantasy_article_filter(article_obj, feed_key)
143
+ else
144
+ set_article_filter_association(article_obj, feed_key)
145
+ end
146
+
147
+ article_obj.save
148
+ else
149
+ Article.transaction do
150
+ article_obj = Article.find_by_digest(guid)
151
+ if article_obj.nil?
152
+ article_obj = Article.find_by_title(item_title)
153
+ end
154
+
155
+ article_obj.title = node.xpath('title').text
156
+ article_obj.published_at = node.xpath('pubDate').text
157
+ article_obj.link = node.xpath('link').text
158
+
159
+ if list_type == "breaking"
160
+ article_obj.author = (!node.xpath('author').nil?) ? node.xpath('author').text : ""
161
+ article_obj.contents = (!node.xpath('description').nil?) ? node.xpath('description').text.strip : ""
162
+ else
163
+ article_obj.author = (!node.xpath('dc:creator').nil?) ? node.xpath('dc:creator').text : ""
164
+ article_obj.contents = (!node.xpath('content:encoded').nil?) ? node.xpath('content:encoded').text.strip : ""
165
+ thumb_image = (!node.xpath('media:thumbnail').nil?) ? node.xpath('media:thumbnail/@url').text : ""
166
+
167
+ if !thumb_image.blank?
168
+ if CONFIG.affiliation_key == 'l.nfl.com'
169
+ article_obj.thumb_image_url = CONFIG.image_service + 'crop/w/110/url/' + CGI::escape(CGI::escape(thumb_image))
170
+ article_obj.article_image_url = CONFIG.image_service + 'transform/w/480/h/480/url/' + CGI::escape(CGI::escape(thumb_image))
171
+ else
172
+ article_obj.thumb_image_url = CONFIG.image_service + 'crop/w/55/url/' + CGI::escape(CGI::escape(thumb_image))
173
+ article_obj.article_image_url = CONFIG.image_service + 'transform/w/280/h/280/url/' + CGI::escape(CGI::escape(thumb_image))
174
+ end
175
+ end
176
+ end
177
+
178
+ if list_type == "fantasy"
179
+ set_fantasy_article_filter(article_obj, feed_key)
180
+ else
181
+ set_article_filter_association(article_obj, feed_key)
182
+ end
183
+ article_obj.save
184
+ end
185
+ end
186
+
187
+ p "Article - #{article_obj.title}"
188
+
189
+ remove_flash_elements(article_obj)
190
+
191
+ if (list_type == "team_news" || list_type == "breaking") && CONFIG.enable_notifications
192
+ if list_type == "team_news"
193
+ if Team.column_names.include?("tsn_key")
194
+ team = Team.find_by_key(feed_key)
195
+ notify_feed_key = team.tsn_key
196
+ else
197
+ notify_feed_key = feed_key
198
+ end
199
+ send_notification(article_obj, notify_feed_key, list_type)
200
+ else
201
+ send_notification(article_obj, feed_key, list_type)
202
+ end
203
+ end
204
+ end
205
+
206
+ p "#{article_count} articles processed"
207
+ end
208
+ end
209
+
210
+ def self.set_article_filter_association(article, feed_key)
211
+ #all
212
+ if !article.news_filters.find(:first, :conditions => "news_filter_key = 'all'")
213
+ filter = NewsFilter.find(:first, :conditions => ["news_filter_key = 'all'"])
214
+ filter.articles << article
215
+ filter.save
216
+ end
217
+
218
+ if feed_key != CONFIG.affiliation_key
219
+ #team
220
+ if Team.column_names.include?("tsn_key") && feed_key.to_s.match(CONFIG.affiliation_key)
221
+ feed_key = tsn_keys_to_stats_key(feed_key)
222
+ end
223
+ team = Team.find_by_key(feed_key)
224
+
225
+ if !team.nil?
226
+ if !article.news_filters.find(:first, :conditions => ["news_filter_key = ?", team.key])
227
+ filter_team = NewsFilter.find(:first, :conditions => ["news_filter_key = ?", team.key])
228
+ if !filter_team.nil?
229
+ filter_team.articles << article
230
+ end
231
+ end
232
+
233
+ #conference
234
+ if CONFIG.affiliation_key.match('l.ncaa.org')
235
+ conference_key = team.conference.key
236
+ else
237
+ conference_key = team.conference
238
+ end
239
+ if !article.news_filters.find(:first, :conditions => ["news_filter_key = ?", conference_key])
240
+ filter_conference = NewsFilter.find(:first, :conditions => ["news_filter_key = ?", conference_key])
241
+ if !filter_conference.nil?
242
+ filter_conference.articles << article
243
+ end
244
+ end
245
+ end
246
+ else
247
+ #league
248
+ if !article.news_filters.find(:first, :conditions => ["news_filter_key = ?", feed_key])
249
+ filter_conference = NewsFilter.find(:first, :conditions => ["news_filter_key = ?", feed_key])
250
+ if !filter_conference.nil?
251
+ filter_conference.articles << article
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ def self.set_fantasy_article_filter(article, feed_key)
258
+ if !article.news_filters.find(:first, :conditions => "news_filter_key = 'fantasy'")
259
+ filter = NewsFilter.find(:first, :conditions => ["news_filter_key = 'fantasy'"])
260
+ if !filter.nil?
261
+ filter.articles << article
262
+ filter.save
263
+ end
264
+ end
265
+ end
266
+
267
+ def self.remove_flash_elements(article)
268
+ doc = Nokogiri::HTML(article.contents)
269
+ objects = doc.search("embed")
270
+ objects.each do |obj|
271
+ obj.remove
272
+ end
273
+
274
+ contents = doc.children[1].to_html
275
+ contents = contents.gsub("<html><body>\n", '')
276
+ contents = contents.gsub('</body></html>', '')
277
+
278
+ article.contents = contents
279
+ article.save
280
+ end
281
+
282
+ def self.send_notification(article, team_key, notify_type)
283
+ #checks to see if the article is new enough
284
+ #checks if notification has been sent yet. if there's a row in the notifications table, then it's been sent
285
+ if !article.nil? && !article.digest.blank?
286
+ n = Notification.find(:first, :conditions => ['title = ? and category = ?', article.title, team_key])
287
+
288
+ if (n.nil? && article.published_at > CONFIG.send_notifications_since.call())
289
+ n = Notification.new
290
+ n.title = article.title
291
+ n.article_digest = article.digest
292
+ n.category = team_key
293
+ n.article_id = article.id
294
+ n.article_link = article.link
295
+ n.notify_sent = 0
296
+
297
+ if team_key != CONFIG.affiliation_key
298
+ team = Team.find_by_tsn_key(team_key)
299
+ if !team.nil?
300
+ n.team_id = team.id
301
+ end
302
+ end
303
+
304
+ n.save
305
+
306
+ elsif (!n.nil? && n.notify_sent == 0 && article.published_at > CONFIG.send_notifications_since.call())
307
+ #putting a delay in for sending out notify rather than sending right when we get the article.
308
+ #i'm sure that there's a caching issue between the backend and front end. hopefully this will help work that out.
309
+ alert_title = article.title[0,90]
310
+ if article.title.length > 90
311
+ alert_title += "..."
312
+ end
313
+
314
+ n.notify_sent = 1
315
+ n.save
316
+
317
+ if notify_type == "team_news" && !n.team_id.nil?
318
+ send_push_notification(alert_title, [team_key], article.digest)
319
+ elsif notify_type == "breaking"
320
+ send_push_notification(alert_title, [team_key], article.digest)
321
+ end
322
+
323
+ else
324
+ if (!n.nil?)
325
+ #Rails.logger.info("Already sent (Notification_id: #{n.id})")
326
+ else
327
+ #Rails.logger.info("Article too old to notify (#{article.digest})")
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ # Sends a notification for the specified app / notification class combo.
334
+ #
335
+ # Parameters:
336
+ # application_name - The name of the application the notification is intended for.
337
+ # tag - data goes into "tags" field
338
+ # alert - The text to display in the notification.
339
+ # digest - An additional field added for NFL - this is the article id.
340
+ # tag_key - An additional field added for NFL - this is the tag that the notifs is subscribed to team or league.
341
+ # sound (optional) - Whether or not to play a sound when the notification is sent. A value of ÔøΩtrueÔøΩ, ÔøΩ1ÔøΩ, or ÔøΩyesÔøΩ means to play the sound. Any other values will not play a sound.
342
+ def self.send_push_notification(alert_text, tags, digest)
343
+ p "--Notified! '#{alert_text[0,50]}' at #{DateTime.now.to_s}: Tag: #{tag}, Response: #{res.code} #{res.message}"
344
+
345
+ notifier = Zumobi::Notifier.new
346
+ notifier.push({
347
+ :aps => {:alert => alert_text, :sound => "1"},
348
+ :android => {:alert => alert_text, :extra => "#{tags.join(',')}|#{digest}"},
349
+ :tags => tags,
350
+ :tag_key => tags.join(','),
351
+ :digest => digest
352
+ })
353
+ end
354
+
355
+ def self.retrieve_feed(url)
356
+ body = make_request(url)
357
+ body
358
+ end
359
+
360
+
361
+ def self.remove_dup_and_old_articles()
362
+ teams = Team.find(:all, :conditions => ["division is not null"])
363
+ teams.each do |t|
364
+ p "#{t.city_name} #{t.team_name}"
365
+
366
+ news_filter = NewsFilter.find(:first, :conditions => ["news_filter_key = ?", t.key])
367
+ remove_by_news_filter(news_filter)
368
+ end
369
+
370
+ p "All"
371
+ news_filter = NewsFilter.find(:first, :conditions => ["news_filter_key = ?", "all"])
372
+ remove_by_news_filter(news_filter)
373
+ end
374
+
375
+ def self.remove_by_news_filter(news_filter)
376
+ if !news_filter.nil?
377
+ article_titles = {}
378
+ team_articles = news_filter.articles.find(:all)
379
+
380
+ team_articles.each do |a|
381
+ article_digest = Digest::SHA1.hexdigest(a.sn_url)
382
+
383
+ if article_titles[article_digest].blank?
384
+ article_titles[article_digest] = a
385
+ p "---- #{a.title}"
386
+ else
387
+ p "Dup! - #{a.title}"
388
+
389
+ this_article = a
390
+ saved_article = article_titles[article_digest]
391
+
392
+ if this_article.published_at > saved_article.published_at
393
+ article_titles[article_digest] = this_article
394
+ saved_article.destroy
395
+ else
396
+ this_article.destroy
397
+ end
398
+ end
399
+ end
400
+ end
401
+ end
402
+
403
+ private
404
+
405
+ def self.make_request(url)
406
+ begin
407
+ c = Curl::Easy.perform(url) do |curl|
408
+ curl.connect_timeout = 120
409
+ curl.follow_location = true
410
+ curl.max_redirects = 10
411
+ curl.timeout = 120
412
+ curl.encoding = 'gzip'
413
+ # curl.verbose = true
414
+ end
415
+ c.body_str
416
+ rescue Curl::Err::TimeoutError
417
+ #
418
+ rescue Curl::Err::GotNothingError
419
+ #
420
+ rescue Curl::Err::RecvError
421
+ #
422
+ end
423
+ end
424
+
425
+ def self.tsn_keys_to_stats_key(tsn_key)
426
+ #static map for stats global-id to tsn team_key
427
+ keys = {
428
+ "l.nfl.com-t.1" => 324,
429
+ "l.nfl.com-t.2" => 338,
430
+ "l.nfl.com-t.3" => 345,
431
+ "l.nfl.com-t.4" => 348,
432
+ "l.nfl.com-t.5" => 352,
433
+ "l.nfl.com-t.6" => 366,
434
+ "l.nfl.com-t.7" => 327,
435
+ "l.nfl.com-t.8" => 329,
436
+ "l.nfl.com-t.9" => 365,
437
+ "l.nfl.com-t.10" => 356,
438
+ "l.nfl.com-t.11" => 336,
439
+ "l.nfl.com-t.12" => 332,
440
+ "l.nfl.com-t.13" => 339,
441
+ "l.nfl.com-t.14" => 341,
442
+ "l.nfl.com-t.15" => 357,
443
+ "l.nfl.com-t.16" => 361,
444
+ "l.nfl.com-t.17" => 355,
445
+ "l.nfl.com-t.18" => 331,
446
+ "l.nfl.com-t.19" => 351,
447
+ "l.nfl.com-t.20" => 354,
448
+ "l.nfl.com-t.21" => 363,
449
+ "l.nfl.com-t.22" => 326,
450
+ "l.nfl.com-t.23" => 334,
451
+ "l.nfl.com-t.24" => 335,
452
+ "l.nfl.com-t.25" => 347,
453
+ "l.nfl.com-t.26" => 362,
454
+ "l.nfl.com-t.27" => 323,
455
+ "l.nfl.com-t.28" => 343,
456
+ "l.nfl.com-t.29" => 364,
457
+ "l.nfl.com-t.30" => 350,
458
+ "l.nfl.com-t.31" => 359,
459
+ "l.nfl.com-t.32" => 325,
460
+ "l.mlb.com-t.1" => 225,
461
+ "l.mlb.com-t.2" => 226,
462
+ "l.mlb.com-t.3" => 234,
463
+ "l.mlb.com-t.4" => 254,
464
+ "l.mlb.com-t.5" => 238,
465
+ "l.mlb.com-t.6" => 228,
466
+ "l.mlb.com-t.7" => 229,
467
+ "l.mlb.com-t.8" => 230,
468
+ "l.mlb.com-t.9" => 231,
469
+ "l.mlb.com-t.10" => 233,
470
+ "l.mlb.com-t.11" => 227,
471
+ "l.mlb.com-t.12" => 235,
472
+ "l.mlb.com-t.13" => 236,
473
+ "l.mlb.com-t.14" => 237,
474
+ "l.mlb.com-t.15" => 239,
475
+ "l.mlb.com-t.16" => 252,
476
+ "l.mlb.com-t.17" => 244,
477
+ "l.mlb.com-t.18" => 245,
478
+ "l.mlb.com-t.19" => 246,
479
+ "l.mlb.com-t.20" => 240,
480
+ "l.mlb.com-t.21" => 241,
481
+ "l.mlb.com-t.22" => 242,
482
+ "l.mlb.com-t.23" => 232,
483
+ "l.mlb.com-t.24" => 247,
484
+ "l.mlb.com-t.25" => 248,
485
+ "l.mlb.com-t.26" => 253,
486
+ "l.mlb.com-t.27" => 251,
487
+ "l.mlb.com-t.28" => 243,
488
+ "l.mlb.com-t.29" => 249,
489
+ "l.mlb.com-t.30" => 250,
490
+ "l.nba.com-t.1" => 2,
491
+ "l.nba.com-t.2" => 14,
492
+ "l.nba.com-t.3" => 17,
493
+ "l.nba.com-t.4" => 18,
494
+ "l.nba.com-t.5" => 19,
495
+ "l.nba.com-t.6" => 20,
496
+ "l.nba.com-t.7" => 27,
497
+ "l.nba.com-t.8" => 1,
498
+ "l.nba.com-t.9" => 3,
499
+ "l.nba.com-t.10" => 4,
500
+ "l.nba.com-t.11" => 5,
501
+ "l.nba.com-t.12" => 8,
502
+ "l.nba.com-t.13" => 11,
503
+ "l.nba.com-t.14" => 15,
504
+ "l.nba.com-t.15" => 28,
505
+ "l.nba.com-t.16" => 6,
506
+ "l.nba.com-t.17" => 7,
507
+ "l.nba.com-t.18" => 10,
508
+ "l.nba.com-t.19" => 29,
509
+ "l.nba.com-t.20" => 16,
510
+ "l.nba.com-t.21" => 24,
511
+ "l.nba.com-t.22" => 26,
512
+ "l.nba.com-t.23" => 9,
513
+ "l.nba.com-t.24" => 12,
514
+ "l.nba.com-t.25" => 13,
515
+ "l.nba.com-t.26" => 21,
516
+ "l.nba.com-t.27" => 22,
517
+ "l.nba.com-t.28" => 23,
518
+ "l.nba.com-t.29" => 25,
519
+ "l.nba.com-t.32" => 5312
520
+ }
521
+
522
+ if !tsn_key.blank? && !keys[tsn_key].blank?
523
+ return keys[tsn_key]
524
+ else
525
+ return ''
526
+ end
527
+ end
528
+
529
+ end
530
+ end
@@ -0,0 +1,78 @@
1
+ module SportsDb
2
+ class TeamAndRosterBuilder
3
+
4
+ def self.update_player_image_urls
5
+ p "update_player_image_urls ..."
6
+ config_feeds = SimpleConfig.for(:feeds)
7
+ require 'open-uri'
8
+ open( config_feeds.player_images_url ) do |file|
9
+ doc = Nokogiri::XML(file.read)
10
+ doc.xpath('//row').each do |player_element|
11
+ # The date is in format '08-MAY-77' and we need '8/5/1977' as a string. However, this still doesn't
12
+ # strip leading zeroes off days, which we need to do to match this date as a string.
13
+ # Convert to string, replace last bit so it says "19xx", parse to date, and then format
14
+ # in the D/M/Y format. Then finally remove leading zeroes.
15
+ if !player_element['BIRTH_DATE'].blank?
16
+ adj_birth_date = DateTime.strptime(player_element['BIRTH_DATE'].to_s, "%m/%d/%Y").to_s
17
+ end
18
+
19
+ # Try only the name first.
20
+ matches = Player.find_by_last_comma_first( player_element['PLAYER_NAME'] )
21
+ # But if there's more than one, then attempt to whittle it down with the birthday
22
+ matches = matches.select {|p| p.birth_date == adj_birth_date } if (matches.length > 1)
23
+
24
+ if (matches.length == 1)
25
+ player = matches[0]
26
+ player.image_url = player_element['PLAYER_MUG']
27
+ player.sporting_news_id = player_element['PLAYER_ID'].to_i
28
+ player.save
29
+
30
+ p "img- #{player_element['PLAYER_NAME']} - #{player_element['PLAYER_MUG']}"
31
+ else
32
+ p "Unable to Match -- #{player_element['PLAYER_NAME']}"
33
+ end
34
+
35
+ end
36
+ end
37
+ rescue Exception => e
38
+ Zumobi::ExceptionHandler.error e
39
+ end
40
+
41
+ def self.update_team_top25_rank
42
+ p "Set Top 25 Rank"
43
+
44
+ rank_issuer_key = map_poll_key(CONFIG.rank_based_on_poll)
45
+
46
+ rankings = PollRanking.all(:conditions => ["issuer_key = ?", rank_issuer_key])
47
+ rankings.each do |obj|
48
+ team_obj = Team.find(obj.team_id)
49
+ # Only rank 1-25 (bug 24359)
50
+ if team_obj.present? && obj.rank.to_i < 26
51
+ p "#{team_obj.city_name} ##{obj.rank}"
52
+ team_obj.rank = obj.rank
53
+ team_obj.save
54
+ end
55
+ end
56
+ end
57
+
58
+ def self.map_poll_key(poll_key)
59
+ case poll_key
60
+ when "poll-ap"
61
+ "1"
62
+ when "poll-usat"
63
+ "2"
64
+ when "ranking-bcs"
65
+ "3"
66
+ when "ap"
67
+ "ap"
68
+ when "coaches"
69
+ "coaches"
70
+ when "rpi"
71
+ "rpi"
72
+ else
73
+ "1"
74
+ end
75
+ end
76
+
77
+ end
78
+ end
@@ -1,3 +1,3 @@
1
1
  module SportsDb
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
data/lib/sports_db.rb CHANGED
@@ -1,8 +1,12 @@
1
1
  require "sports_db/engine"
2
2
  require "sports_db/external_feed_builder"
3
3
  require "sports_db/media_builder"
4
+ require "sports_db/news_builder"
4
5
  require "sports_db/news_filters_builder"
6
+ require "sports_db/sporting_news_feed_builder"
7
+ require "sports_db/team_and_roster_builder"
5
8
  require "sports_db/twitter_builder"
9
+ require "time_service"
6
10
 
7
11
  module SportsDb
8
12
 
@@ -2,3 +2,103 @@
2
2
  # task :sports_db do
3
3
  # # Task goes here
4
4
  # end
5
+
6
+ namespace 'zu' do
7
+
8
+ task :set_logger => :environment do
9
+ RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
10
+ end
11
+
12
+ namespace 'sports' do
13
+ desc "Run sports db migrations."
14
+ task :migrate => 'zu:set_logger' do
15
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
16
+ ActiveRecord::Migrator.migrate("vendor/plugins/sports_db/db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
17
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
18
+ end
19
+
20
+ desc "Drops and recreates the sports_db database (as well as any application-specific migrations)."
21
+ task :reset => [ 'db:drop', 'db:create', 'zu:sports:migrate', 'db:migrate'] do
22
+ # Renamed this reset because there's a db:reset task that does the same thing...
23
+ end
24
+
25
+ desc "Incrementally update the database based on job's frequency. Usage: 'rake zu:sports:update[1]'"
26
+ task :update, [:frequency] => 'zu:set_logger' do |t, args|
27
+ case args.frequency
28
+ when "1" then SportsBuildManager.every_1_minute
29
+ when "15" then SportsBuildManager.every_15_minutes
30
+ when "60" then SportsBuildManager.every_60_minutes
31
+ when "720" then SportsBuildManager.every_720_minutes
32
+ when "1440" then SportsBuildManager.every_1440_minutes
33
+ end
34
+ end
35
+
36
+ desc "Run game_updater (sub-1 minute task)"
37
+ task :run_games_updater, [] => ['zu:set_logger'] do |t|
38
+ SportsBuildManager.games_updater
39
+ end
40
+
41
+ desc "Build the entire database 'from scratch' without reference to job scheduling"
42
+ task :build, [] => ['zu:set_logger'] do |t|
43
+ %w(one_time every_1440_minutes every_720_minutes every_15_minutes every_1_minute).each do |m|
44
+ SportsBuildManager.send(m)
45
+ end
46
+ end
47
+
48
+ desc "Run one time and 12 hour builds prior to starting FeedFetcher on a clean instance of TSN server"
49
+ task :build_to_day, [] => ['zu:set_logger'] do |t|
50
+ SportsBuildManager.one_time
51
+ SportsBuildManager.every_1440_minutes
52
+ end
53
+
54
+ desc "Parse team info xml from sporting news and fetch all team logos to local disk."
55
+ task :get_team_logos => 'zu:set_logger' do
56
+
57
+ mkdir "#{Rails.root.to_s}/public/images/logos/" unless File.exists?( "#{Rails.root.to_s}/public/images/logos/" )
58
+
59
+ config = SimpleConfig.for(:feeds)
60
+ require 'open-uri'
61
+ open( config.team_info_url ) do |file|
62
+
63
+ doc = Nokogiri::XML(file.read)
64
+ doc.xpath('//row').each do |team_element|
65
+ %w{small medium large}.each do |size|
66
+ image = open( team_element['TEAM_LOGO'].gsub( /large/, size ) )
67
+ path = "#{Rails.root.to_s}/public/images/logos/#{size}"
68
+ mkdir path unless File.exists?( path )
69
+ /\.(\w+)$/ =~ team_element['TEAM_LOGO']
70
+ File.open("#{path}/#{team_element['TEAM_NAME_SHORT']}.#{$1}", "w") do |file|
71
+ file.puts( image.read )
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ desc "Set up Stats LLC database, same schema as the mlb database, just with a different name, for testing"
79
+ task :create_statsllc_database => 'zu:set_logger' do
80
+ ActiveRecord::Base.configurations = YAML::load(IO.read("#{Rails.root.to_s}/config/statsllc_database.yml"))
81
+
82
+ ActiveRecord::Base.establish_connection("#{Rails.env}")
83
+ ActiveRecord::Base.connection.drop_database(ActiveRecord::Base.configurations[Rails.env]["database"])
84
+ ActiveRecord::Base.connection.create_database(ActiveRecord::Base.configurations[Rails.env]["database"], ActiveRecord::Base.configurations[Rails.env])
85
+
86
+ ActiveRecord::Base.establish_connection("#{Rails.env}")
87
+
88
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
89
+ ActiveRecord::Migrator.migrate("vendor/plugins/sports_db/db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
90
+ ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
91
+ end
92
+
93
+ desc "Run migrations on statsllc db"
94
+ task :migrate_statsllc_database => 'zu:set_logger' do
95
+ ActiveRecord::Base.configurations = YAML::load(IO.read("#{Rails.root.to_s}/config/statsllc_database.yml"))
96
+
97
+ ActiveRecord::Base.establish_connection("#{Rails.env}")
98
+
99
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
100
+ ActiveRecord::Migrator.migrate("vendor/plugins/sports_db/db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
101
+ ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,9 @@
1
+ class TimeService
2
+ def self.now
3
+ config = SimpleConfig.for(:application)
4
+ config.timeservice.call()
5
+ rescue
6
+ Rails.logger.error("Could not call time service: SimpleConfig is not initialized, there's no application scope, no timeservice property, or it's not a lambda.")
7
+ return DateTime.now.utc
8
+ end
9
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 2
9
- version: 0.0.2
8
+ - 3
9
+ version: 0.0.3
10
10
  platform: ruby
11
11
  authors:
12
12
  - Alx Dark
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2013-04-22 00:00:00 -07:00
17
+ date: 2013-04-26 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -71,16 +71,21 @@ files:
71
71
  - app/models/player_stat.rb
72
72
  - app/models/poll_ranking.rb
73
73
  - app/models/score.rb
74
+ - app/models/score_notification.rb
74
75
  - app/models/twitter.rb
75
76
  - config/routes.rb
76
77
  - lib/sports_db/engine.rb
77
78
  - lib/sports_db/external_feed_builder.rb
78
79
  - lib/sports_db/media_builder.rb
80
+ - lib/sports_db/news_builder.rb
79
81
  - lib/sports_db/news_filters_builder.rb
82
+ - lib/sports_db/sporting_news_feed_builder.rb
83
+ - lib/sports_db/team_and_roster_builder.rb
80
84
  - lib/sports_db/twitter_builder.rb
81
85
  - lib/sports_db/version.rb
82
86
  - lib/sports_db.rb
83
87
  - lib/tasks/sports_db_tasks.rake
88
+ - lib/time_service.rb
84
89
  - MIT-LICENSE
85
90
  - Rakefile
86
91
  - README.rdoc