From 6f1e9df2af5a972833896173db6a6bfde0af4c81 Mon Sep 17 00:00:00 2001 From: depsterr Date: Sun, 5 Sep 2021 19:30:29 +0200 Subject: [PATCH] initial commit --- .gitignore | 1 + CHANGELOG.md | 5 +++ LICENSE | 13 ++++++ app/Main.hs | 6 +++ kino.cabal | 46 +++++++++++++++++++++ src/JSONTypes.hs | 103 ++++++++++++++++++++++++++++++++++++++++++++++ src/Request.hs | 24 +++++++++++ test/MyLibTest.hs | 4 ++ 8 files changed, 202 insertions(+) create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 app/Main.hs create mode 100644 kino.cabal create mode 100644 src/JSONTypes.hs create mode 100644 src/Request.hs create mode 100644 test/MyLibTest.hs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..48a004c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +dist-newstyle diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..b278f4d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for kino + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..7e27a59 --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright (c) 2021 depsterr + +Permission to use, copy, modify, and/or distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright notice +and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS +OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. diff --git a/app/Main.hs b/app/Main.hs new file mode 100644 index 0000000..c3f6bb6 --- /dev/null +++ b/app/Main.hs @@ -0,0 +1,6 @@ +module Main where + +import Request + +main :: IO () +main = print =<< testFunc diff --git a/kino.cabal b/kino.cabal new file mode 100644 index 0000000..e74d374 --- /dev/null +++ b/kino.cabal @@ -0,0 +1,46 @@ +cabal-version: 2.4 +name: kino +version: 0.1.0.0 +synopsis: A terminal interface to the yts.mx api +-- description: +homepage: +-- bug-reports: +license: ISC +license-file: LICENSE +author: depsterr +maintainer: depsterr@protonmail.com +-- copyright: +category: Movie +extra-source-files: CHANGELOG.md + +library + exposed-modules: Request + , JSONTypes + other-modules: + -- other-extensions: + build-depends: base ^>=4.14.1.0 + , wreq + , aeson + , lens-aeson + , lens + , bytestring + , text + hs-source-dirs: src + default-language: Haskell2010 + +executable kino + main-is: Main.hs + -- other-modules: + -- other-extensions: + build-depends: + base ^>=4.14.1.0, + kino + hs-source-dirs: app + default-language: Haskell2010 + +test-suite kino-test + default-language: Haskell2010 + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: MyLibTest.hs + build-depends: base ^>=4.14.1.0 diff --git a/src/JSONTypes.hs b/src/JSONTypes.hs new file mode 100644 index 0000000..daf2f08 --- /dev/null +++ b/src/JSONTypes.hs @@ -0,0 +1,103 @@ +{-# LANGUAGE OverloadedStrings #-} + +module JSONTypes where + +import Data.Aeson +import Data.Aeson.Types +import Data.Text as T +import Data.Aeson.Lens (key, nth) +import qualified Data.ByteString.Lazy.Internal as BL + +data JSONResponse d = JSONResponse + { resp_status :: T.Text + , resp_message :: T.Text + , response_data :: d + } deriving (Show) + +instance (FromJSON d) => FromJSON (JSONResponse d) where + parseJSON (Object v) = JSONResponse + <$> v .: "status" + <*> v .: "status_message" + <*> v .: "data" + parseJSON invalid = + prependFailure "parsing JSONResponse failed, " + (typeMismatch "Object" invalid) + +data JSONListMovies = JSONListMovies + { movies_count :: Int + , movies_limit :: Int + , page_number :: Int + , movies :: [JSONMovie] + } deriving (Show) + +instance FromJSON JSONListMovies where + parseJSON (Object v) = JSONListMovies + <$> v .: "movie_count" + <*> v .: "limit" + <*> v .: "page_number" + <*> v .: "movies" + parseJSON invalid = + prependFailure "parsing JSONListMovies failed, " + (typeMismatch "Object" invalid) + +data JSONMovie = JSONMovie + { movie_id :: Int + , movie_url :: T.Text + , imdb_code :: T.Text + , movie_title :: T.Text + , movie_year :: Int + , movie_rating :: Double + , movie_runtime :: Int + , movie_genres :: [T.Text] + , movie_summary :: T.Text + , movie_language :: T.Text + , movie_state :: T.Text + , movie_torrents :: [JSONTorrent] + } deriving (Show) + +instance FromJSON JSONMovie where + parseJSON (Object v) = JSONMovie + <$> v .: "id" + <*> v .: "url" + <*> v .: "imdb_code" + <*> v .: "title" + <*> v .: "year" + <*> v .: "rating" + <*> v .: "runtime" + <*> v .: "genres" + <*> v .: "summary" + <*> v .: "language" + <*> v .: "state" + <*> v .: "torrents" + parseJSON invalid = + prependFailure "parsing JSONMovie failed, " + (typeMismatch "Object" invalid) + +data JSONTorrent = JSONTorrent + { torrent_url :: T.Text + , torrent_hash :: T.Text + , torrent_quality :: T.Text + , torrent_type :: T.Text + , torrent_seeds :: Int + , torrent_peers :: Int + , torrent_size :: T.Text + , torrent_bytes :: Int + , torrent_uploaded :: T.Text + , torrent_uploaded_unix :: Int -- TODO: better date type? + } deriving (Show) + +instance FromJSON JSONTorrent where + parseJSON (Object v) = JSONTorrent + <$> v .: "url" + <*> v .: "hash" + <*> v .: "quality" + <*> v .: "type" + <*> v .: "seeds" + <*> v .: "peers" + <*> v .: "size" + <*> v .: "size_bytes" + <*> v .: "date_uploaded" + <*> v .: "date_uploaded_unix" + parseJSON invalid = + prependFailure "parsing JSONTorrent failed, " + (typeMismatch "Object" invalid) diff --git a/src/Request.hs b/src/Request.hs new file mode 100644 index 0000000..57341ae --- /dev/null +++ b/src/Request.hs @@ -0,0 +1,24 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Request where + +import JSONTypes + +import Network.Wreq +import Control.Lens +import Data.Aeson +import Data.Text as T +import Data.Aeson.Lens (key, nth) +import qualified Data.ByteString.Lazy.Internal as BL + +testFunc :: IO (JSONResponse JSONListMovies) +testFunc = do + r <- asJSON =<< get "https://yts.mx/api/v2/list_movies.json" + pure $ r ^. responseBody + +getMovies :: IO (Either T.Text JSONListMovies) +getMovies = do + r <- asJSON =<< get "https://yts.mx/api/v2/list_movies.json" + pure $ case (r ^. responseBody) of + (JSONResponse "ok" _ d) -> Right d + (JSONResponse _ m _) -> Left m diff --git a/test/MyLibTest.hs b/test/MyLibTest.hs new file mode 100644 index 0000000..3e2059e --- /dev/null +++ b/test/MyLibTest.hs @@ -0,0 +1,4 @@ +module Main (main) where + +main :: IO () +main = putStrLn "Test suite not yet implemented."