*update* I added the music sort files to a github repo: http://github.com/victusfate/music-sort
I've got a fairly sizable collection of music. It's more than I need, and certainly more than I want to worry about. I decided before nuking it to make one more effort to clean it up and shrink it down to one directory. This script could have been 21 lines of code but I preferred monitoring it with a puts statement.
The first pass code:
require 'fileutils' orig = '/home/messel/Desktop/music/' dest = '/home/messel/Desktop/mobilemusic/' Dir.chdir(orig) Dir.glob('*.m3u') do |m3u_name| m3us = IO.readlines(m3u_name) out_m3u = File.new(dest+m3u_name,'w+') m3us.each do |m3u| m3u.gsub!(/\/,'/') b1 = File.basename(m3u) out_m3u << b1 # write new m3u with carriage return m3u = m3u.chomp # remove carriage return for file manip unless m3u['#'] basename = File.basename(m3u) puts "orig #{orig+m3u} dest #{dest+basename}" if File.exist? orig+m3u and !File.exist? dest+basename FileUtils.cp(orig+m3u,dest+basename) end end end out_m3u.close end
As you can imagine for large music collection operations, there were a number of exception files that were missing or had special characters I failed to handle. My next script identified the missing files from my new music collection folder, but that were still referenced on playlists.
def check_for_file(m3u_name) m3us = IO.readlines(m3u_name) m3us.each do |m3u| m3u = m3u.chomp # remove carriage return for file manip puts "List #{m3u_name} missing #{m3u}" unless File.exist? m3u or m3u['#'] end end if (ARGV.size > 0) check_for_file ARGV[0].to_s else Dir.glob('*.m3u').each do |m3u_name| check_for_file m3u_name end end
For this script I added an optional parameter (ARGV) to let me test it on a single file first before going hog wild in the full directory. After identifying a number of missed files, I modified the missing script to go back and grab the files from another remote disk where I back up much of my older music.
require 'fileutils' def check_for_file(m3u_name,path,opath) m3us = IO.readlines(m3u_name) m3us.each do |m3u| m3u = m3u.chomp # remove carriage return for file manip unless File.exist? m3u or m3u['#'] puts m3u Dir.glob(path+'**/'+m3u).each do |found| puts "found file on FIRELITE #{found}" FileUtils.cp(found,opath + m3u) # Process.exit end end end end path = '/media/FIRELITE_/music/' opath = '/home/messel/Desktop/music/' if (ARGV.size > 0) check_for_file ARGV[0].to_s, path, opath else Dir.glob('*.m3u').each do |m3u_name| check_for_file m3u_name, path, opath end end
Even after all that there were many play lists with files that I no longer had or knew their whereabouts. Thus came the great pruning. The following program identifies at least one missing music file, then creates a new output play list skipping over any missing files.
require 'fileutils' def check_for_file(m3u_name,opath) prune = false m3us = IO.readlines(m3u_name) m3us.each do |m3u| m3u = m3u.chomp # remove carriage return for file manip unless File.exist? m3u or m3u['#'] prune = true break end end if prune puts "Pruning from #{m3u_name}" FileUtils.mv(m3u_name,opath+"back_"+File.basename(m3u_name)) out_m3u = File.new(opath+File.basename(m3u_name),'w+') prevline = '' m3us.each do |m3u_line| m3u = m3u_line.chomp # remove carriage return for file manip if m3u['#'] prevline = m3u + "\n" next end if File.exist? m3u # puts prevline unless prevline.length == 0 # puts m3u_line out_m3u << prevline unless prevline.length == 0 out_m3u << m3u_line prevline = '' end end out_m3u.close end end opath = '/home/messel/Desktop/music/' if (ARGV.size > 0) check_for_file ARGV[0].to_s, opath else Dir.glob('*.m3u').each do |m3u_name| check_for_file m3u_name, opath end end
But I wasn't very careful with my script, and used '\n' instead of "\n" (corrected above) which mean instead of line feeds (carriage returns for ancient typewriter folks like me) between description and file lines, I had ONE BIG MESS. After rolling my sleeves up and spelunking the dangerous caverns of regular expressions I came up with one final script to correct my woes. This script was appropriately labeled "oh_god_why.rb".
require 'fileutils' def check_for_file(m3u_name,opath) prune = false m3us = IO.readlines(m3u_name) out_m3u = File.new(opath+File.basename(m3u_name),'w+') m3us.each do |m3u_line| out_m3u << m3u_line.gsub(/\n/,"\n") end out_m3u.close end opath = '/home/messel/Desktop/music/' if (ARGV.size > 0) check_for_file ARGV[0].to_s, opath else Dir.glob('*.m3u').each do |m3u_name| check_for_file m3u_name, opath end end
Astute readers will notice that I've included several programs beyond the original 22 line script throughout this post. When it comes to doing jobs right, I believe a slight exaggeration goes a long way, but it's best to show your friends the full truth. "Pay no attention to the man behind the curtain".
references: