henchman-sync 0.3.3 → 0.4.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ba50beb7184c552a3a27c1c6c993a70d9eb53496
4
- data.tar.gz: c1c5bb43fd8eb9dd21dd3e976ce22fd8efc8215a
3
+ metadata.gz: 7d27e875da0439ebd8e24c160d77c962202b0f19
4
+ data.tar.gz: 775dfd05202ac8248fc155901845f224adc004e5
5
5
  SHA512:
6
- metadata.gz: 4c06ad0803566f62aa4ad348801409c2b7b0a061cbb4dfea5e1a840cb1597c51c152be9baf260d3d9d0941d26527bbbd875ec34854039aa4cb8832e8ff253d09
7
- data.tar.gz: 4db7132de8baacbc36b82a3890e040742d0fd753e10126e29fa90a7dce3ce3b1ac3b5f6d2f31d4412bb428516fc4d27e0091b80fb0deb9a08238092c88b650aa
6
+ metadata.gz: fd12ef4db1308346aa45ffd3f386f02e90714217430effe5908b8196573275a4dda0133b6dcd8e07409332a4cce8308a45530b8a46c50de1efa2f19c4f54e8ae
7
+ data.tar.gz: 07d8df1684c9e5ec9db629ec9bbffec58c324668bc447ab98d49db7659743bed18eb6670edc0265b14826c70c6402195f8b9a07027fdacd7c1c92f2ff2bf1d38
data/README.md CHANGED
@@ -48,10 +48,6 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
48
48
 
49
49
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
50
50
 
51
- ## TODO
52
-
53
- - Move off of the 'dropbox-sdk' gem, since it uses their API V1, which will be depreciated June 28th, 2017 (or just buck up and update the gem myself)
54
-
55
51
  ## Contributing
56
52
 
57
53
  Bug reports and pull requests are welcome on GitHub at https://github.com/gremerritt/henchman.
@@ -28,7 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.require_paths = ["lib"]
29
29
 
30
30
  spec.add_dependency "commander", "~> 4.4"
31
- spec.add_dependency "dropbox-sdk", "~> 1.6"
31
+ spec.add_dependency "dropbox-sdk-v2", "~> 0.0"
32
32
  spec.add_development_dependency "bundler", "~> 1.12"
33
33
  spec.add_development_dependency "rake", "~> 10.0"
34
34
  spec.add_development_dependency "rspec", "~> 3.0"
@@ -133,7 +133,7 @@ module Henchman
133
133
  "end repeat"
134
134
  end
135
135
 
136
- def get_playlist_tracks_script playlist, skip = [], size = 100
136
+ def get_playlist_tracks_script playlist, skip = [], size = 5
137
137
  "property counter : 0\n"\
138
138
  "tell application \"iTunes\"\n"\
139
139
  " try\n"\
@@ -210,7 +210,7 @@ module Henchman
210
210
  next if track.empty?
211
211
  tmp_track = track.split @delimiter
212
212
  tracks.push( {:id => tmp_track[0],
213
- :date => DateTime.parse(tmp_track[1]),
213
+ :date => (tmp_track[1] != 'missing value') ? DateTime.parse(tmp_track[1]) : DateTime.new,
214
214
  :path => tmp_track[2]} )
215
215
  end
216
216
  tracks
@@ -229,7 +229,7 @@ module Henchman
229
229
  def get_playlist_tracks playlist, skip = []
230
230
  tracks = Array.new
231
231
  tmp_tracks = %x(#{applescript_command(get_playlist_tracks_script playlist, skip)}).chomp
232
- tmp_tracks = tmp_tracks.split @delimiter_major
232
+ tmp_tracks = tmp_tracks.force_encoding("UTF-8").split @delimiter_major
233
233
  tmp_tracks.each do |track|
234
234
  next if track.empty?
235
235
  tmp_track = track.split @delimiter
@@ -274,8 +274,6 @@ module Henchman
274
274
 
275
275
  ret = %x(#{applescript_command(update_track_location_script selection[:id], local_file)}).chomp
276
276
  if ret.empty? || ret == '0'
277
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
278
- "Could not update location of #{selection.reject{|k,v| k == :path || k == :id}.values.join(':')} to #{local_file}"
279
277
  false
280
278
  else
281
279
  true
@@ -35,7 +35,8 @@ module Henchman
35
35
  end
36
36
 
37
37
  def get_time_last_downloaded track
38
- @cache[:history][track[:id].to_i]
38
+ id = track[:id].to_i
39
+ (@cache[:history].include?(id)) ? @cache[:history][id] : DateTime.new
39
40
  end
40
41
 
41
42
  def tag track
@@ -60,6 +61,17 @@ module Henchman
60
61
  end
61
62
  end
62
63
 
64
+ def clear type, value
65
+ raise "Invalid type #{type}" if !@cache[:ignore].keys.include? type
66
+ if @cache[:ignore][type].include? value
67
+ @cache[:ignore][type].delete value
68
+ puts "Deleting #{type} #{value} from cache"
69
+ else
70
+ puts "#{type} #{value} not found"
71
+ end
72
+ flush
73
+ end
74
+
63
75
  end
64
76
 
65
77
  end
@@ -7,7 +7,6 @@ module Henchman
7
7
  class Clean
8
8
 
9
9
  def self.run played_date
10
-
11
10
  puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
12
11
  "Cleanup Starting"
13
12
 
@@ -44,20 +43,20 @@ module Henchman
44
43
 
45
44
  def self.cleanup track
46
45
  filepath = track[:path]
47
- File.delete filepath
48
- @cache.delete track
49
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
50
- "Deleted #{filepath}"
46
+ begin
47
+ File.delete filepath
48
+ @cache.delete track
49
+ puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
50
+ "Deleted #{filepath}"
51
51
 
52
- while File.dirname(filepath) != @config[:root]
53
- filepath = File.dirname(filepath)
54
- begin
52
+ while File.dirname(filepath) != @config[:root]
53
+ filepath = File.dirname(filepath)
55
54
  Dir.rmdir(filepath)
56
55
  puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
57
56
  "Deleted #{filepath}"
58
- rescue SystemCallError => msg
59
- break
60
57
  end
58
+ rescue SystemCallError => msg
59
+ # do nothing
61
60
  end
62
61
  end
63
62
 
@@ -34,7 +34,7 @@ module Henchman
34
34
  if config[:root].empty? || agree("\nUpdate local music directory? (y/n) ")
35
35
  get_local_root config
36
36
  end
37
-
37
+
38
38
  Dir.mkdir(File.dirname(config_file)) if !File.exists?(File.dirname(config_file))
39
39
  File.open(config_file, "w") { |f| f.write( config.to_yaml ) }
40
40
  puts "\nConfiguration complete! Run `henchman start` to start the daemon."
@@ -43,10 +43,10 @@ module Henchman
43
43
  def self.connect config={}
44
44
  begin
45
45
  config = YAML.load_file(File.expand_path("~/.henchman/config")) if config.empty?
46
- client = DropboxClient.new(config[:dropbox][:access_token])
47
- account_info = client.account_info()
46
+ client = Dropbox::Client.new config[:dropbox][:access_token]
47
+ account_info = client.get_current_account()
48
48
  puts "Successfully connected to Dropbox: "
49
- puts " #{account_info['display_name']} [#{account_info['email']}]"
49
+ puts " #{account_info.display_name} [#{account_info.email}]"
50
50
  return client
51
51
  rescue StandardError => err
52
52
  puts "Error connecting to Dropbox account (#{err}). Try deleting the "\
@@ -91,8 +91,6 @@ module Henchman
91
91
  end
92
92
 
93
93
  def self.get_dropbox_root config, client
94
- # paths = Hash.new
95
- # build_dropbox_dirs(paths, client, '/', 0)
96
94
  not_done = true
97
95
  while not_done
98
96
  path = ask("Enter the path to your music directory in Dropbox: (? for help)" )
@@ -115,15 +113,28 @@ module Henchman
115
113
  end
116
114
  end
117
115
 
118
- # def self.build_dropbox_dirs paths, client, path, level
119
- # return if level == 2
120
- # metadata = client.metadata(path)
121
- # metadata['contents'].each do |elem|
122
- # next if !elem['is_dir']
123
- # paths[elem['path']] = Hash.new
124
- # build_dropbox_dirs(paths[elem['path']], client, elem['path'], level+1)
125
- # end
126
- # end
116
+ def self.collect_exts
117
+ config_file = File.expand_path('~/.henchman/config')
118
+ config = YAML.load_file(config_file)
119
+ client = connect config
120
+ exts = Hash.new
121
+ collect_exts_rec client, config[:dropbox][:root], exts
122
+
123
+ puts ""
124
+ exts.each_key { |k| puts k }
125
+ end
126
+
127
+ def self.collect_exts_rec client, path, exts
128
+ metadata = client.metadata(path)
129
+ metadata['contents'].each_with_index do |c, i|
130
+ print "\rCollecting#{'.'*(i%4)}#{' '*(3-(i%4))}"
131
+ if c['is_dir']
132
+ collect_exts_rec client, c['path'], exts
133
+ else
134
+ exts[File.extname(c['path'])] = true
135
+ end
136
+ end
137
+ end
127
138
 
128
139
  def self.get_local_root config
129
140
  not_done = true
@@ -1,4 +1,4 @@
1
- require "dropbox"
1
+ require "dbx_assistant"
2
2
  require "applescript"
3
3
  require "cache"
4
4
  require "yaml"
@@ -7,7 +7,9 @@ module Henchman
7
7
 
8
8
  class Core
9
9
 
10
- def self.run
10
+ def self.run args
11
+ debug = true if args[0] == 'debug'
12
+
11
13
  @appleScript = Henchman::AppleScript.new
12
14
  @cache = Henchman::Cache.new
13
15
  @update_cache = false
@@ -23,6 +25,10 @@ module Henchman
23
25
  @config[:delimiter_major] = Henchman::Templates.config[:delimiter_major]
24
26
  File.open(config_file, "w") { |f| f.write( @config.to_yaml ) }
25
27
  end
28
+ if !(@config.include? :file_extensions)
29
+ @config[:file_extensions] = Henchman::Templates.config[:file_extensions]
30
+ File.open(config_file, "w") { |f| f.write( @config.to_yaml ) }
31
+ end
26
32
 
27
33
  @cache.config @config
28
34
  rescue StandardError => err
@@ -33,10 +39,10 @@ module Henchman
33
39
 
34
40
  @appleScript.setup @config
35
41
  begin
36
- @dropbox = Henchman::DropboxAssistant.new @config
37
- rescue
42
+ @dropbox = Henchman::DropboxAssistant.new @config, debug
43
+ rescue StandardError => msg
38
44
  puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
39
- "Error connecting to Dropbox. Try rerunning `henchman configure`"
45
+ "Error connecting to Dropbox (#{msg}). Try rerunning `henchman configure`"
40
46
  return
41
47
  end
42
48
 
@@ -144,7 +150,10 @@ module Henchman
144
150
  updated = @appleScript.set_track_location track, file_save_path
145
151
 
146
152
  # if the update failed, remove that file
147
- cleanup file_save_path, track if !updated
153
+ if !updated
154
+ cleanup file_save_path, track
155
+ raise "Could not update location of #{track.reject{|k,v| k == :path || k == :id}.values.join(':')} to #{file_save_path}"
156
+ end
148
157
  end
149
158
  rescue StandardError => err
150
159
  puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|#{err}"
@@ -0,0 +1,185 @@
1
+ require 'dropbox'
2
+ require 'yaml'
3
+ require 'json'
4
+
5
+ module Henchman
6
+
7
+ class DropboxAssistant
8
+
9
+ def initialize config, debug
10
+ begin
11
+ @search_limit = 500
12
+ @debug = debug
13
+ @config = config
14
+ @client = Dropbox::Client.new @config[:dropbox][:access_token]
15
+
16
+ # stop words from http://nlp.stanford.edu/IR-book/html/htmledition/dropping-common-terms-stop-words-1.html
17
+ @stop_words = ['a', 'an', 'and', 'are', 'as', 'at', 'be', 'by', 'for', 'from',
18
+ 'has', 'he', 'in', 'is', 'it', 'its', 'of', 'on', 'that', 'the',
19
+ 'to', 'was', 'were', 'will', 'with']
20
+ true
21
+ rescue DropboxError => msg
22
+ puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
23
+ "Couldn't connect to Dropbox (#{msg}). "\
24
+ "Run `henchman stop` then `henchman configure` "\
25
+ "to configure Dropbox connection."
26
+ false
27
+ end
28
+ end
29
+
30
+ def download selection, dropbox_path
31
+ puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
32
+ "Downloading #{selection.reject{|k,v| k == :path || k == :id}.values.join(':')} from #{dropbox_path}"
33
+ begin
34
+ # download the file
35
+ content, body = @client.download dropbox_path
36
+
37
+ # make sure we have the directory to put it in
38
+ trgt_dir = File.join @config[:root], selection[:artist], selection[:album]
39
+ puts trgt_dir if @debug
40
+ system 'mkdir', '-p', trgt_dir
41
+
42
+ # save the file
43
+ file_save_path = File.join trgt_dir, File.basename(dropbox_path)
44
+ puts file_save_path if @debug
45
+ open(file_save_path, 'w') {|f| f.puts body }
46
+ file_save_path
47
+ rescue DropboxError => msg
48
+ puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
49
+ "Error downloading Dropbox file #{dropbox_path}: #{msg}"
50
+ false
51
+ rescue StandardError => msg
52
+ puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
53
+ "Error saving Dropbox file #{dropbox_path} to #{trgt_dir}: #{msg}"
54
+ false
55
+ end
56
+ end
57
+
58
+ def search value, filter = nil, dir = @config[:dropbox][:root]
59
+ puts "Searching for #{value} in #{dir}, filtering by <#{filter}>" if @debug
60
+ begin
61
+ results = @client.search dir, value, 0, @search_limit
62
+ puts "#{results.length} total results found" if @debug
63
+ if filter == :dir
64
+ results.reject! { |result| !result.is_a? Dropbox::FolderMetadata }
65
+ elsif filter == :file
66
+ results.reject! { |result| !result.is_a? Dropbox::FileMetadata ||
67
+ !(@config[:file_extensions].include?(File.extname(result.path_lower)[1..-1])) }
68
+ end
69
+ puts "Returning #{results.length} results for `search` (after filtering)" if @debug
70
+ return results
71
+ rescue DropboxError => msg
72
+ raise "Error accessing Dropbox Search API|#{value}|#{dir}|#{msg}"
73
+ end
74
+ end
75
+
76
+ def get_results track, artist
77
+ puts "`get_results` for #{track} by #{artist}" if @debug
78
+ # Search Dropbox for the file
79
+ # We're only not filtering to get files because we want to check if we get 1000 results
80
+ # (i.e. a maxed out playload) back. This is because the filtering happens in OUR client,
81
+ # not in the Dropbox search. We're doing a simple search on only track name because we
82
+ # want to minimize the number of network calls, and USUALLY this is good enough
83
+ results = search track
84
+
85
+ # If we get 1000 results back, it means we probably have a REALLY simple song title
86
+ # and we're not assured to have the target song in our payload, since we maxed it
87
+ # out. So, we'll do another search call on the artist
88
+ if results.length == @search_limit
89
+ puts "Maximum (#{@search_limit}) results returned" if @debug
90
+ results.clear
91
+ album_dirs = search artist, :dir
92
+ album_dirs.each do |album|
93
+ tmp_rslts = search track, :file, album['path']
94
+ results.push(*tmp_rslts)
95
+ end
96
+ else # Otherwise, filter off all the directories and things without the right extensions
97
+ puts "Filtering out directories and incorrect file extensions" if @debug
98
+ results.reject! { |result| !result.is_a? Dropbox::FileMetadata ||
99
+ !(@config[:file_extensions].include?(File.extname(result.path_lower)[1..-1])) }
100
+ end
101
+ puts "Returning #{results.length} results from `get_results`" if @debug
102
+ return results
103
+ end
104
+
105
+ def search_for selection
106
+ puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
107
+ "Searching for #{selection.reject{|k,v| k == :path || k == :id}.values.join(':')}"
108
+
109
+ results = get_results selection[:track], selection[:artist]
110
+
111
+ # if we still don't have any results, try dropping any brackets and paranthesis
112
+ if results.empty? && (selection[:track].match(%r( *\[.*\] *)) || selection[:track].match(%r( *\(.*\) *)))
113
+ puts "No results. Trying without brackets or parenthesis" if @debug
114
+ track = selection[:track].gsub(%r( *\[.*\] *), " ").gsub(%r( *\(.*\) *), " ")
115
+ results = get_results track, selection[:artist]
116
+ end
117
+
118
+ # if there were no results, raise err
119
+ if results.empty?
120
+ raise "Track not found in Dropbox: #{selection.reject{|k,v| k == :id}.values.join(':')}"
121
+ else
122
+ scores = Hash.new 0
123
+ tokens = Array.new
124
+ track_tokens = Array.new
125
+ [:artist, :album].each do |identifier|
126
+ tokens |= selection[identifier].downcase
127
+ .gsub(%r( +), " ")
128
+ .gsub(%r(-+), "-")
129
+ .strip
130
+ .split(/[\s-]/)
131
+ .delete_if{ |t| @stop_words.include? t }
132
+ end
133
+ @config[:file_extensions].each do |extension|
134
+ track_tokens |= selection[:track].downcase
135
+ .gsub(%r( +), " ")
136
+ .gsub(%r(-+), "-")
137
+ .strip
138
+ .split(/[\s-]/)
139
+ .map { |t| "#{t}.#{extension}" }
140
+ end
141
+
142
+ if @debug
143
+ puts ":artist and :album tokens: #{tokens.inspect}"
144
+ puts ":track tokens: #{track_tokens.inspect}"
145
+ end
146
+
147
+ results.each do |result|
148
+ dir = "#{File.dirname(result.path_lower)}/"
149
+ basename = " #{File.basename(result.path_lower)}"
150
+ tokens.each do |token|
151
+ if dir =~ %r(.*[\s\/-]#{token}[\s\/-].*)
152
+ puts "Token #{token} found in #{dir}" if @debug
153
+ if results.length == 1
154
+ return result.path_display
155
+ else
156
+ scores[result.path_display] += 1
157
+ end
158
+ end
159
+ end
160
+ track_tokens.each do |token|
161
+ if basename =~ %r([.]*[\s-]+#{token})
162
+ puts "Token #{token} found in #{basename}" if @debug
163
+ scores[result.path_display] += 1
164
+ end
165
+ end
166
+ end
167
+
168
+ # if the we only had one track and we're here, that means the path didn't contain
169
+ # any of the album or artist tokens, so we'll say we couldn't find it
170
+ if results.length == 1
171
+ raise "Track not found in Dropbox: #{selection.reject{|k,v| k == :id}.values.join(':')}"
172
+ end
173
+
174
+ # return the path that has the highest score
175
+ scores = scores.sort_by { |path, score| score }
176
+ if @debug
177
+ scores.each { |score| puts score.join ': ' }
178
+ end
179
+ scores[-1][0]
180
+ end
181
+ end
182
+
183
+ end
184
+
185
+ end
@@ -16,7 +16,7 @@ module Henchman
16
16
  c.syntax = 'henchman start'
17
17
  c.description = 'Starts the henchman daemon'
18
18
  c.action do |args, options|
19
- Henchman::LaunchdHandler.start
19
+ Henchman::LaunchdHandler.start args
20
20
  end
21
21
  end
22
22
 
@@ -40,7 +40,7 @@ module Henchman
40
40
  c.syntax = 'henchman run'
41
41
  c.description = 'Main interface into henchman. Should not be ran manually.'
42
42
  c.action do |args, options|
43
- Henchman::Core.run
43
+ Henchman::Core.run args
44
44
  end
45
45
  end
46
46
 
@@ -55,5 +55,31 @@ module Henchman
55
55
  end
56
56
  end
57
57
 
58
+ command :extensions do |c|
59
+ c.syntax = 'henchman extensions'
60
+ c.description = 'Collect file extensions'
61
+ c.action do |args, options|
62
+ Henchman.collect_exts
63
+ end
64
+ end
65
+
66
+ command :log do |c|
67
+ c.syntax = 'henchman log [options]'
68
+ c.description = 'Tails the henchman stdout log'
69
+ c.option '--n <number>', Integer, 'Number of lines to tail'
70
+ c.action do |args, options|
71
+ options.default :n => 10
72
+ puts `tail -n #{options.n} #{File.expand_path('~/.henchman/stdout.log')}`
73
+ end
74
+ end
75
+
76
+ command :clear do |c|
77
+ c.syntax = 'henchman clear <artist/playlist> <title>'
78
+ c.description = 'Clears the the artist or playlist from the cache'
79
+ c.action do |args, options|
80
+ @cache = Henchman::Cache.new
81
+ @cache.clear args[0].to_sym, args[1..-1].join(' ')
82
+ end
83
+ end
58
84
  end
59
85
  end
@@ -1,3 +1,3 @@
1
1
  module Henchman
2
- VERSION = "0.3.3"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -4,7 +4,7 @@ module Henchman
4
4
 
5
5
  class LaunchdHandler
6
6
 
7
- def self.start
7
+ def self.start args
8
8
  if !internet_connection?
9
9
  puts "No internet connection detected - unable to verify correct configuration."
10
10
  return if !agree("Launch henchman anyways? (y/n) ")
@@ -22,7 +22,7 @@ module Henchman
22
22
  shell_script_path_clean = File.expand_path("~/.henchman/clean.sh")
23
23
  cache_path = File.expand_path("~/.henchman/cache")
24
24
  File.write(plist_path_main, plist_main)
25
- File.write(shell_script_path_main, Henchman::Templates.shell_script('run'))
25
+ File.write(shell_script_path_main, Henchman::Templates.shell_script('run', args))
26
26
  File.write(plist_path_clean, plist_clean)
27
27
  File.write(shell_script_path_clean, Henchman::Templates.shell_script('clean'))
28
28
  File.open(cache_path, "w") { |f| f.write( Henchman::Templates.cache.to_yaml ) }
@@ -60,9 +60,9 @@ module Henchman
60
60
  "</plist>"
61
61
  end
62
62
 
63
- def self.shell_script command
63
+ def self.shell_script command, args = []
64
64
  "#!/bin/sh\n"\
65
- "#{`which henchman`.chomp} #{command}"
65
+ "#{`which henchman`.chomp} #{command} #{args.join(' ')}"
66
66
  end
67
67
 
68
68
  def self.config
@@ -77,7 +77,8 @@ module Henchman
77
77
  :poll_track => 3,
78
78
  :reprompt_timeout => 300,
79
79
  :delimiter => '|~|',
80
- :delimiter_major => '|?|'
80
+ :delimiter_major => '|?|',
81
+ :file_extensions => ['mp3', 'm4a']
81
82
  }
82
83
  end
83
84
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: henchman-sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Merritt
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-07-13 00:00:00.000000000 Z
11
+ date: 2016-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: commander
@@ -25,19 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.4'
27
27
  - !ruby/object:Gem::Dependency
28
- name: dropbox-sdk
28
+ name: dropbox-sdk-v2
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.6'
33
+ version: '0.0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.6'
40
+ version: '0.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -104,7 +104,7 @@ files:
104
104
  - lib/clean.rb
105
105
  - lib/configure.rb
106
106
  - lib/core.rb
107
- - lib/dropbox.rb
107
+ - lib/dbx_assistant.rb
108
108
  - lib/henchman.rb
109
109
  - lib/henchman/version.rb
110
110
  - lib/launchd_handler.rb
@@ -1,101 +0,0 @@
1
- require 'dropbox_sdk'
2
- require 'yaml'
3
- require 'json'
4
-
5
- module Henchman
6
-
7
- class DropboxAssistant
8
-
9
- def initialize config
10
- begin
11
- @config = config
12
- @client = DropboxClient.new(@config[:dropbox][:access_token])
13
- true
14
- rescue DropboxError => msg
15
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
16
- "Couldn't connect to Dropbox (#{msg}). "\
17
- "Run `henchman stop` then `henchman configure` "\
18
- "to configure Dropbox connection."
19
- false
20
- end
21
- end
22
-
23
- def download selection, dropbox_path
24
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
25
- "Downloading #{selection.reject{|k,v| k == :path || k == :id}.values.join(':')}"
26
- begin
27
- # download the file
28
- content = @client.get_file(dropbox_path)
29
-
30
- # make sure we have the directory to put it in
31
- trgt_dir = File.join @config[:root], selection[:artist], selection[:album]
32
- system 'mkdir', '-p', trgt_dir
33
-
34
- # save the file
35
- file_save_path = File.join trgt_dir, File.basename(dropbox_path)
36
- open(file_save_path, 'w') {|f| f.puts content }
37
- file_save_path
38
- rescue DropboxError => msg
39
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
40
- "Error downloading Dropbox file #{dropbox_path}: #{msg}"
41
- false
42
- rescue StandardError => msg
43
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
44
- "Error saving Dropbox file #{dropbox_path} to #{trgt_dir}: #{msg}"
45
- false
46
- end
47
- end
48
-
49
- def search_for selection
50
- puts "#{DateTime.now.strftime('%m-%d-%Y %H:%M:%S')}|"\
51
- "Searching for #{selection.reject{|k,v| k == :path || k == :id}.values.join(':')}"
52
-
53
- # search Dropbox for the file
54
- begin
55
- results = @client.search(@config[:dropbox][:root], selection[:track])
56
- rescue DropboxError => msg
57
- raise "Error accessing Dropbox Search API on #{selection.reject{|k,v| k == :path || k == :id}.values.join(':')}: #{msg}"
58
- end
59
-
60
- # get rid of any results that are directories
61
- results.reject! { |result| result['is_dir'] }
62
-
63
- # if we still don't have any results, try dropping any brackets and paranthesis
64
- if results.empty? && (selection[:track].match(%r( *\[.*\] *)) || selection[:track].match(%r( *\(.*\) *)))
65
- track = selection[:track].gsub(%r( *\[.*\] *), " ").gsub(%r( *\(.*\) *), " ")
66
- results = @client.search(@config[:dropbox][:root], track)
67
- results.reject! { |result| result['is_dir'] }
68
- end
69
-
70
- # if there were no results, raise err
71
- if results.empty?
72
- raise "Track not found in Dropbox: #{selection.reject{|k,v| k == :id}.values.join(':')}"
73
-
74
- # if there's only one result, return it
75
- elsif results.length == 1
76
- results[0]['path']
77
-
78
- # if there are multiple results, score them based on artist + album
79
- else
80
- scores = Hash.new 0
81
- results.each do |result|
82
- [:artist, :album].each do |identifier|
83
- tokens = selection[identifier].downcase
84
- .gsub(%r( +), " ")
85
- .gsub(%r(-+), "-")
86
- .strip
87
- .split(/[\s-]/)
88
- tokens.each do |token|
89
- scores[result['path']] += 1 if result['path'].downcase.include? token
90
- end
91
- end
92
- end
93
-
94
- # return the path that has the highest score
95
- (scores.sort_by { |path, score| score })[-1][0]
96
- end
97
- end
98
-
99
- end
100
-
101
- end