I can give iTunes a few rules, and it will update the list of playlist tracks based on those rules, without me having to think about how it is doing that.
But how does it do this? How does it build my simple rules into a filter for tracks? When I tell it things like; “give me everything from The Glitch Mob, produced before 2014, where plays count is less than 20”, it understands what I mean.
Now, we could make these Smart Playlists with many conditionals. If you’re anything like me though, you just cringed at that thought.
RulerZ is a rule engine. It’s an implementation of the Specification pattern. You know where else you’ve seen the Specification pattern? In database abstraction layers like Eloquent and Doctrine!
The basic idea is that you start with some sort of list. It could be users in a database, or expenses in a CSV file. Then you read them into memory (or even filter before that) and filter them according to some chain-based logic. You know the kind:
$list ->whereArtist("The Glitch Mob") ->whereYearLessThan(2015) ->wherePlayCountLessThan(20) ->all();
In database abstraction layers this is usually done by generating SQL. We send that SQL to the database server, where the records are brought into memory and then filtered. What we get is the already-filtered list, but the idea is still the same.
We wouldn’t want to make those filters as conditionals, through PHP. The Specification pattern (and by extension SQL) are great for applying this boolean logic.
Let’s take a look at how to use RulerZ:
use RulerZCompiler; use RulerZParser; use RulerZRulerZ; $compiler = new CompilerEvalCompiler( $parser = new ParserHoaParser() ); $rulerz = new RulerZ( $compiler, [ $visitor = new CompilerTargetArrayVisitor(), ] ); $tracks = [ [ "title" => "Animus Vox", "artist" => "The Glitch Mob", "plays" => 36, "year" => 2010 ], [ "title" => "Bad Wings", "artist" => "The Glitch Mob", "plays" => 12, "year" => 2010 ], [ "title" => "We Swarm", "artist" => "The Glitch Mob", "plays" => 28, "year" => 2010 ] // ... ]; $filtered = $rulerz->filter( $tracks, "artist = :artist and year < :year and plays < :plays", [ "artist" => "The Glitch Mob", "year" => 2015, "plays" => 20 ] );
In this example, we have a list of tracks. This could be something we export from iTunes…
We create a rule compiler, and a new
RulerZ instance. We can then use the
RulerZ instance of filter our track list. We combine the textual rules with the parameter list to create the boolean filter logic.
Like SQL but in PHP, against records stored in memory. It’s simple and elegant!
Building Smart Playlists
Let’s put this knowledge to use! We’ll begin by extracting an iTunes library:
Open iTunes, click “File” → “Library” → “Export Library…”
Save the XML file as
library.xml, in your working directory.
Depending on the size of your library, this file may be large. My
library.xml file is about 46k lines long…
Continue reading %Using the RulerZ Rule Engine to Smarten up Playlist Building%