packages feed

cut-the-crap-2.2.0: src/Cut/CutVideo.hs

{-# OPTIONS_GHC -Wno-type-defaults #-}

-- | Extract sounded parts, and combine again
module Cut.CutVideo
  ( extract
  , extractDir
  , Interval(..)
  , Silent
  , Sound
  , combine
  , combineOutput
  , combineDir
  )
where

import           Control.Lens
import           Control.Monad
import           Control.Monad.Catch
import           Cut.Analyze
import           Cut.Shell
import           Cut.Options
import           Data.Foldable
import           Data.Text           (Text)
import qualified Data.Text           as Text
import           Data.Text.Lens
import           Shelly              hiding (FilePath, shelly)
import           Text.Printf         (printf)

-- | convert a sounded interval into a filename where we write the temporary extracted file in
toFileName :: ListenCutOptions -> FilePath -> Interval Sound -> FilePath
toFileName options tmp inter = tmp
         </> getOutFileName options
         <> "-"
         <> fname
         <> ".mkv"
  where
      fname    = printf "%010d" (truncate $ interval_start inter * 100 :: Integer)

toArgs :: ListenCutOptions -> FilePath -> Interval Sound -> (Interval Sound, [Text])
toArgs options tmp inter =
  ( inter
  , -- keep ter interval for debugging
    ["-y", "-ss", start, "-t", duration, "-i", options ^. lc_fileio . in_file . packed]
    <> specifyTracks options
    <> [ Text.pack $ toFileName options tmp inter
       ]
  )
 where
  start    = floatToText $ interval_start inter
  duration = floatToText $ interval_duration inter

extractDir :: FilePath
extractDir = "/extract"

extract :: ListenCutOptions -> FilePath -> [Interval Sound] -> IO ()
extract options tempDir intervals = do
  shelly $ mkdir_p exdir
  traverse_
      (\(inter, args) -> void $ catch (shelly $ ffmpeg' args) $ \exec -> do
        liftIO
          (print ("expection during edit: ", exec :: SomeException, args, inter)
          )
        pure ["expection"]
      )
    $   toArgs options exdir <$> intervals
  liftIO $ putStrLn "finish extracting"

  where
    exdir = tempDir <> extractDir

combineOutput :: FilePath
combineOutput = "combined-output.mkv"

combine :: FilePath -> Sh ()
combine tempDir = do
  output' <- ffmpeg' args
  liftIO $ print ("output", output')
 where -- https://stackoverflow.com/questions/7333232/how-to-concatenate-two-mp4-files-using-ffmpeg
  args =
    [ "-y"
    , "-f"
    , "concat"
    , "-safe"
    , "0"
    , "-i"
    , Text.pack (tempDir <> "/input.txt")
    , "-c"
    , "copy"
    , Text.pack $ tempDir <> "/" <> combineOutput
    ]

combineDir :: ListenCutOptions -> FilePath -> [Interval Sound] -> Sh ()
combineDir options tempDir intervals = do
  let paths = Text.unlines $ flip (<>) "'" . ("file '" <>) <$> res
  writefile (fromText $ Text.pack $ tempDir <> "/input.txt") paths
  combine tempDir
  where
    res = Text.pack . toFileName options exdir <$> intervals
    exdir = tempDir <> extractDir