Sunday, April 15, 2012

Do it with Vim, Nexus

Today I needed to rename a bunch of mp3 files in the format split-track01.mp3 to their real names as described in a .cue file. All the heavy lifting of splitting the actual music files out of the .ape were handled by cuebreakpoints and shntool. Even the tag data was marshalled over nicely with cuetag. If I had known about the -t flag on shntool's split subcommand, my day would have been over and done with. I didn't, so I was faced with a bunch of uselessly named .mp3 files with the goodies buried in a .cue file.

An exercise for the user! Joy! Well, we know we ain't gonna do that by hand.  So... I could fire up perl or ruby or awk or just sed... Bah. Vim it is then!

I gingerly cradled my freshly microwaved mug of cocoa while pondering how to eat this elephant. Deciding it was too hot yet to enjoy, I jumped into the terminal and typed:

  vim file.cue

Then with a flick of the Vim wrist, I mashed:
 
  :v/^\s\+TITLE/d
  :%s/^\s*TITLE/\=printf("mv split-track%02d.mp3", s1.next())
  :%s/"$/.mp3"/
  :set fileformat=unix
  :saveas rename.sh
  :quit

Ah, almost done. Now, out in the terminal again, I just:

  chmod +x ./rename.sh
  ./rename.sh

And I still had to wait for my cocoa to cool.

NOTE: The fileformat=unix nonsense was because the original had dos line endings.

The pious reader will have noticed a fairly bold cheat in my Vim there. That s1 object looks suspicious. It's not as heinous as you might imagine. He belongs to my Nexus plugin which provides series objects for just these sort of occasions in Vim.

The s1 object has a method called next() which returns the next number in the series. As his name implies, the first such number is 1. There is a corresponding s0 object whose first call to next() yields, of course, the number 0. The gentle user is free to create their own series objects too:

  :let even_seq = Series(0, 2)

The command:

  :echo even_seq.next()

will print 2 on the first call, then 4, then 6, 8, 10, etc, on subsequent calls.

The Series constructor has the following signatures:
  • Series() -> starting at 0 with an increment of 1 -> 1, 2, 3, 4, ...
  • Series(7) -> starting at 0 with an increment of 7 -> 7, 14, 21, 28, ...
  • Series(7, 2) -> starting at 7 with an increment of 2 -> 9, 11, 13, 15, ...
  • Series(2, 7) -> starting at 2 with an increment of 7 -> 9, 16, 23, 30, ...
Nexus's Series Objects provide the following methods:
  • reset() to set the object back to its original values when created
  • next() to increment and return the next number in the series
  • inc() as an alias for next()
  • value() to return the current value without incrementing internal state
  • val() as an alias for value()
  • set() to explicitly alter the internal value (but not increment amount)
I use s1 a lot in my daily vimming. It could be useful to you too.