packages feed

arxiv-client-0.1.0.0: src/Arxiv/Download.hs

-- | Convenient functions for downloading arXiv papers.
module Arxiv.Download where

import Arxiv.Entry
import Control.Monad
import Network.HTTP.Req
import Text.URI (mkURI)
import qualified Data.Text as T
import qualified Data.ByteString.Lazy as BL
import System.Directory (doesFileExist)

downloadPdf :: ArxivEntry -> IO BL.ByteString
downloadPdf entry = runReq defaultHttpConfig $ do
  let url = pdfUrl entry
  uri <- mkURI url
  case useURI uri of
    Just (Left (httpUrl, options)) -> do
      response <- req GET httpUrl NoReqBody lbsResponse options
      return (responseBody response)
    Just (Right (httpsUrl, options)) -> do
      response <- req GET httpsUrl NoReqBody lbsResponse options
      return (responseBody response)
    Nothing -> error $ "Invalid URL: " ++ T.unpack url

-- | Usage:
-- @defaultFileName ".pdf" entry@
defaultFileName :: String -> ArxivEntry -> FilePath
defaultFileName suffix entry = toValidFileName (T.unpack (title entry)) ++ "-" ++ T.unpack (arxivId entry) ++ suffix

toValidFileName :: String -> String
toValidFileName = concatMap replaceInvalid
  where
    replaceInvalid c
      | c `elem` ['a'..'z'] || c `elem` ['A'..'Z'] || c `elem` ['0'..'9'] = [c]
      | c `elem` " ._-" = [c]
      | otherwise = "_"

-- | Detect if the file is already exists before downloading.
downloadPdfToFile :: ArxivEntry -> FilePath -> IO ()
downloadPdfToFile entry filePath = do
  fileExists <- doesFileExist filePath
  unless fileExists $ do
      pdfData <- downloadPdf entry
      BL.writeFile filePath pdfData

downloadSource :: ArxivEntry -> IO BL.ByteString
downloadSource entry = runReq defaultHttpConfig $ do
  let url = sourceUrl entry
  uri <- mkURI url
  case useURI uri of
    Just (Left (httpUrl, options)) -> do
      response <- req GET httpUrl NoReqBody lbsResponse options
      return (responseBody response)
    Just (Right (httpsUrl, options)) -> do
      response <- req GET httpsUrl NoReqBody lbsResponse options
      return (responseBody response)
    Nothing -> error $ "Invalid URL: " ++ T.unpack url

downloadSourceToFile :: ArxivEntry -> FilePath -> IO ()
downloadSourceToFile entry filePath = do
  fileExists <- doesFileExist filePath
  unless fileExists $ do
      srcData <- downloadSource entry
      BL.writeFile filePath srcData