14 min read

(For more resources on Plone, see here.)

Audio enhancements with p4a.ploneaudio

One of the most advanced products to boost the audio features of Plone is p4a.ploneaudio. Like its image sister p4a.ploneimage it doesn’t bring a content type on its own, but expands existing ones. As you might have guessed already, the File content type and the folderish ones (Folder, Large Folder, and Collection) are chosen for the enhancement.

To install it, add the following code to the buildout of our instance:

[buildout]
...
[instance]
...
eggs =
${buildout:eggs}
Plone
p4a.ploneaudio
zcml =
p4a.ploneaudio

After running the buildout and restarting the instance, we need to install the product as an add-on product. We find it with the product name Plone4Artists Audio (p4a.ploneaudio).

Enhancing files

Installing the p4a.ploneaudio product enables the enhancement of the File content type of ATContentTypes. Unlike with the image enhancement, not all files are automatically enhanced with additional audio features. p4a.ploneaudio comes with a MIME type filter. If we upload a file with one of the meta types such as audio/MPEG or application/Ogg, the file will automatically be audio enhanced. All other files (such as ZIP files, EXE files, and so on) stay untouched.

Technically speaking, this works via a named adapter.

The first thing we see is the modified default view for audio-enhanced files:

On the right side we see some technical information about the audio file itself. We find the size, the format (MP3 or Ogg), the bitrate, the frequency, and the length of the track there. As with any other content type, we have the title and the description at the top of the content area. For the audio-enhanced content, the description has changed from a simple text field to a rich text field. We find four buttons after the usual CMS bar (the belowcontenttitle slot) containing the author and the modification date of the file. Each of these buttons retrieves the audio file in a different way:



Button

Action

Description

 

 

Play

An embedded audio player written in Flash. Clicking on it starts playback immediately.

 

 

Pop up

Opens a pop-up window with a Flash player playing the audio track. This is useful if someone wants to play the track while continuing to browse the site.

 

 

Stream

Clicking on the button returns an M3U playlist with the URL of the file. The browser/operating system needs to take care of the handling of the stream. If you have a Mac, the file will be streamed to iTunes.

 

 

Download

This is the standard behavior of Plone’s File content-type. The file is returned to the client like any other file object. It can be saved or opened with the favorite media player of the operating system.

 

We find a long list of additional information on the audio track below the player and streaming buttons. This information is the metadata stored with the audio file and is gathered during the enhancing process. It can be changed and written back to the file.

Let’s take a closer look on the enhancement process.

One important step here is marking the content object with two interfaces:

  • One is p4a.subtyper.interfaces.ISubtyped. This interface marks the content as subtyped.
  • The other interface is p4a.audio.interfaces.IAudioEnhanced. This interface describes the type of enhancement, which is audio content in this case.

All other views and components available with the enhanced version bind to the p4a.audio.interfaces.IAudioEnhanced interface.

Additionally, p4a.ploneaudio tries to extract as much of the metadata information from the file as possible.

The title is retrieved from the metadata and changed.

Let’s see what happens when a file is added in detail:

It is possible to write custom audio enhancers if needed. The enhancers are queried as named adapters by the MIME type on the IAudioDataAccessor interface.

Enhancing containers

With p4a.ploneaudio, we can turn any Plone folder into an audio-enhanced folder by choosing Audio container from the Subtype menu. Two marker interfaces are attached to the container:

p4a.subtyper.interfaces.ISubtyped

p4a.audio.interfaces.IAudioContainerEnhanced

The default view of the container is changed utilizing the IAudioContainerEnhanced interface. The new default view is audio-container.html, which comes with the p4a.ploneaudio product.

In the View option we see one box for each track. For each track, the title and the cover artwork is shown. There is also an embedded Flash player to play each track directly.

There are some other container views that come with the product as follows:

  • audio-album.html (album view)
  • audiocd-popup.html (pop-up view)
  • cd_playlist.xspf

And the default edit view for IAudioContainerEnhaced-marked folders is overridden.

The audio-album.html view presents the audio content of the container in a slightly different way. The single tracks are arranged in a table. Two variants of this view are exposed in the Display menu of the container—Album view and Album view with no track numbers. Both these views are more compact than the default audio container view and have the same layout, except that the second one omits the column with the track numbers. As for the other audio container views, there is a player for each track. Moreover, there are two buttons on the top of the page. One is the commonly used RSS icon

and the other one is the familiar pop-up player button .

By clicking on the RSS icon, we get to the stream (or podcast of the folder). This may not be too interesting for a standard static Folder, but can be for a Collection where the content changes more dynamically.

The pop-up player for a folder looks and operates slightly differently as the file standalone variant. It contains all tracks that are part of the audio container as a playlist.

Lastly, there is the cd_playlist.xspf view. This view is not exposed via a display or as an action. It provides the audio data as a XSPF stream.

The XML Shareable Playlist Format: XSPF

The XML Shareable Playlist Format (XSPF) is an XML file format for storing playlists of digital audio. The audio can be located locally or online. Last.fm uses XSPF for providing its playlists. An example playlist looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<playlist version="1" >
<trackList>
<track>
<location>example.mp3</location>
<creator>Tom</creator>
<album>Thriller</album>
<annotation>A comment</annotation>
</track>
<track>
<location>another.mp3</location>
<creator>Tom</creator>
</track>
</trackList>
</playlist>

There is a list of applications supporting the XSPF format on the XSPF (http://xspf.org/) website. The default XSPF view of p4a.ploneaudio does not include all possible information. It provides the following attributes:

  • location: This is the required location (URL) of the song.
  • image: The album artwork that may be included with each track.
  • annotation: p4a.ploneaudio collects information about the title, artist, album, and year in this field.

It is easy to write a custom implementation of an XSPF view. Look at the available fields at the XSPF home page and the XSPF implementation of p4a.audio. We find the template named cd_playlist.xspf.pt in the p4a.audio.browser module.

p4a.ploneaudio and the Plone catalog

Besides the customized default views and the additional views, p4a.ploneaudio comes with a number of other changes. One very important change is the disclosure of some audio metadata fields to the portal catalog. This allows us to use them in catalog queries in general and smart folders in particular.

The following indexes are added:

  • Artist
  • Genre
  • Track
  • Format

The Artist attribute is exposed as metadata information in the catalog. Also, the genre and the artist name are added to the full text index SearchableText.

The values for the genre field are hardcoded. The ID3 tag genre list is used together with the Winamp extensions. They are stored as a vocabulary. The term titles are resolved for Searchable Text, but not for the index and the Collection field.

Accessing audio metadata in Collections

To access catalog information in collections, it needs to be exposed to the collections tool. This can either be done by a product or TTW in the Plone configuration panel. p4a.ploneaudio comes with a modification of the fields:

  • Artist (Artist name)
  • Genre (Genre)
  • Format (MIME Types)

Let’s say we want a collection of all our MP3 files. All we have to do is add a MIME Types criterion to our collection and set audio/mpeg as the value:

ATAudio migration

If you have an older Plone site (2.5), you probably have ATAudio installed to deal with audio content.ATAudio has features similar to p4a.ploneaudio. This is not surprising as p4a.ploneaudio was derived from ATAudio. The main difference is that ATAudio provides a content type, while p4a.ploneaudio reuses an existing one. If you want to switch from ATAudio to p4a.ploneaudio for one or the other reason, p4a.ploneaudio comes with a migration routine. One reason for switching might be that ATAudio is not actively developed any more and probably doesn’t work with recent versions of Plone. For migrating, you need to call migrate-ataudioconfiglet.html and follow the instructions there.

The migration view is available only if ATAudio is installed. There is a little bit of a catch-22 situation because p4a.ploneaudio doesn’t run on Plone 2.5 and ATAudio doesn’t run on Plone 3. This means there is no good starting point for the migration. At least, there is a version of ATAudio that does install in Plone 3 in the collective repository:

http://svn.plone.org/svn/collective/ATAudio/tags/0.7- plone3migration/.

Extracting metadata with AudioDataAccessors

The IAudioDataAccessor interface is used for extracting metadata from binary audio content. If uploading a file, Plone tries to acquire a named adapter for the interface with the MIME type as the key. It has the following layout:


class IAudioDataAccessor(interface.Interface):
"""Audio implementation accessor (ie MP3, ogg, etc).
"""
audio_type = schema.TextLine(title=_(u'Audio Type'),
required=True,
readonly=True)
def load(filename):
"""Load from filename"""
def store(filename):
"""Store to filename"""

The audio_type field contains a human-readable description of the audio type. In the case of MP3, the Unicode string “MPEG-1 Audio Layer 3” is used. The load and store methods are used for reading/writing the metadata from/to the audio file.

The definition for the MP3 adapter looks like this:

<adapter
for="p4a.audio.interfaces.IPossibleAudio"
factory="._audiodata.MP3AudioDataAccessor"
provides="p4a.audio.interfaces.IAudioDataAccessor"
name="audio/mpeg"
/>

The component is registered for the p4a.audio.interfaces.IPossibleAudio interface. All classes marked with this interface are capable of getting converted to an audio-enhanced object. The standard product marks the File content type with this interface. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface, which is the marker for the lookup. The name attribute of adapter is the key for the lookup and needs to be set to the MIME type of the audio file that should be processed. Now, the factory does the actual work of loading and storing the metadata from the audio file.

p4a.ploneaudio and FLAC

For the moment, p4a.ploneaudio only supports MP3 and Ogg Vorbis. This is a reasonable choice. Both formats are streamable and were made for good audio quality with small file sizes. We want to add FLAC support. We use mutagen for metadata extraction. Mutagen is an audio metadata extractor written in Python. It is capable of reading and writing many audio metadata formats including:

  • FLAC
  • M4A
  • Monkey’s Audio
  • MP3
  • Musepack
  • Ogg Vorbis
  • True Audio
  • WavPack
  • OptimFROG

Let’s remember the flow chart of the audio adding process. We recall that we need a metadata extractor for our FLAC MIME type.

First, we need to register a named adapter for this purpose. This is very similar to the MP3 adapter we saw before:

<adapter
for="p4a.audio.interfaces.IPossibleAudio"
factory=".flac._audiodata.FlacAudioDataAccessor"
provides="p4a.audio.interfaces.IAudioDataAccessor"
name="application/x-flac"
/>

The adapter is used for objects implementing the p4a.audio.interfaces.IPossibleAudio interface. The factory does the work of extracting the metadata. The adapter provides the p4a.audio.interfaces.IAudioDataAccessor interface. This is what the adapter is made for and the name is application/x-flac, which is the MIME type of FLAC audio files.

Next, we define the metadata accessor:

from mutagen.flac import Open as openaudio
...
from p4a.audio.ogg._audiodata import _safe

First, we need some third-party imports. For the metadata extraction, we use the FLAC accessor of the mutagen library. _safe is a helper method. It returns the first element if the given parameter is a list or a tuple, or the element itself.

class FlacAudioDataAccessor(object):
"""An AudioDataAccessor for FLAC"""
implements(IAudioDataAccessor)
def __init__(self, context):
self._filecontent = context

The first lines are the boilerplate part. The adapter class implements the interface the adapter provides. In the constructor, we get the context of the adapter and save it in the _filecontent variable of the instance.

@property
def audio_type(self):
return 'FLAC'
@property
def _audio(self):
return IAudio(self._filecontent)
@property
def _audio_data(self):
annotations = IAnnotations(self._filecontent)
return annotations.get(self._audio.ANNO_KEY, None)

The audio_type property is just for information purposes and required by the interface. It is displayed in the audio view. The _audio property is a shortcut for accessing the IAudio adapter for the context. The audio_data property is a shortcut for accessing the metadata annotated to the context.

def load(self, filename):
flacfile = openaudio(filename)
self._audio_data['title'] = _safe(flacfile.get('title', ''))
self._audio_data['artist'] = _safe(flacfile.get('artist', ''))
self._audio_data['album'] = _safe(flacfile.get('album', ''))
self._audio_data['year'] = _safe(flacfile.get('date', ''))
self._audio_data['idtrack'] = _safe(flacfile.
get('tracknumber', ''))
self._audio_data['genre'] = _safe(flacfile.get('genre', ''))
self._audio_data['comment'] = _safe(flacfile.
get('description', ''))
self._audio_data['bit_rate'] = long(flacfile.info.
bits_per_sample)
self._audio_data['length'] = long(flacfile.info.length)
self._audio_data['frequency'] = long(flacfile.info.
sample_rate)

The load method is required by the IAudioDataAccessor interface. It fetches the metadata using the mutagen method from the audio file and stores it as an annotation on the context.

def store(self, filename):
flacfile = openaudio(filename)
flacfile['title'] = self._audio.title or u''
flacfile['artist'] = self._audio.artist or u''
flacfile['album'] = self._audio.album or u''
flacfile['date'] = self._audio.year or u''
flacfile['tracknumber'] = self._audio.idtrack or u''
flacfile.save()

The store method is required by the IAudioDataAccessor interface as well and its purpose is to write the metadata from the context annotation back to the audio file.

We have covered the following in this article series:

  • Manipulation of audio content stored as File content in Plone
  • The different formats used for the binary storage of audio data
  • Storing and accessing MP3 audio metadata with the ID3 tag format
  • Managing metadata, formats, and playlists with p4a.ploneaudio in Plone
  • Including a custom embedded audio player in Plone
  • Using the Flowplayer product to include an audio player standalone in rich text and as a portlet

>> Continue Reading: Using Flowplayer in Plone 3.


Further resources on this subject:

 

 

 

 


LEAVE A REPLY

Please enter your comment!
Please enter your name here