purdie 0.0.11 → 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 +4 -4
- data/.gitignore +2 -1
- data/.travis.yml +1 -0
- data/README.md +25 -11
- data/_config/defaults.yaml +0 -21
- data/_config/licenses.yaml +33 -0
- data/features/duff-credentials.feature +33 -0
- data/features/flickr-album.feature +1 -1
- data/features/flickr-with-lookups.feature +29 -0
- data/features/rfm.feature +2 -2
- data/features/step_definitions/purdie_steps.rb +26 -0
- data/features/support/fixtures/_config/purdie.yaml +1 -1
- data/features/support/fixtures/vcr/A_URL_we_don_t_understand/Handle_a_URL_we_don_t_recognise.yml +15 -15
- data/features/support/fixtures/vcr/First_contact_with_the_Real_World/Generate_YAML_for_the_Raw_Funk_Maharishi.yml +59 -53
- data/features/support/fixtures/vcr/Flickr/Generate_Flickr_YAML.yml +15 -15
- data/features/support/fixtures/vcr/Flickr/Generate_Flickr_YAML_with_lookups.yml +123 -0
- data/features/support/fixtures/vcr/Flickr_album/Generate_Flickr_YAML_for_an_album.yml +137 -137
- data/features/support/fixtures/vcr/Handle_comments/Handle_comments_in_a_source_file.yml +21 -28
- data/features/support/fixtures/vcr/Missing_or_bad_credentials/Bad_credentials_for_multiple_services.yml +156 -0
- data/features/support/fixtures/vcr/Purdie/Generate_several_YAML.yml +37 -36
- data/features/support/fixtures/vcr/Select_a_file_to_process/Choose_file_to_process.yml +7 -7
- data/features/support/fixtures/vcr/Set_Flickr_picturesize/Generate_Flickr_YAML.yml +16 -16
- data/features/support/fixtures/vcr/Soundcloud/Generate_SoundCloud_YAML.yml +7 -7
- data/features/support/fixtures/vcr/Soundcloud/Generate_SoundCloud_YAML_for_multiple_tracks.yml +14 -14
- data/features/support/fixtures/vcr/Soundcloud_set/Generate_YAML_for_a_SoundCloud_set.yml +58 -33
- data/features/support/fixtures/vcr/Vimeo/Generate_Vimeo_YAML.yml +8 -8
- data/features/support/fixtures/vcr/Vimeo_albums/Generate_YAML_for_a_Vimeo_album.yml +210 -0
- data/features/support/fixtures/vcr/YouTube/Generate_YouTube_YAML.yml +9 -9
- data/features/support/fixtures/vcr/YouTube_playlists/Generate_YAML_for_a_YouTube_playlist.yml +2503 -0
- data/features/vimeo-albums.feature +27 -0
- data/features/youtube-playlist.feature +54 -0
- data/lib/purdie/bernard.rb +24 -1
- data/lib/purdie/cli.rb +4 -0
- data/lib/purdie/exceptions.rb +20 -0
- data/lib/purdie/helpers.rb +17 -2
- data/lib/purdie/ingester.rb +15 -10
- data/lib/purdie/license_manager.rb +41 -0
- data/lib/purdie/services/flickr.rb +14 -2
- data/lib/purdie/services/soundcloud.rb +13 -4
- data/lib/purdie/services/vimeo.rb +13 -6
- data/lib/purdie/services/youtube.rb +46 -4
- data/lib/purdie/source_list.rb +10 -16
- data/lib/purdie/version.rb +1 -1
- data/lib/purdie.rb +10 -0
- data/spec/duff_keys_spec.rb +115 -0
- data/spec/helpers_spec.rb +12 -5
- data/spec/license_manager_spec.rb +20 -0
- data/spec/services/flickr_spec.rb +24 -15
- data/spec/services/soundcloud_spec.rb +2 -2
- data/spec/services/vimeo_spec.rb +6 -6
- data/spec/services/youtube_spec.rb +14 -1
- data/spec/source_list_spec.rb +14 -4
- data/spec/spec_helper.rb +32 -0
- data/spec/support/fixtures/vimeo.vids +1 -0
- data/spec/vcr/Purdie_Services_Flickr/do_the_local_config_lookups/looks_up_the_default_title.yml +123 -0
- data/spec/vcr/Purdie_Services_Flickr/falls_back_to_the_default_photographer_name.yml +20 -19
- data/spec/vcr/Purdie_Services_Flickr/ingests_data_for_a_photo_without_a_specific_photographer_tag.yml +20 -21
- data/spec/vcr/Purdie_Services_Flickr/licenses_items_correctly.yml +180 -0
- data/spec/vcr/Purdie_Services_Vimeo/ingests_a_video.yml +8 -8
- data/spec/vcr/Purdie_Services_Vimeo/resolve_an_album/resolves_an_album_from_a_URL.yml +59 -0
- data/spec/vcr/Purdie_Services_YouTube/gets_the_correct_license.yml +976 -0
- data/spec/vcr/Purdie_Services_YouTube/resolve_a_playlist/resolves_a_playlist_from_a_shitty_YouTube_URL.yml +970 -0
- metadata +37 -4
- data/_data/flickr.yaml +0 -4
- data/_data/soundcloud.yaml +0 -7
@@ -0,0 +1,27 @@
|
|
1
|
+
@vcr
|
2
|
+
Feature: Vimeo albums
|
3
|
+
|
4
|
+
@announce-stdout
|
5
|
+
Scenario: Generate YAML for a Vimeo album
|
6
|
+
Given a file named "_sources/vimeo" with:
|
7
|
+
"""
|
8
|
+
https://vimeo.com/album/3296736
|
9
|
+
"""
|
10
|
+
When I successfully run `purdie fetch`
|
11
|
+
Then a file named "_data/vimeo.yaml" should exist
|
12
|
+
And the file "_data/vimeo.yaml" should contain:
|
13
|
+
"""
|
14
|
+
---
|
15
|
+
- title: Safety On Board
|
16
|
+
id: 111356018
|
17
|
+
license: Attribution-NonCommercial-ShareAlike
|
18
|
+
license_url: http://creativecommons.org/licenses/by-nc-sa/3.0/
|
19
|
+
- title: Trapped In Hawaii
|
20
|
+
id: 110133117
|
21
|
+
license: Attribution-NonCommercial-ShareAlike
|
22
|
+
license_url: http://creativecommons.org/licenses/by-nc-sa/3.0/
|
23
|
+
- title: Discotheque Metamorphosis
|
24
|
+
id: 110132671
|
25
|
+
license: Attribution-NonCommercial-ShareAlike
|
26
|
+
license_url: http://creativecommons.org/licenses/by-nc-sa/3.0/
|
27
|
+
"""
|
@@ -0,0 +1,54 @@
|
|
1
|
+
@vcr
|
2
|
+
Feature: YouTube playlists
|
3
|
+
|
4
|
+
@announce-stdout
|
5
|
+
@announce-stderr
|
6
|
+
Scenario: Generate YAML for a YouTube playlist
|
7
|
+
Given a file named "_sources/youtube" with:
|
8
|
+
"""
|
9
|
+
https://www.youtube.com/playlist?list=PLuPLM2FI60-OIgFTc9YCrGgH5XWGT6znV
|
10
|
+
"""
|
11
|
+
When I successfully run `purdie fetch`
|
12
|
+
Then a file named "_data/youtube.yaml" should exist
|
13
|
+
And the file "_data/youtube.yaml" should contain:
|
14
|
+
"""
|
15
|
+
---
|
16
|
+
- title: Chuck Rainey - Bernard Purdie Project "Love the One Your With...Drink Muddy
|
17
|
+
Water"
|
18
|
+
id: U23Ezi6q30E
|
19
|
+
license: YouTube
|
20
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
21
|
+
- title: Godfathers of Groove Bernard "Pretty" Purdie,Grant Green Jr,Ruben Wilson
|
22
|
+
March 30-31
|
23
|
+
id: _ZbWTg8G6eM
|
24
|
+
license: YouTube
|
25
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
26
|
+
- title: Pretty Purdie - Good Livin' (Good Lovin') HQ
|
27
|
+
id: zJnnNZk9o0Q
|
28
|
+
license: YouTube
|
29
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
30
|
+
- title: Hot Popcorn Bernard Purdie
|
31
|
+
id: baQe6MoSAHw
|
32
|
+
license: YouTube
|
33
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
34
|
+
- title: Red Beans and Rice Bernard Purdie
|
35
|
+
id: NLFP1T1e2BA
|
36
|
+
license: YouTube
|
37
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
38
|
+
- title: Bernard Purdie - Ad Lib
|
39
|
+
id: E9E0WxLbqVA
|
40
|
+
license: YouTube
|
41
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
42
|
+
- title: Bernard Purdie - Black Purd's Theme
|
43
|
+
id: wa-K4LouFVk
|
44
|
+
license: YouTube
|
45
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
46
|
+
- title: Bernard "Pretty" Purdie - Heavy Soul Slinger
|
47
|
+
id: LatmKZQd7-s
|
48
|
+
license: YouTube
|
49
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
50
|
+
- title: 'Bernard "Pretty" Purdie: Funky Grooves in Japan'
|
51
|
+
id: P842kq0bnOc
|
52
|
+
license: YouTube
|
53
|
+
license_url: https://www.youtube.com/static?gl=GB&template=terms
|
54
|
+
"""
|
data/lib/purdie/bernard.rb
CHANGED
@@ -15,6 +15,8 @@ module Purdie
|
|
15
15
|
rescue Errno::ENOENT
|
16
16
|
@sources = nil
|
17
17
|
end
|
18
|
+
|
19
|
+
Purdie.debug @config.inspect
|
18
20
|
end
|
19
21
|
|
20
22
|
def source_file= path
|
@@ -26,6 +28,9 @@ module Purdie
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def process list
|
31
|
+
bad_creds = []
|
32
|
+
bad_licenses = {}
|
33
|
+
|
29
34
|
list.each do |line|
|
30
35
|
next if line[0] == '#'
|
31
36
|
next if line == ''
|
@@ -34,11 +39,29 @@ module Purdie
|
|
34
39
|
print "Processing #{line.strip}... "
|
35
40
|
grab line
|
36
41
|
rescue NoMethodError => nme
|
37
|
-
puts "unrecognised URL [#{line}]" if nme.
|
42
|
+
puts "unrecognised URL [#{line}]" if nme.status == "undefined method `ingest' for nil:NilClass"
|
43
|
+
rescue Purdie::LicenseException => le
|
44
|
+
bad_licenses[Purdie.basename le.service].push le.name rescue bad_licenses[Purdie.basename le.service] = [le.name]
|
45
|
+
puts 'fail'
|
46
|
+
rescue Purdie::CredentialsException => ce
|
47
|
+
bad_creds.push Purdie.basename(ce.service)
|
48
|
+
puts 'fail'
|
38
49
|
else
|
39
50
|
puts 'done'
|
40
51
|
end
|
41
52
|
end
|
53
|
+
|
54
|
+
if bad_creds.any?
|
55
|
+
raise Purdie::CredentialsException.new self, "Missing or duff credentials for: #{bad_creds.uniq.join ', '}"
|
56
|
+
end
|
57
|
+
|
58
|
+
if bad_licenses.any?
|
59
|
+
bad = bad_licenses.map { |k,v| "#{k}: #{v.uniq.join ', '}" }.join '; '
|
60
|
+
message = "Unknown licenses: #{bad}"
|
61
|
+
message += "\n"
|
62
|
+
message += 'Please consider adding the details for these licenses at https://github.com/rawfunkmaharishi/purdie/blob/master/_config/licenses.yaml'
|
63
|
+
raise Purdie::PurdieException.new message
|
64
|
+
end
|
42
65
|
end
|
43
66
|
|
44
67
|
def fetch
|
data/lib/purdie/cli.rb
CHANGED
@@ -15,12 +15,16 @@ module Purdie
|
|
15
15
|
def fetch
|
16
16
|
b = Bernard.new
|
17
17
|
b.source_file = options[:source_file] if options[:source_file]
|
18
|
+
|
18
19
|
begin
|
19
20
|
b.fetch
|
20
21
|
rescue Exception => e
|
22
|
+
$stderr.puts "\n"
|
21
23
|
$stderr.puts e.message
|
22
24
|
# exit 1
|
23
25
|
end
|
24
26
|
end
|
27
|
+
|
28
|
+
default_task :fetch
|
25
29
|
end
|
26
30
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'purdie'
|
2
|
+
|
3
|
+
module Purdie
|
4
|
+
class CredentialsException < Exception
|
5
|
+
attr_reader :service, :message
|
6
|
+
|
7
|
+
def initialize service, message
|
8
|
+
@service = service
|
9
|
+
@message = message
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class PurdieException < Exception
|
14
|
+
attr_reader :message
|
15
|
+
|
16
|
+
def initialize message
|
17
|
+
@message = message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/purdie/helpers.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Purdie
|
2
2
|
def Purdie.strip_scheme url
|
3
|
-
url.match(/http[s]
|
3
|
+
url.match(/http[s]?:(.*)/)[1]
|
4
4
|
end
|
5
5
|
|
6
6
|
def Purdie.sanitise_url url
|
@@ -14,11 +14,26 @@ module Purdie
|
|
14
14
|
when /\?.*v=/
|
15
15
|
return CGI.parse(URI.parse(url).query)['v'].first
|
16
16
|
else
|
17
|
-
Purdie.sanitise_url
|
17
|
+
sanitised = Purdie.sanitise_url url
|
18
|
+
parts = sanitised.split('/')
|
19
|
+
parts.reverse.each do |part|
|
20
|
+
next if ['in', 'photostream'].include? part
|
21
|
+
return part.to_i
|
22
|
+
end
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
26
|
def Purdie.basename obj
|
27
|
+
if obj.class == Class
|
28
|
+
return obj.name.to_s.split('::').last
|
29
|
+
end
|
30
|
+
|
22
31
|
obj.class.name.to_s.split('::').last
|
23
32
|
end
|
33
|
+
|
34
|
+
def Purdie.debug message
|
35
|
+
File.open '../../wtf.log', 'w' do |f|
|
36
|
+
f.write message
|
37
|
+
end
|
38
|
+
end
|
24
39
|
end
|
data/lib/purdie/ingester.rb
CHANGED
@@ -7,6 +7,8 @@ module Purdie
|
|
7
7
|
INGESTERS = []
|
8
8
|
|
9
9
|
def self.included base
|
10
|
+
# Voodoo: http://stackoverflow.com/questions/10692961/inheriting-class-methods-from-mixins
|
11
|
+
base.extend ClassMethods
|
10
12
|
INGESTERS.push base
|
11
13
|
end
|
12
14
|
|
@@ -14,7 +16,8 @@ module Purdie
|
|
14
16
|
INGESTERS
|
15
17
|
end
|
16
18
|
|
17
|
-
def initialize config
|
19
|
+
def initialize config = nil
|
20
|
+
config = Config.new unless config
|
18
21
|
@config = config
|
19
22
|
@items = []
|
20
23
|
|
@@ -22,17 +25,13 @@ module Purdie
|
|
22
25
|
end
|
23
26
|
|
24
27
|
def configure
|
25
|
-
@output_file = "#{Purdie.basename(self).downcase}.yaml"
|
26
|
-
# This still feels like such a hack
|
28
|
+
@output_file = "#{@config['output_dir']}/#{Purdie.basename(self).downcase}.yaml"
|
27
29
|
specific_config = @config['services'][Purdie.basename self] rescue nil
|
28
30
|
|
29
31
|
if specific_config
|
30
|
-
|
31
|
-
|
32
|
-
@output_file = File.basename(@config['services'][Purdie.basename self]['output_file'])
|
32
|
+
specific_config.each_pair do |key, value|
|
33
|
+
self.instance_variable_set("@#{key}", value)
|
33
34
|
end
|
34
|
-
|
35
|
-
@size = specific_config['size'] if specific_config['size']
|
36
35
|
end
|
37
36
|
end
|
38
37
|
|
@@ -58,11 +57,17 @@ module Purdie
|
|
58
57
|
|
59
58
|
def write
|
60
59
|
if self.has_items?
|
61
|
-
FileUtils.mkdir_p @
|
62
|
-
File.open
|
60
|
+
FileUtils.mkdir_p File.dirname @output_file
|
61
|
+
File.open @output_file, 'w' do |f|
|
63
62
|
f.write self.to_yaml
|
64
63
|
end
|
65
64
|
end
|
66
65
|
end
|
66
|
+
|
67
|
+
module ClassMethods
|
68
|
+
def resolve url
|
69
|
+
[url]
|
70
|
+
end
|
71
|
+
end
|
67
72
|
end
|
68
73
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'purdie'
|
2
|
+
|
3
|
+
module Purdie
|
4
|
+
class LicenseManager
|
5
|
+
LOOKUPS = YAML.load File.read File.join(File.dirname(__FILE__), '..', '..', '_config/licenses.yaml')
|
6
|
+
|
7
|
+
def self.get service, raw_name
|
8
|
+
License.new service, raw_name, LOOKUPS[Purdie.basename service][raw_name]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class License
|
13
|
+
def initialize service, raw_name, values
|
14
|
+
raise LicenseException.new service, raw_name unless values
|
15
|
+
@values = values
|
16
|
+
end
|
17
|
+
|
18
|
+
def [] key
|
19
|
+
@values[key]
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing method_name, *args
|
23
|
+
mname = method_name.to_s
|
24
|
+
|
25
|
+
if @values.include? mname
|
26
|
+
@values[mname]
|
27
|
+
else
|
28
|
+
raise NoMethodError
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class LicenseException < Exception
|
34
|
+
attr_reader :service, :name
|
35
|
+
|
36
|
+
def initialize service, name
|
37
|
+
@service = service
|
38
|
+
@name = name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -21,7 +21,13 @@ module Purdie
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def get url
|
24
|
-
|
24
|
+
begin
|
25
|
+
flickr.photos.getInfo photo_id: Purdie.get_id(url)
|
26
|
+
rescue FlickRaw::FlickrAppNotConfigured => fanc
|
27
|
+
raise Purdie::CredentialsException.new self, 'missing' if fanc.message == 'No API key or secret defined!'
|
28
|
+
rescue FlickRaw::FailedResponse => fr
|
29
|
+
raise Purdie::CredentialsException.new self, 'duff' if fr.message == "'flickr.photos.getInfo' - Invalid API Key (Key has invalid format)"
|
30
|
+
end
|
25
31
|
end
|
26
32
|
|
27
33
|
def distill url
|
@@ -32,12 +38,16 @@ module Purdie
|
|
32
38
|
results['title'] = @config['default_title'] if photo['title'] == ''
|
33
39
|
results['date'] = photo['dates']['taken'].split(' ')[0]
|
34
40
|
results['photo_page'] = photo['urls'][0]['_content']
|
41
|
+
# results['photo_page'] = url
|
35
42
|
results['photo_url'] = FlickRaw.send(Flickr.url_for_size(@size), photo)
|
36
43
|
|
37
44
|
license = licenses.select {|l| l['id'] == photo['license']}[0]
|
38
45
|
results['license'] = license['name'].split(' License')[0]
|
39
46
|
results['license_url'] = license['url']
|
40
47
|
|
48
|
+
# WTF?
|
49
|
+
# results.attach_license self, photo['license']
|
50
|
+
|
41
51
|
begin
|
42
52
|
snapper = photo['tags'].select { |t| t['raw'] =~ /photographer/ }[0]
|
43
53
|
results['photographer'] = snapper['raw'].split(':')[1]
|
@@ -82,7 +92,9 @@ module Purdie
|
|
82
92
|
end
|
83
93
|
end
|
84
94
|
|
85
|
-
def self.
|
95
|
+
def self.resolve url
|
96
|
+
return [url] unless url =~ /\/sets\//
|
97
|
+
|
86
98
|
flickr.photosets.getPhotos(photoset_id: Purdie.get_id(url))['photo'].
|
87
99
|
map { |member| member['id'] }.
|
88
100
|
map { |id| flickr.photos.getInfo photo_id: id }.
|
@@ -11,19 +11,28 @@ module Purdie
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def distill url
|
14
|
-
|
14
|
+
begin
|
15
|
+
track = client.get '/resolve', url: url
|
16
|
+
rescue ArgumentError => ae
|
17
|
+
raise CredentialsException.new self, 'missing'
|
18
|
+
rescue ::SoundCloud::ResponseError => re
|
19
|
+
raise CredentialsException.new self, 'duff'
|
20
|
+
end
|
21
|
+
|
15
22
|
results = {}
|
16
23
|
results['title'] = track['title']
|
17
24
|
results['id'] = track['id']
|
18
25
|
results['location'] = track['description']
|
19
26
|
results['date'] = "%4d-%02d-%02d" % [ track['release_year'], track['release_month'], track['release_day'] ]
|
20
|
-
|
21
|
-
results
|
27
|
+
|
28
|
+
results.attach_license self, track['license']
|
22
29
|
|
23
30
|
results
|
24
31
|
end
|
25
32
|
|
26
|
-
def self.
|
33
|
+
def self.resolve url
|
34
|
+
return [url] unless url =~ /\/sets\//
|
35
|
+
|
27
36
|
client = ::SoundCloud.new client_id: ENV['SOUNDCLOUD_CLIENT_ID']
|
28
37
|
client.get('/resolve', url: url).tracks.
|
29
38
|
map { |track| track['permalink_url'] }
|
@@ -9,17 +9,22 @@ module Purdie
|
|
9
9
|
@id = Purdie.get_id url
|
10
10
|
target = "#{Vimeo.host}/videos/#{@id}"
|
11
11
|
response = HTTParty.get target, headers: Vimeo.headers
|
12
|
-
JSON.parse response.body
|
12
|
+
response = JSON.parse response.body
|
13
|
+
if response['error'] == 'A valid user token must be passed.'
|
14
|
+
raise CredentialsException.new self, 'missing and/or duff'
|
15
|
+
else
|
16
|
+
response
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
20
|
def distill url
|
16
21
|
video = get url
|
17
|
-
results = {}
|
18
22
|
|
23
|
+
results = {}
|
19
24
|
results['title'] = video['name']
|
20
25
|
results['id'] = @id
|
21
|
-
|
22
|
-
results
|
26
|
+
|
27
|
+
results.attach_license self, video['license']
|
23
28
|
|
24
29
|
results
|
25
30
|
end
|
@@ -31,10 +36,12 @@ module Purdie
|
|
31
36
|
}
|
32
37
|
end
|
33
38
|
|
34
|
-
def self.
|
39
|
+
def self.resolve url
|
40
|
+
return [url] unless url =~ /\/albums?\//
|
41
|
+
|
35
42
|
target = "#{Vimeo.host}/albums/#{Purdie.get_id url}/videos/"
|
36
43
|
set = JSON.parse (HTTParty.get target, headers: Vimeo.headers).body
|
37
|
-
set['data'].map { |video| video['
|
44
|
+
set['data'].map { |video| video['uri'].sub '/videos', 'https://vimeo.com' }
|
38
45
|
end
|
39
46
|
|
40
47
|
def self.matcher
|
@@ -6,6 +6,9 @@ module Purdie
|
|
6
6
|
class YouTube
|
7
7
|
include Ingester
|
8
8
|
|
9
|
+
API_SERVICE_NAME = 'youtube'
|
10
|
+
API_VERSION = 'v3'
|
11
|
+
|
9
12
|
def configure
|
10
13
|
@api_service_name = 'youtube'
|
11
14
|
@api_version = 'v3'
|
@@ -39,8 +42,13 @@ module Purdie
|
|
39
42
|
end
|
40
43
|
|
41
44
|
def get url
|
42
|
-
|
43
|
-
|
45
|
+
begin
|
46
|
+
data = get_data Purdie.get_id(url), 'status,snippet'
|
47
|
+
JSON.parse data.body
|
48
|
+
rescue Google::APIClient::ClientError => ce
|
49
|
+
raise Purdie::CredentialsException.new self, 'missing' if ce.message.match /Daily Limit for Unauthenticated Use Exceeded/
|
50
|
+
raise Purdie::CredentialsException.new self, 'duff' if ce.message.match /Bad Request/
|
51
|
+
end
|
44
52
|
end
|
45
53
|
|
46
54
|
def distill url
|
@@ -49,12 +57,46 @@ module Purdie
|
|
49
57
|
|
50
58
|
results['title'] = video['items'][0]['snippet']['localized']['title']
|
51
59
|
results['id'] = Purdie.get_id(url)
|
52
|
-
|
53
|
-
results
|
60
|
+
|
61
|
+
results.attach_license self, video['items'][0]['status']['license']
|
54
62
|
|
55
63
|
results
|
56
64
|
end
|
57
65
|
|
66
|
+
def self.resolve url
|
67
|
+
query = CGI.parse(URI.parse(url).query).keys
|
68
|
+
return [url] unless (query.include?('list') and not query.include?('index'))
|
69
|
+
|
70
|
+
set = YouTube.client.execute!(
|
71
|
+
api_method: YouTube.yt_service.playlist_items.list,
|
72
|
+
parameters: {
|
73
|
+
playlistId: 'PLuPLM2FI60-OIgFTc9YCrGgH5XWGT6znV',
|
74
|
+
part: 'contentDetails',
|
75
|
+
maxResults: 50
|
76
|
+
}
|
77
|
+
).body
|
78
|
+
|
79
|
+
ids = JSON.parse(set)['items'].map { |v| v['contentDetails']['videoId'] }
|
80
|
+
|
81
|
+
ids.map { |id| "https://youtube.com/watch?v=#{id}"}
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.client
|
85
|
+
Google::APIClient.new(
|
86
|
+
key: ENV['YOUTUBE_API_KEY'],
|
87
|
+
authorization: nil,
|
88
|
+
application_name: self.class.name.split('::').first,
|
89
|
+
application_version: Purdie::VERSION
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.yt_service
|
94
|
+
client.discovered_api(
|
95
|
+
API_SERVICE_NAME,
|
96
|
+
API_VERSION
|
97
|
+
)
|
98
|
+
end
|
99
|
+
|
58
100
|
def self.matcher
|
59
101
|
'youtube.com'
|
60
102
|
end
|
data/lib/purdie/source_list.rb
CHANGED
@@ -5,20 +5,12 @@ module Purdie
|
|
5
5
|
include Enumerable
|
6
6
|
|
7
7
|
def initialize sources
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@sources += SourceList.resolve_set source
|
15
|
-
else
|
16
|
-
@sources.push source
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
@sources.select! { |i| i !~ /^#/ }
|
21
|
-
@sources.uniq! { |item| Purdie.strip_scheme item }
|
8
|
+
@sources = [sources].
|
9
|
+
flatten.
|
10
|
+
select { |i| i !~ /^#/ }.
|
11
|
+
map { |source| SourceList.resolve source }.
|
12
|
+
flatten.
|
13
|
+
uniq { |item| Purdie.strip_scheme item }
|
22
14
|
end
|
23
15
|
|
24
16
|
def [] key
|
@@ -39,8 +31,10 @@ module Purdie
|
|
39
31
|
SourceList.new File.readlines(source_file).map { |l| l.strip }
|
40
32
|
end
|
41
33
|
|
42
|
-
def self.
|
43
|
-
Ingester.ingesters.select { |service| source =~ /#{service.matcher}/ }[0]
|
34
|
+
def self.resolve source
|
35
|
+
service_class = Ingester.ingesters.select { |service| source =~ /#{service.matcher}/ }[0]
|
36
|
+
return [] unless service_class
|
37
|
+
service_class.resolve source
|
44
38
|
end
|
45
39
|
end
|
46
40
|
end
|
data/lib/purdie/version.rb
CHANGED
data/lib/purdie.rb
CHANGED
@@ -12,6 +12,8 @@ require 'purdie/bernard'
|
|
12
12
|
require 'purdie/config'
|
13
13
|
require 'purdie/ingester'
|
14
14
|
require 'purdie/source_list'
|
15
|
+
require 'purdie/license_manager'
|
16
|
+
require 'purdie/exceptions'
|
15
17
|
|
16
18
|
require 'purdie/services/soundcloud'
|
17
19
|
require 'purdie/services/flickr'
|
@@ -19,3 +21,11 @@ require 'purdie/services/vimeo'
|
|
19
21
|
require 'purdie/services/youtube'
|
20
22
|
|
21
23
|
Dotenv.load
|
24
|
+
|
25
|
+
class Hash
|
26
|
+
def attach_license service, license
|
27
|
+
l = Purdie::LicenseManager.get service, license
|
28
|
+
self['license'] = l['full_name']
|
29
|
+
self['license_url'] = l['url']
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Purdie
|
4
|
+
module Services
|
5
|
+
describe Flickr do
|
6
|
+
before :each do
|
7
|
+
unset_env
|
8
|
+
end
|
9
|
+
|
10
|
+
after :each do
|
11
|
+
reset_env
|
12
|
+
FlickRaw.api_key = ENV['FLICKR_API_KEY']
|
13
|
+
FlickRaw.shared_secret = ENV['FLICKR_SECRET']
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'responds usefully in the face of no credentials' do
|
17
|
+
FlickRaw.api_key = nil
|
18
|
+
FlickRaw.shared_secret = nil
|
19
|
+
f = Flickr.new
|
20
|
+
### expect { f.distill 'https://www.flickr.com/photos/rawfunkmaharishi/15631479625/' }.to raise_exception { |e|
|
21
|
+
### expect(e).to be_a Purdie::CredentialsException
|
22
|
+
### expect(e.message).to eq 'Flickr credentials missing'
|
23
|
+
### }
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'responds usefully in the face of duff credentials' do
|
27
|
+
FlickRaw.api_key = 'abc'
|
28
|
+
FlickRaw.shared_secret = '123'
|
29
|
+
f = Flickr.new
|
30
|
+
### expect { f.distill 'https://www.flickr.com/photos/rawfunkmaharishi/15631479625/' }.to raise_exception { |e|
|
31
|
+
### expect(e).to be_a Purdie::CredentialsException
|
32
|
+
### expect(e.message).to eq 'Flickr credentials might be duff'
|
33
|
+
### }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe SoundCloud do
|
38
|
+
after :each do
|
39
|
+
reset_env
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'responds usefully in the face of no credentials' do
|
43
|
+
unset_env
|
44
|
+
s = SoundCloud.new
|
45
|
+
expect { s.distill 'https://soundcloud.com/rawfunkmaharishi/bernard' }.to raise_exception { |e|
|
46
|
+
expect(e).to be_a Purdie::CredentialsException
|
47
|
+
expect(e.service.class).to eq Purdie::Services::SoundCloud
|
48
|
+
expect(e.message).to eq 'missing'
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'responds usefully in the face of duff credentials' do
|
53
|
+
randomise_env
|
54
|
+
s = SoundCloud.new
|
55
|
+
expect { s.distill 'https://soundcloud.com/rawfunkmaharishi/bernard' }.to raise_exception { |e|
|
56
|
+
expect(e).to be_a Purdie::CredentialsException
|
57
|
+
expect(e.service.class).to eq Purdie::Services::SoundCloud
|
58
|
+
expect(e.message).to eq 'duff'
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe Vimeo do
|
64
|
+
after :each do
|
65
|
+
reset_env
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'responds usefully in the face of no credentials' do
|
69
|
+
unset_env
|
70
|
+
v = Vimeo.new
|
71
|
+
expect { v.distill 'https://vimeo.com/111356018' }.to raise_exception { |e|
|
72
|
+
expect(e).to be_a Purdie::CredentialsException
|
73
|
+
expect(e.service.class).to eq Purdie::Services::Vimeo
|
74
|
+
expect(e.message).to eq 'missing and/or duff'
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'responds usefully in the face of duff credentials' do
|
79
|
+
randomise_env
|
80
|
+
v = Vimeo.new
|
81
|
+
expect { v.distill 'https://vimeo.com/111356018' }.to raise_exception { |e|
|
82
|
+
expect(e).to be_a Purdie::CredentialsException
|
83
|
+
expect(e.service.class).to eq Purdie::Services::Vimeo
|
84
|
+
expect(e.message).to eq 'missing and/or duff'
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe YouTube do
|
90
|
+
after :each do
|
91
|
+
reset_env
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'responds usefully in the face of no credentials' do
|
95
|
+
unset_env
|
96
|
+
y = YouTube.new
|
97
|
+
expect { y.distill 'https://www.youtube.com/watch?v=JCix1XW329g' }.to raise_exception { |e|
|
98
|
+
expect(e).to be_a Purdie::CredentialsException
|
99
|
+
expect(e.service.class).to eq Purdie::Services::YouTube
|
100
|
+
expect(e.message).to eq 'missing'
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'responds usefully in the face of duff credentials' do
|
105
|
+
randomise_env
|
106
|
+
y = YouTube.new
|
107
|
+
expect { y.distill 'https://www.youtube.com/watch?v=JCix1XW329g' }.to raise_exception { |e|
|
108
|
+
expect(e).to be_a Purdie::CredentialsException
|
109
|
+
expect(e.service.class).to eq Purdie::Services::YouTube
|
110
|
+
expect(e.message).to eq 'duff'
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|