Friday, December 28, 2012

Convert .ogg to .mp3

Short recipe I found, but can't find the source for. Half my sound files are in .ogg form, and sometimes I need that to be .mp3. This is the extended version, useful for converting many files at once.
for x in *.ogg; do avconv -i "$x" -acodec libmp3lame "`basename "$x" .ogg`.mp3"; done
Note that on Linux Mint, I needed to install lame as well as some of the *extra* audio libraries from ubuntu-restricted-extras (and resolve conflicts with already installed libraries) for this to work.

Saturday, December 1, 2012

Acer C7 Chromebook - Best Deal on the Internet?

Back in July I bought myself an Acer AO756. It's an awesome Netbook-class machine, and for $350 it was a steal compared to Ultrabook prices at the time. And would still be a relative steal today.

I just picked up an Acer C7 Chromebook for my wife for Christmas for $199. She doesn't know I have this blog, so this is cool. Anyway, the Acer C7 Chromebook is essentially the same as my Acer AO756, but with only 2GB RAM, and a slightly slower Celeron. I think that Acer has cleaned up a couple of details on the finish of the machine as well. I like the finish.

This is a 3 lb. machine with an 11.6" screen. Very portable.

The keyboard is roomy and comfortable. The solid built-in mousepad gestures mean you don't need a mouse most of the time. Two-finger scroll is amazingly good.

This machine is a little thicker than an Ultrabook, and Acer takes advantage of this to offer such niceties as a real VGA port and a real ethernet port. No adapters needed.

Although I am planning on leaving Chrome OS on the machine (it is perfect for my wife), it occurs to me that the Acer C7 Chromebook might just be the best deal going on a Linux-compatible laptop/netbook. And unlike the Samsung ARM-based Chromebooks, this one should just work. It's built around Celeron and Intel-integrated graphic acceleration, both well supported by various Linux distributions. And it is spec'd out well enough to run Linux well, not like the old Atom-based Netbooks.

Google must be selling this machine for a loss. But I have to say, as a consumer, I am loving this $199 price-point standard they are pushing. These are definitely priced for the masses.


As a follow up, with not quite the same rosy opinion, here is a more thorough breakdown from arstechnica. For what it is worth, I don't think the screen wash out is that bad, and the display is otherwise beautiful.

And I don't know if it applies to this machine, but here is a link to info on ChrUbuntu. The Acer C7 is not an ARM architecture, so it should be able to run standard Ubuntu, no special instructions, from a stick. But I haven't tried it.


I generally like ChromeOS. I like it right up to the point it doesn't do something stupidly simple, like playing MP3's from the Google Drive without having to "install" a 3rd party app. And having to find that app in a rather poorly organized sea of eye candy that looks like Windows Metro. Can we just bring back some reasonable white space and grid layouts, please? I don't like UIs that are designed to confuse my brain.

The paradigm used in the Ubuntu Software Center works a lot better when you have hundreds or thousands of applications. That's a hint, if anyone from Google happens to read this blog entry.


Historical Footnote: The ChromeBook was the best selling laptop during the 2012 Christmas season. While I don't think ChromeOS will necessarily displace heavyweight operating systems like Windows and OS-X in the near term, if it takes even a small percentage of the total market it could eat into the profit margins of the big boys. Interesting times.

Tuesday, August 14, 2012

Why is My Stupid Hard-Drive Full?

This is one of those simple things you didn't know about but that you can't live without. Linux and Mac both support du, which tells you your disk usage. If you want to see your usage in a particular folder, use this form:

~ $ du -hs *

Maybe it's time to finally clean out that ~/Videos folder. Works great for cleaning out servers too.

Rumors of Linux Desktop Death Exaggerated

In the 2010 blog post Is the Linux desktop dream dead?, Steven Vaughan-Nichols asks if a Linux desktop will ever go mainstream. In the same year, PCWorld pronounced The Dream is Dead. In a follow on article, The Linux desktop is dead; Long live the Linux desktop, written in 2011, Steven pulls a Sybil. This year, PCWorld seems to have done a 180 with If Desktop Linux Is Dead, Someone Had Better Tell All Those Users.

It's not really about the desktop, is it?

I used Unity for a while, and it's actually not bad. I wanted more control over certain aspects of the user experience, though, and so I switched to Xubuntu (XFCE desktop). Recently, I bought a netbook and installed Linux Mint 13 XFCE, and was very impressed. Mint is beautiful, and "just works" out of the box, and Canonical should hire those guys as artistic consultants for Unity. But I digress.

My wife and kids, none of whom are geeks, routinely bounce around between computers in my house. They use Unity, Xubuntu, and Linux Mint 13 XFCE desktops, and occasionally Windows, interchangably. There is nothing hard about using Linux from the desktop, and it's not hard to get your bearings even when switching from Windows.

Any of these desktops is easily the equal of (some might use the term "superior to") the old XP desktop, which - let's be honest here - is still what the majority of Windows users see every day. And by the way, for most users, XP is good enough, and it just works, and you don't have to pay $250 for a new version of Office which you never use anyway. The various desktops that are available for Linux are really quite good.

And it isn't like using Linux is any harder than using Windows. I would contend that once you know what you are doing, getting things done is easier, but that's an opinion. In poorer countries, where there really isn't a choice to use Windows, people seem to have adapted to Linux easily. There are several distributions designed for children, after all. Yeah, it's popular with programmers, but it's also popular with people who buy status cell-phones and have no idea they are running Linux.

So what is holding adoption of Linux back in first-world countries?

Recently, when I was shopping for a laptop, I had a really hard time finding a name-brand laptop that did not have Windows pre-installed. Try it if you don't believe me. Even Dell, who has announced they will eventually ship laptops with either Ubuntu or Red Hat Linux pre-installed, won't sell you one now, and won't sell you one without Windows pre-installed. If you buy a Dell laptop right now, you will accept and pay for a Windows license.

Full disclosure: I ended up buying an Acer netbook. I purchased Windows as part of the deal.

I understand that this is reality. I just don't understand why it is considered legal.

Maybe it's time to stop arguing over which distribution is best, or which desktop environment is Linus's favorite, or whether the Linux desktop is dead, and change the argument.

Windows does not run programs faster than Linux - it's usually the other way around. Windows is not easier to use than Linux, and Linux doesn't have many of the quirks in Windows (disk defragment - what's that?). With Linux, you have several very good desktops to choose from. Take your pick. Unless you are tied to Office or Exchange, Windows is not more capable than Linux. Most of the software you use day to day is available for free on Linux, and software repositories are well stocked and well organized. Linux has a great community of people who help beginners, and companies like Red Hat and Canonical offer professional paid support, cheap.

We all know that Linux runs on most laptops and desktops, even if the manufacturer does not officially support it. At this time, all the major manufacturers only support Windows - across the board.

The real question is, I think, why does Microsoft still have this near-monopoly on everything that is not controlled by Apple, and what can be done about it?

By the way ... Linux Mint 13 XFCE is amazing both in looks and performance on this 11.6", 1366x768 Acer netbook. Yeah, I am one of those guys who still doesn't know that the netbook is dead. Don't harsh my mellow, dude. Anyway, I may have been forced to pay for Windows to get the hardware, but that doesn't mean I have to use it.


One thing that holds Mint back is the lack of an upgrade path. When it comes time to upgrade, you essentially have to backup, install the new version from scratch, and restore. This pain is multiplied by the number of installations you have (Linux users tend to have more than one). Not cool.

Saturday, August 11, 2012

Rocking Bash with ... PHP?!?

Here's another solution to the common scripting problem of adapting ls output for use by other commands ... solved with a (very) little PHP!

So I'm using tar to create a simple backup for a web site. Only now the website has podcasts, and I don't need to back those up. I've got a copy elsewhere, and they dwarf the size of the original site.

tar lets me specify a whole set of files and folders, so that's not the problem. I just want an automated way to specify "everything, but not this and not that." I can use ls to get a list of files, but how do I remove just a few programmatically, and how do I get ls to return the full path?

To get the list of all files in my public_html folder, one per line:

ls -a1 $HOME/public_html

To get the path to my public_html folder:

ls -d $HOME/public_html

Now, if I pipe the file names to a PHP script, and pass in the parent folder as an argument, I can use PHP to generate the full path and also selectively cull out items I don't want (including '.' and '..', which ls includes unconditionally). The -R flag runs the PHP script once for each line in the input. Very convenient.

ls -a1 $HOME/public_html | \
  php -R \
    'if(!in_array($argn, array(".","..","podcasts"))) echo $argv[1]."/".$argn."\n";' \
    $(ls -d $HOME/public_html)
$argv[] contains the command-line arguments. $argn is the line from stdin.

The completed command looks like this. It seems like there ought to be a simpler way, but this works, and I will still be able to read this next time I need to modify the script. Neat.

tar -czf $HOME/backups/web-$(date +%Y-%m-%d).tar.gz \
  $(ls -a1 $HOME/public_html | \
    php -R \
      'if(!in_array($argn, array(".","..","podcasts"))) echo $argv[1]."/".$argn."\n";' \
      $(ls -d $HOME/public_html))

Friday, August 3, 2012

Re-enable Screen Brightness Controls on Acer Aspire One (Ubuntu)

There appears to be a problem with some computers and Ubuntu-based distributions (verified on Linux Mint 13 and Lubuntu 12.10) where you can't adjust the screen brightness. This only applies if the brightness controls pop up and appear to work, but the brightness does not actually change - it's stuck at full-bright. If you aren't seeing the brightness popup, that's a different problem.

Here is how I re-enabled brightness controls on my Acer Aspire One.

gksudo gedit /etc/default/grub

Find this line:

GRUB_CMDLINE_LINUX=""

Change it to this:

GRUB_CMDLINE_LINUX="acpi_backlight=vendor"

Save changes and update Grub:

sudo update-grub

Reboot.

After doing this, I can fade all the way to black. Great for battery life! Hard to read though.

Thursday, August 2, 2012

XFCE window title and borders gone; no focus, no move

Experienced this problem on Linux Mint 13 XFCE. Not to worry. This post from Linux and Friends puts it all right.
~$ xfwm4 --replace
Many thanks! If I hadn't stumbled across this tip, I don't know how I would have been able to fix this.

This has happened to me three times now.

It appears to have something to do with corruption of the session when you log out. To avoid the problem altogether, set up your desktop the way you want it, and the log out while saving session state (it's a checkbox on the logout dialog). The next time you log out, uncheck that box. If you don't save, you can't get corruption on save, right? That's the theory anyway.


After not experiencing the problem for about 4 months, I have to give a thumbs up to the uncheck the "Save Session State" solution. Theory confirmed. Or someone fixed the bug.

Saturday, July 28, 2012

Where are all my Audacity plugins?

I end up having to do this every time I (re)install Linux on one of my machines, so it's getting blogged. The base install of Audacity, for some reason, doesn't install the LADSPA libraries, which means you get a very limited set of plugins. Run this to get the whole kaboodle:
~$ sudo aptitude install vco-plugins tap-plugins swh-plugins rev-plugins omins mcp-plugins
Credit goes to Jeff Ammons. In a recent version of Mint Debian, Audacity was still unable to find the LADSPA plugins. I was able to get it to work by setting the LADSPA_PATH environment variable in /etc/environment (using the find command to locate the LADSPA folders):
LADSPA_PATH="/usr/lib/ladspa:/usr/share/ladspa"

Adding "Users and Groups" Back into Linux Mint 13 XFCE

Linux Mint 13 XFCE is beautiful, and just works. It is missing System -> Users and Groups for some inexplicable reason. I assume at some point they'll realize the problem and fix it. In the meantime, you can add it back in like this:

~$ sudo aptitude install gnome-system-tools

Friday, May 11, 2012

Ubuntu Desktop Security Primer

You weren't born yesterday. You know what a firewall is. You know what anti-virus software is. You know what a man page is, and you've Googled more times than you can count. Let's keep this simple, shall we?

Firewall

Ubuntu includes ufw (Uncomplicated Firewall) by default. And by default, it is turned off. Turn it on:

$ sudo ufw enable
Firewall is active and enabled on system startup

Congratulations. Your computer is now wrapped in electronic cellophane.

Anti-Virus

Most viruses are still targeted at Windows, but the paranoid can never be too careful. Here is the version for those with short attention spans.

  • Install it:

    $ sudo apt-get install clamav
  • Update it:

    $ sudo freshclam
  • Run it:

    $ sudo clamscan / -ir --exclude-dir=^/sys --exclude-dir=^/proc --detect-pua

If you'd like a GUI, check out ClamTk.

Tuesday, May 1, 2012

Xubuntu Tip: Switch Users without Logging Out

I've recently installed Xubuntu on a couple of my computers, and generally I prefer it over stock Ubuntu. I had almost forgotten how nice having launchers on the desktop was. Almost. One feature I missed from Ubuntu, though, was being able to switch between different logged in users. With the default Xubuntu setup, you have to log out before you can log into a different account. Problem solved.

  • $ sudo apt-get install xfswitch-plugin
  • Add User Switching plugin to one of your panels.

Nice.

Maven 3: Default Values for Mojo Parameters that are Collections

I love my custom Maven mojos (or plugins). However, I recently ran into a situation where I needed a parameter that was a list of archive types (zip, tar, etc.), and I wanted to specify some reasonable default. Have you ever tried this by specifying a default-value or an expression? After searching for about an hour, I have come to the conclusion that the designers of Maven didn't thing this through all the way.

Not to fear though! There is a way to get this to work, and I like it so much I think I will start using the "hack" in preference to the "right way."

The trick is to specify a default value for the variable in Java. Don't use default-value or expression at all. If the user doesn't override the value, the variable doesn't get set, so it just picks up the default value you've assigned.

The second part of the trick is to document your default settings in the JavaDoc. Since you aren't specifying the value as part of the @parameter annotation, the site-doc report and help won't pick up the value you've assigned.

Here is an example.

/**
 * Types of archives to create. Any of <code>zip</code>, 
 * <code>tar</code>, <code>tar.gz</code>, <code>tar.bz2</code>.
 * <br><strong>Default</strong>: <tt>["zip", "tar.gz"]</tt>
 * @parameter 
 */
protected List<String> types = Arrays.asList("zip", "tar.gz");

One thing to note is that this will only work for constants. Any default values that have to be pulled from the project context (such as project file paths) are going to require an expression. This can't be helped. Those values have to be injected after the plugin is constructed.

Saturday, April 28, 2012

Extract a DVD to an ISO Image

I needed to copy an old DVD (playable home movies), and came across this gem. This command will extract the DVD to an ISO image, ready for burning. I don't know if it works with copy-protected DVDs, but it was exactly what I needed.

$ readom dev=/dev/cdrom f=target.iso

Friday, April 13, 2012

Shrinking a Decade's Worth of ... Part 2

The video compression (see the previous post) worked really well. It worked so well, in fact, that now my videos are much smaller, in total, than my photos.

Here we go again! Well, not exactly. You see, there is a much easier solution to batch-shrinking image files. It doesn't require any scripting at all.

Warning! mogrify modifies files in place!
Before you do this, make sure you have another copy of your image files. mogrify modifies the originals in place. JPEG is a lossy format, and recompressing the files will result in some loss of image quality. As an example of what can go wrong:

DON'T! $ mogrify -quality 7 *.jpg DON'T!

would essentially destroy your originals.

Here are the steps for Ubuntu. Windows users, you are on your own for the installation.

  • Install ImageMagick.
    $ sudo apt-get install imagemagick
  • cd to the directory with your images.
  • Assuming JPEG format, type:
    $ mogrify -quality 75 *.jpg

Wow, that was easy. I love Ubuntu!

For my images, which came from a Digital Elph, the re-compressed images take up less than half the space of the originals, and to me the images look just as good. Experiment with the quality setting and see what works best for you.

Tuesday, April 10, 2012

Shrinking a Decade's Worth of Video Clips

My family just loves to shoot video clips with our digital cameras. I must admit, I love watching old videos of the kids when they were little. But storing all those videos is becoming a nightmare. The library has grown more than the kids!

I figured I could convert the videos to some other format and save some space. I was thinking there had to be a reason why AVI isn't used for streaming web videos. I poked around on the web, and after some trial and error, came up with the following command pattern using ffmpeg.

user@computer:~/Videos$ ffmpeg -threads 0 -i movie001.AVI -b 1500K \
  -vcodec libx264 -vpre slow movie001.mp4

As it turns out, all of my cameras are really bad at on-the-fly video compression. As an example, I have a 33 second, 61MB video clip. After transcoding to mp4 it's 6.4MB. The new clip looks as good as the original. This is going to solve all my video storage problems.

Okay, so I am motivated, and I have a command that will do what I want. But I need to do this for hundreds of video clips, and my bash programming stinks. I am pretty good with one-liners. Throw in looping and awk or sed and I'm lost.

What's a Java programmer to do?

Java isn't the best scripting language. Perl and Python are great for scripting, but I use them so seldom that I am constantly looking up simple stuff. I like Beanshell, but it lacks polish for command-line programming. So how about Groovy?

Groovy syntax matches Java almost exactly (better than Beanshell) and also extends it with Ruby-esque extensions and code-scrunching syntactical sugar. In other words, I can write a concise script that I can still read in six months - when I need it again.

The Groovy script below takes a list of video files and converts them to mp4. You can modify it to allow different file types or to tweak the ffmpeg settings:

user@computer:~/Videos$ transcode.gy *.avi

Here is the full listing for transcode.gy. It's "enigmatic" Groovy (closures, syntactic sugar, etc.), but if you are comfortable with Java you won't have any trouble following along. Enjoy!

 #!/usr/bin/env groovy 
 /**
  * This software is distributed WITHOUT WARRANTIES OR CONDITIONS OF ANY
  * KIND, either express or implied. Copy it, use it, sell it, even 
  * take credit for it if you want. But don't come back to me if there
  * is a problem.
  */  
 import java.util.regex.Matcher  
 import java.util.regex.Pattern  
 List<File> files = args.collect { new File(it).canonicalFile }  
 files.each {   
     if(it.isDirectory())   
         throw new IOException("Can't process folder: " + it.path)  
     if(!it.isFile())  
         throw new FileNotFoundException(it.path) 
     /* Update this regular-expression to allow different video types. */
     if(!(it.name ==~ /(?i).*\.((avi)|(mod)|(mpeg))/))   
         throw new IOException("File type not supported: " + it.path) 
 }  
 files.each {  
     Matcher matcher = (it.name =~ /.*\.([a-zA-Z]+)/)  
     matcher.find()  
     String ext = matcher.group(1)  
     String newName = "${it.name[0..-ext.size()-2]}.mp4"  
     Process p =   
         ["ffmpeg",   
         "-threads", "0", 
             /* 0 indicates use all cores. */  
         "-i", it.canonicalPath,
         "-b", "1500K",
             /* Default 200K. You can tweak this setting to change video 
              * size and quality. */
         "-vcodec", "libx264",   
         "-vpre", "slow", 
             /* Preset file. Also default, normal, veryslow, max, hq. 
              * Search for files ending in '.ffpreset' to see what's 
              * available to you. */
         "-y", 
             /* Overwrite the .mp4 file if one already exists. */
         new File(it.parentFile, newName)].execute()  
     p.waitForProcessOutput(System.out, System.err)
     if(p.exitValue() != 0) 
         throw new Exception("Failed: ffmpeg ${p.exitValue()} ${it.path}")
 }  

Thanks to John Dyer for posting simplified command-line examples of ffmpeg for several popular video formats, including H.264.


Paul Williams pointed out in the comments that you can do much the same thing with this simple Bash script.

for i in `ls <input_dir>` 
do 
    ffmpeg \
        -threads 0 \
        -i $i \
        -b 1500K \
        -vcodec libx264 \
        -vpre slow \
        <output_dir>/`basename $i .AVI`.mp4
done

I hardly ever get to use for ... in in my common Bash tasks because most commands I use take multiple files as input, whereas ffmpeg does not. I'll have to try to remember this next time I run into a similar situation.

If I left out the error checking and comments in the Groovy script, it would be a lot shorter, but not that short. I wonder how small I could make the program if I wrote it in Java? That could be interesting...


Here's a Java version using Jaks and Apache commons-io for a cleaner implementation. Lots of standard Java boilerplate (I use Eclipse to manage that bit), and there is a Maven component to this that I'm not going to go into. Keeping in mind that I left in some error checking code, the meat of the program is comparable to the size of the Bash script, and somewhat shorter than the original Groovy script - which is mostly due to me being a bit rusty with enigmatic Groovy, I think.

 1:  import static java.util.Arrays.asList;  
 2:  import static org.apache.commons.io.FilenameUtils.getBaseName;  
 3:  import static org.apache.commons.io.FilenameUtils.getExtension;  
 4:  import java.io.File;  
 5:  import java.io.FileNotFoundException;  
 6:  import java.util.List;  
 7:  import com.googlecode.jaks.cli.AbstractJaksCommand;  
 8:  import com.googlecode.jaks.cli.JaksNonOption;  
 9:  import com.googlecode.jaks.system.Subprocess;  
10:  public class Transcode extends AbstractJaksCommand  
11:  {  
12:      @JaksNonOption(required=true)  
13:      public List<File> vids;  
14:      @Override  
15:      public void execute() throws Exception   
16:      {  
17:          for(final File vid : vids)  
18:          {  
19:              if(!asList("avi", "mod", "mpeg").contains(getExtension(vid.getName())))  
20:              {  
21:                  throw new IllegalArgumentException(vid.getPath() + " is not a convertable file type.");  
22:              }  
23:              if(!vid.isFile())  
24:              {  
25:                  throw new FileNotFoundException(vid.getPath());  
26:              }  
27:              new Subprocess("ffmpeg",   
28:                      "-threads", "0",  
29:                      "-i", vid.getCanonicalPath(),  
30:                      "-b", "1500K",  
31:                      "-vcodec", "libx264",  
32:                      "-vpre", "slow",  
33:                      "-y",  
34:                      new File(vid.getParentFile(), getBaseName(vid.getName()) + ".mp4").getPath()  
35:                  ).call();  
36:          }  
37:      }  
38:  }