Converting podcasts to regular tracks in iTunes

I have spent the better part of the morning trying to work out how to
convert podcasts to “regular” tracks in iTunes, so they would show up in
shuffle, etc. Mostly this was for my collection of Jonathan Coulton
Thing a Week” episodes, but it would be useful for anything you
wanted to move out of your podcast list into the main audio portion of
the library. I suppose the reason it took so long to find the solution
is I started by searching for it on Google instead of just looking
through the iTunes menu options, though as you will see the solution
wasn’t immediately obvious even once I had found it.

I knew that iTunes would let me change settings like “Remember
playback position” and “Skip when shuffling” from the info dialog
(Cmd-I), so I started there. The only setting that even mentioned
podcast was the genre, and I already knew that was not what I needed to
change. Some of the tracks already had “real” genres and only some were
set to “Podcast”.

I also knew there is a separate podcast flag available for queries in
Smart Lists and AppleScript, since I used it to create my “Active Queue”
podcast playlist with selections of episodes from various podcast series
(it’s like creating your own mix tape, but for talk radio). I tried to
write a simple AppleScript to change the podcast flag of selected tracks
to true. It turns out the flag is a read-only attribute. No amount of
searching uncovered any way to change the setting using AppleScript.

The first useful looking suggestions I ran into were to convert the
ID3 tag format to an older version
, then convert it back. Doing that
erased most of the comments and other meta-data associated with the
tracks, though, so I didn’t like the results.

Next I found a few forum and blog posts that talked about an
ITUNESPODCAST setting in the extended ID3 tags. They all mentioned a
Windows program for removing or changing the flag, though. I examined a
few of the files with Ned Batchelder’s python module id3reader, but
didn’t see anything that looked like “ITUNESPODCAST” in the output.

Going back to Google, I finally found a reference to converting the
files to AAC using an option in the Advanced menu. That seemed like
overkill, but at this point I was becoming fed up and just wanted to be
done with the whole thing. I could always re-encode as MP3, after all.
Well, iTunes didn’t have a menu option to “Encode as AAC”. It did have
“Convert selection to MP3”, which didn’t make much sense to me. As far
as I knew, the tracks were already MP3 files. But lo and behold,
selecting that menu option did enable them in the iTunes Music Library.
It made copies of all of the tracks as it converted them, so I could
even delete the podcast subscription.

So, if you want to add podcast episodes you have already downloaded to
your music library and turn off the podcast flag, select the track and
choose Advanced->Convert selection to MP3.

Unexpectedly broken, and fixed: svnbackup

Yesterday Pierre Lemay sent me one of the clearest bug reports I’ve
seen in quite a while, and a patch to fix the problem. He was having
trouble with svnbackup duplicating changesets in the dump files. It
turns out every changeset that appeared on a “boundary” (at the end of
one dump file and the beginning of the next) was included in both dumps.
Oops.

When I tested the script, I was able to recover the repository without
any trouble. I didn’t check 2 cases that Pierre encountered. First,
the changeset revision numbers did not stay consistent. When the
changeset was duplicated, that threw off all of the subsequent
changeset ids by 1. For each duplicate. That in itself is only
annoying. The more troubling problem is when a duplicate changeset
includes a delete operation. The second delete would fail while
restoring, which prevented Pierre from importing the rest of the
backup.

In his email describing all of that, he gave me great details about
how he had tested, the specific scenario that caused the problem, and
then provided the fix!

So, if you are using version 1.0, go on over and download version
1.1 with Pierre’s fixes.

Unexpectedly popular: svnbackup

PyMOTW: atexit

The atexit module provides a simple interface to register
functions to be called when a program closes down normally. The
sys module also provides a hook, sys.exitfunc, but only one
function can be registered there. The atexit registry can be used
by multiple modules and libraries simultaneously.

Read more at pymotw.com: atexit

PyMOTW: subprocess

The subprocess module provides a consistent interface to creating and
working with additional processes. It offers a higher-level interface
than some of the other available modules, and is intended to replace
functions such as os.system, os.spawn*, os.popen*, popen2.* and
commands.*. To make it easier to compare subprocess with those other
modules, this week I will re-create earlier examples using the functions
being replaced.

Read more at pymotw.com: subprocess

PyMOTW: pickle and cPickle

The pickle module implements an algorithm for turning an arbitrary
Python object into a series of bytes (“serializing” the object). The
byte stream can then be transmitted or stored, and later reconstructed
to create a new object with the same characteristics.

The cPickle module implements the same algorithm, in C instead of
Python. It is many times faster than the Python implementation, but does
not allow the user to subclass from Pickle. If sub-classing is not
important for your use, you probably want to use cPickle.

Read more at pymotw.com: pickle

DjangoKit help?

I spent a little time last night trying to assemble an application
using DjangoKit without much success.

I’m running Python 2.5 on a PowerBook with Mac OS 10.4. I downloaded
and installed PyObjC from source so it would compile (I thought) against
the right version of Python, then installed DjangoKit using
python setup.py install. Everything seemed to be working, and I was
able to build an application. But when I ran that app, it produced an
error about the version of the SQLite libraries being used (2 instead of
3) and missing libraries.

I gave up on Python 2.5, re-installed PyObjC and DjangoKit for 2.4 and
tried again. Same error.

Just for grins, I copied the app over to my wife’s laptop (she has a
MacBook Pro). The result was, of course, a new error about the platform.
No universal binaries? Really?

I’m sure there are options, or something, that I’m leaving out when I
build the app. This was mostly an experiment, and I was in a hurry, so I
gave up easily and just installed the django code I wanted on an
existing (Linux) web server and let her use that instead of messing with
a desktop application.

Has anyone else had more success building portable Python apps, esp.
with django, on Mac OS X?

Updated

Of course I knew better than to post in frustration when I posted this
originally. In my haste, I didn’t post sample code, the error message,
or much of the rest of the information I would have wanted if I was the
DjangoKit author trying to help someone out. Nonetheless, Tom did some
digging anyway and offered suggestions. Others did as well. Thanks! I
finally found time to follow up, and am coming closer to an answer.

Here are the full details

The application is very, very simple. The model just contains 2
classes for creating an index of a pile of Cook’s Illustrated magazine
we have laying around the house. There is no front-end, since the admin
views already provide the functionality she wanted. I thought I would be
cute and bundle it as a desktop app for Ms. PyMOTW, instead of setting
the app up on my web server. I have packaged the sample code and placed
it on my server.

I have included 2 separate setup.py files (setup.py and
djangokit_setup.py). I couldn’t package the source using the DjangoKit
version of setup:

$ python djangokit_setup.py sdist --force-manifest
Loading 'initial_data' fixtures...
No fixtures found.
running sdist
warning: sdist: missing required meta-data: name, url
warning: sdist: manifest template 'MANIFEST.in' does not exist (using default file list)
error: dist/Cook's Illustrated Index.app/Contents/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5/Frameworks/Python.framework/Versions/2.5: File name too long

I only seem to get the error if my dist directory includes the
application, too. Otherwise I get a minimal package with the name
‘UNKNOWN’. So, the tarball was packaged with a regular distutils
setup.py. That’s not a big problem, since it is easy to use separate
files.

When I ran python djangokit_setup.py py2app, the first time it
reported this error:

*** creating application bundle: Cook's Illustrated Index ***
error: can't copy 'media': doesn't exist or not a regular file

I eventually figured out (guessed) that even though I don’t have any
external media, I need a media directory at the same level in the
directory tree as the setup file. Creating the directory let me create
the app. Running that app gives me this traceback:

Traceback (most recent call last):
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/__boot__.py", line 31, in
    _run('app.py')
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/__boot__.py", line 28, in _run
    execfile(path, globals(), globals())
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/app.py", line 9, in
    from pysqlite2 import dbapi2 as sqlite
ImportError: No module named pysqlite2

That brings the error reporting up to date, without trying any of the
suggestions in the comments, yet. As I mentioned, the code itself works
if I run django outside of the packaged application (from the command
line, etc.). So I’m confident that my own imports are valid, etc.

Based on a hint from Tom (in the comments, he suggests that I install
pysqlite2), I tried editing the app.py file created inside the
application to import from sqlite3 instead of sqlite2. Editing the file
directly didn’t do it. Editing the copy already in my application
changed the error message to:

Traceback (most recent call last):
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/__boot__.py", line 31, in
    _run('app.py')
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/__boot__.py", line 28, in _run
    execfile(path, globals(), globals())
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/app.py", line 10, in
    from sqlite3 import dbapi2 as sqlite
ImportError: No module named sqlite3

Next I tried editing the version of app.py in
/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/site-packages/djangokit.
After removing the application and rebuilding, I see the same error.

So I finally broke down and installed the pysqlte2 package Tom
pointed out for me. The package seems to imply that it is for Python
2.4, and I’m running 2.5, but I installed it anyway.

The application Packaged with python 2.5 gave me “No module named
pysqlite2” when I ran it. Repackaged using “python2.4
djangokit_setup.py py2app”, I got the app to run but it does not seem
to actually work. The console log shows this:

2007-06-23 15:07:28.403 Cook's Illustrated Index[14739] creating support folder /Users/dhellmann/Library/Application Support/DjangoKit/CooksIndex
2007-06-23 15:07:28.405 Cook's Illustrated Index[14739] installing default database
Starting web server on port 10557
Unhandled exception in thread started by
Traceback (most recent call last):
  File "/Users/dhellmann/Devel/personal/CooksIndex/trunk/dist/Cook's Illustrated Index.app/Contents/Resources/app.py", line 81, in startWebServer
    handler = AdminMediaHandler(WSGIHandler(), path)
TypeError: __init__() takes exactly 2 arguments (3 given)

So, I am a lot closer but not quite where I would like to be. I don’t
really care whether I package under 2.4 or 2.5, so long as the result
runs on my wife’s laptop, which doesn’t have any development packages
installed.