{-# LANGUAGE DataKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} -- | Deal with downloading and the cli options involved module Cut.Download ( downloadIfNeccisary , downloadCutifNeccisary ) where import Control.Lens import Control.Monad import Control.Monad.Catch import Control.Monad.IO.Class import Cut.Options import Cut.Shell import Data.Foldable (traverse_) import Data.Word import Network.URI (URI) import Options.Applicative import Shelly hiding (FilePath) import System.Random -- | Downloads a URI to the filepath returned runYoutubeDL :: FileIO a -> URI -> IO FilePath runYoutubeDL opts x = do -- we need to make our own because youtube-dl doesn't write to existing files -- System.IO.Temp would've worked neatly here. inputNumbers :: Word32 <- randomIO let inputChars :: String -- youtube-dl doesn't do .mkv (not supported) inputChars = show inputNumbers filePath :: String filePath = maybe inputChars (flip () inputChars) $ opts ^. work_dir void $ shelly $ youtube_dl x filePath pure (filePath <> ".mkv") -- because 'youtube_dl' sets merge-output-format aquireFilePath :: FileIO InputSource -> IO (FileIO FilePath) aquireFilePath x = do result <- sequence $ (runYoutube <|> alreadyLocal) case result of Nothing -> error $ "Couldn't find " <> show x Just y -> pure $ x & in_file .~ y where runYoutube :: Maybe (IO FilePath) runYoutube = x ^? in_file . input_src_remote . to (runYoutubeDL x) alreadyLocal :: Maybe (IO FilePath) alreadyLocal = preview (in_file . input_src_local_file . to pure) x removeDownloaded :: FileIO InputSource -> FileIO FilePath -> IO () removeDownloaded cliInput aquiredPath = traverse_ (const $ -- only do this if we got it from remote (we did the download) traverse_ (shelly . rm) $ aquiredPath ^? in_file ) $ cliInput ^? in_file . input_src_remote -- | 'FileIO' can have a remote, if so we download that and pass the downloaded -- path to the continuation, if not we simply pass the input path to -- the continuation. -- We need a continuation to clean up the downloaded file. downloadIfNeccisary :: MonadMask m => MonadIO m => FileIO InputSource -> (FileIO FilePath -> m a) -> m a downloadIfNeccisary x = bracket (liftIO $ aquireFilePath x) (liftIO . removeDownloaded x) -- | this does the same as 'downloadIfNeccisary' but makes it work for -- 'ListenCutOptionsT' with some type weaving downloadCutifNeccisary :: MonadMask m => MonadIO m => ListenCutOptionsT InputSource -> ((ListenCutOptionsT FilePath) -> m a) -> m a downloadCutifNeccisary cut fun = downloadIfNeccisary (cut ^. lc_fileio) $ fun . (\y -> lc_fileio .~ y $ cut)