Class: Ramekin::SamplePack

Inherits:
Object
  • Object
show all
Extended by:
Enumerable
Defined in:
lib/ramekin/sample_pack.rb

Direct Known Subclasses

CustomSamplePack

Constant Summary collapse

TUNING_RE =
%r(
  "(.*?[.]brr)" \s*
    [$](\h\h) \s*
    [$](\h\h) \s*
    [$](\h\h) \s*
    [$](\h\h) \s*
    [$](\h\h)
)x

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ SamplePack

Returns a new instance of SamplePack.



97
98
99
# File 'lib/ramekin/sample_pack.rb', line 97

def initialize(data)
  @meta = data
end

Class Method Details

.add_custom(name, path) ⇒ Object



93
94
95
# File 'lib/ramekin/sample_pack.rb', line 93

def self.add_custom(name, path)
  custom_packs[name] = path
end

.custom_packsObject



89
90
91
# File 'lib/ramekin/sample_pack.rb', line 89

def self.custom_packs
  @custom_packs ||= {}
end

.download_all!Object



260
261
262
263
# File 'lib/ramekin/sample_pack.rb', line 260

def self.download_all!
  smwc_each(&:download)
  each(&:index_and_save!)
end

.each(&b) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/ramekin/sample_pack.rb', line 70

def self.each(&b)
  return enum_for(:each) unless block_given?

  custom_packs.each do |name, path|
    Dir.chdir(path) do
      yield CustomSamplePack.new(name, path)
    end
  end

  Dir.chdir Ramekin.config.packages_dir do
    Dir.entries('.').sort.each do |subd|
      next unless /\A\d+\z/ =~ subd
      Dir.chdir(subd) do
        yield new(JSON.load_file(".meta.json"))
      end
    end
  end
end

.find(name) ⇒ Object



61
62
63
64
65
66
67
# File 'lib/ramekin/sample_pack.rb', line 61

def self.find(name)
  each do |pack|
    return pack if pack.name == name
  end

  return nil
end

.smwc_each(&b) ⇒ Object



50
51
52
53
54
55
56
57
58
59
# File 'lib/ramekin/sample_pack.rb', line 50

def self.smwc_each(&b)
  params = { a: 'getsectionlist', s: 'brrsamples' }
  page = APIEndpoint.get!(**params)
  page['data'].each { |e| yield new(e) }

  (2..page['last_page']).each do |n|
    page = APIEndpoint.get!(n: n, **params)
    page['data'].each { |e| yield new(e) }
  end
end

Instance Method Details

#authorsObject



113
114
115
# File 'lib/ramekin/sample_pack.rb', line 113

def authors
  (@meta['authors'] || []).map { |a| a && a['name'] }.compact
end

#brrsObject



247
248
249
# File 'lib/ramekin/sample_pack.rb', line 247

def brrs
  cached_index['brrs']
end

#cached_indexObject



231
232
233
# File 'lib/ramekin/sample_pack.rb', line 231

def cached_index
  @cached_index ||= JSON.load_file("#{dir}/.index.json")
end

#cached_jsonObject



270
271
272
273
274
# File 'lib/ramekin/sample_pack.rb', line 270

def cached_json
  @cached_json ||= JSON.load_file(meta_file)
rescue Errno::ENOENT
  nil
end

#dirObject



284
285
286
# File 'lib/ramekin/sample_pack.rb', line 284

def dir
  "#{Ramekin.config.packages_dir}/#{id}"
end

#downloadObject



288
289
290
291
292
293
294
295
296
# File 'lib/ramekin/sample_pack.rb', line 288

def download
  unless needs_download?
    $stderr.puts "skipping: #{name}:#{id}"
    return
  end

  $stderr.puts "downloading: #{name}:#{id}"
  download!
end

#download!Object



298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/ramekin/sample_pack.rb', line 298

def download!
  $stderr.puts "downloading to #{dir}"
  FileUtils.rm_rf(dir, secure: true)
  FileUtils.mkdir_p(dir)

  Dir.chdir(dir) do
    zip = URI.open(download_url).read
    Zip::File.open_buffer(zip).each do |entry|
      # look of disapproval
      next if entry.directory?
      next if entry.name =~ /__MACOSX/
      next unless File.expand_path(name).start_with?(File.expand_path('.'))

      $stderr.puts " -> #{entry.name}"
      FileUtils.mkdir_p(File.dirname(entry.name))
      entry.extract(entry.name)
    end
  end

  File.write(meta_file, JSON.dump(@meta))
end

#download_urlObject



131
132
133
# File 'lib/ramekin/sample_pack.rb', line 131

def download_url
  @meta['download_url'] or raise 'no download_url'
end

#exists?Boolean

Returns:

  • (Boolean)


276
277
278
# File 'lib/ramekin/sample_pack.rb', line 276

def exists?
  File.exist?(meta_file) && !!cached_json && !!cached_json['id']
end

#find(path) ⇒ Object



117
118
119
120
# File 'lib/ramekin/sample_pack.rb', line 117

def find(path)
  path = path.chomp('.brr')
  File.join(prefix_dir, "#{path}.brr")
end

#find_tunings(name_re) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/ramekin/sample_pack.rb', line 158

def find_tunings(name_re)
  raw = []
  Dir.glob('**/*.txt', File::FNM_CASEFOLD).sort.each do |entry|
    next unless File.basename(entry).downcase =~ name_re

    contents = File.read(entry, encoding: 'binary')

    contents.gsub!(/;.*$/, '')
    # windows paths...
    contents.gsub!(/\\/, '/')

    # contents.scan /#path\s*"(.*?)"/ do |(path)|
    #   paths << path
    # end

    contents.scan TUNING_RE do |(path, *hexes)|
      raw << [entry, path, hexes]
    end
  end

  out = Hash.new {|h,k| h[k] = []}
  raw.each do |tuning_path, name, hexes|
    out[File.basename(name).downcase] << [tuning_path, name, hexes]
  end

  out
end

#has?(path) ⇒ Boolean

Returns:

  • (Boolean)


122
123
124
# File 'lib/ramekin/sample_pack.rb', line 122

def has?(path)
  File.exist?(find(path))
end

#idObject



105
106
107
# File 'lib/ramekin/sample_pack.rb', line 105

def id
  @meta['id'].to_i or raise 'no id'
end

#index!Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/ramekin/sample_pack.rb', line 198

def index!
  paths = []
  raw_tunings = []

  patterns_tunings = find_tunings(/\A!patterns[.]txt\z/)
  other_tunings = find_tunings(/\Atuning/)
  misc_tunings = find_tunings(//)

  @brrs = Dir.glob('**/*.brr', File::FNM_CASEFOLD)
  @brrs.sort!
  @brrs.uniq!
  @prefix = shortest_prefix(@brrs.map(&File.method(:dirname)))

  @tunings = {}
  @brrs.each do |brr|
    base = File.basename(brr).downcase
    next if base == 'empty.brr'

    candidates = patterns_tunings[base]
    candidates = other_tunings[base] if candidates.empty?
    candidates = misc_tunings[base] if candidates.empty?

    candidates = candidates.uniq { |_,_,h| h }

    # if there is more than one candidate, prioritize the one that's closest
    if candidates.size >= 2
      candidates.sort_by! { |path, _, _| -shortest_prefix([brr, path]).size }
    end

    @tunings[brr] = candidates.map { |p, _, h| [p, h] }
  end
end

#index_and_save!Object



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/ramekin/sample_pack.rb', line 186

def index_and_save!
  index!

  File.write('.index.json', JSON.dump(
    prefix: @prefix,
    brrs: @brrs,
    tunings: @tunings,
  ))

  @cached_index = nil
end

#meta_fileObject



280
281
282
# File 'lib/ramekin/sample_pack.rb', line 280

def meta_file
  "#{dir}/.meta.json"
end

#nameObject



101
102
103
# File 'lib/ramekin/sample_pack.rb', line 101

def name
  @meta['name'] or raise 'no name'
end

#needs_download?Boolean

Returns:

  • (Boolean)


265
266
267
268
# File 'lib/ramekin/sample_pack.rb', line 265

def needs_download?
  return true unless exists?
  @meta['time'] > cached_json['time']
end

#prefixObject



235
236
237
# File 'lib/ramekin/sample_pack.rb', line 235

def prefix
  cached_index['prefix']
end

#prefix_dirObject



255
256
257
258
# File 'lib/ramekin/sample_pack.rb', line 255

def prefix_dir
  return dir if prefix == '.'
  File.join(dir, prefix)
end

#shortest_prefix(paths) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/ramekin/sample_pack.rb', line 135

def shortest_prefix(paths)
  paths = paths.map { |x| x.split('/') }.sort_by(&:size)

  prefix = []
  loop do
    break if paths[0].empty?
    init = paths.map(&:shift).uniq
    break if init.size > 1
    prefix << init[0]
  end

  prefix.join('/')
end

#tuningsObject



251
252
253
# File 'lib/ramekin/sample_pack.rb', line 251

def tunings
  cached_index['tunings']
end

#tunings_for(path) ⇒ Object



126
127
128
129
# File 'lib/ramekin/sample_pack.rb', line 126

def tunings_for(path)
  rel = Pathname.new(find(path)).relative_path_from(dir).to_s
  (tunings[rel] || []).map(&:last)
end

#unprefix(path) ⇒ Object



239
240
241
# File 'lib/ramekin/sample_pack.rb', line 239

def unprefix(path)
  Pathname.new(dir).join(path).relative_path_from(prefix_dir).to_s
end

#unprefixed_brrsObject



243
244
245
# File 'lib/ramekin/sample_pack.rb', line 243

def unprefixed_brrs
  brrs.map(&method(:unprefix))
end

#urlObject



109
110
111
# File 'lib/ramekin/sample_pack.rb', line 109

def url
  "https://www.smwcentral.net/?p=section&a=details&id=#{id}"
end