packages feed

pgdl-8.0: src/NameAlgo.hs

{-# LANGUAGE OverloadedStrings #-}

module NameAlgo where

import Video

import Data.Function
import Data.Array
import Data.List
import Data.Ord
import Data.Text (Text)
import qualified Data.Text as T

-- | the video name parsing is only for specific type of videos...( [subtitle][video name][episode].... )
-- for most filename, the parsing function will just return the video name itself.
beaut :: Video -> T.Text
beaut (Video str _ _ _) = beautT str
beaut (Folder str _ _)  = beautT str

beautT :: T.Text -> T.Text
beautT str = case cutName str of
    Left x -> "\n" `apd` x
    Right (sbt:nam:eps:_) -> T.unlines  [ ws 4  `apd` sbt
                                        , ws 10 `apd` nam
                                        , ws 30 `apd` eps
                                        ]
    _ -> error "something wrong in video name parsing function"
    where apd = T.append
          ws t = T.replicate t " "

-- | cut the name into pisces
cutName :: T.Text -> Either T.Text [T.Text]
cutName str
    | length dat < 3 = Left str
      -- parsing failure
    | otherwise      = Right [sbtitle, name, episode]
      -- ok.
    where (sbtitle:name:episode:_) = dat
          dat = filter (not . T.null) . getTags ["[", "]"] $ [str]
          getTags :: [T.Text] -> -- ^ the delimiters
                     [T.Text] -> -- ^ initial patterns
                     [T.Text]
          getTags dl s = foldl (\ls d -> concatMap (T.splitOn d) ls) s dl

-- | return the edit distance of two string
editDis :: T.Text -> T.Text -> Int
editDis t1 t2 = dp!(len1, len2)
    where (s1, s2) = (T.unpack t1, T.unpack t2)
          (len1, len2) = (length s1, length s2)
          a1 = listArray (1, len1) s1
          a2 = listArray (1, len2) s2
          bnd = ((0, 0), (len1, len2))
          dp = listArray bnd [go i j | (i, j) <- range bnd]
          go i 0 = i
          go 0 j = j
          go i j = minimum [ dp!(i, j-1) + 1
                           , dp!(i-1, j) + 1
                           , dp!(i-1, j-1) + cost
                           ]
            where cost = if a1!i == a2!j then 0 else 1

-- | caculate whether the edit distance of two video
-- name is less than half of the first video's length
isAlike :: Video -> Video -> Bool
isAlike vf1 vf2 = dis <= lim
    where (n1, n2) = (getName vf1, getName vf2)
          (e1, e2) = (cutName n1, cutName n2)
          vn1 = either id (!!1) e1
          vn2 = either id (!!1) e2
          -- vn1 and vn2 are the video name without subtitle or episode if being parsed.
          lim = length (T.unpack vn1) `div` 2
          dis = editDis vn1 vn2

{-
search :: [Video] ->  -- ^ video list
          [String] -> -- ^ a list of target string
          [Video]
search vids par = filter (\v -> vidInfx v (map T.pack par)) vids
-}

vidInfx :: Video -> [Text] -> Bool
vidInfx _ [] = True
vidInfx v (x:xs) = (x `ifx` getName v) && vidInfx v xs
    where ifx = T.isInfixOf `on` T.toCaseFold

sortByName :: [Video] -> [Video]
sortByName = sortBy (comparing getName)

sortVid :: [Video] -> [Video]
sortVid = sortBy cmpv
    where cmpv :: Video -> Video -> Ordering
          cmpv = cmp `on` dt
            where dt v
                    | isVid v = vidDate v
                    | otherwise = fldDate v
          cmp :: T.Text -> T.Text -> Ordering
          cmp = flip compare `on` prs
            where prs tx = [year, tranMon mon, day, time] 
                    where [day, mon, year, time] = T.splitOn "-" tx
                          tranMon :: T.Text -> T.Text
                          tranMon m = case m of
                            "Jan" -> "A"
                            "Feb" -> "B"
                            "Mar" -> "C"
                            "Apr" -> "D"
                            "May" -> "E"
                            "Jun" -> "F"
                            "Jul" -> "G"
                            "Aug" -> "H"
                            "Sep" -> "I"
                            "Oct" -> "J"
                            "Nov" -> "K"
                            "Dec" -> "L"
                            _     -> " "