Trying to make a case for adding this as it's clearly the overwhelming request in open tickets.

So before the requisite "patches welcome" response or immediate ticket deletion ensues, I'd like to clarify that I'd love to help. I've browsed the http SVN code (for trunk), and it looks like the virtual directories are specified by SapphireMovieDirectory?.h and returned by SapphireMovieDirectory?.m. But I'm unclear if this is the only location where virtual movie directories are defined. If this is the right location, I'd probably add functionality to read in an xml file that defines a virtual directory name and perhaps regex style filter (or enumerated match list) for filenames (possibly other attributes as well).

A few things are preventing me from doing this. First, I'm not sure how best to setup the build/development environment for 1.0b7. The only setup I've found is:

and that uses BR Dev kit 1.1.1. Since version 2.4(?) seems like it's available (somewhere -- I don't recall where I found it), I'm wondering what version to use (especially with 10.b7) and if this wiki environment setup is still valid.

Second, how can I get the entire code base without downloading every file from the web? I recall there was once SVN access, but I don't know what/where that is anymore, nor do I know if the trunk is 1.0b7p5. I'll be developing on 10.5.8 with XCode 3.1 (latest).

A little clarification on your part might be able to get this feature added.

and that uses BR Dev kit 1.1.1. Since version 2.4(?) seems like it's available

That's the job of the compatibility classes. They make it run on the whole range.

Second, how can I get the entire code base without downloading every file from the web? I recall there was once SVN access, but I don't know what/where that is anymore, nor do I know if the trunk is 1.0b7p5. I'll be developing on 10.5.8 with XCode 3.1 (latest).

If you don't already have/used SVN clients before I have found Versions (free 30day trial) to be a very friendly one (​http://versionsapp.com/).

As far as adding custom virtual directories; I would suggest you start by looking at how we retrieve and build directories for TVShows. You'll also want to study the CoreData models (located in Sapphire.xcdatamodeld) this will show you all the data relationships/dependencies associated with a given episode or movie.

OK. Thanks for the pointers. I have the repository locally and will make a patch based on the CoreData version. Also thanks for the pointer to check out TVShow directories. I'll see what I can put together this weekend. I hope I can leverage the xml reading facilities used for overriding metadata so that it's just a matter of coming up with a suitable xml format and cobbling together existing pieces of functionality.

I've built custom movie virtual directories into the CoreData version (1.0b7p5) of Sapphire. The patch file is attached, so are some screenshots of an example custom movie virtual directory. Additionally, I've attached the xml file that created the custom virtual directory.

The basic idea is as follows. Create an xml file in the application support directory (usually ~/Library/Application?Support/Sapphire?) named virtualDirs.xml. This file will be read everytime Sapphire starts up and creates the Movies virtual directory. The custom virtual directories are not stored in the core data model (yet). It appears that there are a number of changes waiting to be added when the core data model is regenerated so I didn't want to mess with it. Additionally, if these custom directories are stored in the db, there'll need to be functionality included to manage (add/remove/edit) these custom virtual directories. I didn't want to add that myself. Thus, to edit the custom virtual directories, just restart FrontRow?.

<movieMatch name="..." description="...">
Each movieMatch creates a new custom movie virtual directory. The name attribute defines the name in the Movies menu. The description attribute defines the text description of the custom movie virtual directory. (Currently don't support custom icons). Both name and description are required. All children of this element define matching characteristics for movies to appear in this custom movie virtual directory.

<title [type="i"]>...</title>
Match on movie title. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<title>Die Hard*</title>

This matches movies with title starting with Die Hard.

<plot [type="i"]>...</plot>
Match on movie plot. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<plot>*must save the world*</plot>

This matches movies with a plot that contains the text "...must save the world...".

<genre [type="i"]>...</genre>
Match on movie genre. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<genre>Action</genre>

This matches movies tagged with the Action genre.

<cast [type="i"]>...</cast>
Match on movie cast member name. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<cast>Bruce Willis</cast>

This matches movies with Bruce Willis as a cast member.

<director [type="i"]>...</director>
Match on movie director. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<director>Ron Howard</director>

This matches movies directed by Ron Howard.

<mpaaRating [type="i"]>...</mpaaRating>
Match on movie MPAA rating. Wildcards {*,?} may be used. Value must be text (e.g. PG, PG-13, R, etc.). The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<mpaaRating>R</mpaaRating>

This matches movies rated R by the MPAA.

<subtitles [type="i"]>...</subtitles>
Match on movie subtitles language. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<subtitles>Spanish</subtitles>

This matches movies that have Spanish subtitles.

<videoDescription [type="i"]>...</videoDescription>
Match on movie video description. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<audioDescription [type="i"]>...</audioDescription>
Match on movie audio description. Wildcards {*,?} may be used. Value must be text. The type attribute is optional and if specified with value i, makes the match a case insensitive match. Example:

<audioDescription>English</audioDescription>

This matches movies with an English audio track. Note, common values for this field are like: "English", "Spanish", or "MPEG Layer3, Stereo, 44.100 kHz", etc. (depends on container type: DVD, .mkv, ...).

<duration>...</duration>
Match on movie duration greater than or equal to the value. Value specified in minutes and must be numeric (can be floats). Example:

<duration>90</duration>

This matches movies that are at least 90 minutes long.

<imdbUserRating>...</imdbUserRating>
Match on movie IMDB user rating greater than or equal to the value. Value specified on scale of 1-10 and must be numeric (can be floats). Example:

<imdbUserRating>5.4</imdbUserRating>

This matches movies that have an IMDB user rating of at least 5.4/10.

<imdbTop250>...</imdbTop250>
Match on movie IMDB Top 250 ranking less than or equal to the value. Value specified on scale of 1-250 and must be numeric (integer). Example:

<imdbTop250>33</imdbTop250>

This matches movies that have an IMDB Top 250 ranking of 33 or less.

<releaseDate>...</releaseDate>
Match on movie release date greater than or equal to the value. Value must be a common string representation of a date (e.g. 10/15/2007). Example:

<releaseDate>10/15/2007</releaseDate>

This matches movies that have a release date greater than or equal to October 15, 2007.

<watched>...</watched>
Match on movie being watched or not. Value must be either 1 (watched) or 0 (not watched). Example:

<watched>0</watched>

This matches movies that have not been watched.

<wonOscars>...</wonOscars>
Match on movie having won at least 1 Oscar or no Oscars. Value must be either 1 (has won at least 1 Oscar) or 0 (not won any Oscars). Example:

<wonOscars>1</wonOscars>

This matches movies that have won at least 1 Oscar.

<not>...</not>
Negates the matching criteria of the child element. Value must be a single child element. Example:

<not>

<cast>Bruce Willis</cast>

</not>

This matches movies that do not have Bruce Wills as a cast member.

<any>...</any>
Serves as a way to specify that movies can match on any criteria specified by child elements. Nesting of any movie matching elements is supported (including <any> and <all> elements). Example:

<any>

<title>Die Hard</title>
<title>Die Hard 2</title>

</any>

This will match both Die Hard and Die Hard 2.

<all>...</all>
Serves as a way to specify that movies must match on all criteria specified by child elements. Nesting of any movie matching elements is supported (including <any> and <all> elements). Example:

<all>

<title>Die Hard*</title>
<cast>Bruce Willis</cast>

</all>

This will match all movies with titles that start with Die Hard and have Bruce Willis.
As a side note, the <movieMatch> element behaves as an <all> element insofar as when child elements are added directly to it.

Perhaps the addition of the XML based directories should be done within reloadDirectoryContents instead of within init. This way it wouldn't require a restart to get the new dirs, but instead just re-enter the Movies dir. The modification date on the XML file can be cached so as to only re-import when it has actually changed.

I think the filters should default to case-insensitive with an option to make case sensitive. I feel this is more convenient to users.

The massive if-else block in createPredicate can likely be done better. First, doing a lowercaseString on [elem name] and then doing a isEqualToString on the same lower case string each time is more efficient than doing repeated caseInsensitiveCompare: since the lower case string does not change in the course of the if statements.
Additionally, I can see this massive if-else block being changed into an NSDictionary where the elements in the dictionary include the format string and some sort of number indicating what to do with the element in that format.

Otherwise, looks very good. I'll have to look at it further when I have time.

P.S. The branch is now trunk since we realized we will do no further development on the older code.

Good suggestions. I think I agree with all the changes. Though, they may have to wait as the quarter's started up again and I need to focus on my research for a bit. Please feel free to change and/or integrate this into a release. I'm not sure that I'll be able to get back on it for a few months.