vimeta-0.3.0.0: src/Vimeta/Core/Download.hs
-- |
--
-- 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
--
-- Utility functions for downloading files.
module Vimeta.Core.Download
( withArtwork,
withDownload,
)
where
import qualified Data.ByteString.Lazy as LByteString
import qualified Data.Text as Text
import qualified Network.HTTP.Client as HC
import System.FilePath
import System.IO (hFlush)
import System.IO.Temp (withSystemTempFile)
import Vimeta.Core.Config
import Vimeta.Core.Vimeta
-- | Try to download artwork and run the given function. The
-- function will be passed a 'FilePath' if the artwork was downloaded.
--
-- See the 'withDownload' function for more details.
withArtwork ::
(MonadIO m) =>
[Text] ->
(Maybe FilePath -> Vimeta IO a) ->
Vimeta m a
withArtwork urls = withDownload (listToMaybe $ candidates urls)
where
candidates :: [Text] -> [Text]
candidates = filter checkExtension . reverse
checkExtension :: Text -> Bool
checkExtension = goodExtension . takeExtension . toString . Text.toLower
goodExtension :: String -> Bool
goodExtension ext = ext == ".jpg" || ext == ".png"
-- | Download the given URL to a temporary file and pass the file
-- name to the given function.
--
-- The reason a function needs to be passed to 'withDownload' is the
-- result of using 'withSystemTempFile' to store the downloaded file.
-- The file will be automatically removed after the given function
-- completes.
withDownload ::
(MonadIO m) =>
-- | URL.
Maybe Text ->
-- | Function to call and pass the file name to.
(Maybe FilePath -> Vimeta IO a) ->
-- | Result of above function.
Vimeta m a
withDownload Nothing f = do
verbose "no URL to download"
runIOE $ runVimeta (f Nothing)
withDownload url f = do
context <- ask
let dryRun = configDryRun $ ctxConfig context
manager = ctxManager context
case (dryRun, url) of
(True, Nothing) ->
verbose "dry-run: nothing to download"
>> runWithoutTempFile f
(False, Nothing) ->
verbose "nothing to download"
>> runWithoutTempFile f
(True, Just u) ->
verbose ("dry-run:" <> u)
>> runWithoutTempFile f
(False, Just u) ->
verbose u
>> runWithTempFile u manager f
-- | Helper function to run the download action with a temporary file.
runWithTempFile ::
(MonadIO m) =>
Text ->
HC.Manager ->
(Maybe FilePath -> Vimeta IO a) ->
Vimeta m a
runWithTempFile url manager vio = do
context <- ask
runIOE $
withSystemTempFile "vimeta" $ \name h -> do
downloadToHandle manager (toString url) h
execVimetaWithContext context $ vio (Just name)
-- | Helper function to run an action without needing a temporary file.
runWithoutTempFile ::
(MonadIO m) =>
(Maybe FilePath -> Vimeta IO a) ->
Vimeta m a
runWithoutTempFile vio = do
context <- ask
runIOE $ execVimetaWithContext context $ vio Nothing
-- | Helper function to the actual HTTP downloading into a file handle.
downloadToHandle :: HC.Manager -> String -> Handle -> IO ()
downloadToHandle manager url handle = do
request <- HC.parseRequest url
response <- HC.httpLbs request manager
LByteString.hPut handle (HC.responseBody response)
hFlush handle