yourub 2.0.3 → 3.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.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +0 -4
- data/Gemfile +3 -3
- data/README.md +59 -53
- data/config/yourub.yml +0 -2
- data/lib/yourub/client.rb +92 -16
- data/lib/yourub/config.rb +16 -10
- data/lib/yourub/country_codes.rb +28 -0
- data/lib/yourub/meta_search.rb +116 -43
- data/lib/yourub/rest/categories.rb +6 -5
- data/lib/yourub/rest/request.rb +13 -13
- data/lib/yourub/rest/videos.rb +1 -3
- data/lib/yourub/result.rb +1 -0
- data/lib/yourub/validator.rb +21 -28
- data/lib/yourub/version.rb +2 -2
- data/lib/yourub.rb +1 -0
- data/spec/fixtures/categories_list.json +316 -1
- data/spec/fixtures/search_list.json +182 -1
- data/spec/fixtures/video_with_200_views.json +63 -1
- data/spec/fixtures/videos_list.json +62 -1
- data/spec/support/shared_context_result_load_fixture.rb +12 -1
- data/spec/support/shared_context_result_search_list.rb +18 -4
- data/spec/support/shared_context_result_search_list_with_single_videos.rb +30 -8
- data/spec/support/shared_context_stub_client_connection.rb +0 -8
- data/spec/yourub/client_spec.rb +62 -1
- data/spec/yourub/count_spec.rb +7 -7
- data/spec/yourub/integration.rb +3 -7
- data/spec/yourub/meta_search_spec.rb +93 -56
- data/spec/yourub/rest/categories_spec.rb +30 -6
- data/spec/yourub/rest/request_spec.rb +3 -3
- data/spec/yourub/validator_spec.rb +36 -16
- data/yourub.gemspec +3 -3
- metadata +19 -24
- data/spec/fixtures/categories_list_formatted.json +0 -1
- data/spec/fixtures/single_video.json +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 8d722c005745a329557fad47e8b494e1fd42e18f2e7f2df397a6b467bee9a599
|
|
4
|
+
data.tar.gz: 5e0c6ffc16c546c32b3d21f0354cb19976756b0436e71260e9dcf937aa2af7e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 90b6010eeb9cd2f0311ef0217b152ab800ed038d7ac18557d983b877d8e4653e890f5046490f490c18130a7a871a60919255823cda38920295626391ec7f8241
|
|
7
|
+
data.tar.gz: 58beed04c2d831215d74129c9c41e9029d7daaa671b68c711be1df41076b0b9819f1fb8854a5d922f4bf7aa68633a5f1646853415577e9cf170a8fa936e1eea5
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
[](http://badge.fury.io/rb/yourub)
|
|
2
|
-
|
|
3
|
-
[](https://travis-ci.org/edap/yourub)
|
|
4
|
-
[](https://codeclimate.com/github/edap/yourub)
|
|
2
|
+
|
|
5
3
|
|
|
6
4
|
# Yourub
|
|
7
|
-
Yourub is a gem
|
|
5
|
+
Yourub is a gem for searching YouTube videos using the YouTube Data API v3.
|
|
8
6
|
|
|
9
7
|
## Installation
|
|
10
8
|
|
|
@@ -28,10 +26,8 @@ rails app, create a app/config/yourub.yml file as follow:
|
|
|
28
26
|
```
|
|
29
27
|
yourub_defaults: &yourub_defaults
|
|
30
28
|
developer_key: 'YoUrDevEl0PerKey'
|
|
31
|
-
youtube_api_service_name: 'youtube'
|
|
32
|
-
youtube_api_version: 'v3'
|
|
33
29
|
application_name: "yourub"
|
|
34
|
-
application_version: "0.
|
|
30
|
+
application_version: "0.2"
|
|
35
31
|
log_level: WARN
|
|
36
32
|
|
|
37
33
|
development:
|
|
@@ -45,7 +41,8 @@ test:
|
|
|
45
41
|
```
|
|
46
42
|
|
|
47
43
|
If you want to use it from the console, or in another program, you can simply
|
|
48
|
-
pass an hash containing the needed options
|
|
44
|
+
pass an hash containing the needed options. Change 'yourub' with the name of your application.
|
|
45
|
+
|
|
49
46
|
```ruby
|
|
50
47
|
options = { developer_key: 'mySecretKey',
|
|
51
48
|
application_name: 'yourub',
|
|
@@ -58,18 +55,21 @@ client = Yourub::Client.new(options)
|
|
|
58
55
|
|
|
59
56
|
### Examples
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
**`search`** always requires a non-empty `:query` (YouTube `search.list` uses the `q` parameter). Optional filters narrow results.
|
|
59
|
+
|
|
60
|
+
Recent sports-related videos in Germany (category is matched by **name**, see below):
|
|
61
|
+
|
|
62
62
|
```ruby
|
|
63
|
-
client = Yourub::Client.new
|
|
64
|
-
client.search(country: "DE", category: "sports", order:
|
|
63
|
+
client = Yourub::Client.new(developer_key: "…", application_name: "yourub", application_version: "1.0")
|
|
64
|
+
client.search(query: "highlights", country: "DE", category: "sports", order: "date") do |v|
|
|
65
65
|
puts v
|
|
66
66
|
end
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
Search by text only (optional `country` sets `regionCode` on the API request):
|
|
70
70
|
|
|
71
71
|
```ruby
|
|
72
|
-
client = Yourub::Client.new
|
|
72
|
+
client = Yourub::Client.new(developer_key: "…", application_name: "yourub", application_version: "1.0")
|
|
73
73
|
client.search(query: "aliens") do |v|
|
|
74
74
|
puts v
|
|
75
75
|
end
|
|
@@ -79,59 +79,65 @@ that is the content of the response:
|
|
|
79
79
|
[{"kind"=>"youtube#video", "etag"=>"\"N5Eg36Gl054SUNiWWc-Su3t5O-k/U6AzLXvcnZt2WFqpnq9_dksV7DA\"", "id"=>"NisCkxU544c", "snippet"=>{"publishedAt"=>"2009-04-05T05:20:10.000Z", "channelId"=>"UCCHcEUksSVKsRDH86j77Ntg", "title"=>"Like A Boss (ft. Seth Rogen) - Uncensored Version", "description"=>"http://www.itunes.com/thelonelyisland\r\n\r\nThe new single from The Lonely Island's debut album \"INCREDIBAD\" In stores now!\r\n\r\nFeaturing Seth Rogen.\r\n\r\nThe Lonely Island is Andy Samberg, Akiva Schaffer & Jorma Taccone.", "thumbnails"=>{"default"=>{"url"=>"https://i1.ytimg.com/vi/NisCkxU544c/default.jpg", "width"=>120, "height"=>90}, "medium"=>{"url"=>"https://i1.ytimg.com/vi/NisCkxU544c/mqdefault.jpg", "width"=>320, "height"=>180}, "high"=>{"url"=>"https://i1.ytimg.com/vi/NisCkxU544c/hqdefault.jpg", "width"=>480, "height"=>360}, "standard"=>{"url"=>"https://i1.ytimg.com/vi/NisCkxU544c/sddefault.jpg", "width"=>640, "height"=>480}, "maxres"=>{"url"=>"https://i1.ytimg.com/vi/NisCkxU544c/maxresdefault.jpg", "width"=>1280, "height"=>720}}, "channelTitle"=>"thelonelyisland", "categoryId"=>"23", "liveBroadcastContent"=>"none"}, "statistics"=>{"viewCount"=>"120176425", "likeCount"=>"594592", "dislikeCount"=>"15121", "favoriteCount"=>"0", "commentCount"=>"208109"}}]
|
|
80
80
|
```
|
|
81
81
|
### Available parameters
|
|
82
|
-
`:query` String, example `aliens`
|
|
83
82
|
|
|
84
|
-
`:
|
|
83
|
+
`:query` — **Required.** Non-empty string (after stripping whitespace). Sent as YouTube **`q`**.
|
|
85
84
|
|
|
86
|
-
`:
|
|
85
|
+
`:country` — Optional. One or more [ISO 3166-1 alpha-2](https://www.iso.org/iso-3166-country-codes.html) codes, e.g. `"US"` or `"IT,DE"`. Each code is applied as **`regionCode`** on `search.list`. Codes are validated against `Yourub::CountryCodes::ISO_3166_1_ALPHA2` (also exposed as `Yourub::Validator::COUNTRIES` / `client.countries`).
|
|
87
86
|
|
|
88
|
-
`:
|
|
87
|
+
`:category` — Optional. If the name of a category is set, Yourub resolves a category_id from the name: it calls `list_video_categories`, cached on the client), finds the first item whose title contains your string (case-insensitive). Omit `category` entirely when you do not want a category filter. If the name does not match any category, `ArgumentError` lists `id: title` lines of the available categories.
|
|
89
88
|
|
|
90
|
-
`:
|
|
89
|
+
`:count_filter` — Optional hash, e.g. `{ views: ">= 100" }` or `{ views: "== 600" }` (applied after fetching full video resources).
|
|
91
90
|
|
|
92
|
-
`:
|
|
91
|
+
`:max_results` — Optional integer from 1 to 50.
|
|
93
92
|
|
|
94
|
-
|
|
93
|
+
`:order` — Optional. One of: `date`, `rating`, `relevance`, `title`, `videoCount`, `viewCount`. Default `relevance`.
|
|
95
94
|
|
|
96
95
|
### Methods
|
|
97
|
-
* `search
|
|
96
|
+
* `search` — Runs a YouTube search and yields each video hash that passes optional filters. Requires `:query` and typically a block.
|
|
97
|
+
|
|
98
98
|
```ruby
|
|
99
|
-
client = Yourub::Client.new
|
|
100
|
-
client.search(query: "space missions")
|
|
99
|
+
client = Yourub::Client.new(developer_key: "…", application_name: "yourub", application_version: "1.0")
|
|
100
|
+
client.search(query: "space missions") { |v| puts v["id"] }
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
* `
|
|
104
|
-
|
|
103
|
+
* `get` — Fetches one video’s metadata (`snippet` + `statistics`).
|
|
104
|
+
|
|
105
105
|
```ruby
|
|
106
|
-
client = Yourub::Client.new
|
|
107
|
-
client.
|
|
106
|
+
client = Yourub::Client.new(developer_key: "…", application_name: "yourub", application_version: "1.0")
|
|
107
|
+
client.get("G2b0OIkTraI")
|
|
108
108
|
```
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
|
|
110
|
+
* `list_video_categories`
|
|
111
|
+
|
|
112
|
+
Calls YouTube [`videoCategories.list`](https://developers.google.com/youtube/v3/docs/videoCategories/list) using only **`regionCode`** (via `region_code:`). The API does not use category IDs in this helper; you pass an [ISO 3166-1 alpha-2](https://www.iso.org/iso-3166-country-codes.html) region when you want that country’s category list.
|
|
113
|
+
|
|
114
|
+
**`region_code`:** Optional. If omitted or blank, the request is sent without `regionCode`, which matches the documented default catalog (United States).
|
|
115
|
+
|
|
116
|
+
**`hl`:** Optional. Sets the `hl` query parameter so snippet titles in the response use the requested locale (e.g. Spanish labels for Spain).
|
|
117
|
+
|
|
118
|
+
**Caching:** Responses are cached per client instance, keyed by `region_code` and `hl`, because category metadata changes rarely. Repeat calls with the same arguments return the same in-memory result without another HTTP request.
|
|
119
|
+
|
|
120
|
+
**Return value:** A `Google::Apis::YoutubeV3::VideoCategoryListResponse` (from `google-apis-youtube_v3`). Use `#items` to iterate categories (each has `#id` and `#snippet`).
|
|
121
|
+
|
|
111
122
|
```ruby
|
|
112
|
-
client = Yourub::Client.new
|
|
113
|
-
|
|
123
|
+
client = Yourub::Client.new(options)
|
|
124
|
+
|
|
125
|
+
# Default catalog (documented as US when region is not specified)
|
|
126
|
+
us_like = client.list_video_categories
|
|
127
|
+
|
|
128
|
+
# Explicit region
|
|
129
|
+
de_categories = client.list_video_categories(region_code: "DE")
|
|
130
|
+
|
|
131
|
+
# Region + localized labels
|
|
132
|
+
es_labels = client.list_video_categories(region_code: "ES", hl: "es")
|
|
114
133
|
```
|
|
115
134
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
##TODO
|
|
126
|
-
Here there is a [list](https://developers.google.com/youtube/v3/docs/) of the available methods.
|
|
127
|
-
Currently, this gem implements: [videos.list](https://developers.google.com/youtube/v3/docs/videos/list), [search.list](https://developers.google.com/youtube/v3/docs/search/list) and [videoCategories.list](https://developers.google.com/youtube/v3/docs/videoCategories/list).
|
|
128
|
-
The next methods that will be implemented are [playlist.list](https://developers.google.com/youtube/v3/docs/playlists/list) and [channelis.list](https://developers.google.com/youtube/v3/docs/channels/list)
|
|
129
|
-
## Contributing
|
|
130
|
-
|
|
131
|
-
1. Fork it
|
|
132
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
133
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
134
|
-
4. Run the test, run the spec/yourub/integration.rb file with a valid developer
|
|
135
|
-
key
|
|
136
|
-
5. Push to the branch (`git push origin my-new-feature`)
|
|
137
|
-
4. Create new Pull Request
|
|
135
|
+
* `flush_video_categories_cache!`
|
|
136
|
+
|
|
137
|
+
Clears all cached `list_video_categories` results for this client. Call this if you need to force a fresh fetch (e.g. after a long-lived process or for tests).
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
client.flush_video_categories_cache!
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
|
data/config/yourub.yml
CHANGED
data/lib/yourub/client.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require 'yourub/meta_search'
|
|
2
|
-
require 'google/
|
|
2
|
+
require 'google/apis/youtube_v3'
|
|
3
3
|
|
|
4
4
|
module Yourub
|
|
5
|
-
class Client
|
|
5
|
+
class Client
|
|
6
6
|
include Yourub::MetaSearch
|
|
7
7
|
|
|
8
8
|
attr_reader :videos
|
|
@@ -34,30 +34,106 @@ module Yourub
|
|
|
34
34
|
Yourub::Config.override_config_file(options)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
43
|
-
super(args)
|
|
37
|
+
@service = Google::Apis::YoutubeV3::YouTubeService.new
|
|
38
|
+
@service.key = config.developer_key
|
|
39
|
+
@service.client_options.application_name = config.application_name
|
|
40
|
+
@service.client_options.application_version = config.application_version
|
|
41
|
+
@video_categories_cache = {}
|
|
44
42
|
end
|
|
45
43
|
|
|
46
|
-
# @return countries [Array] contain a list of the available alpha-2 country codes ISO 3166-1
|
|
47
44
|
def countries
|
|
48
45
|
Yourub::Validator.available_countries
|
|
49
46
|
end
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
48
|
+
def list_video_categories(region_code: nil, hl: nil)
|
|
49
|
+
key = video_categories_cache_key(region_code, hl)
|
|
50
|
+
return @video_categories_cache[key] if @video_categories_cache.key?(key)
|
|
51
|
+
|
|
52
|
+
part = "snippet"
|
|
53
|
+
kwargs = {}
|
|
54
|
+
unless region_code.nil? || region_code.to_s.strip.empty?
|
|
55
|
+
kwargs[:region_code] = region_code.to_s.strip.upcase
|
|
56
|
+
end
|
|
57
|
+
kwargs[:hl] = hl.to_s.strip if hl && !hl.to_s.strip.empty?
|
|
58
|
+
|
|
59
|
+
@video_categories_cache[key] = @service.list_video_categories(part, **kwargs)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def flush_video_categories_cache!
|
|
63
|
+
@video_categories_cache.clear
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Compatibility shim used by Yourub::REST::Request
|
|
67
|
+
def execute!(api_method:, parameters:)
|
|
68
|
+
case api_method
|
|
69
|
+
when :search_list
|
|
70
|
+
part = parameters.delete(:part) || parameters.delete('part') || 'snippet'
|
|
71
|
+
opts = normalize_search_params(parameters)
|
|
72
|
+
data = @service.list_searches(part, **opts)
|
|
73
|
+
OpenStruct.new(data: data, status: 200)
|
|
74
|
+
when :videos_list
|
|
75
|
+
part = parameters.delete(:part) || parameters.delete('part') || 'snippet'
|
|
76
|
+
opts = normalize_videos_params(parameters)
|
|
77
|
+
data = @service.list_videos(part, **opts)
|
|
78
|
+
OpenStruct.new(data: data, status: 200)
|
|
79
|
+
when :video_categories_list
|
|
80
|
+
part = parameters.delete(:part) || parameters.delete('part') || 'snippet'
|
|
81
|
+
opts = normalize_categories_params(parameters)
|
|
82
|
+
data = @service.list_video_categories(part, **opts)
|
|
83
|
+
OpenStruct.new(data: data, status: 200)
|
|
84
|
+
else
|
|
85
|
+
raise ArgumentError, "Unsupported api_method #{api_method.inspect}"
|
|
86
|
+
end
|
|
57
87
|
end
|
|
58
88
|
|
|
59
89
|
def config
|
|
60
90
|
Yourub::Config
|
|
61
91
|
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
|
|
95
|
+
def video_categories_cache_key(region_code, hl)
|
|
96
|
+
region = if region_code.nil? || region_code.to_s.strip.empty?
|
|
97
|
+
"_default"
|
|
98
|
+
else
|
|
99
|
+
region_code.to_s.strip.upcase
|
|
100
|
+
end
|
|
101
|
+
hl_part = (hl.nil? || hl.to_s.strip.empty?) ? "" : hl.to_s.strip
|
|
102
|
+
"#{region}\0#{hl_part}"
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def normalize_search_params(params)
|
|
106
|
+
query = params[:q] || params['q'] || ""
|
|
107
|
+
|
|
108
|
+
transform_common_params(params).merge(
|
|
109
|
+
{
|
|
110
|
+
q: query,
|
|
111
|
+
type: params[:type] || params['type'],
|
|
112
|
+
order: params[:order] || params['order'],
|
|
113
|
+
safe_search: params[:safeSearch] || params['safeSearch']
|
|
114
|
+
}.compact
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def normalize_videos_params(params)
|
|
119
|
+
transform_common_params(params).merge(
|
|
120
|
+
{
|
|
121
|
+
id: params[:id] || params['id'],
|
|
122
|
+
fields: params[:fields] || params['fields']
|
|
123
|
+
}.compact
|
|
124
|
+
)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def normalize_categories_params(params)
|
|
128
|
+
transform_common_params(params)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def transform_common_params(params)
|
|
132
|
+
{
|
|
133
|
+
max_results: params[:maxResults] || params['maxResults'],
|
|
134
|
+
region_code: params[:regionCode] || params['regionCode'],
|
|
135
|
+
video_category_id: params[:videoCategoryId] || params['videoCategoryId']
|
|
136
|
+
}.compact
|
|
137
|
+
end
|
|
62
138
|
end
|
|
63
139
|
end
|
data/lib/yourub/config.rb
CHANGED
|
@@ -9,17 +9,18 @@ module Yourub
|
|
|
9
9
|
extend Forwardable
|
|
10
10
|
attr_accessor :config
|
|
11
11
|
|
|
12
|
-
def_delegators :@config, :developer_key
|
|
13
|
-
:
|
|
12
|
+
def_delegators :@config, :developer_key, :log_level,
|
|
13
|
+
:application_name, :application_version
|
|
14
14
|
|
|
15
15
|
MANDATORY_KEYS = [:developer_key, :application_name, :application_version, :log_level]
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
# Only these keys are read from YAML or from +Client.new(opts)+. The API is always
|
|
18
|
+
# YouTube Data API v3 via google-apis-youtube_v3 (+YouTubeService+).
|
|
19
|
+
USER_CONFIG_KEYS = %i[developer_key application_name application_version log_level].freeze
|
|
20
|
+
|
|
21
21
|
def load!(file_path, environment)
|
|
22
|
-
|
|
22
|
+
raw = YAML.load_file(file_path)[environment]
|
|
23
|
+
@config = OpenStruct.new(prune_config_hash(raw))
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
def override_config_file(hash)
|
|
@@ -29,8 +30,15 @@ module Yourub
|
|
|
29
30
|
|
|
30
31
|
private
|
|
31
32
|
|
|
33
|
+
def prune_config_hash(h)
|
|
34
|
+
return {} unless h.is_a?(Hash)
|
|
35
|
+
|
|
36
|
+
h.transform_keys { |k| k.to_sym }.slice(*USER_CONFIG_KEYS)
|
|
37
|
+
end
|
|
38
|
+
|
|
32
39
|
def valid_options(hash)
|
|
33
|
-
|
|
40
|
+
normalized = hash.transform_keys { |k| k.to_sym }
|
|
41
|
+
opt = default_options.merge(normalized.slice(*USER_CONFIG_KEYS))
|
|
34
42
|
raise ArgumentError.new(
|
|
35
43
|
"please provide an hash containing at least a valid developer_key"
|
|
36
44
|
) if opt[:developer_key].empty?
|
|
@@ -40,8 +48,6 @@ private
|
|
|
40
48
|
def default_options
|
|
41
49
|
{
|
|
42
50
|
developer_key: "",
|
|
43
|
-
youtube_api_service_name: "youtube",
|
|
44
|
-
youtube_api_version: "v3",
|
|
45
51
|
application_name: "yourub",
|
|
46
52
|
application_version: Yourub::VERSION,
|
|
47
53
|
log_level: "WARN"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Yourub
|
|
2
|
+
# ISO 3166-1 alpha-2 codes used for YouTube +regionCode+ style parameters.
|
|
3
|
+
#
|
|
4
|
+
# Derived from the +slim-2.csv+ dataset:
|
|
5
|
+
# https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes (249 entries).
|
|
6
|
+
module CountryCodes
|
|
7
|
+
ISO_3166_1_ALPHA2 = %w[
|
|
8
|
+
AD AE AF AG AI AL AM AO AQ AR AS AT AU AW
|
|
9
|
+
AX AZ BA BB BD BE BF BG BH BI BJ BL BM BN
|
|
10
|
+
BO BQ BR BS BT BV BW BY BZ CA CC CD CF CG
|
|
11
|
+
CH CI CK CL CM CN CO CR CU CV CW CX CY CZ
|
|
12
|
+
DE DJ DK DM DO DZ EC EE EG EH ER ES ET FI
|
|
13
|
+
FJ FK FM FO FR GA GB GD GE GF GG GH GI GL
|
|
14
|
+
GM GN GP GQ GR GS GT GU GW GY HK HM HN HR
|
|
15
|
+
HT HU ID IE IL IM IN IO IQ IR IS IT JE JM
|
|
16
|
+
JO JP KE KG KH KI KM KN KP KR KW KY KZ LA
|
|
17
|
+
LB LC LI LK LR LS LT LU LV LY MA MC MD ME
|
|
18
|
+
MF MG MH MK ML MM MN MO MP MQ MR MS MT MU
|
|
19
|
+
MV MW MX MY MZ NA NC NE NF NG NI NL NO NP
|
|
20
|
+
NR NU NZ OM PA PE PF PG PH PK PL PM PN PR
|
|
21
|
+
PS PT PW PY QA RE RO RS RU RW SA SB SC SD
|
|
22
|
+
SE SG SH SI SJ SK SL SM SN SO SR SS ST SV
|
|
23
|
+
SX SY SZ TC TD TF TG TH TJ TK TL TM TN TO
|
|
24
|
+
TR TT TV TW TZ UA UG UM US UY UZ VA VC VE
|
|
25
|
+
VG VI VN VU WF WS YE YT ZA ZM ZW
|
|
26
|
+
].freeze
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/yourub/meta_search.rb
CHANGED
|
@@ -11,35 +11,31 @@ module Yourub
|
|
|
11
11
|
# client.search(country: "DE", category: "sports", order: 'date')
|
|
12
12
|
def search(criteria)
|
|
13
13
|
begin
|
|
14
|
+
Yourub::CountFilter.filter = nil
|
|
15
|
+
|
|
14
16
|
@api_options= {
|
|
15
17
|
:part => 'snippet',
|
|
16
18
|
:type => 'video',
|
|
17
19
|
:order => 'relevance',
|
|
18
20
|
:safeSearch => 'none',
|
|
19
|
-
|
|
21
|
+
:q => nil
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
@categories = []
|
|
21
25
|
@count_filter = {}
|
|
26
|
+
|
|
27
|
+
@api_options[:q] = criteria[:query] if criteria[:query]
|
|
28
|
+
|
|
22
29
|
@criteria = Yourub::Validator.confirm(criteria)
|
|
23
30
|
search_by_criteria do |result|
|
|
24
31
|
yield result
|
|
25
32
|
end
|
|
26
33
|
rescue ArgumentError => e
|
|
27
34
|
Yourub.logger.error "#{e}"
|
|
35
|
+
raise
|
|
28
36
|
end
|
|
29
37
|
end
|
|
30
38
|
|
|
31
|
-
# return the number of times a video was watched
|
|
32
|
-
# @param video_id[Integer]
|
|
33
|
-
# @example
|
|
34
|
-
# client = Yourub::Client.new
|
|
35
|
-
# client.get_views("G2b0OIkTraI")
|
|
36
|
-
def get_views(video_id)
|
|
37
|
-
params = { :id => video_id, :part => 'statistics' }
|
|
38
|
-
request = Yourub::REST::Videos.list(self,params)
|
|
39
|
-
v = Yourub::Result.format(request).first
|
|
40
|
-
v ? Yourub::CountFilter.get_views_count(v) : nil
|
|
41
|
-
end
|
|
42
|
-
|
|
43
39
|
# return an hash containing the metadata for the given video
|
|
44
40
|
# @param video_id[Integer]
|
|
45
41
|
# @example
|
|
@@ -61,62 +57,84 @@ private
|
|
|
61
57
|
end
|
|
62
58
|
end
|
|
63
59
|
|
|
64
|
-
def merge_criteria_with_api_options
|
|
65
|
-
mappings = {query: :q, max_results: :maxResults, country: :regionCode}
|
|
66
|
-
@api_options.merge! @criteria
|
|
67
|
-
@api_options.keys.each do |k|
|
|
68
|
-
@api_options[ mappings[k] ] = @api_options.delete(k) if mappings[k]
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
60
|
|
|
72
|
-
def
|
|
73
|
-
if @criteria
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def retrieve_videos
|
|
80
|
-
consume_criteria do |criteria|
|
|
81
|
-
begin
|
|
82
|
-
req = Yourub::REST::Search.list(self, criteria)
|
|
83
|
-
get_details_for_each_video(req) do |v|
|
|
84
|
-
yield v
|
|
85
|
-
end
|
|
86
|
-
rescue StandardError => e
|
|
87
|
-
Yourub.logger.error "Error #{e} retrieving videos for the criteria: #{criteria.to_s}"
|
|
88
|
-
end
|
|
89
|
-
end
|
|
61
|
+
def merge_criteria_with_api_options
|
|
62
|
+
@api_options[:q] = @criteria[:query] if @criteria[:query]
|
|
63
|
+
@api_options[:maxResults] = @criteria[:max_results] if @criteria[:max_results]
|
|
64
|
+
@api_options[:order] = @criteria[:order] if @criteria[:order]
|
|
90
65
|
end
|
|
91
66
|
|
|
92
67
|
def consume_criteria
|
|
93
|
-
to_consume = @api_options
|
|
94
68
|
if @criteria[:country]
|
|
95
69
|
@criteria[:country].each do |country|
|
|
70
|
+
to_consume = @api_options.dup
|
|
96
71
|
to_consume[:regionCode] = country
|
|
97
72
|
consume_categories(to_consume) do |cat|
|
|
98
73
|
yield cat
|
|
99
74
|
end
|
|
100
75
|
end
|
|
101
76
|
else
|
|
102
|
-
|
|
77
|
+
consume_categories(@api_options.dup) do |cat|
|
|
78
|
+
yield cat
|
|
79
|
+
end
|
|
103
80
|
end
|
|
104
81
|
end
|
|
105
82
|
|
|
106
83
|
def consume_categories(to_consume)
|
|
107
84
|
if @categories.size > 0
|
|
108
85
|
@categories.each do |cat|
|
|
109
|
-
|
|
110
|
-
|
|
86
|
+
current_params = to_consume.dup
|
|
87
|
+
current_params[:videoCategoryId] = cat.keys[0].to_i
|
|
88
|
+
yield current_params
|
|
111
89
|
end
|
|
112
90
|
else
|
|
113
91
|
yield to_consume
|
|
114
92
|
end
|
|
115
93
|
end
|
|
116
94
|
|
|
95
|
+
def retrieve_categories
|
|
96
|
+
return unless @criteria.key?(:category)
|
|
97
|
+
|
|
98
|
+
term = @criteria[:category].to_s.strip
|
|
99
|
+
if term.empty?
|
|
100
|
+
@categories = []
|
|
101
|
+
return
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
if term.casecmp("all").zero?
|
|
105
|
+
raise ArgumentError,
|
|
106
|
+
'category "all" is not supported; omit :category to search without a video category filter.'
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
region_code = region_code_for_category_catalog
|
|
110
|
+
list = list_video_categories(region_code: region_code)
|
|
111
|
+
items = video_category_list_items(list)
|
|
112
|
+
match = find_category_item_by_partial_name(items, term)
|
|
113
|
+
if match.nil?
|
|
114
|
+
raise ArgumentError, category_not_found_message(term, items)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
cid = video_category_item_id(match)
|
|
118
|
+
@categories = [{ cid.to_s => term }]
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def retrieve_videos
|
|
122
|
+
consume_criteria do |criteria|
|
|
123
|
+
begin
|
|
124
|
+
req = Yourub::REST::Search.list(self, criteria)
|
|
125
|
+
get_details_for_each_video(req) do |v|
|
|
126
|
+
yield v
|
|
127
|
+
end
|
|
128
|
+
rescue StandardError => e
|
|
129
|
+
Yourub.logger.error "Error #{e} retrieving videos for the criteria: #{criteria.to_s}"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
|
|
117
135
|
def get_details_for_each_video(video_list)
|
|
118
136
|
video_list.data.items.each do |video_item|
|
|
119
|
-
v = Yourub::REST::Videos.single_video(self, video_item.id.
|
|
137
|
+
v = Yourub::REST::Videos.single_video(self, video_item.id.video_id)
|
|
120
138
|
v = Yourub::Result.format(v)
|
|
121
139
|
if v && Yourub::CountFilter.accept?(v.first)
|
|
122
140
|
yield v.first
|
|
@@ -130,5 +148,60 @@ private
|
|
|
130
148
|
end
|
|
131
149
|
end
|
|
132
150
|
|
|
151
|
+
def region_code_for_category_catalog
|
|
152
|
+
return nil unless @criteria[:country].is_a?(Array) && @criteria[:country].any?
|
|
153
|
+
|
|
154
|
+
@criteria[:country].first
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def video_category_list_items(list)
|
|
158
|
+
raw =
|
|
159
|
+
if list.respond_to?(:items)
|
|
160
|
+
list.items
|
|
161
|
+
elsif list.is_a?(Hash)
|
|
162
|
+
list["items"]
|
|
163
|
+
end
|
|
164
|
+
Array(raw)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def find_category_item_by_partial_name(items, search_term)
|
|
168
|
+
needle = search_term.to_s.strip.downcase
|
|
169
|
+
return nil if needle.empty?
|
|
170
|
+
|
|
171
|
+
items.find do |item|
|
|
172
|
+
title = video_category_item_title(item).to_s.downcase
|
|
173
|
+
title.include?(needle)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def video_category_item_title(item)
|
|
178
|
+
if item.respond_to?(:snippet) && item.snippet.respond_to?(:title)
|
|
179
|
+
item.snippet.title
|
|
180
|
+
elsif item.is_a?(Hash)
|
|
181
|
+
item.dig("snippet", "title")
|
|
182
|
+
else
|
|
183
|
+
""
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def video_category_item_id(item)
|
|
188
|
+
if item.respond_to?(:id)
|
|
189
|
+
id = item.id
|
|
190
|
+
id.is_a?(Hash) ? id["videoId"] || id[:videoId] : id
|
|
191
|
+
elsif item.is_a?(Hash)
|
|
192
|
+
item["id"]
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def category_not_found_message(term, items)
|
|
197
|
+
lines = items.map do |it|
|
|
198
|
+
"#{video_category_item_id(it)}: #{video_category_item_title(it)}"
|
|
199
|
+
end
|
|
200
|
+
<<~MSG.chomp
|
|
201
|
+
category not found, this is the list of the available categories:
|
|
202
|
+
#{lines.join("\n")}
|
|
203
|
+
MSG
|
|
204
|
+
end
|
|
205
|
+
|
|
133
206
|
end
|
|
134
207
|
end
|