Get your Windows Media music collection presented in the excellent Gerbera DLNA media server by rating

I really rate Gerbera (formerly Mediatomb) and have used it for years as a media server at home. It serves video content to our TVs but also audio to my DLNA-capable Pioneer receiver, a VSX-921. One of the frustrations for me, however, is that a lot of the time I just want to play a selection of music out of my catalogue - I'm not fussed for a genre, year, album or artist... just anything that I've added a rating to in Windows Media Player, since I use that to mark tracks I like. By default, Gerbera doesn't consider this metadata if it finds it in MP3s... but, good news, it can if you want it to.

First things first, you'll need a few extra lines in the import section of your config.xml. The relevant lines are below, in the <library-options> tag, and basically enable the scraping of certain auxiliary tags out of the metadata. I've added a number of additional items, but POPM is the "popularity" measure, which is essentially your star rating of the track :


  <import hidden-files="no">
    <scripting script-charset="UTF-8">
      <common-script>/usr/share/gerbera/js/common.js</common-script>
      <playlist-script>/usr/share/gerbera/js/playlists.js</playlist-script>
      <virtual-layout type="js">
        <import-script>/usr/share/gerbera/js/import.js</import-script>
      </virtual-layout>
    </scripting>
...
    <library-options>
      <id3>
        <auxdata>
          <add-data tag="POPM"/>
          <add-data tag="TCON"/>
          <add-data tag="TYER"/>
          <add-data tag="TIT2"/>
          <add-data tag="TPE1"/>
          <add-data tag="TPE2"/>
        </auxdata>
      </id3>
    </library-options>
...
  </import>

Now it's time to change your import script so that when it's reading in your audio files, it includes the relevant rating into the metadata of the track when it inserts it into the database. You'll need to fiddle with your import.js (typically in /usr/share/gerbera/js/). Here are the relevant lines from mine; there's a few other enhancements in it over the standard file.

function addAudio(obj) {
    var desc = '';
    var artist_full;
    var album_full;

    // first gather data
    var title = obj.meta[M_TITLE];
    var alt_title = orig.aux["TIT2"];
    if (!title) {
        if (alt_title) {
          // No idv3 tag for title but it's in an aux metadata tag so let's use that instead
          title = orig.aux["TIT2"];
          print("Used alternative title [" + title + "]");
        } else {
          // Just use the title of the object (the filename?)
          title = obj.title;
        }
    }

    var artist = obj.meta[M_ARTIST];

    // If artist is null, try getting it from auxiliary metadata tags
    if (!artist) {
        artist = orig.aux["TPE1"];
    }

    // If artist is still null then we're buggered :)
    if (!artist) {
        artist = 'Unknown';
        artist_full = null;
    } else {
        artist_full = artist;
        desc = artist;
    }

    var album = obj.meta[M_ALBUM];
    if (!album) {
        album = 'Unknown';
        album_full = null;
    } else {
        desc = desc + ', ' + album;
        album_full = album;
    }

    if (desc) {
        desc = desc + ', ';
    }
    desc = desc + title;

    var date = obj.meta[M_DATE];
    if (!date) {
        // Try getting data from aux metadata
        date = orig.aux["TYER"];
    }

    if (!date) {
        date = 'Unknown';
    } else {
        date = getYear(date);
        desc = desc + ', ' + date;
    }

    var genre = obj.meta[M_GENRE];
    if (!genre) {
        // Try getting genre from aux metadata
        genre = orig.aux["TCON"];
    }

    if (!genre) {
        genre = 'Unknown';
    } else {
        desc = desc + ', ' + genre;
    }

    var description = obj.meta[M_DESCRIPTION];
    if (!description) {
        obj.meta[M_DESCRIPTION] = desc;
    }

    var popm = orig.aux['POPM'];
    var rating = '0';
    if (popm) {
      if (popm.match(/rating/)) {
        print("Item appears to contain a rating in POPM aux attribute");
        var tmp1rating = popm.match(/rating=[0-9]+/i);
        var tmp2rating = tmp1rating[0].split("=");
        if (tmp2rating[1] == 1) {
                rating = '1';
        } else if (tmp2rating[1] <= 64) {
                rating = '2';
        } else if (tmp2rating[1] <= 128) {
                rating = '3';
        } else if (tmp2rating[1] <= 196) {
                rating = '4';
        } else if (tmp2rating[1] >= 255) {
                rating = '5';
        } else {
                // Some unknown format/value, cannot parse - mark it as unrated
                rating = '0';
        }

      }
    }


    var track = '';

    chain = ['Audio', 'Artists', artist, 'All - full name'];
    addCdsObject(obj, createContainerChain(chain));

    chain = ['Audio', 'Artists', artist, album];
    obj.title = track + title;
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_ALBUM);

    chain = ['Audio', 'Albums', album];
    obj.title = track + title;
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_ALBUM);

    chain = ['Audio', 'Genres', genre];
    addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);

    chain = ['Audio', 'Year', date];
    addCdsObject(obj, createContainerChain(chain));

    if (rating > 0) {
      chain = ['Audio', 'Rating (Stars)', rating];
    } else {
      chain = ['Audio', 'Rating (Stars)', 'Unrated'];
    }
    addCdsObject(obj, createContainerChain(chain));

    if (rating >= 4) {
        chain = ['Audio', 'Rating (Stars)', '4+'];
        addCdsObject(obj, createContainerChain(chain));
        chain = ['Audio', 'Rating (Stars)', '4+ by Genre', genre];
        addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);
    }

    if (rating >= 3) {
        chain = ['Audio', 'Rating (Stars)', '3+'];
        addCdsObject(obj, createContainerChain(chain));
        chain = ['Audio', 'Rating (Stars)', '3+ by Genre', genre];
        addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);
    }

    if (rating >= 2) {
        chain = ['Audio', 'Rating (Stars)', '2+'];
        addCdsObject(obj, createContainerChain(chain));
        chain = ['Audio', 'Rating (Stars)', '2+ by Genre', genre];
        addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);
    }

    if (rating >= 1) {
        chain = ['Audio', 'Rating (Stars)', '1+'];
        addCdsObject(obj, createContainerChain(chain));
        chain = ['Audio', 'Rating (Stars)', '1+ by Genre', genre];
        addCdsObject(obj, createContainerChain(chain), UPNP_CLASS_CONTAINER_MUSIC_GENRE);
    }

}

Now, when you browse your library from the DLNA client you should see a Ratings subfolder, which will arrange your tunes by rating (number of stars). You list by exact number of stars or, if you want to play everything rated 2 stars or above (for example) use the "2+" subfolder - it shows all tracks rated 2, 3, 4 or 5 stars.