myanimelist-export 0.2.0.0 → 0.3.0.0
raw patch · 5 files changed
+57/−39 lines, 5 filesdep ~aesondep ~containersdep ~http-clientPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aeson, containers, http-client, http-client-tls
API changes (from Hackage documentation)
- MyAnimeList.Export: exportLists :: (Functor f, Foldable f) => Text -> Text -> Manager -> f MediaType -> IO (f URI)
+ MyAnimeList.Export: exportLists :: (Functor f, Foldable f) => Text -> Text -> Manager -> f MediaType -> IO (CookieJar, f URI)
Files
- ChangeLog.md +7/−0
- app/Main.hs +14/−13
- myanimelist-export.cabal +22/−16
- src/MemoizedTraverse.hs +2/−2
- src/MyAnimeList/Export.hs +12/−8
ChangeLog.md view
@@ -1,3 +1,10 @@+## 0.3.0.0++* Now supports http-client version >= 0.4.30 and+ http-client-tls version >= 0.2.4+* Work around MyAnimeList update: `exportLists` now also returns the CookieJar+ which is required in order to access the download URL(s)+ ## 0.2.0.0 * Clearer error messages on crash
app/Main.hs view
@@ -1,4 +1,4 @@--- Copyright (C) 2017 Matthew Harm Bekkema+-- Copyright (C) 2017-2018 Matthew Harm Bekkema -- -- This file is part of myanimelist-export. --@@ -43,12 +43,11 @@ import System.Directory (XdgDirectory(XdgConfig), getXdgDirectory) -import Network.URI (URI)-import Network.HTTP.Client (BodyReader, Manager, brRead,- defaultRequest, withResponse,- responseBody)-import Network.HTTP.Client.TLS (newTlsManager)-import Network.HTTP.Client.Internal (setUri)+import Network.URI (URI, uriToString)+import Network.HTTP.Client (Manager, BodyReader, CookieJar,+ withResponse, parseRequest,+ responseBody, brRead, cookieJar)+import Network.HTTP.Client.TLS (getGlobalManager) import MyAnimeList.Export @@ -66,20 +65,22 @@ main = do configPath <- getXdgDirectory XdgConfig "myanimelist-export.yaml" Config {..} <- either throwIO pure =<< decodeFileEither configPath- manager <- newTlsManager+ manager <- getGlobalManager putStrLn "exporting" let wanted = mapMaybe sequence [ (Anime, animeXmlPath) , (Manga, mangaXmlPath) ]- Compose uris <- exportLists username password manager $ Compose $+ (cj, Compose uris) <- exportLists username password manager $ Compose $ fmap (\x -> (x, fst x)) wanted forM_ uris $ \((mt, fp), uri) -> do putStrLn $ "downloading " ++ mediaTypeString mt ++ " list"- downloadList manager uri fp+ downloadList manager cj uri fp -downloadList :: Manager -> URI -> FilePath -> IO ()-downloadList manager uri fp = do- request <- setUri defaultRequest uri+downloadList :: Manager -> CookieJar -> URI -> FilePath -> IO ()+downloadList manager cj uri fp = do+ request <- fmap (\x -> x { cookieJar = Just cj }) $+ parseRequest $+ uriToString id uri "" withResponse request manager $ \res -> runConduitRes $ sourceBodyReader (responseBody res) .| ungzip
myanimelist-export.cabal view
@@ -1,5 +1,5 @@ name: myanimelist-export-version: 0.2.0.0+version: 0.3.0.0 synopsis: Export from MyAnimeList description: Export anime or manga lists from MyAnimeList in XML format. Uses the web@@ -11,30 +11,33 @@ license-file: LICENSE author: Matthew Harm Bekkema maintainer: mbekkema97@gmail.com-copyright: 2017 Matthew Harm Bekkema+copyright: 2017-2018 Matthew Harm Bekkema category: Web build-type: Simple extra-source-files: README.md , ChangeLog.md cabal-version: >=1.10-tested-with: GHC >= 8.0.0 && <= 8.2.2+tested-with: GHC == 8.0.2+ , GHC == 8.2.2+ , GHC == 8.4.3 library hs-source-dirs: src exposed-modules: MyAnimeList.Export other-modules: MemoizedTraverse ghc-options: -Wall- build-depends: base >= 4.9 && < 4.11- , async >= 2.1 && < 2.2- , bytestring >= 0.10 && < 0.11- , conduit >= 1.2 && < 1.3- , containers >= 0.5 && < 0.6- , exceptions >= 0.4 && < 0.9- , http-client >= 0.5 && < 0.6- , network-uri >= 2.6 && < 2.7- , tagstream-conduit >= 0.5 && < 0.6- , text >= 1.2 && < 1.3+ build-depends: base >= 4.9 && < 4.12+ , async >= 2.1 && < 2.3+ , bytestring >= 0.10 && < 0.11+ , conduit >= 1.2 && < 1.4+ , containers >= 0.5 && < 0.7+ , exceptions >= 0.4 && < 0.11+ , http-client >= 0.4.30 && < 0.6+ , network-uri >= 2.6 && < 2.7+ , tagstream-conduit >= 0.5 && < 0.6+ , text >= 1.2 && < 1.3 default-language: Haskell2010+ other-extensions: OverloadedStrings executable myanimelist-export hs-source-dirs: app@@ -48,12 +51,15 @@ , network-uri , text - , aeson >= 0.7 && < 1.2- , conduit-extra >= 1.1 && < 1.2+ , aeson >= 0.7 && < 1.5+ , conduit-extra >= 1.1 && < 1.4 , directory >= 1.2.3 && < 1.4- , http-client-tls >= 0.3.4 && < 0.4+ , http-client-tls >= 0.2.4 && < 0.4 , yaml >= 0.8.4 && < 0.9 default-language: Haskell2010+ other-extensions: TemplateHaskell+ OverloadedStrings+ RecordWildCards source-repository head type: git
src/MemoizedTraverse.hs view
@@ -1,4 +1,4 @@--- Copyright (C) 2017 Matthew Harm Bekkema+-- Copyright (C) 2017-2018 Matthew Harm Bekkema -- -- This file is part of myanimelist-export. --@@ -30,7 +30,7 @@ memoizedTraverse f xs = vals <&> \vals' -> lookupErr "myanimelist-export:memoizedTraverse: lookup error" vals' <$> xs where- keys = foldl' (flip (flip M.insert ())) M.empty xs+ keys = foldl' (\acc x -> M.insert x () acc) M.empty xs vals = M.traverseWithKey (\k () -> f k) keys lookupErr :: Ord a => String -> Map a b -> a -> b
src/MyAnimeList/Export.hs view
@@ -1,4 +1,4 @@--- Copyright (C) 2017 Matthew Harm Bekkema+-- Copyright (C) 2017-2018 Matthew Harm Bekkema -- -- This file is part of myanimelist-export. --@@ -24,7 +24,6 @@ -- Stability : experimental ----------------------------------------------------------------------------- -{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE OverloadedStrings #-} module MyAnimeList.Export@@ -58,7 +57,10 @@ import Network.URI (URI, parseURIReference, uriPath, relativeTo)-import Network.HTTP.Client+import Network.HTTP.Client (Manager, Request, BodyReader, CookieJar,+ withResponse, parseRequest_,+ urlEncodedBody, getUri, path, cookieJar,+ responseBody, responseCookieJar, brRead) import MemoizedTraverse (memoizedTraverse) @@ -77,7 +79,7 @@ malHomePage :: Request-malHomePage = "https://myanimelist.net/"+malHomePage = parseRequest_ "https://myanimelist.net/" malLoginPage :: Request malLoginPage = malHomePage { path = "/login.php" }@@ -100,18 +102,20 @@ ((_, e):_) -> Just e --- | Export list(s) and return URL(s) to gzipped XML+-- | Export list(s) and return URL(s) to gzipped XML and a CookieJar which must+-- be used in order to access them. exportLists :: (Functor f, Foldable f) => Text -- ^ Username -> Text -- ^ Password -> Manager -- ^ Manager (must support TLS) -> f MediaType -- ^ Which list(s) to export- -> IO (f URI)+ -> IO (CookieJar, f URI) exportLists username password manager mediaTypes = do (cj, csrf) <- getCsrf manager cj' <- login username password cj csrf manager- runConcurrently $ memoizedTraverse+ urls <- runConcurrently $ memoizedTraverse (Concurrently . exportList cj' csrf manager) mediaTypes+ pure (cj', urls) login :: Text -- ^ Username -> Text -- ^ Password@@ -173,7 +177,7 @@ tagToCsrf :: Token -> Maybe CSRF-tagToCsrf (TagOpen "meta" xs False) = case (lookup "name" xs) of+tagToCsrf (TagOpen "meta" xs False) = case lookup "name" xs of Just "csrf_token" -> CSRF <$> lookup "content" xs _ -> Nothing tagToCsrf _ = Nothing