h-booru-0.3.0.0: src/Main.hs
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DataKinds #-}
module Main where
import Control.Applicative ((<$>))
import Control.Concurrent (forkIO)
import Control.Concurrent.STM
import Control.Monad (void, filterM)
import Data.Map
import Data.Monoid
import Data.Vinyl (rGet)
import HBooru.Network
import HBooru.Parsers.Gelbooru
import HBooru.Parsers.Ichijou
import HBooru.Parsers.Konachan
import HBooru.Parsers.Safebooru
import HBooru.Parsers.Yandere
import HBooru.Types
import System.Directory
import System.Environment (getArgs)
import System.Exit
import System.FilePath
main ∷ IO ()
main = getArgs >>= \case
[] → putStr help
"-d":d:ts → downloadTo d ts
xs → fetchImageLinks xs >>= \x → mapM_ putStrLn [ y | Right y ← x ]
-- | Downloads all the images with the given tag to the given
-- directory.
downloadTo ∷ FilePath → [Tag] → IO ()
downloadTo fp xs = doesDirectoryExist fp >>= \case
False → print (fp <> " doesn't exist.") >> exitFailure
True → do
let f p = run <$> fetchAllTaggedPosts p XML xs
where
run s =
fromList [ (md5 `rGet` r, file_url `rGet` r) | Right r ← s ]
g ← f Gelbooru
i ← f Ichijou
k ← f Konachan
s ← f Safebooru
y ← f Yandere
let ls = g <> i <> k <> s <> y
mkFp (m, u) = let e = snd $ splitExtension u
in fp </> m <.> e
dcs ← Prelude.map (fp </>) <$> getDirectoryContents fp
let notInFiles = (`notElem` dcs) . snd
fs = Prelude.filter notInFiles [ (snd x, mkFp x) | x ← assocs ls ]
lfs = show $ length fs
ds ← atomically newTChan
got ← newTVarIO 0
let loop = atomically (readTChan ds) >>= \case
EndOfQueue → putStrLn "Done."
x → do
v ← atomically $ modifyTVar got succ >> readTVar got
putStrLn (concat ["(", show v, "/", lfs, "): ", show x]) >> loop
void . forkIO $ downloadFiles fs ds 5
loop
-- | Fetches a map of images, with keys being the md5 and values being
-- URLs.
fetchImageLinks ∷ [Tag] → IO [Parse String]
fetchImageLinks xs = do
let f p = Prelude.map getInfo <$> fetchAllTaggedPosts p XML xs
where
getInfo (Left (PF m)) = Left . PF $ unwords [show p, m]
getInfo (Right r) = return $ file_url `rGet` r
g ← f Gelbooru
i ← f Ichijou
k ← f Konachan
s ← f Safebooru
y ← f Yandere
let ls = g <> i <> k <> s <> y
return $ length ls `seq` ls
help ∷ String
help = unlines $
[ "Usage: h-booru tag1 [tag2] … [tagN]"
, ""
, "Prints a list of links matching the tags"
, ""
, "h-booru -d DIRECTORY tag1 [tag2] … [tagN]"
, ""
, "Downloads the files with the given tags to the given directory."
, "Naming scheme is md5.originalextension"
, "The dowloader will skip files it already sees downloaded, by filename."
]