active_public_resources 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +19 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +3 -0
  5. data/Gemfile +24 -0
  6. data/Guardfile +9 -0
  7. data/LICENSE.txt +18 -0
  8. data/README.md +326 -0
  9. data/Rakefile +7 -0
  10. data/active_public_resources.gemspec +27 -0
  11. data/active_public_resources_config.yml.example +10 -0
  12. data/lib/active_public_resources/base_response_type.rb +11 -0
  13. data/lib/active_public_resources/base_return_type.rb +17 -0
  14. data/lib/active_public_resources/client.rb +22 -0
  15. data/lib/active_public_resources/driver.rb +21 -0
  16. data/lib/active_public_resources/driver_response.rb +15 -0
  17. data/lib/active_public_resources/drivers/khan_academy.rb +143 -0
  18. data/lib/active_public_resources/drivers/quizlet.rb +92 -0
  19. data/lib/active_public_resources/drivers/schooltube.rb +99 -0
  20. data/lib/active_public_resources/drivers/vimeo.rb +181 -0
  21. data/lib/active_public_resources/drivers/youtube.rb +113 -0
  22. data/lib/active_public_resources/request_criteria.rb +51 -0
  23. data/lib/active_public_resources/response_types/exercise.rb +11 -0
  24. data/lib/active_public_resources/response_types/folder.rb +18 -0
  25. data/lib/active_public_resources/response_types/image.rb +11 -0
  26. data/lib/active_public_resources/response_types/quiz.rb +11 -0
  27. data/lib/active_public_resources/response_types/video.rb +12 -0
  28. data/lib/active_public_resources/return_types/file.rb +11 -0
  29. data/lib/active_public_resources/return_types/iframe.rb +11 -0
  30. data/lib/active_public_resources/return_types/image_url.rb +11 -0
  31. data/lib/active_public_resources/return_types/oembed.rb +11 -0
  32. data/lib/active_public_resources/return_types/url.rb +11 -0
  33. data/lib/active_public_resources/version.rb +3 -0
  34. data/lib/active_public_resources.rb +55 -0
  35. data/spec/lib/active_public_resources/client_spec.rb +75 -0
  36. data/spec/lib/active_public_resources/driver_spec.rb +48 -0
  37. data/spec/lib/active_public_resources/drivers/khan_academy_spec.rb +106 -0
  38. data/spec/lib/active_public_resources/drivers/quizlet_spec.rb +50 -0
  39. data/spec/lib/active_public_resources/drivers/schooltube_spec.rb +50 -0
  40. data/spec/lib/active_public_resources/drivers/vimeo_spec.rb +71 -0
  41. data/spec/lib/active_public_resources/drivers/youtube_spec.rb +52 -0
  42. data/spec/lib/active_public_resources/live_client_spec.rb +91 -0
  43. data/spec/lib/active_public_resources/request_criteria_spec.rb +53 -0
  44. data/spec/spec_helper.rb +46 -0
  45. data/spec/vcr/active_public_resources/client/khan_academy_should_traverse_folders.yml +1039 -0
  46. data/spec/vcr/active_public_resources/client/quizlet_should_perform_request.yml +70 -0
  47. data/spec/vcr/active_public_resources/client/shooltube_should_perform_request.yml +815 -0
  48. data/spec/vcr/active_public_resources/client/vimeo_should_perform_request.yml +70 -0
  49. data/spec/vcr/active_public_resources/client/youtube_should_perform_request.yml +212 -0
  50. data/spec/vcr/active_public_resources/drivers/khan_academy_driver_perform_request/should_get_folder_cs/programming.yml +117 -0
  51. data/spec/vcr/active_public_resources/drivers/khan_academy_driver_perform_request/should_get_folder_cs.yml +72 -0
  52. data/spec/vcr/active_public_resources/drivers/khan_academy_driver_perform_request/should_get_folder_science/mcat/society_and_culture/social_structures.yml +578 -0
  53. data/spec/vcr/active_public_resources/drivers/khan_academy_driver_perform_request/should_get_root_folders.yml +122 -0
  54. data/spec/vcr/active_public_resources/drivers/khan_academy_perform_request/should_get_folder_cs/programming.yml +120 -0
  55. data/spec/vcr/active_public_resources/drivers/khan_academy_perform_request/should_get_folder_cs.yml +73 -0
  56. data/spec/vcr/active_public_resources/drivers/khan_academy_perform_request/should_get_folder_science/mcat/society_and_culture/social_structures.yml +577 -0
  57. data/spec/vcr/active_public_resources/drivers/khan_academy_perform_request/should_get_root_folders.yml +119 -0
  58. data/spec/vcr/active_public_resources/drivers/quizlet_driver_perform_request/should_perform_request.yml +75 -0
  59. data/spec/vcr/active_public_resources/drivers/quizlet_perform_request/should_perform_request.yml +72 -0
  60. data/spec/vcr/active_public_resources/drivers/schooltube_driver_perform_request/should_perform_request.yml +815 -0
  61. data/spec/vcr/active_public_resources/drivers/schooltube_perform_request/should_perform_request.yml +810 -0
  62. data/spec/vcr/active_public_resources/drivers/vimeo_driver_perform_request/should_perform_request.yml +279 -0
  63. data/spec/vcr/active_public_resources/drivers/vimeo_perform_request/should_perform_request.yml +70 -0
  64. data/spec/vcr/active_public_resources/drivers/youtube_driver_perform_request/should_perform_request.yml +212 -0
  65. data/spec/vcr/active_public_resources/drivers/youtube_perform_request/should_perform_request.yml +209 -0
  66. metadata +182 -0
@@ -0,0 +1,143 @@
1
+ require 'net/https'
2
+
3
+ module ActivePublicResources
4
+ module Drivers
5
+ class KhanAcademy < Driver
6
+
7
+ BASE_URL = "https://www.khanacademy.org/api/v1/"
8
+
9
+ def perform_request(request_criteria)
10
+ request_criteria.folder ||= 'root'
11
+ results, videos, exercises = get_folder(request_criteria.folder)
12
+ parse_results(request_criteria, results, videos, exercises)
13
+ end
14
+
15
+ private
16
+
17
+ def perform_rest_request(path)
18
+ uri = URI( BASE_URL + path )
19
+ res = Net::HTTP.get_response(uri)
20
+ JSON.parse(res.body)
21
+ end
22
+
23
+ def get_folder(folder_id)
24
+ results = perform_rest_request("topic/#{folder_id}")
25
+ child_data_types = results['child_data'].map { |item| item['kind'] }.uniq
26
+ videos = []
27
+ if child_data_types.include? "Video"
28
+ videos = get_videos(folder_id)
29
+ end
30
+ exercises = []
31
+ if child_data_types.include? "Exercise"
32
+ exercises = get_exercises(folder_id)
33
+ end
34
+ [results, videos, exercises]
35
+ end
36
+
37
+ def get_videos(folder_id)
38
+ perform_rest_request("topic/#{folder_id}/videos")
39
+ end
40
+
41
+ def get_exercises(folder_id)
42
+ perform_rest_request("topic/#{folder_id}/exercises")
43
+ end
44
+
45
+ def parse_results(request_criteria, results, videos=[], exercises=[])
46
+ parent_id = parse_parent_id(results['slug'], results['extended_slug'])
47
+
48
+ driver_response = DriverResponse.new(
49
+ :criteria => request_criteria,
50
+ :next_criteria => nil,
51
+ :total_items => results['children'].length
52
+ )
53
+
54
+ topics = results['children'].find_all { |item| item['kind'] == 'Topic' }
55
+ topics.each do |topic|
56
+ driver_response.items << parse_folder(topic, parent_id)
57
+ end
58
+
59
+ videos.each do |video_data|
60
+ driver_response.items << parse_video(video_data)
61
+ end
62
+
63
+ exercises.each do |exercise_data|
64
+ driver_response.items << parse_exercise(exercise_data)
65
+ end
66
+
67
+ driver_response
68
+ end
69
+
70
+ def parse_folder(data, parent_id)
71
+ folder = ActivePublicResources::ResponseTypes::Folder.new
72
+ folder.id = data['id']
73
+ folder.title = data['title']
74
+ folder.parent_id = parent_id
75
+ folder
76
+ end
77
+
78
+ def parse_video(data)
79
+ video = ActivePublicResources::ResponseTypes::Video.new
80
+ video.id = data['readable_id']
81
+ video.title = data['title']
82
+ video.description = data['description']
83
+ video.thumbnail_url = data['image_url']
84
+ video.url = data['url']
85
+ video.duration = data['duration'] ? data['duration'].to_i : 0
86
+ video.num_views = 0
87
+ video.num_likes = 0
88
+ video.num_comments = 0
89
+ video.created_date = data['date_added'].present? ? Date.parse(data['date_added']) : nil
90
+ video.username = data['author_names'].present? ? data['author_names'].first : ''
91
+ video.width = 640
92
+ video.height = 360
93
+
94
+ # Return Types
95
+ video.return_types << APR::ReturnTypes::Url.new(
96
+ :url => video.url,
97
+ :text => video.title,
98
+ :title => video.title
99
+ )
100
+ video.return_types << APR::ReturnTypes::Iframe.new(
101
+ :url => "//www.youtube.com/embed/#{data['youtube_id']}?feature=oembed",
102
+ :text => video.title,
103
+ :title => video.title,
104
+ :width => 640,
105
+ :height => 360
106
+ )
107
+ video
108
+ end
109
+
110
+ def parse_exercise(data)
111
+ exercise = ActivePublicResources::ResponseTypes::Exercise.new
112
+ exercise.id = data['global_id']
113
+ exercise.title = data['display_name']
114
+ exercise.description = data['description']
115
+ exercise.thumbnail_url = data['image_url_256']
116
+ exercise.url = data['ka_url']
117
+
118
+ exercise.return_types << APR::ReturnTypes::Url.new(
119
+ :url => exercise.url,
120
+ :text => exercise.title,
121
+ :title => exercise.title
122
+ )
123
+
124
+ exercise
125
+ end
126
+
127
+ def parse_parent_id(slug, extended_slug)
128
+ if extended_slug.present?
129
+ if extended_slug != slug
130
+ parts = extended_slug.split("/")
131
+ parts.pop
132
+ parts.last
133
+ else
134
+ 'root'
135
+ end
136
+ else
137
+ nil
138
+ end
139
+ end
140
+
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,92 @@
1
+ require 'net/https'
2
+
3
+ module ActivePublicResources
4
+ module Drivers
5
+ class Quizlet < Driver
6
+
7
+ def initialize(config_options={})
8
+ validate_options(config_options, [:client_id])
9
+ @client_id = config_options[:client_id]
10
+ end
11
+
12
+ def perform_request(request_criteria)
13
+ raise StandardError.new("driver has not been initialized properly") unless @client_id.present?
14
+ request_criteria.validate_presence!([:query])
15
+
16
+ uri = URI('https://api.quizlet.com/2.0/search/sets')
17
+ params = {
18
+ 'q' => request_criteria.query,
19
+ 'page' => request_criteria.page || 1,
20
+ 'per_page' => request_criteria.per_page || 25,
21
+ 'client_id' => @client_id
22
+ }
23
+ uri.query = URI.encode_www_form(params)
24
+ res = Net::HTTP.get_response(uri)
25
+ results = JSON.parse(res.body)
26
+
27
+ return parse_results(request_criteria, results)
28
+ end
29
+
30
+ private
31
+
32
+ def parse_results(request_criteria, results)
33
+ @driver_response = DriverResponse.new(
34
+ :criteria => request_criteria,
35
+ :next_criteria => next_criteria(request_criteria, results),
36
+ :total_items => results['total_results'],
37
+ :items => results['sets'].map { |data| parse_quiz(data) }
38
+ )
39
+ end
40
+
41
+ def next_criteria(request_criteria, results)
42
+ if results['total_pages'] > results['page']
43
+ return RequestCriteria.new({
44
+ :query => request_criteria.query,
45
+ :page => (request_criteria.page || 1) + 1,
46
+ :per_page => (request_criteria.per_page || 25)
47
+ })
48
+ end
49
+ end
50
+
51
+ def parse_quiz(data)
52
+ quiz = ActivePublicResources::ResponseTypes::Quiz.new
53
+ quiz.id = data['id']
54
+ quiz.title = data['title']
55
+ quiz.description = data['description']
56
+ quiz.url = data['url']
57
+ quiz.term_count = data['term_count']
58
+ quiz.created_date = Time.at(data['created_date']).utc.to_date
59
+ quiz.has_images = data['has_images']
60
+ quiz.subjects = data['subjects']
61
+
62
+ # Return Types
63
+
64
+ quiz.return_types << APR::ReturnTypes::Url.new(
65
+ :url => quiz.url,
66
+ :text => quiz.title,
67
+ :title => quiz.title
68
+ )
69
+
70
+ # See http://quizlet.com/help/can-i-embed-quizlet-on-my-website
71
+ { flashcards: "Flashcards",
72
+ learn: "Learn",
73
+ scatter: "Scatter",
74
+ speller: "Speller",
75
+ test: "Test",
76
+ spacerace: "Space Race" }.each do |k,v|
77
+
78
+ quiz.return_types << APR::ReturnTypes::Iframe.new(
79
+ :url => "https://quizlet.com/#{data['id']}/#{k}/embedv2",
80
+ :text => v,
81
+ :title => quiz.title,
82
+ :width => "100%",
83
+ :height => 410
84
+ )
85
+ end
86
+
87
+ quiz
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,99 @@
1
+ require 'net/https'
2
+
3
+ module ActivePublicResources
4
+ module Drivers
5
+ class Schooltube < Driver
6
+
7
+ def perform_request(request_criteria)
8
+ request_criteria.validate_presence!([:query])
9
+ uri = URI('http://www.schooltube.com/api/v1/video/search/')
10
+ params = {
11
+ 'term' => request_criteria.query,
12
+ 'orderby' => normalize_request_criteria(request_criteria, 'sort') || '-view_count',
13
+ 'offset' => offset(request_criteria.page, request_criteria.per_page),
14
+ 'limit' => request_criteria.per_page || 25
15
+ }
16
+ uri.query = URI.encode_www_form(params)
17
+ res = Net::HTTP.get_response(uri)
18
+ results = JSON.parse(res.body)
19
+
20
+ return parse_results(request_criteria, results)
21
+ end
22
+
23
+ private
24
+
25
+ def offset(page, per_page)
26
+ p = page || 1
27
+ pp = per_page || 25
28
+ p * pp - pp
29
+ end
30
+
31
+ def normalize_request_criteria(request_criteria, field_name)
32
+ case field_name
33
+ when 'sort'
34
+ case request_criteria.instance_variable_get("@#{field_name}")
35
+ when 'views'
36
+ return '-view_count'
37
+ else
38
+ return '-view_count'
39
+ end
40
+ else
41
+ request_criteria.instance_variable_get("@#{field_name}")
42
+ end
43
+ end
44
+
45
+ def parse_results(request_criteria, results)
46
+ @driver_response = DriverResponse.new(
47
+ :criteria => request_criteria,
48
+ :next_criteria => next_criteria(request_criteria, results),
49
+ :total_items => nil,
50
+ :items => results['objects'].map { |data| parse_video(data) }
51
+ )
52
+ end
53
+
54
+ def next_criteria(request_criteria, results)
55
+ if results['meta']['has_next']
56
+ return RequestCriteria.new({
57
+ :query => request_criteria.query,
58
+ :page => (request_criteria.page || 1) + 1,
59
+ :per_page => results['meta']['limit'].to_i
60
+ })
61
+ end
62
+ end
63
+
64
+ def parse_video(data)
65
+ video = ActivePublicResources::ResponseTypes::Video.new
66
+ video.id = data['vkey']
67
+ video.title = data['title']
68
+ video.description = data['description']
69
+ video.thumbnail_url = data['thumbnail_url']
70
+ video.url = data['short_url']
71
+ video.duration = data['duration'] ? data['duration'].to_i : 0
72
+ video.num_views = data['view_count'] ? data['view_count'].to_i : 0
73
+ video.num_likes = data['thumbs_up'] ? data['thumbs_up'].to_i : 0
74
+ video.num_comments = 0
75
+ video.created_date = Date.parse(data['create_date'])
76
+ video.username = data['username']
77
+ video.width = 640
78
+ video.height = 360
79
+
80
+ # Return Types
81
+ video.return_types << APR::ReturnTypes::Url.new(
82
+ :url => video.url,
83
+ :text => video.title,
84
+ :title => video.title
85
+ )
86
+ video.return_types << APR::ReturnTypes::Iframe.new(
87
+ :url => "//www.schooltube.com/embed/#{data['vkey']}",
88
+ :text => video.title,
89
+ :title => video.title,
90
+ :width => 640,
91
+ :height => 360
92
+ )
93
+
94
+ video
95
+ end
96
+
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,181 @@
1
+ require 'vimeo'
2
+
3
+ module ActivePublicResources
4
+ module Drivers
5
+ class Vimeo < Driver
6
+ attr_reader :client
7
+
8
+ DEFAULT_CRITERIA = {
9
+ :page => 1,
10
+ :per_page => 25,
11
+ :sort => 'relevant',
12
+ :content_filter => 'safe'
13
+ }
14
+
15
+ # Constructor
16
+ #
17
+ # @param [Hash] config_options the options which the vimeo gem requires
18
+ # @option config_options [String] :consumer_key Vimeo consumer key (required)
19
+ # @option config_options [String] :consumer_secret Vimeo consumer secret (required)
20
+ # @option config_options [String] :access_token Vimeo access token (required)
21
+ # @option config_options [String] :access_token_secret Vimeo access token secret (required)
22
+ def initialize(config_options={})
23
+ validate_options(config_options,
24
+ [:consumer_key, :consumer_secret, :access_token, :access_token_secret])
25
+
26
+ @client = ::Vimeo::Advanced::Video.new(
27
+ config_options[:consumer_key],
28
+ config_options[:consumer_secret],
29
+ token: config_options[:access_token],
30
+ secret: config_options[:access_token_secret]
31
+ )
32
+ end
33
+
34
+ # Perform search request to Vimeo with search criteria
35
+ #
36
+ # @param [Hash] criteria the criteria used to perform the search
37
+ # @option criteria [String] :query The query text to search for (required)
38
+ # @option criteria [Integer] :page The page number
39
+ # @option criteria [Integer] :per_page The number of items per page
40
+ # @option criteria [String] :sort The sort filter
41
+ # @option criteria [String] :content_filter The content filter of which to apply
42
+ # this is not supported yet - https://developer.vimeo.com/api/docs/spec
43
+ #
44
+ # @example Request
45
+ # driver = ActivePublicResources::Drivers::Vimeo.new({ .. config options .. })
46
+ # results = driver.perform_request({ query: 'education' })
47
+ #
48
+ # @example Returns
49
+ # {
50
+ # 'items': [
51
+ # {
52
+ # 'kind' : 'video',
53
+ # 'id' : '1',
54
+ # 'title' : '',
55
+ # 'description' : '',
56
+ # 'thumbnail_url' : '',
57
+ # 'url' : '',
58
+ # 'duration' : 150,
59
+ # 'num_views' : 13,
60
+ # 'num_likes' : 1,
61
+ # 'num_comments' : 2,
62
+ # 'created_date' : '',
63
+ # 'username' : '',
64
+ # 'embed_html' : '',
65
+ # 'width' : 640,
66
+ # 'height' : 360
67
+ # },
68
+ # ...
69
+ # ],
70
+ # 'meta': {
71
+ # 'nextCriteria': {
72
+ # 'query' : 'education',
73
+ # 'page' : 2
74
+ # 'per_page' : 25
75
+ # 'sort' : 'relevant'
76
+ # 'content_filter' : 'safe'
77
+ # }
78
+ # }
79
+ # }
80
+ #
81
+ # @return [JSON] the normalized response object
82
+ def perform_request(request_criteria)
83
+ request_criteria.validate_presence!([:query])
84
+ raise StandardError.new("driver has not been initialized properly") unless @client
85
+
86
+ results = @client.search(request_criteria.query, {
87
+ :page => request_criteria.page || 1,
88
+ :per_page => request_criteria.per_page || 25,
89
+ :full_response => 1,
90
+ :sort => request_criteria.sort || "relevant",
91
+ :user_id => nil,
92
+ :content_filter => request_criteria.content_filter || 'safe'
93
+ })
94
+
95
+ return parse_results(request_criteria, results)
96
+ end
97
+
98
+ private
99
+
100
+ def sort(val)
101
+ case val
102
+ when APR::RequestCriteria::SORT_RELEVANCE
103
+ 'relevant'
104
+ when APR::RequestCriteria::SORT_RECENT
105
+ 'newest'
106
+ when APR::RequestCriteria::SORT_POPULAR
107
+ 'most_played'
108
+ else
109
+ 'relevant'
110
+ end
111
+ end
112
+
113
+ def content_filter(val)
114
+ case val
115
+ when APR::RequestCriteria::CONTENT_FILTER_NONE
116
+ 'safe'
117
+ when APR::RequestCriteria::CONTENT_FILTER_STRICT
118
+ 'safe'
119
+ else
120
+ 'safe'
121
+ end
122
+ end
123
+
124
+ def parse_results(request_criteria, results)
125
+ @driver_response = DriverResponse.new(
126
+ :criteria => request_criteria,
127
+ :next_criteria => next_criteria(request_criteria, results),
128
+ :total_items => results['videos']['total'].to_i,
129
+ :items => results['videos']['video'].map { |data| parse_video(data) }
130
+ )
131
+ end
132
+
133
+ def next_criteria(request_criteria, results)
134
+ page = results['videos']['page'].to_i
135
+ per_page = results['videos']['perpage'].to_i
136
+ total = results['videos']['total'].to_i
137
+ if ((page * per_page) < total)
138
+ return RequestCriteria.new({
139
+ :query => request_criteria.query,
140
+ :page => page + 1,
141
+ :per_page => per_page
142
+ })
143
+ end
144
+ end
145
+
146
+ def parse_video(data)
147
+ video = ActivePublicResources::ResponseTypes::Video.new
148
+ video.id = data['id']
149
+ video.title = data['title']
150
+ video.description = data['description']
151
+ video.thumbnail_url = data['thumbnails']['thumbnail'][0]['_content']
152
+ video.url = data['urls']['url'][0]['_content']
153
+ video.duration = data['duration'].to_i
154
+ video.num_views = data['number_of_plays'].to_i
155
+ video.num_likes = data['number_of_likes'].to_i
156
+ video.num_comments = data['number_of_comments'].to_i
157
+ video.created_date = Date.parse(data['upload_date'])
158
+ video.username = data['owner']['display_name']
159
+ video.width = 640
160
+ video.height = 360
161
+
162
+ # Return Types
163
+ video.return_types << APR::ReturnTypes::Url.new(
164
+ :url => video.url,
165
+ :text => video.title,
166
+ :title => video.title
167
+ )
168
+ video.return_types << APR::ReturnTypes::Iframe.new(
169
+ :url => "//player.vimeo.com/video/#{data['id']}",
170
+ :text => video.title,
171
+ :title => video.title,
172
+ :width => 640,
173
+ :height => 360
174
+ )
175
+
176
+ video
177
+ end
178
+
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,113 @@
1
+ require 'net/https'
2
+
3
+ module ActivePublicResources
4
+ module Drivers
5
+ class Youtube < Driver
6
+
7
+ def perform_request(request_criteria)
8
+ request_criteria.validate_presence!([:query])
9
+
10
+ uri = URI('https://gdata.youtube.com/feeds/api/videos')
11
+ params = {
12
+ 'v' => 2,
13
+ 'q' => request_criteria.query,
14
+ 'orderby' => sort(request_criteria.sort),
15
+ 'alt' => 'json',
16
+ 'safeSearch' => content_filter(request_criteria.content_filter),
17
+ 'start-index' => request_criteria.page || 1,
18
+ 'max-results' => request_criteria.per_page || 25
19
+ }
20
+
21
+ uri.query = URI.encode_www_form(params)
22
+
23
+ res = Net::HTTP.get_response(uri)
24
+ results = JSON.parse(res.body)
25
+
26
+ return parse_results(request_criteria, results)
27
+ end
28
+
29
+ private
30
+
31
+ def sort(val)
32
+ case val
33
+ when APR::RequestCriteria::SORT_RELEVANCE
34
+ 'relevance'
35
+ when APR::RequestCriteria::SORT_RECENT
36
+ 'relevance'
37
+ when APR::RequestCriteria::SORT_POPULAR
38
+ 'relevance'
39
+ else
40
+ 'relevance'
41
+ end
42
+ end
43
+
44
+ def content_filter(val)
45
+ case val
46
+ when APR::RequestCriteria::CONTENT_FILTER_NONE
47
+ 'strict'
48
+ when APR::RequestCriteria::CONTENT_FILTER_STRICT
49
+ 'strict'
50
+ else
51
+ 'strict'
52
+ end
53
+ end
54
+
55
+ def parse_results(request_criteria, results)
56
+ @driver_response = DriverResponse.new(
57
+ :criteria => request_criteria,
58
+ :next_criteria => next_criteria(request_criteria, results),
59
+ :total_items => results['feed']['openSearch$totalResults']['$t'].to_i,
60
+ :items => results['feed']['entry'].map { |data| parse_video(data) }
61
+ )
62
+ end
63
+
64
+ def next_criteria(request_criteria, results)
65
+ page = results['feed']['openSearch$startIndex']['$t'].to_i
66
+ per_page = results['feed']['openSearch$itemsPerPage']['$t'].to_i
67
+ total = results['feed']['openSearch$totalResults']['$t'].to_i
68
+ if ((page * per_page) < total)
69
+ return RequestCriteria.new({
70
+ :query => request_criteria.query,
71
+ :page => page + 1,
72
+ :per_page => per_page
73
+ })
74
+ end
75
+ end
76
+
77
+ def parse_video(data)
78
+ video_id = data['id']['$t'].split(':').last
79
+ video = APR::ResponseTypes::Video.new
80
+ video.id = video_id
81
+ video.title = data['title']['$t']
82
+ video.description = data['media$group']['media$description']['$t']
83
+ video.thumbnail_url = data['media$group']['media$thumbnail'][0]['url']
84
+ video.url = data['media$group']['media$player']['url']
85
+ video.duration = data['media$group']['yt$duration']['seconds'].to_i
86
+ video.num_views = data['yt$statistics'] ? data['yt$statistics']['viewCount'].to_i : 0
87
+ video.num_likes = data['yt$rating'] ? data['yt$rating']['numLikes'].to_i : 0
88
+ video.num_comments = data['gd$comments'] ? data['gd$comments']['gd$feedLink']['countHint'] : 0
89
+ video.created_date = Date.parse(data['published']['$t'])
90
+ video.username = data['author'][0]['name']['$t']
91
+ video.width = 640
92
+ video.height = 360
93
+
94
+ # Return Types
95
+ video.return_types << APR::ReturnTypes::Url.new(
96
+ :url => video.url,
97
+ :text => video.title,
98
+ :title => video.title
99
+ )
100
+ video.return_types << APR::ReturnTypes::Iframe.new(
101
+ :url => "//www.youtube.com/embed/#{video_id}?feature=oembed",
102
+ :text => video.title,
103
+ :title => video.title,
104
+ :width => 640,
105
+ :height => 360
106
+ )
107
+
108
+ video
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,51 @@
1
+ module ActivePublicResources
2
+ class RequestCriteria
3
+
4
+ SORTS = [
5
+ SORT_RELEVANCE = 'relevance',
6
+ SORT_RECENT = 'recent',
7
+ SORT_POPULAR = 'popular'
8
+ ]
9
+
10
+ CONTENT_FILTERS = [
11
+ CONTENT_FILTER_NONE = 'none',
12
+ CONTENT_FILTER_STRICT = 'strict'
13
+ ]
14
+
15
+ attr_accessor :query, :page, :per_page, :content_filter, :sort, :folder
16
+
17
+ def initialize(args={})
18
+ args.each do |k,v|
19
+ if k.to_s == 'sort' && !SORTS.include?(v)
20
+ raise ArgumentError.new("sort is invalid. Must be in [#{SORTS.join(', ')}]")
21
+ end
22
+ if k.to_s == 'content_filter' && !CONTENT_FILTERS.include?(v)
23
+ raise ArgumentError.new("content_filter is invalid. Must be in [#{CONTENT_FILTERS.join(', ')}]")
24
+ end
25
+ instance_variable_set("@#{k}", v) unless v.nil?
26
+ end
27
+ end
28
+
29
+ def sort=(val)
30
+ unless SORTS.include?(val)
31
+ raise ArgumentError.new("is invalid. Must be in [#{SORTS.join(', ')}]")
32
+ end
33
+ @sort = val
34
+ end
35
+
36
+ def content_filter=(val)
37
+ unless CONTENT_FILTERS.include?(val)
38
+ raise ArgumentError.new("is invalid. Must be in [#{CONTENT_FILTERS.join(', ')}]")
39
+ end
40
+ @content_filter = val
41
+ end
42
+
43
+ def validate_presence!(attr_names)
44
+ attr_names.each do |k|
45
+ if instance_variable_get("@#{k}").blank?
46
+ raise ArgumentError.new("must include #{attr_names.join(', ')}")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,11 @@
1
+ module ActivePublicResources
2
+ module ResponseTypes
3
+ class Exercise < BaseResponseType
4
+ attr_accessor :thumbnail_url, :url
5
+
6
+ def kind
7
+ 'exercise'
8
+ end
9
+ end
10
+ end
11
+ end