dribbble-bucket-sync 0.0.1 → 0.0.2

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