----------------------------------------------------------------------------- -- -- Module : Network.Google.Books -- Copyright : (c) 2012-13 Brian W Bush -- License : MIT -- -- Maintainer : Brian W Bush -- Stability : Stable -- Portability : Portable -- -- | Functions for the Google Books API, see . -- ----------------------------------------------------------------------------- module Network.Google.Books ( -- * Types ShelfId -- * Functions , listBooks , listBookshelves ) where import Control.Monad (liftM) import Data.Maybe (fromMaybe) import Network.Google (AccessToken, appendQuery, doRequest, makeRequest) import Network.HTTP.Conduit (Request) import Text.JSON (JSObject, JSValue(..), Result(Ok), decode, fromJSObject, toJSObject, valFromObj) -- | The host for API access. booksHost :: String booksHost = "www.googleapis.com" -- | The API version used here. booksApi :: (String, String) booksApi = ("Gdata-version", "2") -- | Bookshelf ID. type ShelfId = String -- | List the bookshelves, see . listBookshelves :: AccessToken -- ^ The OAuth 2.0 access token. -> IO JSValue -- ^ The action returning the bookshelves' metadata in JSON format. listBookshelves accessToken = doRequest $ booksRequest accessToken Nothing 0 -- | List the bookshelf IDs, see . listBookshelfIds :: AccessToken -- ^ The OAuth 2.0 access token. -> IO [String] -- ^ The action returning list of bookshelf IDs. listBookshelfIds accessToken = do JSObject result <- listBookshelves accessToken let extractId :: JSValue -> String extractId (JSObject x) = let y :: Rational Ok (JSRational _ y) = valFromObj "id" x in show (round y :: Int) items :: [JSValue] Ok (JSArray items) = valFromObj "items" result return $ map extractId items -- | List the books, see . listBooks :: AccessToken -- ^ The OAuth 2.0 access token. -> [ShelfId] -- ^ The bookshelf IDs. -> IO JSValue -- ^ The action returning the books' metadata in JSON format. listBooks accessToken shelves = do shelves' <- if null shelves then listBookshelfIds accessToken else return shelves results <- mapM (listShelfBooks accessToken) shelves' return $ JSArray results -- | List the books in a shelf, see . listShelfBooks :: AccessToken -- ^ The OAuth 2.0 access token. -> ShelfId -- ^ The bookshelf ID. -> IO JSValue -- ^ The action returning the books' metadata in JSON format. listShelfBooks accessToken shelf = do x <- listShelfBooks' accessToken shelf Nothing let y :: [JSValue] y = concatMap items x JSObject o = head x z :: [(String, JSValue)] z = fromJSObject o u :: [(String, JSValue)] u = filter (\w -> fst w /= "items") z v :: [(String, JSValue)] v = ("items", JSArray y) : u return $ JSObject $ toJSObject v -- | List the books in a shelf, see . listShelfBooks' :: AccessToken -- ^ The OAuth 2.0 access token. -> ShelfId -- ^ The bookshelf ID. -> Maybe Int -- ^ The start index in the list of metadata. -> IO [JSValue] -- ^ The action returning the books' metadata in JSON format. listShelfBooks' accessToken shelf startIndex = do let startIndex' :: Int startIndex' = fromMaybe 0 startIndex books <- doRequest $ booksRequest accessToken (Just shelf) startIndex' let startIndex'' = startIndex' + length (items books) liftM (books :) $ if startIndex' + 1 <= totalItems books then listShelfBooks' accessToken shelf $ Just startIndex'' else return [] -- | Find the total number of items in a shelf. totalItems :: JSValue -- ^ The books' metadata. -> Int -- ^ The total number of books in the shelf. totalItems (JSObject books) = let Ok count = "totalItems" `valFromObj` books in count -- | Find the items in a list of books' metadata. items :: JSValue -- ^ The books' metadata -> [JSValue] -- ^ The books in the metadata. items (JSObject books) = let list = "items" `valFromObj` books f (Ok x) = x f _ = [] in f list -- | Make an HTTP request for Google Books. booksRequest :: AccessToken -- ^ The OAuth 2.0 access token. -> Maybe ShelfId -- ^ The bookshelf ID. -> Int -- ^ The starting index -> Request m -- ^ The request. booksRequest accessToken shelf startIndex = appendQuery [ ("maxResults", "40") , ("startIndex", show startIndex) ] $ makeRequest accessToken booksApi "GET" ( booksHost , "/books/v1/mylibrary/bookshelves" ++ maybe "" (\x -> "/" ++ x ++ "/volumes") shelf )