packages feed

movie-monad-0.0.2.0: src/VideoInfo.hs

{-
  Movie Monad
  (C) 2017 David lettier
  lettier.com
-}

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module VideoInfo where

import System.Exit
import Text.Read
import Data.Maybe
import Data.Text
import Data.IORef

import qualified Records as R
import Uri
import Utils

getVideoInfoRaw :: Prelude.String -> IO (Maybe Prelude.String)
getVideoInfoRaw uri = do
  (code, out, _) <- safeRunProcessGetOutput "gst-discoverer-1.0" [uri, "-v"]
  if code == System.Exit.ExitSuccess
    then return (Just out)
    else return Nothing

getVideoInfo :: IORef R.VideoInfo -> Prelude.String -> IO R.VideoInfo
getVideoInfo videoInfoRef filePathName = do
  videoInfoGathered <- readIORef videoInfoRef
  uri <- addUriSchemeIfNone filePathName
  cacheDo (R.uri videoInfoGathered == uri) videoInfoGathered uri
  where
    widthField :: Data.Text.Text
    widthField = "width: "
    heightField :: Data.Text.Text
    heightField = "height: "
    seekableField :: Data.Text.Text
    seekableField = "seekable: "
    cacheDo :: Bool -> R.VideoInfo -> Prelude.String -> IO R.VideoInfo
    cacheDo True  videoInfoGathered _   = return videoInfoGathered
    cacheDo False _                 uri = do
      videoInfoRaw <- getVideoInfoRaw uri
      processVideoInfoRaw videoInfoRaw uri
    processVideoInfoRaw :: Maybe Prelude.String -> Prelude.String -> IO R.VideoInfo
    processVideoInfoRaw Nothing _ = do
      let videoInfoGathered = R.defaultVideoInfo
      atomicWriteIORef videoInfoRef videoInfoGathered
      return videoInfoGathered
    processVideoInfoRaw (Just str) uri = do
      let text      = Data.Text.toLower $ Data.Text.pack str
      let textLines = Data.Text.lines text
      let videoInfoGathered = R.VideoInfo {
              R.uri          = uri
            , R.isLocalFile  = hasFileUriScheme uri
            , R.isVideo      = "video: video/" `Data.Text.isInfixOf` text
            , R.isSeekable   = "yes" == getField seekableField textLines
            , R.videoWidth   = getDimension R.videoWidth  widthField textLines
            , R.videoHeight  = getDimension R.videoHeight heightField textLines
          }
      atomicWriteIORef videoInfoRef videoInfoGathered
      return videoInfoGathered
    getDimension :: (R.VideoInfo -> Int) -> Data.Text.Text -> [Data.Text.Text] -> Int
    getDimension f field lines' = fromMaybe (
        f R.defaultVideoInfo
      ) (readMaybe (Data.Text.unpack $ getField field lines') :: Maybe Int)
    getField :: Data.Text.Text -> [Data.Text.Text] -> Data.Text.Text
    getField field =
      Prelude.foldl (\ acc l ->
          if not $ Data.Text.null acc
            then acc
            else if field `Data.Text.isInfixOf` l
              then Data.Text.replace field "" $ Data.Text.strip l
              else ""
        ) ""