Rhythmbox ID3 Tag Issues

Posted on July 8th, 2008 in Tech Tips by gmendoza

So I recently noticed that Rhythmbox was behaving strangely when reading the ID3 tags of my MP3 collection purchased online via Amazon.com. No matter what ID3 tag editor I used to try to correct the issue, Rhythmbox appeared to be displaying tag information that didn’t seem to match any of the values they should be. Artist names would not appear as I set them. Track numbers and genres would display as blank values. ‘What gives?’, I thought.

So I decided to use “strings” to take a look inside the MP3’s and find out what’s going on. It turns out my MP3’s were double tagged with v1 metadata and it was screwing up Rhythmbox’s organizational skills! Boo!

Some brief background info on ID3 tagging is needed before we continue. ID3 v1.x tags are located at the tail end of an MP3, whereas v2.x tags are located at the beginning of the file. To view the raw tag data, open up a terminal window and use the strings command to parse the mp3 for text.

$ strings songname.mp3 | head
$ strings songname.mp3 | tail

Here’s an example of the output obtained from one of my problematic tracks. I wanted the artist name to appear as “Bob Marley”, but Rhythmbox insisted on displaying “Bob Marley & The Wailers”.

$ strings 01\ -\ Is\ This\ Love.mp3 | tail
J/q:
X0aZ
-g%U
TAGIs This Love
Bob Marley & The Wailers
Legend
TAGIs This Love
Bob Marley
Legend
2002Amazon.com Song ID: 20254105

In this example, you can see I have two ID3v1.x tags at the end of the file. Each tag starts with “TAG”, immediately followed by the track name, artist and album. Rhythmbox was only reading the first one, but all of the tag editors I tried were working with the last one.

Solution:
Simply remove all ID3v1.x tags twice, then re-write them if you wish. An easy command line application for this job is “eyeD3“. Others may work as well, but of course your mileage may vary.

Install eyeD3 from repositories if you use Debian/Ubuntu.

$ sudo apt-get install eyed3

Display the outer-most ID3v1.x tag

$ eyeD3 -1 01\ -\ Is\ This\ Love.mp3

Remove the outer-most ID3v1.x tag twice, or until they’re all gone. I trimmed the output below for brevity.

$ eyeD3 --remove-v1 01\ -\ Is\ This\ Love.mp3 1>/dev/null
Removing ID3 v1.x tag: SUCCESS
$ eyeD3 --remove-v1 01\ -\ Is\ This\ Love.mp3 1>/dev/null
Removing ID3 v1.x tag: SUCCESS

Doing so immediately resolves the Rhythmbox tag display issue, as it reverts back to using the v2.x tags at the beginning of the file.

Fixing the problem in bulk:
If you want to fix all of your MP3’s fast, you can use any of the following methods. Remember, you must run them at least twice, or until all v1.x tags have been removed. The commands listed below use "1>/dev/null to remove all standard output, but still allows standard error messages to be shown. Interestingly, the SUCCESS messages eyeD3 uses are written to standard error, so you’ll see those too.

If all your MP3’s are in the same directory:

$ for i in *.mp3 ; do eyeD3 --remove-v1 "$i" 1>/dev/null ; done

If all your MP3’s span multiple subdirectories:

$ find . -type f -name *.mp3 -exec eyeD3 --remove-v1 '{}' 1>/dev/null \;

Alternatively, you can use a python script written by UlyssesR, originally contributed on the Ubuntu Forums here. The script has the advantage of only needing to be run once and it is relatively safe to use. I actually used it on my entire collection before using eyeD3 in this manner with no problems. I then reapplied my tags using EasyTag.

Rename Files in Bulk from the Command Line

Posted on July 6th, 2008 in Tech Tips by gmendoza

Renaming a large number of files can seem like a daunting task, but no worries, your trusty Linux CLI is at your service. For this example, we will rename a number of MP3’s located in multiple subdirectories with a couple very easy commands; “find” and “rename”.

By listing the following directory, you’ll see that the MP3’s have been named with “(LP Version)”, and of course I don’t like this naming convention.

$ cd ~/Music/Metallica/Metallica/
$ ls -1
01 - Enter Sandman (LP Version).mp3
02 - Sad But True (LP Version).mp3
03 - Holier Than Thou (LP Version).mp3
04 - The Unforgiven (LP Version).mp3
05 - Wherever I May Roam (LP Version).mp3
06 - Don't Tread On Me (LP Version).mp3
07 - Through The Never (LP Version).mp3
08 - Nothing Else Matters (LP Version).mp3
09 - Of Wolf And Man (LP Version).mp3
10 - The God That Failed (LP Version).mp3
11 - My Friend Of Misery (LP Version).mp3
12 - The Struggle Within (LP Version).mp3

We’ll use the “rename” command to search for and delete the string ” (LP Version)” in any of the mp3 file names.

Syntax:

$ rename (search command) (files)
$ rename 's/search_for_string/replace_string_with_this/' files

To delete the matching string, simply leave the replace area empty like so:

$ rename 's/search_for_string//' files

Our Example:

$ rename 's/ \(LP Version\)//' *.mp3

Notice, the left and right parentheses need to be preceded with a backslash “\” character, although the spaces do not. The backslash is a metacharacter used to give you control over what your are matching against. For more info, here’s a link to a decent tutorial on the matter.

You can see the results of the command below.

$ ls -1
01 - Enter Sandman.mp3
02 - Sad But True.mp3
03 - Holier Than Thou.mp3
04 - The Unforgiven.mp3
05 - Wherever I May Roam.mp3
06 - Don't Tread On Me.mp3
07 - Through The Never.mp3
08 - Nothing Else Matters.mp3
09 - Of Wolf And Man.mp3
10 - The God That Failed.mp3
11 - My Friend Of Misery.mp3
12 - The Struggle Within.mp3

Now, to rename a large number of files spanning multiple directories, simply combine “rename” with the power of the “find” command.

Syntax:

find . -type f -name *.mp3 -exec rename 's/ \(LP Version\)//' '{}' \;

In this example, we searched starting from the current directory for only files with .mp3 in their file names. We use the find command’s -exec option to execute the rename command against the result set. See the find(1) manpage for more info.

Other useful examples:

Replace all spaces with underscores
rename 's/ /\_/g' *.mp3

Replace all uppercase with lowercase characters
rename 'y/[A-Z]/[a-z]/' *.mp3

Easy stuff, and you don’t even need any fancy applications to do the job!

Generate Text From Templates, Scripts and CSV Data

Posted on March 6th, 2008 in Tech Tips by gmendoza

If you are working on a project requiring that you generate hundreds or thousands of similar but unique text files, you probably will be looking for some type of task automation process. For example, a recent project required that we configure hundreds of Cisco switch configuration files, each being uniquely individualized with IP addresses, OSPF configurations, random passwords, etc. We also needed to configure an import data file for over a thousand DHCP ranges, obviously not something we felt like doing by hand.

For tasks like these, the best tools of the trade are text file templates that represent what the finished product should look like, spreadsheets for basic math and to create import data in the form of CSV’s (comma-separated values), and GNU/Linux shell scripting to pull it all together.

The process can be summarized as follows:

1. Use a template text file and identify the parts you wish to customize with easy to recognize variables.

2. Generate unique data in the CSV format that will serve to populate the template.

3. Run a Linux shell script that performs a search and replace function against the template, and outputs new text files with the values obtained from the CSV file.

In the following example, we will work with a basic Cisco switch configuration file that is condensed for brevity. Notice, we clearly label text within the template that we will use to search for and replace with values obtained from the CSV data. These variables are VAR_HOSTNAME, VAR_IPADDR, VAR_NETMASK, VAR_OSPF_KEY, VAR_TACACS_KEY.

Sample Template: import-template.txt

!
hostname VAR_HOSTNAME
!
interface Vlan100
ip address VAR_IPADDR VAR_NETMASK
ip ospf message-digest-key 1 md5 VAR_OSPF_KEY
!
tacacs-server host 1.1.1.1
tacacs-server key VAR_TACACS_KEY
!

The CSV file in our example is organized as follows:
Field 1=”Host name”, Field 2=”IP address”, Field 3=”Subnet Mask”, Field 4=”OSPF key”, and Field 5=”TACACS key”

Sample Data CSV File: import-data.txt

switch-01,10.1.1.1,255.255.255.0,ospf-key-1,tacacs-key-1
switch-02,10.1.1.2,255.255.255.0,ospf-key-2,tacacs-key-2
switch-03,10.1.1.3,255.255.255.0,ospf-key-3,tacacs-key-3
switch-04,10.1.1.4,255.255.255.0,ospf-key-4,tacacs-key-4
switch-05,10.1.1.5,255.255.255.0,ospf-key-5,tacacs-key-5

Here’s how we pull all of this together using a Linux shell script. First, we define the location of our CSV import file. Next we run a “for loop” that reads the CSV line by line, assigning each data value to a variable name. Lastly, the script concatenates the template, replacing each defined search result with values from the CSV, and sends the output to individualized text files. These text files are appropriately named according the unique value, which in this case is the switches host name.

Import Shell Script: import-script.sh

#!/bin/bash
IMPORT="./data/import-data.txt"
TEMPLATE="./data/import-template.txt"
 
for i in `cat ${IMPORT}`
do
VAR_HOSTNAME=`echo $i | awk -F, '{print $1}'`
VAR_IPADDR=`echo $i | awk -F, '{print $2}'`
VAR_NETMASK=`echo $i | awk -F, '{print $3}'`
VAR_OSPF_KEY=`echo $i | awk -F, '{print $4}'`
VAR_TACACS_KEY=`echo $i | awk -F, '{print $5}'`
cat $TEMPLATE | sed -e s/VAR_HOSTNAME/$VAR_HOSTNAME/g \
-e s/VAR_IPADDR/$VAR_IPADDR/g \
-e s/VAR_NETMASK/$VAR_NETMASK/g \
-e s/VAR_OSPF_KEY/$VAR_OSPF_KEY/g \
-e s/VAR_TACACS_KEY/$VAR_TACACS_KEY/g \
| tee ./output/$VAR_HOSTNAME.txt 1>/dev/null
done

Step By Step:

To follow along, you can download the above mentioned files, or copy and paste them from the text above. Place the import-data.txt and import-template.txt files in a new directory called “data”, create a directory called “output”, and make the import-script.sh file executable. The final step of course is to run the import script. Here is a step by step to get you going.

$ wget http://www.savvyadmin.com/download/import-script/import-script.sh
$ wget http://www.savvyadmin.com/download/import-script/import-data.txt
$ wget http://www.savvyadmin.com/download/import-script/import-template.txt
$ mkdir data output
$ mv ./import-template.txt ./import-data.txt ./data/
$ chmod 755 ./import-script.sh
$ ./import-script.sh

After you run the script successfully, list the “output” directory to see the newly created files.

$ ls -l output/
total 20
-rw-r--r-- 1 gmendoza gmendoza 184 2008-03-06 21:33 switch-01.txt
-rw-r--r-- 1 gmendoza gmendoza 184 2008-03-06 21:33 switch-02.txt
-rw-r--r-- 1 gmendoza gmendoza 184 2008-03-06 21:33 switch-03.txt
-rw-r--r-- 1 gmendoza gmendoza 184 2008-03-06 21:33 switch-04.txt
-rw-r--r-- 1 gmendoza gmendoza 184 2008-03-06 21:33 switch-05.txt

The contents of the first file in the example can be viewed as follows. Note that all the variables from the template have been replaced appropriately by the data from the CSV.

$ cat output/switch-01.txt
!
hostname switch-01
!
interface Vlan100
ip address 10.1.1.1 255.255.255.0
ip ospf message-digest-key 1 md5 ospf-key-1
!
tacacs-server host 1.1.1.1
tacacs-server key tacacs-key-1
!

I certainly hope this gives you some great ideas on how to make effective use of Linux scripts to make large amounts of work into manageable tasks. Comments and questions are welcome.

Amazon MP3 Downloader for Linux!

Posted on February 29th, 2008 in News by gmendoza

For those of you that have been waiting for Amazon.com to deliver on their promise, you will be happy to know they have just released a Linux version of the Amazon MP3 Downloader! This application is required when purchasing full mp3 albums on Amazon.com’s MP3 service, which are typically priced lower than buying all the songs individually. This is important because customers using Linux can enjoy the same cost benefits that up until now, were only available for Windows and Mac platforms.

The installer is currently advertised as available for Ubuntu 7.10, Debian 4 Etch, Fedora 8, and OpenSUSE 10.3, and I am very happy to report that it is a native application! The installation process is very easy as they are packaged using the standard packaging formats for each platform, and using the application is extremely easy.

Here’s a screen shot of my very first purchase using the MP3 Downloader.

Amazon MP3 Downloader

All the songs are conveniently downloaded to a directory of your choice, and organized in directories named after the artist and album.

For many months, I had been writing emails asking that they please release a Linux version of the application, or simply provide an alternate method of purchasing full albums. I am absolutely thrilled that they have listened to their customers, and urge that the Linux community send their messages of gratitude to Amazon.com. Of course, the best way to do that is to return the favour by using their service on the platform of YOUR choice.

Extract NT Backup Files in Linux Using mtftar

Posted on January 26th, 2008 in Tech Tips by gmendoza

If you would like to extract the contents of an NT backup (.bkf) file in Linux, mtftar is a utility that translates a Microsoft Tape Format (MTF) stream into the tar format. You can pick up mtftar from the authors site at http://gpl.internetconnection.net.

To get started, download the source code and compile.

$ wget http://gpl.internetconnection.net/files/mtftar.tar.gz
$ tar zxfv mtftar.tar.gz
$ cd mtftar
$ make
$ sudo cp mtftar /usr/bin/
- or -
$ su -c "cp mtftar /usr/bin/"

Using this utility is straight forward, as shown in the following example.

$ mtftar < MyBackup.bkf | tar xvf -
C:
C:/Stuff/Pictures/Misc Family Photos
C:/Stuff/Pictures/Misc Family Photos/First Bikes
C:/Stuff/Pictures/Misc Family Photos/First Bikes/First Bikes 001.jpg
C:/Stuff/Pictures/Misc Family Photos/First Bikes/First Bikes 002.jpg
C:/Stuff/Pictures/Misc Family Photos/First Bikes/First Bikes 003.jpg
C:/Stuff/Pictures/Misc Family Photos/First Bikes/First Bikes 004.jpg
C:/Stuff/Pictures/Misc Family Photos/First Bikes/First Bikes 005.jpg

An alternate mtf reader for Linux can be found here at http://laytongraphics.com/mtf/. The site also references a PDF written by Seagate that describes the MTF format if you’re interested.

Resize and Watermark Images in Linux

Posted on December 30th, 2007 in Tech Tips by gmendoza

If you need to resize and watermark large number of images, there is an easy way to do so using Linux command line tools and a very basic shell script. The easiest and most straight-forward method you can use is through the use of the ImageMagick toolkit. If you don’t have it installed already, you can download it from their site. Most distributions have binaries already built for you. Ubuntu and Debian users can install ImageMagick from the main repositories.

Install ImageMagick

$ sudo apt-get install imagemagick

Prepare your working environment

Make a directory to store the watermark image (~/Pictures/watermark) and photos you’re working on (~/Pictures/temp). Copy the watermark image and original photos to their respective directories.

$ mkdir -p ~/Pictures/temp/
$ mkdir -p ~/Pictures/watermark/
$ cp /path/to/watermark.jpg ~/Pictures/watermark/
$ cp /path/to/original-photos/*.jpg ~/Pictures/temp/


$ ls -l ~/Pictures/watermark/
-rw-r--r-- 1 gmendoza gmendoza 3311 2007-12-30 17:35 watermark.jpg


$ ls -l ~/Pictures/temp
-rw-r--r-- 1 gmendoza gmendoza 885788 2007-12-30 17:35 ubuntu1.jpg
-rw-r--r-- 1 gmendoza gmendoza 128922 2007-12-30 17:31 ubuntu2.jpg

Change directories to begin working on your photos.

$ cd ~/Pictures/temp/

Resizing with “convert”

Let’s say you want to specify a maximum width of 440 pixels (height being adjusted proportionally) in order for you to post the images appropriately within the specifications of your website borders. The syntax would be the following:

$ convert -resize 440 original-image.jpg new-image.jpg

In this example, we will specify the same name for the output files, which will overwrite the original copies.

$ convert -resize 440 ubuntu1.jpg ubuntu1.jpg
$ convert -resize 440 ubuntu2.jpg ubuntu2.jpg

Watermark with “composite”

You will probably want to watermark the images after they have been resized, this way there is no distortion of the watermark, and it is appropriately sized. In this example, we will also set the watermark transparency level to 15%, and overwrite the original file again.

$ composite -gravity northeast -dissolve 15 ../watermark/watermark.jpg \
ubuntu1.jpg ubuntu1.jpg
$ composite -gravity northeast -dissolve 15 ../watermark/watermark.jpg \
ubuntu2.jpg ubuntu2.jpg

Your photos will now have a nice watermark in their upper right hand corners.

Automating the process with a script

You can automate these steps and apply them to a large number of files using a script of course. Feel free to download this one and modify it to your liking.

http://www.savvyadmin.com/downloads/watermark.sh

#!/bin/bash
WATERMARK="$HOME/Pictures/watermark/watermark.jpg"
 
echo "*****************************************"
echo "* Image Resize and Watermarking Script  *"
echo "* By Gilbert Mendoza -  SavvyAdmin.com! *"
echo "*****************************************"
echo " "
 
for each in ~/Pictures/temp/*{.jpg,.jpeg,.png}
 do
  echo "Working on $each ..."
  convert -resize 440 $each $each 2> /dev/null
  composite -gravity northeast -dissolve 15.3 $WATERMARK $each $each 2> /dev/null
  echo "... Done!"
 done
exit 0

Additional Options

Please check out the ImageMagick website for more information on the many options and features their products have to offer.

http://www.imagemagick.org/script/command-line-processing.php

http://www.imagemagick.org/script/command-line-options.php

http://www.imagemagick.org/Usage

Console Framebuffer in Ubuntu

Posted on December 25th, 2007 in Tech Tips by gmendoza

The Linux console framebuffer allows you to achieve higher screen resolutions within your Linux console. However, as of this writing, Ubuntu 7.10 Gutsy by default does not load the required kernel modules. By passing the “vga=XXX” kernel option without these modules loaded, you are left with a blinking cursor in the upper-left hand corner of your screen. Here’s how to get the console framebuffer in working order.

1. Ensure the initrd image includes framebuffer support by adding “fbcon” and “vesafb” to /etc/initramfs-tools/modules.

$ echo "vesafb" | sudo tee -a /etc/initramfs-tools/modules
$ echo "fbcon" | sudo tee -a /etc/initramfs-tools/modules

2. Remove (or comment out) “vesafb” from blacklisted modules in /etc/modprobe.d/blacklist-framebuffer.

#blacklist vesafb

3. Add the desired framebuffer variable to the default kernel options section in /boot/grub/menu.lst. For 1024×768, the string should look like the following.

#defoptions=quiet splash vga=791

4. Update GRUB.

$ sudo update-grub

5. If Usplash is configured for a higher resolution than your framebuffer, it will appear off-centered. So adjust /etc/usplash.conf to use the same resolution.

xres=1024
yres=768

6. Update initramfs to rebuild the initrd image.

$ sudo update-initramfs -u

After rebooting, your usplash will appear as normal and you can Ctrl+Alt+F1 to a console after your X environment has finished loading. The text in your console should now appear much smaller and will be much easier to use for large amounts of console work.

Batch MP3 Encoding with Linux and LAME

Posted on December 2nd, 2007 in Tech Tips by gmendoza

If you have a number of audio files that you would like to convert to mp3, but don’t want to hassle with graphical applications, there is a simple way to accomplish the task using Linux, LAME and a little shell scripting. By performing a basic “for loop” to invoke LAME, you can easily convert any group of audio files using one line of shell code.

Here is an example of a “for loop” that runs the command “lame” against a set of files in your current working directory with the .wav file extension.

$ for f in *.wav ; do lame $f ; done

If your audio file names have spaces in them, then you will need to use quotation marks around “$f” variable.

$ for f in *.wav ; do lame "$f" ; done

I typically create my original audio files without the file name extension of .wav or .au. This is because when you run lame against a file name, and do not omit the extension in the output option, the resulting file will have two extensions in the file name. e.g. filename.wav.mp3. Yes, I can use sed or basename in the for loop to prevent this, but to keep it simple, I just choose to not use the file extension to begin with.

If you are working with a group of files that have all been named using the convention of “Artist - Album - ## - Track Title”, (notice the spaces in the name), the following will work.

$ for f in Artist\ -\ Album* ; do lame "$f" ; done

Once the job is finished, you will be left with a directory full of your original audio files, and your newly created mp3’s.

Extra Credit

Okay, since we’re on the topic of shell scripting. If you want to delete all the original audio files (the ones without any file name extensions), and without first moving the new mp3’s to a different directory, one overly complicated example would be the following.

for f in *.mp3 ; do AUFILE=`basename "$f" .mp3` ; rm "$AUFILE"; done

This would have been easier if the original files could have been identified with .wav extensions, (rm *.wav), but since they had no file extensions to begin with, a wild card alone would not work. Now folks, this is just an example, and there’s a million other ways you can go about this. But in any case, I hope it helps you start exploring on your own!

Perform GnuPG Functions Within Vim

Posted on October 8th, 2007 in Tech Tips by gmendoza

Performing GnuPG functions from Vim is actually pretty helpful if you work heavily with both applications on a regular basis. I was recently looking for a simple way to both word wrap and clearsign various text files within Vim, and found just what I was looking for.

1. (optional) Set the word wrap of text in Vim to a maximum text width of 70 characters. This can be done manually, or by simply adding the following text to your “~/.vimrc” file:

:set textwidth=70

2. As for the ability to clearsign, encrypt, decrypt and verify the text from within Vim, you can create command mode aliases as shortcuts for longer commands in Vim. Simply add the following to your “~/.vimrc” file:

:cmap cs %!gpg --clearsign
:cmap es %!gpg -seat
:cmap ee %!gpg -eat
:cmap de %!gpg -d

Once you save the changes to your .vimrc file, open any text file with vim, enter command mode, and type any of the shortcuts mentioned in step two; “cs” to clearsign, “es” to encrypt and sign, “ee” to encrypt with no signature, and “de” to decrypt or verify. The shortcut will display the command about to be issued, to which you can hit can enter to execute it. You will be prompted for recipients, and/or the private key passphrase depending on the function you choose.

If you are familiar with GnuPG syntax, you can change or add any of the above commands to your liking. For instance, for those of you with multiple PGP keys, you can add the “-u”option to specify which one you would like to use.

To wrap an existing unwrapped text file, simply higlight the entire message by placing the Vim cursor at the top of the file, press <shift>+V, followed by <shift>+G. This highlights all text as you will notice. While everything is highlighted, simply press “gq”. This will wrap everything according to your “textwidth” variable.

Feel free to test it out, and provide as much feedback as you like. Have fun.

Special Note:
When using the “textwidth” variable, you may find that it is useful to toggle the paste function. If you are pasting text that has a larger text width than that of which you have specified in Vim (in this case 70 characters), then your paste will automatically be word wrapped to 70.

You may not want this behavior, so the two opposing options you can set manually are:

:set paste
:set nopaste

Better yet, you can map a quick function key to toggle it on or off by adding the following to your .vimrc file:

:set pastetoggle=<F10>

To test, while in insert mode of Vim, press the F10 key, and you will notice that the mode will be clearly identified with:
"-- INSERT (paste) --"

This will allow you to paste text in it’s unwrapped form.

Vim in Color

Posted on September 30th, 2007 in Tech Tips by gmendoza

Turing on colored syntax highlighting in Vim can make it easier when looking through complicated text files, scripts, and source code. To quickly turn on or off the feature, use the “syntax” command within Vim:

:syntax on
:syntax off

The results are great. Here’s a screenshot of Vim in color.

Vim in Color

To make the feature permanent, edit the file /etc/vim/vimrc, or as your Vim package maintainer may suggest, /etc/vim/vimrc.local. One can also make the change simply for their user only by editing ~/.vimrc. In all cases, simply add the following line at the end of the file:

:syntax on

Users of Ubuntu by default have vim-tiny, which as it’s name suggests, is a smaller version of the Vim editor. This version does not support syntax highlighting and a number of other features. Of course, remedying this is very easy by installing the full featured vim:

# sudo apt-get install vim

Happy editing.