Media browser has a bunch Entities that it deals with, for example: Movies, Episodes and Shows. We scan the file system and figure out what files and folders map to what entities.

This is done using entity resolution.

I have defined a new set of classes that take in a location and spit out a factory that knows how to create an entity. Sounds a bit tricky, but this trickiness gives us tons of flexibility. The beauty of this system is that code now lives in a very logical place. If a user is trying to figure out why a particular file is not being detected as a Movie we know to look at the MovieResolver which contains all the logic for movie resolution. Additionally, this architecture is very plug-in friendly and incredibly testable.

For example, I just fixed up a bug where folders were not being detected as movies properly.

Writing the fix was really easy, first I started with this test case:

[Test]
public void TestRecusiveMovieResolution()
{
    var resolver =  resolver = new ChainedEntityResolver() { 
        new MovieResolver(2, true), // maximum 2 videos per movie, allow for recursive search
        new FolderResolver()
    };
    var movieFolder = MockFolderMediaLocation.CreateMockLocation(@"
|Rushmore
 |part 1
  a.avi
 |part 2
  b.avi
");

    Assert.AreEqual(resolver.ResolveType(movieFolder), typeof(Movie));
}

Some observations:

  • I wrote an awesome little mock filesystem that allows us to test our algorithms without creating files.
  • We do chained resolution, meaning that if a resolver at the top of the chain resolves the type of a location we stop and return.

Next comes the fix in MovieResolver.cs:

  videoCount += childFolders
     .Select(child => ChildVideos(child))
     .SelectMany(x => x)
     .Take((maxVideosPerMovie - videoCount) + 1)
     .Count();
</code></pre>

and

private IEnumerable<IMediaLocation> ChildVideos(IFolderMediaLocation location) {
    foreach (var child in location.Children) {
        if (child.IsVideo()) { 
            yield return child;
        }
        var folder = child as IFolderMediaLocation;
        if (folder != null) {
            foreach (var grandChild in ChildVideos(folder)) {
                yield return grandChild;  
            } 
        }
    }

}

Observations:

  • SelectMany is a really useful LINQ method, that allows you to lazily chain your enumerables.

Comments

Stephen about 5 years ago
Stephen

Thanks Sam!


I’d like to contribute once I get my development environment up and running, problem is I’m running Enterprise and that does not include the MC dlls.


Stephen

Jas_Manghera about 5 years ago
Jas_Manghera

If you can get your hands on the MC dlls, it should be relatively straight forward to dump them into enterprise.


comments powered by Discourse