Skip to main content

M3U.NET: Parsing and Output of .m3u files in .NET

I've been reorganizing my media library using the very cool MusicBrainz Picard, but of course all my m3u files broke. So I wrote the free M3U.NET library, and then wrote a utility called FixM3U that regenerates an M3U file by searching your music folder for the media files based on whatever extended M3U information is available:

> FixM3u.exe /order:title,artist foo.m3u bar.m3u ...

The M3U.NET library itself has a fairly simple interface:

// Parsing M3U files.
public static class M3u
{
  // Write a media list to an extended M3U file.
  public static string Write(IEnumerable<MediaFile> media);
  // Parse an M3U file.
  public static IEnumerable<MediaFile> Parse(
         string input,
         DirectiveOrder order);
  // Parse an M3U file.
  public static IEnumerable<MediaFile> Parse(
         IEnumerable<string> lines,
         DirectiveOrder order);
}

The 3 exported types are straightforward. A MediaFile just has a full path to the file itself and a list of directives supported by the extended M3U format:

// A media file description.
public sealed class MediaFile
{
    // The full absolute path to the file.
    public string Path { get; set; }
    // Extended M3U directives.
    public List<MediaDirective> Directives { get; set; }
}

The directives are represented in this library as key-value pairs:

// An extended M3U directive.
public struct MediaDirective
{
    // The directive name.
    public string Name { get; set; }
    // The directive value.
    public string Value { get; set; }
    // The separator delineating this field from the next.
    public char? Separator { get; set; }
}

The currently supported keys are "Artist", "Title" and "Length".

The M3U format is supposed to order directives as "length, artist - title", but iTunes seems to reverse the order of artist and title. I've thus made this configurable via a parsing parameter of type DirectiveOrder, and you can specify the ordering when parsing:

// The order of the title and artist directives.
public enum DirectiveOrder
{
    // Artist followed by title.
    ArtistTitle,
    // Title followed by artist.
    TitleArtist,
}

Comments

Popular posts from this blog

async.h - asynchronous, stackless subroutines in C

The async/await idiom is becoming increasingly popular. The first widely used language to include it was C#, and it has now spread into JavaScript and Rust. Now C/C++ programmers don't have to feel left out, because async.h is a header-only library that brings async/await to C! Features: It's 100% portable C. It requires very little state (2 bytes). It's not dependent on an OS. It's a bit simpler to understand than protothreads because the async state is caller-saved rather than callee-saved. #include "async.h" struct async pt; struct timer timer; async example(struct async *pt) { async_begin(pt); while(1) { if(initiate_io()) { timer_start(&timer); await(io_completed() || timer_expired(&timer)); read_data(); } } async_end; } This library is basically a modified version of the idioms found in the Protothreads library by Adam Dunkels, so it's not truly ground bre...

Easy Automatic Differentiation in C#

I've recently been researching optimization and automatic differentiation (AD) , and decided to take a crack at distilling its essence in C#. Note that automatic differentiation (AD) is different than numerical differentiation . Math.NET already provides excellent support for numerical differentiation . C# doesn't seem to have many options for automatic differentiation, consisting mainly of an F# library with an interop layer, or paid libraries . Neither of these are suitable for learning how AD works. So here's a simple C# implementation of AD that relies on only two things: C#'s operator overloading, and arrays to represent the derivatives, which I think makes it pretty easy to understand. It's not particularly efficient, but it's simple! See the "Optimizations" section at the end if you want a very efficient specialization of this technique. What is Automatic Differentiation? Simply put, automatic differentiation is a technique for calcu...

Building a Query DSL in C#

I recently built a REST API prototype where one of the endpoints accepted a string representing a filter to apply to a set of results. For instance, for entities with named properties "Foo" and "Bar", a string like "(Foo = 'some string') or (Bar > 99)" would filter out the results where either Bar is less than or equal to 99, or Foo is not "some string". This would translate pretty straightforwardly into a SQL query, but as a masochist I was set on using Google Datastore as the backend, which unfortunately has a limited filtering API : It does not support disjunctions, ie. "OR" clauses. It does not support filtering using inequalities on more than one property. It does not support a not-equal operation. So in this post, I will describe the design which achieves the following goals: A backend-agnostic querying API supporting arbitrary clauses, conjunctions ("AND"), and disjunctions ("OR"). Implemen...