-- | -- -- Copyright: -- This file is part of the package vimeta. It is subject to the -- license terms in the LICENSE file found in the top-level -- directory of this distribution and at: -- -- https://github.com/pjones/vimeta -- -- No part of this package, including this file, may be copied, -- modified, propagated, or distributed except according to the terms -- contained in the LICENSE file. -- -- License: BSD-2-Clause -- -- The configuration file. module Vimeta.Core.Config ( Config (..), defaultConfig, configFileName, readConfig, writeConfig, ) where import Control.Monad.Except import Data.Aeson hiding (encodeFile) import Data.Aeson.Types (typeMismatch) import Data.Yaml (decodeFileEither, encodeFile) import Network.API.TheMovieDB (Key) import System.Directory ( XdgDirectory (XdgConfig), createDirectoryIfMissing, doesFileExist, getXdgDirectory, ) import System.FilePath (takeDirectory, ()) import Vimeta.Core.Tagger -- | Vimeta configuration. data Config = Config { configTMDBKey :: Key, configFormatMovie :: Text, configFormatTV :: Text, configVerbose :: Bool, configDryRun :: Bool } instance FromJSON Config where parseJSON (Object v) = Config <$> v .: "tmdb_key" <*> v .: "cmd_movie" <*> v .: "cmd_tv" <*> v .:? "verbose" .!= False <*> v .:? "dryrun" .!= False parseJSON x = typeMismatch "configuration" x instance ToJSON Config where toJSON c = object [ "tmdb_key" .= configTMDBKey c, "cmd_movie" .= configFormatMovie c, "cmd_tv" .= configFormatTV c ] defaultConfig :: Tagger -> Config defaultConfig tagger = Config { configTMDBKey = "your API key goes here", configFormatMovie = fmtMovie, configFormatTV = fmtTV, configVerbose = False, configDryRun = False } where (fmtMovie, fmtTV) = formatStringsForTagger tagger -- | Get the name of the configuration file. configFileName :: IO FilePath configFileName = getXdgDirectory XdgConfig "vimeta" <&> ( "config.yml") -- | Read the configuration file and return a 'Config' value or an error. readConfig :: (MonadIO m) => ExceptT String m Config readConfig = do filename <- liftIO configFileName exists <- liftIO (doesFileExist filename) if exists then decodeConfig filename else throwError $ missingFile filename where decodeConfig :: (MonadIO m) => FilePath -> ExceptT String m Config decodeConfig fn = do result <- liftIO $ decodeFileEither fn case result of Left e -> throwError (show e) Right a -> return a missingFile :: FilePath -> String missingFile fn = "no config file found, use the `config' command " ++ "to create " ++ fn writeConfig :: (MonadIO m) => Config -> ExceptT String m FilePath writeConfig c = do (filename, exists) <- liftIO $ do fn <- configFileName ex <- doesFileExist fn return (fn, ex) when exists $ throwError (existError filename) liftIO (createDirectoryIfMissing True (takeDirectory filename)) liftIO (encodeFile filename c) return filename where existError :: FilePath -> String existError fn = "please remove the existing config file first: " ++ fn