diff --git a/classify.cabal b/classify.cabal
--- a/classify.cabal
+++ b/classify.cabal
@@ -1,6 +1,6 @@
 Cabal-version:  >=1.6
 Name:           classify
-Version:        2012.10.22
+Version:        2012.10.23
 Build-Type:     Simple
 License:        PublicDomain
 License-File:   LICENSE
@@ -13,9 +13,11 @@
   Build-Depends:  base >= 4 && <= 5, mtl, containers
   HS-Source-Dirs: src
   Exposed-Modules:
-    Data.Classify.DataTypes,
-    Data.Classify.Rank,
-    Data.Classify.Parser,
+    Data.Classify.Television
+  Other-Modules:
+    Data.Classify.DataTypes
+    Data.Classify.Rank
+    Data.Classify.Parser
     Data.Classify.Printer
 Source-repository head
   type:          darcs
diff --git a/src/Data/Classify/DataTypes.hs b/src/Data/Classify/DataTypes.hs
--- a/src/Data/Classify/DataTypes.hs
+++ b/src/Data/Classify/DataTypes.hs
@@ -1,4 +1,4 @@
-{-# OPTIONS -fglasgow-exts #-}
+{-# LANGUAGE DeriveDataTypeable #-}
 module Data.Classify.DataTypes where
 
 import Data.Typeable
diff --git a/src/Data/Classify/Parser.hs b/src/Data/Classify/Parser.hs
--- a/src/Data/Classify/Parser.hs
+++ b/src/Data/Classify/Parser.hs
@@ -59,7 +59,7 @@
               , do string (drop 2 (show year))
                    return (year, 0)
               ]
-              | year <- [2001..2015]] -- Try years from 2001 to 2015
+              | year <- [2000..2015]] -- Try years from 2000 to 2015
 
 getDigits n
     = do ds <- many1 digit
diff --git a/src/Data/Classify/Rank.hs b/src/Data/Classify/Rank.hs
--- a/src/Data/Classify/Rank.hs
+++ b/src/Data/Classify/Rank.hs
@@ -93,6 +93,8 @@
            , ("the.colbert.report.9.19.07.dsr.xvid.iht.[VTV].avi", colbert, DateVersion 2007 9 19)
            , ("the.daily.show.9.19.07.dsr.xvid.iht.[VTV].avi", daily, DateVersion 2007 9 19)
            , ("Saturday Night Live S38E05 Bruno Mars PROPER HDTV x264-BAJSKORV", "Saturday Night Live", Version 38 5)
+           , ("Conan 2010 11 08 Seth Rogen HDTV XviD-FQM", "Conan", DateVersion 2010 11 08)
+           , ("Conan 2000 11 08 Seth Rogen HDTV XviD-FQM", "Conan", DateVersion 2000 11 08)
 
            , ("Time.Warp.S01E02.HDTV.XviD-GNARLY.avi", "Time Warp", Version 1 2)
            , ("True.Blood.S01E07.720p.HDTV.x264-2HD.mkv", "True Blood", Version 1 7)
diff --git a/src/Data/Classify/Television.hs b/src/Data/Classify/Television.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Classify/Television.hs
@@ -0,0 +1,64 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module      :  Data.Classify.Television
+-- Copyright   :  PublicDomain
+--
+-- Maintainer  :  lemmih@gmail.com
+-- Portability :  portable
+--
+-- This module defines a parser for television media files commonly found in
+-- filesharing communities. The internals of the parser are non-deterministic
+-- and heuristics are used to select the interpretation most likely to be correct.
+--
+module Data.Classify.Television
+  ( -- * Types
+    Name,
+    Version(..),
+    Title,
+    -- * Classify
+    tryClassify,
+    classify
+  ) where
+
+import Data.Classify.DataTypes        ( Element(..), Name, Version(..), Title )
+import Data.Classify.Parser           ( run, parseElement )
+import Data.Classify.Rank             ( sortByRank )
+
+import qualified Data.Map as Map
+import Data.Char                      ( isAlphaNum, isSpace, toLower )
+import Data.List                      ( inits, tails, isPrefixOf )
+
+tryClassify :: [Name] -> String -> Maybe (Name, Version, Title)
+tryClassify knownNames inp =
+  case sortByRank possibleParses of
+    []     -> Nothing
+    sorted ->
+      let elt = last sorted
+      in Just (name elt, version elt, title elt)
+  where
+    idx = Map.fromList [ (src, name) | name <- knownNames, src <- stripName name ]
+    possibleParses = run (parseElement idx) inp
+
+classify :: [Name] -> String -> (Name, Version, Title)
+classify knownNames inp =
+  case tryClassify knownNames inp of
+    Nothing     -> error $ "Data.Classify.Television.classify: Failed to parse: " ++ show inp
+    Just result -> result
+
+stripName :: String -> [String]
+stripName = worker . filter isAlphaNum . filter (not . isSpace) . map toLower
+  where
+    alts = [ ("the", "")
+           , ("newyork", "ny")
+           , ("los angeles", "la") ]
+    doesMatch key [] = Nothing
+    doesMatch key (x:xs)
+      | fst x `isPrefixOf` key = Just x
+      | otherwise              = doesMatch key xs
+    expand lst = lst : concatMap expand [ before ++ new ++ drop (length old) after
+                 | (before, after) <- split lst
+                 , Just (old, new) <- [doesMatch after alts] ]
+    worker lst = expand lst
+
+split :: String -> [(String,String)]
+split str = zip (inits str) (tails str)
