Overview

pytagsfs is a FUSE filesystem that presents media files in a virtual directory structure based on the file tags. This provides an easy way to see many different "views" of your tagged media files, making it easy to find files based on a wide variety of criteria.

Organizing media files into a virtual directory structure has a number of advantages. The virtual files can be opened and played in your media player, just like any other file. It complements the feature set of your current software, which already knows how to deal with files and directories. This is especially useful if your favorite media player doesn't organize your music for you (many very nice media players don't do this, and their users like things that way).

pytagsfs also has some neat features that make these virtual files even more useful:

An Example

I have a small collection of flac files contained in a single source directory. Let's see what we can do with them. I'm kind of a command-line junky, so I'll be using common command-line utilities throughout this example.

Here's a listing of the files I'll be playing with. For brevity's sake, I've trimmed it down.

$ tree source
source
|-- Nomadiqa - Sans Frontieres
|   |-- 01 Nomadiqa - Orient House [Sans Frontieres].flac
|   |-- 02 Nomadiqa - Birds Of Babylon [Sans Frontieres].flac
|   |-- 03 Nomadiqa - Capture [Sans Frontieres].flac
...
|-- Rasputina - Oh Perilous World
|   |-- disc1 - side 1
|   |   |-- 01 Rasputina - 1816, The Year Without A Summer [Oh Perilous World].flac
|   |   |-- 02 Rasputina - Chose Me For Champion [Oh Perilous World].flac
|   |   |-- 03 Rasputina - Cage In A Cave [Oh Perilous World].flac
...
|   `-- disc2 - side 2
|       |-- 01 Rasputina - The Question Of Time [Oh Perilous World Side 2].flac
|       |-- 02 Rasputina - Identity Tokens [Oh Perilous World Side 2].flac
|       |-- 03 Rasputina - The Humanized Mice [Oh Perilous World Side 2].flac
...
`-- Various - Platinum Breakz
    |-- disc1
    |   |-- 01 Rufige Kru - V.I.P. Rider'S Ghost [Various - Platinum Breakz Disc 1].flac
    |   |-- 02 Peshay - Psychosis [Various - Platinum Breakz Disc 1].flac
    |   |-- 03 Doc Scott - Far Away [Various - Platinum Breakz Disc 1].flac
...
    `-- disc2
        |-- 01 Doc Scott - Unofficial Ghost [Various - Platinum Breakz Disc 2].flac
        |-- 02 Lemon D - In My Life [Various - Platinum Breakz Disc 2].flac
        |-- 03 Source Direct - A Made Up Sound [Various - Platinum Breakz Disc 2].flac
...

7 directories, 49 files

Since I'm pretty meticulous (and some people prefer less polite words for this), these files are already pretty well organized, but let's see what we can do.

Mounting

For starters, let's rearrange them by genre with a new pytagsfs mount:

$ mkdir by-genre
$ pytagsfs -o format='/%g/%a - %t.%e' source by-genre
$ tree by-genre
by-genre/
|-- Drum & Bass
|   |-- Alex Reece - Pulp Fiction.flac
|   |-- Asylum - Da Base II Dark.flac
|   |-- Digital - Down Under.flac
...
`-- Gothic Rock
    |-- Rasputina - 1816, The Year Without A Summer.flac
    |-- Rasputina - A Retinue Of Moons%The Infindel Is Me.flac
    |-- Rasputina - Cage In A Cave.flac
...

2 directories, 40 files

Note that any files lacking the necessary tags required to represent them in this layout are simply omitted from the resulting directory structure. In this case, the Nomadiqa album was left out, since those files lack a genre tag.

Setting the genre tag for those files causes them to be included:

$ pytags --set genre=Electronic 'source/Nomadiqa - Sans Frontieres'/*.flac
source/Nomadiqa - Sans Frontieres/01 Nomadiqa - Orient House [Sans Frontieres].flac
source/Nomadiqa - Sans Frontieres/02 Nomadiqa - Birds Of Babylon [Sans Frontieres].flac
source/Nomadiqa - Sans Frontieres/03 Nomadiqa - Capture [Sans Frontieres].flac
...
$ ls by-genre/Electronic
Nomadiqa - Birds Of Babylon.flac  Nomadiqa - Evolution.flac     Nomadiqa - Orient House.flac
Nomadiqa - Capture.flac           Nomadiqa - Exhibition.flac    Nomadiqa - Sa O Roma.flac
Nomadiqa - Dynamic.flac           Nomadiqa - Goctu Kervan.flac  Nomadiqa - Seventh Mode.flac

Renaming & Moving Files

If we change our minds and decide to retag that album with genre "World", we can do that a few different ways. One of those is by renaming the Electronic directory:

$ cd by-genre
$ mv Electronic World
$ ls World
Nomadiqa - Birds Of Babylon.flac  Nomadiqa - Evolution.flac     Nomadiqa - Orient House.flac
Nomadiqa - Capture.flac           Nomadiqa - Exhibition.flac    Nomadiqa - Sa O Roma.flac
Nomadiqa - Dynamic.flac           Nomadiqa - Goctu Kervan.flac  Nomadiqa - Seventh Mode.flac

Doing this would retag other songs as well, though, if they also happened to be tagged with genre "Electronic". Thus, we might prefer to create a new directory, and only move some songs to that new directory:

$ mv World Electronic
$ mkdir World
$ mv 'Electronic/Nomadiqa - Birds Of Babylon.flac' World
$ ls
Drum & Bass  Electronic  Gothic Rock  World
$ ls World
Nomadiqa - Birds Of Babylon.flac

And, to prove that the files are actually being retagged:

$ pytags 'World/Nomadiqa - Birds Of Babylon.flac'
World/Nomadiqa - Birds Of Babylon.flac
FLAC, 363.81 seconds, 44100 Hz (audio/x-flac)
album=Sans Frontieres
tracknumber=02
artist=Nomadiqa
genre=World
title=Birds Of Babylon

Removing the last file from a non-empty virtual directory causes that directory to disappear:

$ mv World/* Electronic/
$ ls
Drum & Bass  Electronic  Gothic Rock

On the other hand, empty directories stick around for as long as we need them (just like they would on a traditional filesystem):

$ mkdir foo
$ ls
Drum & Bass  Electronic  foo  Gothic Rock
$ rmdir foo
$ ls
Drum & Bass  Electronic  Gothic Rock

Creating Multiple Views

We can create as many new pytagsfs mounts as we like, of course. The provides the ability to easily look at our media files in many different ways.

For instance, we could rearrange them by artist, and then album:

$ mkdir by-artist-album
$ pytagsfs -o format='/%a/%l/%N %t.%e' source by-artist-album
$ tree by-artist-album
by-artist-album
|-- Alex Reece
|   `-- Various - Platinum Breakz Disc 1
|       `-- 09 Pulp Fiction.flac
|-- Asylum
|   `-- Various - Platinum Breakz Disc 2
|       `-- 05 Da Base II Dark.flac
|-- Digital
|   `-- Various - Platinum Breakz Disc 2
|       `-- 04 Down Under.flac
...
|-- Nomadiqa
|   `-- Sans Frontieres
|       |-- 01 Orient House.flac
...
|-- Peshay
|   |-- Various - Platinum Breakz Disc 1
|   |   `-- 02 Psychosis.flac
|   `-- Various - Platinum Breakz Disc 2
|       `-- 08 The Nocturnal (Back On The Firm).flac
|-- Photek
|   `-- Various - Platinum Breakz Disc 1
|       `-- 06 Consiousness.flac
|-- Rasputina
|   |-- Oh Perilous World
|   |   |-- 01 1816, The Year Without A Summer.flac
...
|   `-- Oh Perilous World Side 2
|       |-- 01 The Question Of Time.flac
...
|-- Rufige Cru
|   `-- Various - Platinum Breakz Disc 2
|       `-- 09 Dark Metal.flac
...

Note the interesting arrangement of "Various Artists" compilations.

Filtering

In addition to specifying a directory structure, it is also possible to specify which files ought to be included. To do this, we filter paths using regular expressions.

For instance, maybe we only want to see songs by Rasputina:

$ mkdir rasputina
$ pytagsfs -o format='/%a/%t.%e',dstfilter='/Rasputina/.*' source rasputina
$ tree rasputina
rasputina/
`-- Rasputina
    |-- 1816, The Year Without A Summer.flac
    |-- A Retinue Of Moons%The Infindel Is Me.flac
    |-- Cage In A Cave.flac
...

More complex filtering can be done, as well. This wouldn't be appropriate for the collection I've been using as an example, but maybe you want to see all of your rock songs released in the 1970s:

$ mkdir 70s-rock
$ pytagsfs -o format='/%g/%y/%a - %t.%e',dstfilter='/Rock/197[0-9]/.*' source 70s-rock

Filters can be inverted, too. This would give you all of your music not released in the 1970s:

$ mkdir not-70s
$ pytagsfs -o format='/%y/%a - %t.%e',dstfilter='!/197[0-9]/.*' source not-70s

More Information

The following pages are helpful if you are looking for more information:

If you're ready to give pytagsfs a try:

Introduction (last edited 2008-03-25 03:37:01 by ForestBond)