purdie 0.0.11 → 0.0.12
Sign up to get free protection for your applications and to get access to all the features.
- 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
|