music_videos 0.0.12
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 +15 -0
- data/.DS_Store +0 -0
- data/.gitignore +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +2 -0
- data/lib/music_videos.rb +237 -0
- data/lib/music_videos/version.rb +3 -0
- data/music_videos.gemspec +29 -0
- data/spec/music_videos.spec +5 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
Njc0M2YwNmMwOTRhMzZkMjk4YjFlNDVkMTI5Y2U1YjNiNzY1YTc3Yg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
M2FjMDZhNmJjZDIyMDEzZjEyNGFlZWEyNTc5ZGUzNzE2ZjAyYzFjOQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmU0NGVlZjVhODExODQ3MTIwODA2ZTVlY2UyYjdhMmNiNmY3MjEwZGY3NDUx
|
10
|
+
MWZjZjljNWNiMGJiMGUyNWI2ZTA3Mzk3ZTE1N2Q2OTczMDJhOGViZDA5NzMw
|
11
|
+
NGQyMzg4MGRhMTcxNjhhODAzNTA3MDQ4ODAyZTk0NzkwMWFmMzU=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YjRkNzc0OTg1OWQ2MTlmZDljYmU3MmE5YTA1MWZkOGI0MWQxNWZkOTQ2YjAx
|
14
|
+
ZmU2NjcyMTQzYzhjOWEyMzVjNGNlYTZkYmZhMjg5ZjQ1YWI1MDE2OTNhNzA0
|
15
|
+
YTU4Yzg1Yjc4NDIyY2Q5MzRlMzEzOTYxMmRkYjBmZWQzNzI3MjA=
|
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2016 thenotic
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# MusicVideos
|
2
|
+
|
3
|
+
To get an artist's music videos you need a lastfm api key as well as a youtube api key.
|
4
|
+
|
5
|
+
```ruby
|
6
|
+
v = MusicVideos::Find.new(LASTFM_API_KEY, 30711e29ad09c493dad2831eb0bbd08",YOUTUBE_API_KEY)
|
7
|
+
music_videos = v.find_artist_music_videos("gucci mane")
|
8
|
+
|
9
|
+
v.first
|
10
|
+
##<Object:0x007fe4ed1d2638 @artist="chief keef", @title="early morning getting it", @youtube_url="Mt07J2k8myM">
|
11
|
+
```
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'music_videos'
|
19
|
+
```
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install music_videos
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
TODO: Write usage instructions here
|
32
|
+
|
33
|
+
## Contributing
|
34
|
+
|
35
|
+
1. Fork it ( https://github.com/[my-github-username]/music_videos/fork )
|
36
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
37
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
38
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
39
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/music_videos.rb
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'json'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'rmagick'
|
6
|
+
|
7
|
+
module MusicVideos
|
8
|
+
class Find
|
9
|
+
|
10
|
+
def initialize(lastfm_api_key, youtube_api_key)
|
11
|
+
@lastfm_api_key = lastfm_api_key
|
12
|
+
@youtube_api_key = youtube_api_key
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_artist_songs(lastfm_name)
|
16
|
+
tracks = []
|
17
|
+
for i in (0..5)
|
18
|
+
url = "http://ws.audioscrobbler.com/2.0/?api_key=#{@lastfm_api_key}&format=json&artist=#{lastfm_name}&method=artist.getTopTracks&limit=100&page=#{i}"
|
19
|
+
tracks << JSON.parse(open(url).read)['toptracks']['track'].map{|x| x['name']} rescue next
|
20
|
+
end
|
21
|
+
return tracks
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def artist_search(artist_name)
|
26
|
+
url = "http://ws.audioscrobbler.com/2.0/?api_key=#{@lastfm_api_key}&format=json&artist=#{URI.encode(artist_name)}&method=artist.search"
|
27
|
+
lastfm_name = JSON.parse(open(url).read)['results']['artistmatches']['artist'][0]['url'].gsub("http://www.last.fm/music/","")
|
28
|
+
return lastfm_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_clean_tracks(tracks)
|
32
|
+
tracks_clean = tracks.flatten.uniq.reject{|x| x.to_s.downcase.gsub(/\([^()]*\)/,"").scan(/feat|ft|\)|prod| \- |\||\]|dir/).count > 0 rescue next}.map{|x| x.downcase.gsub("in'","ing").gsub(/\([^()]*\)/,"")}.uniq
|
33
|
+
tt = []
|
34
|
+
tracks_clean.compact.each do |x|
|
35
|
+
if x[0].match(/[0-9]/)
|
36
|
+
tt << x.gsub(/^[0-9]*/,'')[1..-1].join(" ").gsub(".","").strip rescue next
|
37
|
+
else
|
38
|
+
tt << x
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return tt
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_youtube_links(artist,tt)
|
45
|
+
l = artist
|
46
|
+
i = 1
|
47
|
+
yy = []
|
48
|
+
checkyy = []
|
49
|
+
hydra = Typhoeus::Hydra.new
|
50
|
+
tt.compact.each do |x|
|
51
|
+
i = i+1;puts i
|
52
|
+
artist = l
|
53
|
+
title = x
|
54
|
+
artist.gsub!('&',' and ')
|
55
|
+
title.gsub!('&',' and ')
|
56
|
+
search ="#{URI.encode(artist.gsub(/\(.*?\)/, ''))}%20#{URI.encode(title.gsub(/\(.*?\)/, ''))}"
|
57
|
+
url = "https://www.googleapis.com/youtube/v3/search?q=#{search}&key=#{@youtube_api_key}&part=snippet&type=video" #api key as 2nd gmail
|
58
|
+
request = Typhoeus::Request.new(url, followlocation: false)
|
59
|
+
request.on_complete do |response|
|
60
|
+
page = JSON.parse(Nokogiri::HTML(response.body)) rescue next
|
61
|
+
first_link = page['items'][0]['id']['videoId'] rescue next
|
62
|
+
y_title = page['items'][0]['snippet']['title'] rescue next
|
63
|
+
x_title = "#{x} #{l}"
|
64
|
+
confidence = x_title.downcase ^ y_title.downcase
|
65
|
+
confidence2 = ccc(artist,title,y_title)
|
66
|
+
if confidence > 0.6 || (confidence2 > 0.65)
|
67
|
+
unless y_title.downcase.match(/lyric|review|cover/)
|
68
|
+
yy << [x, first_link, y_title, title, confidence]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
hydra.queue(request)
|
73
|
+
end
|
74
|
+
hydra.run
|
75
|
+
|
76
|
+
return yy
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def ccc(artist,title,y_title)
|
82
|
+
total_title = "#{artist.gsub(/\(.*?\)/, '').downcase} #{title.downcase}".split(' ')
|
83
|
+
y_title_real = y_title.downcase.split(' ')
|
84
|
+
score = (1.to_f - (total_title - y_title_real).count.to_f / total_title.count.to_f)
|
85
|
+
return score
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def get_previews(yy)
|
90
|
+
yy = yy.uniq{|x| x[1]}
|
91
|
+
k = []
|
92
|
+
hydra = Typhoeus::Hydra.new(max_concurrency: 20)
|
93
|
+
yy.each do |x|
|
94
|
+
url = "http://www.genyoutube.com/preview.php?id=#{x[1]}"
|
95
|
+
request = Typhoeus::Request.new(url, followlocation: false, )
|
96
|
+
request.on_complete do |response|
|
97
|
+
page = Nokogiri::HTML(response.body) rescue next
|
98
|
+
image_url = page.css('img').select{|x| x.attr('src').to_s.include?('/M1')}[0].attr('src').to_s rescue page.css('img')[0].attr('src').to_s rescue next
|
99
|
+
k << [x[0], x[1].gsub('watch.php?v=',''), image_url]
|
100
|
+
end
|
101
|
+
hydra.queue(request)
|
102
|
+
end
|
103
|
+
hydra.run
|
104
|
+
|
105
|
+
return k
|
106
|
+
end
|
107
|
+
|
108
|
+
def vid3(image_url)
|
109
|
+
|
110
|
+
image = Magick::ImageList.new
|
111
|
+
urlimage = open(image_url) # Image Remote URL
|
112
|
+
image.from_blob(urlimage.read)
|
113
|
+
|
114
|
+
width = image.columns/5
|
115
|
+
height = image.rows/5
|
116
|
+
images = []
|
117
|
+
0.upto(5-1) do |x|
|
118
|
+
0.upto(5-1) do |y|
|
119
|
+
images << image.crop( Magick::NorthWestGravity, x*width, y*height, width, height, true)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
diff = images[10].difference(images[11])
|
124
|
+
|
125
|
+
return diff[1]
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
def get_videos(artist, k)
|
131
|
+
videos = []
|
132
|
+
i = 0
|
133
|
+
k.each do |x|
|
134
|
+
i = i+1;puts i
|
135
|
+
size = vid3(x[2]).to_f
|
136
|
+
if size > 0.01
|
137
|
+
videos << [x[0], size, x[1]]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
video_output = []; i = 0
|
141
|
+
videos.each do |x|
|
142
|
+
bb = Object.new
|
143
|
+
bb.class.module_eval { attr_accessor :artist, :title, :youtube_url}
|
144
|
+
bb.artist = artist
|
145
|
+
bb.title = x.flatten[0]
|
146
|
+
bb.youtube_url = x.flatten[2]
|
147
|
+
video_output << bb
|
148
|
+
end
|
149
|
+
return video_output
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
def find_artist_music_videos(artist)
|
156
|
+
lastfm_name = artist_search(artist)
|
157
|
+
tracks = get_artist_songs(lastfm_name)
|
158
|
+
clean_tracks = get_clean_tracks(tracks)
|
159
|
+
youtube_links = get_youtube_links(artist, clean_tracks)
|
160
|
+
previews = get_previews(youtube_links)
|
161
|
+
videos = get_videos(artist, previews)
|
162
|
+
|
163
|
+
return videos
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
class String
|
173
|
+
|
174
|
+
def clean_name
|
175
|
+
return self.gsub(/\(.*?\)/, '').strip
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
# Jaro-Winkler distance
|
180
|
+
# @param [String] other string
|
181
|
+
# @return [Float] distance, normalized between 0.0 (no match) and 1.0 (perfect match)
|
182
|
+
def ^(other)
|
183
|
+
return 1.0 if self == other
|
184
|
+
return 0.0 if self.empty? or other.empty?
|
185
|
+
|
186
|
+
s1 = self.codepoints.to_a
|
187
|
+
s2 = other.codepoints.to_a
|
188
|
+
s1, s2 = s2, s1 if s1.size > s2.size
|
189
|
+
s1s, s2s = s1.size, s2.size
|
190
|
+
m, t = 0.0, 0
|
191
|
+
max_dist = s2s/2 - 1
|
192
|
+
|
193
|
+
m1 = Array.new(s1s, -1)
|
194
|
+
m2 = Array.new(s2s, false)
|
195
|
+
|
196
|
+
# find m
|
197
|
+
s1.each_with_index do |a, ia|
|
198
|
+
lower = ia > max_dist ? ia-max_dist : 0
|
199
|
+
upper = ia+max_dist < s2s ? ia+max_dist : s2s
|
200
|
+
s2[lower..upper].each_with_index do |b, ib|
|
201
|
+
ib += lower
|
202
|
+
if a == b and !m2[ib]
|
203
|
+
m, m1[ia], m2[ib] = m+1, ib, true
|
204
|
+
break
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
return 0.0 if m.zero?
|
210
|
+
|
211
|
+
m1.reduce do |a, b|
|
212
|
+
# if either a or b are nil, that means there was no match
|
213
|
+
# if a > b, that means the previous value is greater than the current
|
214
|
+
# which means it went down
|
215
|
+
if a > -1 and b > -1 and a > b
|
216
|
+
t += (a-b > 1 ? 1 : 2)
|
217
|
+
end
|
218
|
+
b
|
219
|
+
end
|
220
|
+
|
221
|
+
dj = (m/s1s + m/s2s + (m - t/2)/m) / 3
|
222
|
+
|
223
|
+
# winkler adjustment
|
224
|
+
l = 0
|
225
|
+
for i in 0..3
|
226
|
+
if s1[i] != s2[i]
|
227
|
+
l = i
|
228
|
+
break
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# standard weight (p) for winkler == 0.1
|
233
|
+
dj + l*0.1*(1-dj)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "music_videos"
|
7
|
+
spec.version = '0.0.12'
|
8
|
+
spec.authors = ["thenotic"]
|
9
|
+
spec.email = ["liban.aliyusuf@gmail.com"]
|
10
|
+
spec.summary = "Finds Artist Music Videos"
|
11
|
+
spec.description = "Yes"
|
12
|
+
spec.homepage = ""
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
21
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
22
|
+
spec.add_dependency "typhoeus"
|
23
|
+
spec.add_dependency "rmagick"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: music_videos
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.12
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- thenotic
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: typhoeus
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rmagick
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.2'
|
83
|
+
description: 'Yes'
|
84
|
+
email:
|
85
|
+
- liban.aliyusuf@gmail.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- .DS_Store
|
91
|
+
- .gitignore
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE.txt
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- lib/music_videos.rb
|
97
|
+
- lib/music_videos/version.rb
|
98
|
+
- music_videos-0.0.0.gem
|
99
|
+
- music_videos-0.0.1.gem
|
100
|
+
- music_videos-0.0.2.gem
|
101
|
+
- music_videos-0.0.3.gem
|
102
|
+
- music_videos-0.0.5.gem
|
103
|
+
- music_videos-0.0.6.gem
|
104
|
+
- music_videos-0.0.7.gem
|
105
|
+
- music_videos-0.0.8.gem
|
106
|
+
- music_videos.gemspec
|
107
|
+
- spec/music_videos.spec
|
108
|
+
homepage: ''
|
109
|
+
licenses:
|
110
|
+
- MIT
|
111
|
+
metadata: {}
|
112
|
+
post_install_message:
|
113
|
+
rdoc_options: []
|
114
|
+
require_paths:
|
115
|
+
- lib
|
116
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 2.2.2
|
129
|
+
signing_key:
|
130
|
+
specification_version: 4
|
131
|
+
summary: Finds Artist Music Videos
|
132
|
+
test_files:
|
133
|
+
- spec/music_videos.spec
|