diff --git a/config/devices.yml b/config/devices.yml index 29a35bd..4506b0f 100644 --- a/config/devices.yml +++ b/config/devices.yml @@ -17,6 +17,7 @@ devices: unsupported_characters: - "™" - '"' + uppercase_paths: true - name: Octatrack sample_rates: diff --git a/lib/wavesync/device.rb b/lib/wavesync/device.rb index ed922f3..5d9c6f0 100644 --- a/lib/wavesync/device.rb +++ b/lib/wavesync/device.rb @@ -12,9 +12,10 @@ class Device attr_reader :bar_multiple #: Integer? attr_reader :unsupported_characters #: Array[String] attr_reader :transliterate_metadata #: bool + attr_reader :uppercase_paths #: bool - #: (name: String, sample_rates: Array[Integer], file_types: Array[String], ?bit_depths: Array[Integer], ?bpm_source: Symbol?, ?bar_multiple: Integer?, ?unsupported_characters: Array[String], ?transliterate_metadata: bool) -> void - def initialize(name:, sample_rates:, file_types:, bit_depths: [], bpm_source: nil, bar_multiple: nil, unsupported_characters: [], transliterate_metadata: false) + #: (name: String, sample_rates: Array[Integer], file_types: Array[String], ?bit_depths: Array[Integer], ?bpm_source: Symbol?, ?bar_multiple: Integer?, ?unsupported_characters: Array[String], ?transliterate_metadata: bool, ?uppercase_paths: bool) -> void + def initialize(name:, sample_rates:, file_types:, bit_depths: [], bpm_source: nil, bar_multiple: nil, unsupported_characters: [], transliterate_metadata: false, uppercase_paths: false) @name = name @sample_rates = sample_rates @bit_depths = bit_depths @@ -23,6 +24,7 @@ def initialize(name:, sample_rates:, file_types:, bit_depths: [], bpm_source: ni @bar_multiple = bar_multiple @unsupported_characters = unsupported_characters @transliterate_metadata = transliterate_metadata + @uppercase_paths = uppercase_paths end #: () -> String @@ -52,7 +54,8 @@ def self.load_from_yaml bpm_source: attrs['bpm_source']&.to_sym, bar_multiple: attrs['bar_multiple'], unsupported_characters: attrs['unsupported_characters'] || [], - transliterate_metadata: attrs['transliterate_metadata'] || false + transliterate_metadata: attrs['transliterate_metadata'] || false, + uppercase_paths: attrs['uppercase_paths'] || false ) end end diff --git a/lib/wavesync/path_resolver.rb b/lib/wavesync/path_resolver.rb index f69805b..3b25678 100644 --- a/lib/wavesync/path_resolver.rb +++ b/lib/wavesync/path_resolver.rb @@ -24,7 +24,8 @@ def resolve(source_file_path, audio, target_file_type: nil) bpm = audio.bpm target_path = add_bpm_to_filename(target_path, bpm) if @device.bpm_source == :filename && bpm - strip_unsupported_characters(target_path) + target_path = strip_unsupported_characters(target_path) + uppercase_relative_path(target_path) end #: (Pathname target_path, Audio audio) -> Array[Pathname] @@ -59,6 +60,15 @@ def strip_unsupported_characters(path) Pathname(path.to_s.delete(@device.unsupported_characters.join)) end + #: (Pathname path) -> Pathname + def uppercase_relative_path(path) + return path unless @device.uppercase_paths + + relative = path.relative_path_from(@target_library_path) + uppercased = relative.each_filename.map(&:upcase).join('/') + @target_library_path.join(uppercased) + end + #: (Pathname path) -> Pathname def remove_bpm_from_filename(path) ext = path.extname diff --git a/test/wavesync/device_test.rb b/test/wavesync/device_test.rb index 153ec17..2fb1842 100644 --- a/test/wavesync/device_test.rb +++ b/test/wavesync/device_test.rb @@ -51,6 +51,20 @@ class DeviceTest < Wavesync::TestCase assert_includes tp7.unsupported_characters, '"' end + test 'TP-7 has uppercase_paths enabled' do + tp7 = Device.find_by(name: 'TP-7') + assert_equal true, tp7.uppercase_paths + end + + test 'uppercase_paths defaults to false' do + device = Device.new( + name: 'Test', + sample_rates: [44_100], + file_types: ['wav'] + ) + assert_equal false, device.uppercase_paths + end + test 'Octatrack device attributes are correct' do octatrack = Device.find_by(name: 'Octatrack') refute_nil octatrack diff --git a/test/wavesync/file_converter_test.rb b/test/wavesync/file_converter_test.rb index 795ddbb..4b36051 100644 --- a/test/wavesync/file_converter_test.rb +++ b/test/wavesync/file_converter_test.rb @@ -52,7 +52,7 @@ def teardown test 'convert skips when converted file already exists in target location' do source_aiff = File.join(@source_dir, 'track.aiff') FileUtils.touch(source_aiff) - FileUtils.touch(File.join(@target_dir, 'track.mp3')) + FileUtils.touch(File.join(@target_dir, 'TRACK.MP3')) Audio.any_instance.stubs(:duration).returns(0) audio = stub(bpm: nil, duration: 0) diff --git a/test/wavesync/path_resolver_test.rb b/test/wavesync/path_resolver_test.rb index 0998cb6..d8543c1 100644 --- a/test/wavesync/path_resolver_test.rb +++ b/test/wavesync/path_resolver_test.rb @@ -17,7 +17,7 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio) - assert_equal '/media/device/music/artist/album/song.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST/ALBUM/SONG.WAV', target_path.to_s end test 'resolve changes file extension when target_file_type provided' do @@ -25,7 +25,7 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio, target_file_type: 'wav') - assert_equal '/media/device/music/artist/album/song.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST/ALBUM/SONG.WAV', target_path.to_s end test 'resolve handles complex paths with spaces and special characters' do @@ -33,7 +33,7 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio, target_file_type: 'wav') - assert_equal '/media/device/music/electronic/aphex twin/selected ambient works/xtal.wav', + assert_equal '/media/device/music/ELECTRONIC/APHEX TWIN/SELECTED AMBIENT WORKS/XTAL.WAV', target_path.to_s end @@ -52,7 +52,7 @@ def setup audio = stub(bpm: nil) target_path = resolver.resolve(source_file, audio) - assert_equal '/media/device/artist/song.wav', target_path.to_s + assert_equal '/media/device/ARTIST/SONG.WAV', target_path.to_s end test 'handles source library with trailing slash' do @@ -62,7 +62,7 @@ def setup audio = stub(bpm: nil) target_path = resolver.resolve(source_file, audio) - assert_equal '/media/device/artist/song.wav', target_path.to_s + assert_equal '/media/device/ARTIST/SONG.WAV', target_path.to_s end test 'adds bpm to filename when device has bpm_source :filename' do @@ -78,7 +78,7 @@ def setup audio = stub(bpm: 140) target_path = resolver_for('TP-7').resolve(source_file, audio) - assert_equal '/media/device/music/artist/song.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST/SONG.WAV', target_path.to_s end test 'does not add bpm to filename when audio has no bpm' do @@ -186,7 +186,7 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio) - assert_equal '/media/device/music/artist/song.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST/SONG.WAV', target_path.to_s end test 'resolve strips double-quote from filename' do @@ -194,7 +194,7 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio) - assert_equal '/media/device/music/artist/song remix.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST/SONG REMIX.WAV', target_path.to_s end test 'resolve strips unsupported characters from filename for Octatrack with bpm' do @@ -218,7 +218,7 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio) - assert_equal '/media/device/music/artist/song.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST/SONG.WAV', target_path.to_s end test 'resolve strips double-quote from directory names' do @@ -226,7 +226,23 @@ def setup audio = stub(bpm: nil) target_path = resolver_for('TP-7').resolve(source_file, audio) - assert_equal '/media/device/music/artist label/song.wav', target_path.to_s + assert_equal '/media/device/music/ARTIST LABEL/SONG.WAV', target_path.to_s + end + + test 'resolve uppercases folder and file names for TP-7' do + source_file = '/home/user/music/Deep House/my track.wav' + audio = stub(bpm: nil) + target_path = resolver_for('TP-7').resolve(source_file, audio) + + assert_equal '/media/device/music/DEEP HOUSE/MY TRACK.WAV', target_path.to_s + end + + test 'resolve does not uppercase for Octatrack' do + source_file = '/home/user/music/Deep House/my track.wav' + audio = stub(bpm: nil) + target_path = resolver_for('Octatrack').resolve(source_file, audio) + + assert_equal '/media/device/music/Deep House/my track.wav', target_path.to_s end test 'find_files_to_cleanup does not include the target file itself' do diff --git a/test/wavesync/scanner_test.rb b/test/wavesync/scanner_test.rb index d77469c..ebcc56b 100644 --- a/test/wavesync/scanner_test.rb +++ b/test/wavesync/scanner_test.rb @@ -40,7 +40,7 @@ def teardown source_wav = File.join(@source_dir, 'track.wav') FileUtils.cp(fixture('44100_16.wav'), source_wav) - target_wav = File.join(@target_dir, 'track.wav') + target_wav = File.join(@target_dir, 'TRACK.WAV') FileUtils.cp(fixture('44100_16.wav'), target_wav) cue_points = [{ identifier: 1, sample_offset: 44_100, label: 'Marker' }] CueChunk.write(target_wav, "#{target_wav}.tmp", cue_points) @@ -61,7 +61,7 @@ def teardown CueChunk.write(source_wav, "#{source_wav}.tmp", cue_points) FileUtils.mv("#{source_wav}.tmp", source_wav) - target_wav = File.join(@target_dir, 'track.wav') + target_wav = File.join(@target_dir, 'TRACK.WAV') FileUtils.cp(source_wav, target_wav) Audio.any_instance.expects(:write_cue_points).never @@ -97,7 +97,7 @@ def teardown source_wav = File.join(File.expand_path(@source_dir), 'track.wav') FileUtils.cp(fixture('44100_16.wav'), source_wav) - expected_target = Pathname(File.join(File.expand_path(@target_dir), 'track.wav')) + expected_target = Pathname(File.join(File.expand_path(@target_dir), 'TRACK.WAV')) Audio.any_instance.stubs(:bpm).returns(120) AcidChunk.stubs(:write_bpm) Logger.expects(:log_error).with( @@ -112,7 +112,7 @@ def teardown source_wav = File.join(File.expand_path(@source_dir), 'track.wav') FileUtils.cp(fixture('44100_16.wav'), source_wav) - expected_target = Pathname(File.join(File.expand_path(@target_dir), 'track.wav')) + expected_target = Pathname(File.join(File.expand_path(@target_dir), 'TRACK.WAV')) Audio.any_instance.stubs(:bpm).returns(nil) FileUtils.stubs(:install) Logger.expects(:log_error).with( @@ -127,7 +127,7 @@ def teardown source_aiff = File.join(File.expand_path(@source_dir), 'track.aiff') FileUtils.cp(fixture('44100_16.aiff'), source_aiff) - expected_target = Pathname(File.join(File.expand_path(@target_dir), 'track.wav')) + expected_target = Pathname(File.join(File.expand_path(@target_dir), 'TRACK.WAV')) Audio.any_instance.stubs(:transcode).returns(true) Logger.expects(:log_error).with( instance_of(RuntimeError), @@ -152,7 +152,7 @@ def teardown Audio.any_instance.expects(:transcode).never Scanner.new(@source_dir).sync(@target_dir, @device) - target_mp3 = File.join(@target_dir, 'track.mp3') + target_mp3 = File.join(@target_dir, 'TRACK.MP3') assert File.exist?(target_mp3) end @@ -160,7 +160,7 @@ def teardown source_wav = File.join(File.expand_path(@source_dir), 'track.wav') FileUtils.cp(fixture('44100_16.wav'), source_wav) - expected_target = Pathname(File.join(File.expand_path(@target_dir), 'track.wav')) + expected_target = Pathname(File.join(File.expand_path(@target_dir), 'TRACK.WAV')) FileUtils.stubs(:install).raises(Errno::ENOENT) Logger.expects(:log_error).with( instance_of(Errno::ENOENT),