dribbble-bucket-sync 0.0.1 → 0.0.2

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.
data/README.md CHANGED
@@ -33,8 +33,12 @@ Output should be like this:
33
33
  $ dribbble_bucket_sync ryantownsend ~/dribbble
34
34
  Starting synchronisation...
35
35
  ryantownsend has 29 buckets.
36
- Timelines has 2 shots.
37
- Colour Palettes has 1 shots.
36
+ Timelines has 20 shots.
37
+ Connecting to dribbble.s3.amazonaws.com:80
38
+ Downloading 20 files:
39
+ ....................
40
+ Infographics has 12 shots.
41
+ [...]
38
42
  Synchronisation complete.
39
43
 
40
44
  The syntax to run within your own app is fairly straight-forward:
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.require_paths = ["lib"]
16
16
  s.version = DribbbleBucketSync::VERSION
17
17
 
18
- s.add_dependency "dribbble-bucket-api"
18
+ s.add_dependency "dribbble-bucket-api", "~> 0.0.6"
19
19
  s.add_development_dependency "rspec"
20
20
  s.add_development_dependency "simplecov"
21
21
  end
@@ -1,6 +1,7 @@
1
1
  require "fileutils"
2
2
  require "uri"
3
3
  require "net/http"
4
+ require "timeout"
4
5
 
5
6
  class DribbbleBucketSync
6
7
  class Folder
@@ -17,23 +18,35 @@ class DribbbleBucketSync
17
18
  end
18
19
 
19
20
  def add_shot(shot)
20
- url = shot.image_url
21
- # add the file to the shots list
22
- filename = "#{shot.id}#{File.extname(url)}"
23
- @shots << filename
21
+ # calculate the filename
22
+ filename = "#{shot.id}.#{shot.ext}"
24
23
  # calculate the path
25
24
  path = File.join(@path, filename)
26
- # download if it doesn't exist
27
- unless File.exist?(path)
28
- download(url, path)
25
+ # add the shot to the storage
26
+ @shots << { filename: filename, destination: path, url: shot.image_url }
27
+ end
28
+
29
+ def sync
30
+ download_new_shots
31
+ remove_old_shots
32
+ end
33
+
34
+ # downloads any shots missing from the folder
35
+ def download_new_shots
36
+ # select all the shots that don't exist
37
+ new_shots = @shots.select do |s|
38
+ !File.exist?(s[:destination])
29
39
  end
40
+ # download them all
41
+ download_files(new_shots)
30
42
  end
31
43
 
44
+ # deletes any shots in the folder that no longer exist in the bucket
32
45
  def remove_old_shots
33
46
  # loop through all shots in the folder
34
47
  current_shot_files.each do |file|
35
48
  # delete file if the shot isn't in the array
36
- unless @shots.include?(File.basename(file))
49
+ unless @shots.map { |s| s[:filename] }.include?(File.basename(file))
37
50
  FileUtils.rm(file)
38
51
  end
39
52
  end
@@ -45,12 +58,39 @@ class DribbbleBucketSync
45
58
  end
46
59
 
47
60
  private
48
- # downloads a URL to a local path
49
- def download(url, destination)
50
- # parse the URL
51
- uri = URI.parse(url)
52
- # connect to the site
53
- Net::HTTP.start(uri.host, uri.port) do |http|
61
+ # download URLs to a local path
62
+ def download_files(files)
63
+ # map the urls into groups by hostname
64
+ groups = files.inject({}) do |result,file|
65
+ uri = URI.parse(file[:url])
66
+ result["#{uri.host}:#{uri.port}"] ||= []
67
+ result["#{uri.host}:#{uri.port}"] << {
68
+ destination: file[:destination],
69
+ uri: uri
70
+ }
71
+ result
72
+ end
73
+ # loop through each group
74
+ groups.each do |key, files|
75
+ host = files.first[:uri].host
76
+ port = files.first[:uri].port
77
+ puts "Connecting to #{host}:#{port}"
78
+ # connect to the site
79
+ Net::HTTP.start(host, files.first[:uri].port) do |http|
80
+ puts "Downloading #{files.size} files:"
81
+ # loop through each uri
82
+ files.each do |file|
83
+ # download the file
84
+ download_file(http, file[:uri], file[:destination])
85
+ print "."
86
+ end
87
+ puts ""
88
+ end
89
+ end
90
+ end
91
+
92
+ def download_file(http, uri, destination)
93
+ Timeout::timeout(30) do
54
94
  # download the file
55
95
  resp = http.get(uri.request_uri)
56
96
  # open the local file
@@ -59,6 +99,10 @@ class DribbbleBucketSync
59
99
  file.write(resp.body)
60
100
  end
61
101
  end
102
+ rescue Timeout::Error => e
103
+ puts "Request timed out: #{uri.request_uri}, moving on to next... (#{e.class.name})"
104
+ rescue EOFError => e
105
+ puts "Request failed: #{uri.request_uri}, moving on to next... (#{e.class.name})"
62
106
  end
63
107
 
64
108
  # ensure the folder exists
@@ -1,3 +1,3 @@
1
1
  class DribbbleBucketSync
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -31,6 +31,9 @@ class DribbbleBucketSync
31
31
  buckets.each do |bucket|
32
32
  sync_bucket(bucket, directory)
33
33
  end
34
+ # being nice to Dribbble site
35
+ # sleep for 1 - 3 seconds every 5 buckets
36
+ sleep(3) + 1
34
37
  end
35
38
  end
36
39
 
@@ -54,9 +57,12 @@ class DribbbleBucketSync
54
57
  shots.each do |shot|
55
58
  folder.add_shot(shot)
56
59
  end
60
+ # being nice to Dribbble site
61
+ # sleep for 0 - 2 seconds every 15 shots
62
+ sleep(3)
57
63
  end
58
- # remove old shots
59
- folder.remove_old_shots
64
+ # process downloads / deletions
65
+ folder.sync
60
66
  end
61
67
 
62
68
  def connection
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dribbble-bucket-sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -16,17 +16,17 @@ dependencies:
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
- - - ! '>='
19
+ - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '0'
21
+ version: 0.0.6
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
- - - ! '>='
27
+ - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: '0'
29
+ version: 0.0.6
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rspec
32
32
  requirement: !ruby/object:Gem::Requirement