Previously, we tried to shut down everything very nicely by sending along a
channel poison message when an exception occurred. That, of course, was
disastrous because some of the pipeline was no longer running and the poison
was unlikely to get all the way through. Now we just abort every thread and
clear every queue (to force the abort even when blocking on enqueues). This
problem manifested as a deadlock when an exception occurred in the final
stage.
Previously, the producer thread (i.e., the first stage) would continue running
to completion even when an exception was raised! And, depending on the size of
the queue, deadlock was even possible if the next stage was no longer consuming
the produced values.
This makes the apply_choices coroutine run even for albums that are skipped or
still in the library. This (along with making things more predictable) lets the
apply_choices stage write the progress value as albums are retired even if they
are skipped.
This makes way more sense than fetching every metadata request from the
database. The performance of "beet ls -a" and the like should be drastically
better.
As part of this, the BaseLibrary class was also adapted to include a notion of
albums. This is reflected by the new BaseAlbum class, which the Album class
(formerly _AlbumInfo) completely replaces in the concrete Library. The BaseAlbum
class just fetches metadata from the underlying items.
Previously, importing without autotagging just imported a bunch of Items. Now,
like the autotagging version, "import -A" creates albums based on the directory
hierarchy. The effect is exactly as if the user chose "use as-is" every time in
the interactive procedure. One side effect is that "import -A" can now only take
directories, where previously it could take single items on the command line. We
need a new solution for this kind of import in the future.