Skip to content

Instantly share code, notes, and snippets.

@alexblackie
Last active February 20, 2018 02:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexblackie/8e3688b245991c0d574df4d97f695b51 to your computer and use it in GitHub Desktop.
Save alexblackie/8e3688b245991c0d574df4d97f695b51 to your computer and use it in GitHub Desktop.
This is how I manage my music library. SHA256 hashes as filenames, transcoded to MP3@320K, is what gets distributed to my phones, laptops, etc. FLAC/MP3 masters get left on the NAS.
# vim: ts=4 sw=4 noexpandtab
require "digest"
require "fileutils"
class Transcoder
CONCURRENCY = 8.freeze
DEFAULT_OUTPUT_DIR = File.join(File.dirname(__FILE__), "..", "mp3s").freeze
MANIFEST_FILE = ".transcode.manifest".freeze
MANIFEST_DELIMITER = "||".freeze
# @param output [String] path to the directory to store output MP3s
def initialize(target: DEFAULT_OUTPUT_DIR)
@flacs = Dir["**/*.flac"]
@mp3s = Dir["**/*.mp3"]
@existing = Dir["#{ target }/*.mp3"]
@target = target
@manifest = populate_manifest()
FileUtils.mkdir_p(@target)
end
def transcode
@flacs.each do |f|
next if @manifest.has_key?(f)
target = dest(f)
puts "Transcoding #{ f} -> #{ target }"
unless File.exist?(target)
`ffmpeg -loglevel panic -i "#{ f }" -threads #{ CONCURRENCY } -acodec libmp3lame -b:a 320k '#{ dest(f) }'`
end
@manifest[f] = target
end
@mp3s.each do |f|
next if @manifest.has_key?(f)
target = dest(f)
puts "Copying #{ f } -> #{ target }"
unless File.exist?(target)
FileUtils.cp(f, target)
end
@manifest[f] = target
end
write_manifest()
end
private
def dest(file)
"#{ @target }/#{ hashify(file) }.mp3"
end
def hashify(file)
Digest::SHA256.hexdigest(File.read(file)).upcase
end
def write_manifest
content = @manifest.reduce(""){|acc, (orig,dest)| acc + orig + MANIFEST_DELIMITER + dest + "\n"}
File.write(MANIFEST_FILE, content)
end
def populate_manifest
FileUtils.touch(MANIFEST_FILE) unless File.exist?(MANIFEST_FILE)
File.
read(MANIFEST_FILE).
lines.
reduce({}) do |acc, l|
line = l.split(MANIFEST_DELIMITER)
acc[line.first] = line.last
acc
end
end
end
Transcoder.new.transcode
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment