cut-the-crap-1.4.0: src/Cut/Options.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
module Cut.Options
( ProgramOptions
, FileIO
, ListenCutOptions
, parseProgram
, lc_fileio
, in_file
, out_file
, seg_size
, silent_treshold
, detect_margin
, voice_track
, music_track
, silent_duration
, cut_noise
, work_dir
, simpleOptions
, voice_track_map
, specifyTracks
, getOutFileName
, gnerate_sub_prism
, listen_cut_prism
)
where
import Control.Lens
import Data.Generics.Product.Fields
import Data.Generics.Sum
import qualified Data.Text as Text
import Data.Text.Lens
import GHC.Generics hiding (to)
import Options.Applicative
simpleFileIO :: FileIO
simpleFileIO = FileIO { fi_inFile = "in.mkv" , fi_outFile = "out.mkv"
, fi_workDir = Nothing
}
in_file :: Lens' FileIO FilePath
in_file = field @"fi_inFile"
out_file :: Lens' FileIO FilePath
out_file = field @"fi_outFile"
work_dir :: Lens' FileIO (Maybe FilePath)
work_dir = field @"fi_workDir"
simpleOptions :: ListenCutOptions
simpleOptions = ListenCutOptions
{ lc_fileIO = simpleFileIO
, lc_segmentSize = _Just # def_seg_size
, lc_silentTreshold = _Just # def_silent
, lc_detectMargin = _Just # def_margin
, lc_voiceTrack = _Just # 2
, lc_musicTrack = Nothing
, lc_silentDuration = _Just # def_duration
, lc_cutNoise = def_cut_noise
}
getOutFileName :: ListenCutOptions -> FilePath
getOutFileName = reverse . takeWhile ('/' /=) . reverse . view (lc_fileio . out_file)
-- | Deals with having an input file and a target output file
data FileIO = FileIO
{ fi_inFile :: FilePath
, fi_outFile :: FilePath
, fi_workDir :: Maybe FilePath -- ^ for consistency (or debugging) we may want to specify this.
}
deriving (Show, Generic)
-- | Cut out by listening to sound options
data ListenCutOptions = ListenCutOptions
{ lc_fileIO :: FileIO
, lc_segmentSize :: Maybe Int
, lc_silentTreshold :: Maybe Double
, lc_silentDuration :: Maybe Double
, lc_detectMargin :: Maybe Double
, lc_voiceTrack :: Maybe Int
, lc_musicTrack :: Maybe Int
, lc_cutNoise :: Bool
}
deriving (Show, Generic)
data ProgramOptions = ListenCut ListenCutOptions
| GenerateSubtitles FileIO
deriving (Show, Generic)
listen_cut_prism :: Prism' ProgramOptions ListenCutOptions
listen_cut_prism = _Ctor @"ListenCut"
gnerate_sub_prism :: Prism' ProgramOptions FileIO
gnerate_sub_prism = _Ctor @"GenerateSubtitles"
def_seg_size :: Int
def_seg_size = 20
def_margin :: Double
def_margin = 0.05
def_cut_noise :: Bool
def_cut_noise = False
def_silent :: Double
def_silent = 0.0001
def_duration :: Double
def_duration = 0.25
def_voice :: Int
def_voice = 1
lc_fileio :: Lens' ListenCutOptions FileIO
lc_fileio = field @"lc_fileIO"
seg_size :: Lens' ListenCutOptions Int
seg_size = field @"lc_segmentSize" . non def_seg_size
detect_margin :: Lens' ListenCutOptions Double
detect_margin = field @"lc_detectMargin" . non def_margin
silent_treshold :: Lens' ListenCutOptions Double
silent_treshold = field @"lc_silentTreshold" . non def_silent
silent_duration :: Lens' ListenCutOptions Double
silent_duration = field @"lc_silentDuration" . non def_duration
voice_track :: Lens' ListenCutOptions Int
voice_track = field @"lc_voiceTrack" . non def_voice
music_track :: Lens' ListenCutOptions (Maybe Int)
music_track = field @"lc_musicTrack"
cut_noise :: Lens' ListenCutOptions Bool
cut_noise = field @"lc_cutNoise"
voice_track_map :: ListenCutOptions -> Text.Text
voice_track_map = mappend "0:" . view (voice_track . to show . packed)
specifyTracks :: ListenCutOptions -> [Text.Text]
specifyTracks options =
[ "-map"
, "0:0"
, "-map" -- then copy only the voice track
, voice_track_map options
]
parseFile :: Parser FileIO
parseFile = FileIO
<$> option str (long "inFile" <> help "The input video")
<*> option str (long "outFile" <> help "The output name without format")
<*> optional
(option
str
( long "workDir"
<> help
"If specified will use this as temporary directory to store intermeidate files in, good for debugging. Needs to be absolute"
)
)
parseProgram :: Parser ProgramOptions
parseProgram =
subparser $
command "listen" (info (ListenCut <$> parseSound) $ progDesc "Cut out by listening to sound options. We listen for silences and cut out the parts that are silenced.")
<>
command "subtitles" (info (GenerateSubtitles <$> parseFile) $ progDesc "Generate subtiles for a video. This is an intermediate (but usefull) feature developed for recognizing human speech vs background noise.")
parseSound :: Parser ListenCutOptions
parseSound = ListenCutOptions
<$> parseFile
<*> optional
(option
auto
(long "segmentSize" <> help "The size of video segments in minutes")
)
<*> optional
(option
auto
( long "silentTreshold"
<> help
"The treshold for determining intersting sections, closer to zero is detects more audio (n: https://ffmpeg.org/ffmpeg-filters.html#silencedetect)"
)
)
<*> optional
(option
auto
( long "silentDuration"
<> help
"The duration before soemthing can be considered a silence (d: https://ffmpeg.org/ffmpeg-filters.html#silencedetect)"
)
)
<*> optional
(option
auto
(long "detectMargin" <> help "Margin seconds around detection")
)
<*> optional
(option
auto
(long "voiceTrack" <> help "The track to detect the silences upon")
)
<*> optional
(option auto (long "musicTrack" <> help "The track to integrate"))
<*> switch
(long "cutNoise" <> help "Whether to cut noise instead of silence")