Browse Source

Add 'vendor/themoviedb/' from commit '08c8e93ac0d63d2d32420aeba1ac786d4f292c4b'

git-subtree-dir: vendor/themoviedb
git-subtree-mainline: 38ce8d2e60
git-subtree-split: 08c8e93ac0
tags/v0.2.2.0
Peter J. Jones 3 years ago
parent
commit
7d94b7e849
32 changed files with 1598 additions and 0 deletions
  1. 5
    0
      vendor/themoviedb/.gitignore
  2. 30
    0
      vendor/themoviedb/CHANGES
  3. 24
    0
      vendor/themoviedb/LICENSE
  4. 22
    0
      vendor/themoviedb/README.md
  5. 2
    0
      vendor/themoviedb/Setup.hs
  6. 13
    0
      vendor/themoviedb/TODO.org
  7. 154
    0
      vendor/themoviedb/example/Main.hs
  8. 78
    0
      vendor/themoviedb/src/Network/API/TheMovieDB.hs
  9. 107
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Actions.hs
  10. 78
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Internal/Configuration.hs
  11. 62
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Internal/Date.hs
  12. 70
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Internal/HTTP.hs
  13. 32
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Internal/SearchResults.hs
  14. 111
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Internal/TheMovieDB.hs
  15. 64
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Internal/Types.hs
  16. 87
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Types/Episode.hs
  17. 42
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Types/Genre.hs
  18. 94
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Types/Movie.hs
  19. 83
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Types/Season.hs
  20. 109
    0
      vendor/themoviedb/src/Network/API/TheMovieDB/Types/TV.hs
  21. 15
    0
      vendor/themoviedb/test/Main.hs
  22. 73
    0
      vendor/themoviedb/test/MovieTest.hs
  23. 78
    0
      vendor/themoviedb/test/TVTest.hs
  24. 42
    0
      vendor/themoviedb/test/TestHelper.hs
  25. 1
    0
      vendor/themoviedb/test/config-good.json
  26. 1
    0
      vendor/themoviedb/test/movie-bad.json
  27. 1
    0
      vendor/themoviedb/test/movie-good.json
  28. 1
    0
      vendor/themoviedb/test/search-good.json
  29. 1
    0
      vendor/themoviedb/test/search-tv-good.json
  30. 1
    0
      vendor/themoviedb/test/season-good.json
  31. 1
    0
      vendor/themoviedb/test/tv-good.json
  32. 116
    0
      vendor/themoviedb/themoviedb.cabal

+ 5
- 0
vendor/themoviedb/.gitignore View File

@@ -0,0 +1,5 @@
/dist
/.deps.mk
/cabal.sandbox.config
/.cabal-sandbox
/default.nix

+ 30
- 0
vendor/themoviedb/CHANGES View File

@@ -0,0 +1,30 @@
-*- org -*-
#+title: Version History
#+startup: showall

* 1.1.1.0 (July 22, 2015)

- Widen dependencies for aeson, either, and text-binary

* 1.1.0.0 (May 22, 2015)

- Added Ord instance for TV, Season, and Episode
- Removed unused dependencies from build-depends
- Changes to build with GHC 7.8.4. and 7.10.1

* 1.0.0.0 (April 5, 2015)

- Major rewrite of the interface
- Removed utility functions for loading API keys
- Added types and functions for TV series information
- Fixed bug: https://github.com/pjones/themoviedb/issues/1
- Fixed bug: https://github.com/pjones/themoviedb/issues/2

* 0.1.0.1 (December 17, 2012)

- Small internal changes to compile with GHC 7.6.1.
- Also compiles with GHC 7.4.2 and HP 2012.4.0.0.

* 0.1.0.0 (December 14, 2012)

- Initial release.

+ 24
- 0
vendor/themoviedb/LICENSE View File

@@ -0,0 +1,24 @@
# Copyright and Authors

Copyright (C) 2012-2015 Peter Jones <pjones@devalot.com>

# License (MIT)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 22
- 0
vendor/themoviedb/README.md View File

@@ -0,0 +1,22 @@
# TheMovieDB API for Haskell

This is a simple library that provides functions for retrieving movie
metadata from [TheMovieDB][] API. To use this library you need to
request an API key from TheMovieDB. Follow the directions on the
[API][] page.

[TheMovieDB]: http://themoviedb.org
[API]: http://docs.themoviedb.apiary.io

# Documentation

See the [Network.API.TheMovieDB][] module for complete documentation.

[Network.API.TheMovieDB]: https://github.com/pjones/themoviedb/blob/master/Network/API/TheMovieDB.hs

# Example

There's an [example][] application in the `example` directory.
Surprising, I know.

[example]: https://github.com/pjones/themoviedb/blob/master/example/Main.hs

+ 2
- 0
vendor/themoviedb/Setup.hs View File

@@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

+ 13
- 0
vendor/themoviedb/TODO.org View File

@@ -0,0 +1,13 @@
#+title: TheMovieDB To-do List

* Milestone: Release 1.0.0.0
** DONE Switch to HTTPS/SSL/TLS (via http-conduit)
CLOSED: [2015-03-20 Fri 18:02]
- This requires using something other than Network.HTTP.
** DONE Remove key utility functions
CLOSED: [2015-03-20 Fri 18:02]
** DONE Ensure parsing errors are handled properly
CLOSED: [2015-03-20 Fri 18:02]
** TODO Prune unneeded dependencies in the cabal file
** TODO Clean up documentation
** TODO Clean up tests

+ 154
- 0
vendor/themoviedb/example/Main.hs View File

@@ -0,0 +1,154 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Main (main) where

--------------------------------------------------------------------------------
import Control.Monad.IO.Class (liftIO)
import Data.Maybe (listToMaybe)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time (formatTime)
import Data.Time.Locale.Compat (defaultTimeLocale)
import Network.API.TheMovieDB
import System.Environment (getArgs)
import System.Exit (exitFailure, exitSuccess)
import Text.Printf (printf)

--------------------------------------------------------------------------------
-- | Simple banner style printing of a 'Movie'.
printMovieHeader :: Movie -> IO ()
printMovieHeader m =
printf "%8d: %s (%s)\n" (movieID m) (T.unpack $ movieTitle m) year
where year = case movieReleaseDate m of
Just d -> formatTime defaultTimeLocale "%Y" d
Nothing -> "----"

--------------------------------------------------------------------------------
-- | Simple banner style printing of a 'TV'.
printTVHeader :: TV -> IO ()
printTVHeader t =
printf "%8d: %s (%s)\n" (tvID t) (T.unpack $ tvName t) year
where year = case tvFirstAirDate t of
Just d -> formatTime defaultTimeLocale "%Y" d
Nothing -> "----"

--------------------------------------------------------------------------------
-- | Print more detailed information for a 'Movie'.
printMovieDetails :: Movie -> IO ()
printMovieDetails m =
do putStrLn $ "Popularity: " ++ show (moviePopularity m)
putStrLn $ strJoin $ map genreName (movieGenres m)
putStrLn "-- "
putStrLn $ T.unpack (movieOverview m)
where strJoin = T.unpack . T.intercalate ", "

--------------------------------------------------------------------------------
-- | Print information about a season.
printSeason :: Season -> IO ()
printSeason s =
do putStrLn $ "Season " ++ show (seasonNumber s) ++ " " ++ year
mapM_ (putStrLn . episode) $ seasonEpisodes s

where
episode e = "\tE" ++ show (episodeNumber e) ++ " "
++ T.unpack (episodeName e)

year = case seasonAirDate s of
Just d -> formatTime defaultTimeLocale "%Y" d
Nothing -> "----"

--------------------------------------------------------------------------------
-- | Search for movies with a query string.
searchAndListMovies :: Text -> TheMovieDB ()
searchAndListMovies query = do
movies <- searchMovies query
liftIO $ mapM_ printMovieHeader movies

--------------------------------------------------------------------------------
-- | Find a specific movie given its ID.
fetchAndPrintMovie :: ItemID -> TheMovieDB ()
fetchAndPrintMovie mid = do
cfg <- config
movie <- fetchMovie mid

liftIO $ do
printMovieHeader movie
mapM_ (putStrLn . T.unpack) (moviePosterURLs cfg movie)
printMovieDetails movie

--------------------------------------------------------------------------------
-- | Search for TV series using a query string.
searchAndListTV :: Text -> TheMovieDB ()
searchAndListTV query = do
tvs <- searchTV query
liftIO $ mapM_ printTVHeader tvs

--------------------------------------------------------------------------------
-- | Find a specific TV series given its ID.
fetchAndPrintTV :: ItemID -> TheMovieDB ()
fetchAndPrintTV tid = do
tv <- fetchTV tid
liftIO $ printTVHeader tv
liftIO $ mapM_ printSeason (tvSeasons tv)

--------------------------------------------------------------------------------
fetchAndPrintSeason :: ItemID -> Int -> TheMovieDB ()
fetchAndPrintSeason t s = do
season <- fetchTVSeason t s
liftIO $ printSeason season

--------------------------------------------------------------------------------
fetchAndPrintFullTV :: ItemID -> TheMovieDB ()
fetchAndPrintFullTV t = do
tv <- fetchFullTVSeries t
liftIO $ printTVHeader tv
liftIO $ mapM_ printSeason (tvSeasons tv)

--------------------------------------------------------------------------------
-- | Low budget command line parsing and dispatch.
main :: IO ()
main = do
args <- getArgs
let key = maybe T.empty T.pack (listToMaybe args)

result <- runTheMovieDB key $
case args of
[_, "search", query] -> searchAndListMovies (T.pack query)
[_, "fetch", mid] -> fetchAndPrintMovie (read mid)
[_, "tsearch", query] -> searchAndListTV (T.pack query)
[_, "tfetch", tid] -> fetchAndPrintTV (read tid)
[_, "season", t, s] -> fetchAndPrintSeason (read t) (read s)
[_, "tfull", t] -> fetchAndPrintFullTV (read t)
_ -> liftIO (putStrLn usage >> exitFailure)

case result of
Left err -> print err >> exitFailure
Right _ -> exitSuccess

where usage = "Usage: tmdb key {search|fetch|tsearch|tfetch|season|tfull}\n\n" ++
"Description:\n" ++
" search: search TheMovieDB\n" ++
" fetch: fetch info about one movie\n" ++
" tsearch: search for TV series\n" ++
" tfetch: fetch TV series by ID\n" ++
" season: fetch one season by TV ID and season num\n" ++
" tfull: pull everything about TV series by ID\n" ++
"Examples:\n" ++
" tmdb KEY search \"back to the future\"\n" ++
" tmdb KEY fetch 105\n" ++
" tmdb KEY tsearch Firefly\n" ++
" tmdb KEY tfetch 1437\n" ++
" tmdb KEY season 1437 1\n" ++
" tmdb KEY tfull 1437\n"

+ 78
- 0
vendor/themoviedb/src/Network/API/TheMovieDB.hs View File

@@ -0,0 +1,78 @@
{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

{- |

This library provides some data types and functions for fetching movie
metadata from <http://TheMovieDB.org>. To use this library start by
requesting an API key from <http://docs.themoviedb.apiary.io>.

Example:

@
import Network.API.TheMovieDB

main :: IO ()
main = do
-- The API key assigned to you (as a 'Text' value).
let key = "your API key"

-- The 'fetch' function will get a 'Movie' record based on its ID.
result <- runTheMovieDB key (fetchMovie 9340)

-- Do something with the result (or error).
putStrLn (show result)
@

This library also includes an example executable in the @example@
directory.
-}
module Network.API.TheMovieDB
( -- * Types
Movie (..)
, TV (..)
, Season (..)
, Episode (..)
, Genre (..)
, Error (..)
, ItemID
, Key

-- * API Functions
, TheMovieDB
, runTheMovieDB
, runTheMovieDBWithManager
, searchMovies
, fetchMovie
, searchTV
, fetchTV
, fetchTVSeason
, fetchFullTVSeries

-- * Utility Types and Functions
, Configuration
, config
, moviePosterURLs
, tvPosterURLs
, seasonPosterURLs
, episodeStillURLs
) where

--------------------------------------------------------------------------------
import Network.API.TheMovieDB.Actions
import Network.API.TheMovieDB.Internal.Configuration
import Network.API.TheMovieDB.Internal.TheMovieDB
import Network.API.TheMovieDB.Internal.Types
import Network.API.TheMovieDB.Types.Episode
import Network.API.TheMovieDB.Types.Genre
import Network.API.TheMovieDB.Types.Movie
import Network.API.TheMovieDB.Types.Season
import Network.API.TheMovieDB.Types.TV

+ 107
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Actions.hs View File

@@ -0,0 +1,107 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Actions
( searchMovies
, fetchMovie
, searchTV
, fetchTV
, fetchTVSeason
, fetchFullTVSeries
, config
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Text (Text)
import Network.API.TheMovieDB.Internal.Configuration
import Network.API.TheMovieDB.Internal.SearchResults
import Network.API.TheMovieDB.Internal.TheMovieDB
import Network.API.TheMovieDB.Internal.Types
import Network.API.TheMovieDB.Types.Movie
import Network.API.TheMovieDB.Types.Season
import Network.API.TheMovieDB.Types.TV

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | Search TheMovieDB using the given query string.
--
-- The movies returned will not have all their fields completely
-- filled out, to get a complete record you'll need to follow this
-- call up with a call to 'fetchMovie'.
searchMovies :: Text -> TheMovieDB [Movie]
searchMovies query = searchResults <$> search
where search = getAndParse "search/movie" [("query", Just query)]

--------------------------------------------------------------------------------
-- | Fetch the metadata for the 'Movie' with the given ID.
fetchMovie :: ItemID -- ^ TheMovieDB ID for the movie.
-> TheMovieDB Movie
fetchMovie mid = getAndParse ("movie/" ++ show mid) []

--------------------------------------------------------------------------------
-- | Search TheMovieDB for matching 'TV' series.
--
-- The 'TV' values returned from this function will be partial
-- records. The only fields that will be available are 'tvID',
-- 'tvName', 'tvPosterPath', 'tvPopularity', and possibly
-- 'tvFirstAirDate'.
--
-- To get full 'TV' records you need to follow this function with a
-- call to 'fetchTV' using the desired 'tvID' value.
searchTV :: Text -> TheMovieDB [TV]
searchTV query = searchResults <$> search
where search = getAndParse "search/tv" [("query", Just query)]

--------------------------------------------------------------------------------
-- | Fetch metadata for a 'TV' series given its TheMovieDB ID. The
-- metadata for 'Season's listed in the TV series will not have
-- complete 'Episode' information.
--
-- After calling this function you should call 'fetchTVSeason' to fill
-- in the 'Episode' metadata, or just begin with 'fetchFullTVSeries'.
fetchTV :: ItemID -- ^ TheMovieDB ID for the TV series.
-> TheMovieDB TV
fetchTV i = getAndParse ("tv/" ++ show i) []

--------------------------------------------------------------------------------
-- | Fetch metadata for a 'Season', including all 'Episode's.
fetchTVSeason :: ItemID -- ^ TheMovieDB ID for the TV series.
-> Int -- ^ Season number (not season ID).
-> TheMovieDB Season
fetchTVSeason i n = getAndParse ("tv/" ++ show i ++ "/season/" ++ show n) []

--------------------------------------------------------------------------------
-- | Fetch full metadata for a 'TV' series, including all seasons and
-- episodes.
--
-- This function will make multiple HTTP requests to TheMovieDB API.
fetchFullTVSeries :: ItemID -- ^ TheMovieDB ID for the TV series.
-> TheMovieDB TV
fetchFullTVSeries i = do
tv <- fetchTV i
seasons <- mapM (fetchTVSeason i . seasonNumber) (tvSeasons tv)
return tv {tvSeasons = seasons}

--------------------------------------------------------------------------------
-- | Fetch the API configuration information such as base URLs for
-- movie posters. The resulting configuration value should be cached
-- and only requested every few days.
config :: TheMovieDB Configuration
config = getAndParse "configuration" []

+ 78
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Internal/Configuration.hs View File

@@ -0,0 +1,78 @@
{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
-- | Internal configuration information for TheMovieDB API.
module Network.API.TheMovieDB.Internal.Configuration
( Configuration (..)
, posterURLs
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Binary
import Data.Monoid
import Data.Text (Text)
import Data.Text.Binary ()
import GHC.Generics (Generic)

--------------------------------------------------------------------------------
-- | TheMovieDB API tries to preserve bandwidth by omitting
-- information (such as full URLs for poster images) from most of the
-- API calls. Therefore in order to construct a complete URL for a
-- movie poster you'll need to use the 'config' function to retrieve
-- API configuration information.
--
-- A helper function is provided ('moviePosterURLs') that constructs a
-- list of all poster URLs given a 'Movie' and 'Configuration'.
--
-- According to the API documentation for TheMovieDB, you should cache
-- the 'Configuration' value and only request it every few days.
-- Therefore, it is an instance of the 'Binary' class so it can be
-- serialized to and from a cache file on disk.
--
-- Alternatively, the 'FromJSON' and 'ToJSON' instances can be used to
-- cache the 'Configuration' value.
data Configuration = Configuration
{ cfgImageBaseURL :: Text -- ^ The base URL for images.
, cfgImageSecBaseURL :: Text -- ^ Base URL for secure images.
, cfgPosterSizes :: [Text] -- ^ List of possible image sizes.
} deriving (Generic)

--------------------------------------------------------------------------------
instance Binary Configuration

--------------------------------------------------------------------------------
instance FromJSON Configuration where
parseJSON (Object v) =
Configuration <$> images "base_url"
<*> images "secure_base_url"
<*> imagesM "poster_sizes" []
where images key = (v .: "images") >>= (.: key)
imagesM key def = (v .: "images") >>= (\x -> x .:? key .!= def)
parseJSON _ = empty

--------------------------------------------------------------------------------
instance ToJSON Configuration where
toJSON c = object [ "images" .= object
[ "base_url" .= cfgImageBaseURL c
, "secure_base_url" .= cfgImageSecBaseURL c
, "poster_sizes" .= cfgPosterSizes c
]]


--------------------------------------------------------------------------------
-- | Return a list of URLs for all possible posters posters.
posterURLs :: Configuration -> Text -> [Text]
posterURLs c p = [cfgImageBaseURL c <> size <> p | size <- cfgPosterSizes c]

+ 62
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Internal/Date.hs View File

@@ -0,0 +1,62 @@
{-# OPTIONS_GHC -Wwarn #-} -- Kludge to not error out on parseTime deprecation.
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
-- | Utility type for working with release dates.
module Network.API.TheMovieDB.Internal.Date
( Date (..)
, parseDay
, (.::)
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (Parser, typeMismatch)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time (Day(..), parseTime)
import Data.Time.Locale.Compat (defaultTimeLocale)

--------------------------------------------------------------------------------
-- | A simple type wrapper around 'Day' in order to parse a movie's
-- release date, which may be null or empty.
newtype Date = Date {day :: Maybe Day} deriving (Eq, Show)

--------------------------------------------------------------------------------
-- | Aeson helper function to parse dates in TheMovieDB API.
parseDay :: Object -> Text -> Parser (Maybe Day)
parseDay v key =
do m <- date
return $ case m of
Nothing -> Nothing
Just d -> day d
where
date :: Parser (Maybe Date)
date = v .:? key <|> pure Nothing

--------------------------------------------------------------------------------
(.::) :: Object -> Text -> Parser (Maybe Day)
(.::) = parseDay

--------------------------------------------------------------------------------
-- | Parse release dates in JSON.
instance FromJSON Date where
parseJSON (Null) = return (Date Nothing)
parseJSON (String t)
| T.null t = return (Date Nothing)
| otherwise = case parseTime defaultTimeLocale "%Y-%m-%d" (T.unpack t) of
Just d -> return $ Date (Just d)
_ -> fail "could not parse TheMovieDB date field"
parseJSON v = typeMismatch "Date" v

+ 70
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Internal/HTTP.hs View File

@@ -0,0 +1,70 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
-- | Simple interface for fetching JSON files from the API via HTTP.
module Network.API.TheMovieDB.Internal.HTTP
( apiGET
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Control.Exception
import Network.API.TheMovieDB.Internal.Types
import qualified Network.HTTP.Client as HC
import Network.HTTP.Types

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | The base URL for the version of the API we're using.
apiBaseURL :: String
apiBaseURL = "https://api.themoviedb.org/3/"

--------------------------------------------------------------------------------
-- | Build a HTTP request that can be used to access the API.
mkAPIRequest :: Key -> Path -> QueryText -> IO HC.Request
mkAPIRequest key path params = do
req <- HC.parseUrl (apiBaseURL ++ path)

return $ req { HC.queryString = query
, HC.requestHeaders = headers
}

where
query = renderQuery False . queryTextToQuery $ allParams
allParams = params ++ [("api_key", Just key)]
headers = [("Accept", "application/json")]

--------------------------------------------------------------------------------
-- | Build a URL and do an HTTP GET to TheMovieDB.
apiGET :: HC.Manager -> Key -> Path -> QueryText -> IO (Either Error Body)
apiGET manager key path params = do
request <- mkAPIRequest key path params
response <- catch (Right <$> HC.httpLbs request manager) httpError

return $ case response of
Left e -> Left e
Right r
| statusIsSuccessful (HC.responseStatus r) -> Right (HC.responseBody r)
| otherwise -> Left (ServiceError . show $ HC.responseStatus r)

where
httpError :: HC.HttpException -> IO (Either Error (HC.Response Body))
httpError e = return $ case e of
HC.StatusCodeException (Status 401 _) _ _ -> Left InvalidKeyError
_ -> Left (HttpExceptionError e)

+ 32
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Internal/SearchResults.hs View File

@@ -0,0 +1,32 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
-- | Utility type for processing movie search results.
module Network.API.TheMovieDB.Internal.SearchResults
( SearchResults (..)
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson

--------------------------------------------------------------------------------
-- | Internal wrapper to parse a list of results from JSON.
newtype SearchResults a = SearchResults {searchResults :: [a]}
deriving (Eq, Show)

--------------------------------------------------------------------------------
instance (FromJSON a) => FromJSON (SearchResults a) where
parseJSON (Object v) = SearchResults <$> v .: "results"
parseJSON _ = empty

+ 111
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Internal/TheMovieDB.hs View File

@@ -0,0 +1,111 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Internal.TheMovieDB
( TheMovieDB
, RequestFunction
, getAndParse
, tmdbError
, runTheMovieDB
, runTheMovieDBWithManager
, runTheMovieDBWithRequestFunction
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Control.Monad.Reader
import Control.Monad.Trans.Either
import Data.Aeson
import Network.API.TheMovieDB.Internal.HTTP
import Network.API.TheMovieDB.Internal.Types
import Network.HTTP.Client (Manager, withManager)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import Network.HTTP.Types

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | The type for functions that make requests to the API (or pretend
-- to make a request for testing purposes).
type RequestFunction = (Path -> QueryText -> IO (Either Error Body))

--------------------------------------------------------------------------------
-- | Result type for operations involving TheMovieDB API.
newtype TheMovieDB a =
TheMovieDB {unTMDB :: ReaderT RequestFunction (EitherT Error IO) a}
deriving (Functor, Applicative, Monad, MonadIO)

--------------------------------------------------------------------------------
-- | Helper function for making a request using the request function
-- stashed away in the reader monad.
runRequest :: Path -> QueryText -> TheMovieDB Body
runRequest path params = TheMovieDB $ do
func <- ask
result <- liftIO (func path params)
lift (hoistEither result)

--------------------------------------------------------------------------------
-- | Helper function to preform an HTTP GET and decode the JSON result.
getAndParse :: FromJSON a => Path -> QueryText -> TheMovieDB a
getAndParse path params = do
body <- runRequest path params

case eitherDecode body of
Left e -> tmdbError $ ResponseParseError ("bad JSON: " ++ e) (Just body)
Right a -> return a

--------------------------------------------------------------------------------
-- | Create a 'TheMovieDB' value representing an error.
tmdbError :: Error -> TheMovieDB a
tmdbError = TheMovieDB . lift . left

--------------------------------------------------------------------------------
-- | Execute requests for TheMovieDB with the given API key and produce
-- either an error or a result.
--
-- This version creates a temporary 'Manager' using
-- 'tlsManagerSettings'. If you want to use an existing 'Manager' you
-- should use 'runTheMovieDBWithManager' instead.
runTheMovieDB
:: Key -- ^ The API key to include in all requests.
-> TheMovieDB a -- ^ The API calls to make.
-> IO (Either Error a) -- ^ Response or error.
runTheMovieDB k t =
withManager tlsManagerSettings (\m -> runTheMovieDBWithManager m k t)

--------------------------------------------------------------------------------
-- | Execute requests for TheMovieDB with the given API key and produce
-- either an error or a result.
--
-- This version allows you to provide a 'Manager' value which should
-- have been created to allow TLS requests (e.g., with 'tlsManagerSettings').
runTheMovieDBWithManager
:: Manager -- ^ The 'Manager' to use.
-> Key -- ^ The API key to include in all requests.
-> TheMovieDB a -- ^ The API calls to make.
-> IO (Either Error a) -- ^ Response or error.
runTheMovieDBWithManager m k = runTheMovieDBWithRequestFunction (apiGET m k)

--------------------------------------------------------------------------------
-- | Low-level interface for executing a 'TheMovieDB' using the given
-- request function.
runTheMovieDBWithRequestFunction
:: RequestFunction -- ^ The request function to use.
-> TheMovieDB a -- ^ The API calls to make.
-> IO (Either Error a) -- ^ Response.
runTheMovieDBWithRequestFunction f t = runEitherT $ runReaderT (unTMDB t) f

+ 64
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Internal/Types.hs View File

@@ -0,0 +1,64 @@
{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
-- | Simple types and synonyms, mostly to make the type signatures
-- easier to read.
module Network.API.TheMovieDB.Internal.Types
( ItemID
, Key
, Body
, Path
, Error (..)
) where

--------------------------------------------------------------------------------
import Data.ByteString.Lazy (ByteString)
import Data.Text (Text)
import Network.HTTP.Client (HttpException)

--------------------------------------------------------------------------------
-- | Type to represent IDs used by the API.
type ItemID = Int

--------------------------------------------------------------------------------
-- | Type for the API key issued by TheMovieDB.
type Key = Text

--------------------------------------------------------------------------------
-- | URL path.
type Path = String
--------------------------------------------------------------------------------
-- | HTTP body.
type Body = ByteString

--------------------------------------------------------------------------------
-- | Possible errors returned by the API.
data Error = InvalidKeyError
-- ^ Missing or invalid API key. Make sure you are using
-- a valid API key issued by
-- <https://www.themoviedb.org/faq/api>.

| HttpExceptionError HttpException
-- ^ An exception relating to HTTP was thrown while
-- interacting with the API.
| ServiceError String
-- ^ The HTTP interaction with the API service did not
-- result in a successful response. Information about
-- the failure is encoded in the String.
| ResponseParseError String (Maybe ByteString)
-- ^ Invalid or error response from the API.
deriving (Show)


+ 87
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Types/Episode.hs View File

@@ -0,0 +1,87 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Types.Episode
( Episode (..)
, episodeStillURLs
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
import Data.Text (Text)
import Data.Time (Day (..))
import Network.API.TheMovieDB.Internal.Configuration
import Network.API.TheMovieDB.Internal.Date
import Network.API.TheMovieDB.Internal.Types

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | Metadata for a TV Episode.
--
-- * The 'episodeStillPath' field is an incomplete URL. To
-- construct a complete URL you'll need to use the 'Configuration'
-- type and the 'episodeStillURLs' helper function.
data Episode = Episode
{ episodeID :: ItemID
-- ^ TheMovieDB unique ID.

, episodeNumber :: Int
-- ^ Episode sequence number.

, episodeName :: Text
-- ^ Episode name.

, episodeOverview :: Text
-- ^ Short description of the episode.

, episodeSeasonNumber :: Int
-- ^ The season this episode belongs to.

, episodeAirDate :: Maybe Day
-- ^ Episode air date, if it ever aired.

, episodeStillPath :: Text
-- ^ Incomplete URL to a still image from the episode. See the
-- 'episodeStillURLs' function for more information.

} deriving (Eq, Show)

--------------------------------------------------------------------------------
instance Ord Episode where
compare a b = compare (episodeSeasonNumber a, episodeNumber a)
(episodeSeasonNumber b, episodeNumber b)

--------------------------------------------------------------------------------
instance FromJSON Episode where
parseJSON (Object v) =
Episode <$> v .: "id"
<*> v .: "episode_number"
<*> v .: "name"
<*> v .: "overview"
<*> v .: "season_number" .!= 0
<*> v .:: "air_date"
<*> v .: "still_path" .!= ""
parseJSON v = typeMismatch "Episode" v

--------------------------------------------------------------------------------
-- | Return a list of URLs for all possible episode still images.
episodeStillURLs :: Configuration -> Episode -> [Text]
episodeStillURLs c e = posterURLs c (episodeStillPath e)

+ 42
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Types/Genre.hs View File

@@ -0,0 +1,42 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Types.Genre
( Genre(..)
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
import Data.Text (Text)
import Network.API.TheMovieDB.Internal.Types

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | Metadata for a genre.
data Genre = Genre
{ genreID :: ItemID -- ^ TheMovieDB unique ID.
, genreName :: Text -- ^ The name of the genre.
} deriving (Eq, Show)

--------------------------------------------------------------------------------
instance FromJSON Genre where
parseJSON (Object v) = Genre <$> v .: "id" <*> v .: "name"
parseJSON v = typeMismatch "Genre" v

+ 94
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Types/Movie.hs View File

@@ -0,0 +1,94 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Types.Movie
( Movie(..)
, moviePosterURLs
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
import Data.Text (Text)
import Data.Time (Day (..))
import Network.API.TheMovieDB.Internal.Configuration
import Network.API.TheMovieDB.Internal.Date
import Network.API.TheMovieDB.Internal.Types
import Network.API.TheMovieDB.Types.Genre

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | Metadata for a movie.
--
-- * The 'moviePosterPath' field is an incomplete URL. To construct
-- a complete URL you'll need to use the 'Configuration' type and
-- the 'moviePosterURLs' helper function.
data Movie = Movie
{ movieID :: ItemID
-- ^ TheMovieDB unique ID.

, movieTitle :: Text
-- ^ The name/title of the movie.

, movieOverview :: Text
-- ^ Short plot summary.

, movieGenres :: [Genre]
-- ^ List of 'Genre's.

, moviePopularity :: Double
-- ^ Popularity ranking.

, moviePosterPath :: Text
-- ^ Incomplete URL for poster image. See 'moviePosterURLs'.

, movieReleaseDate :: Maybe Day
-- ^ Movie release date. (Movie may not have been released yet.)

, movieAdult :: Bool
-- ^ TheMovieDB adult movie flag.

, movieIMDB :: Text
-- ^ IMDB.com ID.

, movieRunTime :: Int
-- ^ Movie length in minutes.

} deriving (Eq, Show)

--------------------------------------------------------------------------------
instance FromJSON Movie where
parseJSON (Object v) =
Movie <$> v .: "id"
<*> v .: "title"
<*> v .:? "overview" .!= ""
<*> v .:? "genres" .!= []
<*> v .:? "popularity" .!= 0.0
<*> v .:? "poster_path" .!= ""
<*> v .:: "release_date"
<*> v .:? "adult" .!= False
<*> v .:? "imdb_id" .!= ""
<*> v .:? "runtime" .!= 0
parseJSON v = typeMismatch "Movie" v

--------------------------------------------------------------------------------
-- | Return a list of URLs for all possible movie posters.
moviePosterURLs :: Configuration -> Movie -> [Text]
moviePosterURLs c m = posterURLs c (moviePosterPath m)

+ 83
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Types/Season.hs View File

@@ -0,0 +1,83 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Types.Season
( Season (..)
, seasonPosterURLs
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
import Data.Text (Text)
import Data.Time (Day (..))
import Network.API.TheMovieDB.Internal.Configuration
import Network.API.TheMovieDB.Internal.Date
import Network.API.TheMovieDB.Internal.Types
import Network.API.TheMovieDB.Types.Episode

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | Metadata for a TV Season.
--
-- * The 'seasonPosterPath' field is an incomplete URL. To
-- construct a complete URL you'll need to use the 'Configuration'
-- type and the 'seasonPosterURLs' helper function.
data Season = Season
{ seasonID :: ItemID
-- ^ TheMovieDB unique ID.

, seasonNumber :: Int
-- ^ Season sequence number. Remember that season 0 is sometimes
-- used to hold unreleased/unaired episodes.

, seasonAirDate :: Maybe Day
-- ^ The date this season began to air, if ever.

, seasonEpisodeCount :: Int
-- ^ Number of episodes in this season.

, seasonPosterPath :: Text
-- ^ Incomplete URL for poster image. See 'seasonPosterURLs'.

, seasonEpisodes :: [Episode]
-- ^ List of 'Episode's.

} deriving (Eq, Show)

--------------------------------------------------------------------------------
instance Ord Season where
compare a b = seasonNumber a `compare` seasonNumber b

--------------------------------------------------------------------------------
instance FromJSON Season where
parseJSON (Object v) =
Season <$> v .: "id"
<*> v .: "season_number" .!= 0
<*> v .:: "air_date"
<*> v .:? "episode_count" .!= 0
<*> v .: "poster_path" .!= ""
<*> v .:? "episodes" .!= []
parseJSON v = typeMismatch "Season" v

--------------------------------------------------------------------------------
-- | Return a list of URLs for all possible season posters.
seasonPosterURLs :: Configuration -> Season -> [Text]
seasonPosterURLs c s = posterURLs c (seasonPosterPath s)

+ 109
- 0
vendor/themoviedb/src/Network/API/TheMovieDB/Types/TV.hs View File

@@ -0,0 +1,109 @@
{-# LANGUAGE OverloadedStrings #-}

{-

This file is part of the Haskell package themoviedb. It is subject to
the license terms in the LICENSE file found in the top-level directory
of this distribution and at git://pmade.com/themoviedb/LICENSE. No
part of themoviedb package, including this file, may be copied,
modified, propagated, or distributed except according to the terms
contained in the LICENSE file.

-}

--------------------------------------------------------------------------------
module Network.API.TheMovieDB.Types.TV
( TV(..)
, tvPosterURLs
) where

--------------------------------------------------------------------------------
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (typeMismatch)
import Data.Text (Text)
import Data.Time (Day (..))
import Network.API.TheMovieDB.Internal.Configuration
import Network.API.TheMovieDB.Internal.Date
import Network.API.TheMovieDB.Internal.Types
import Network.API.TheMovieDB.Types.Genre
import Network.API.TheMovieDB.Types.Season

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
-- | Metadata for a TV series.
--
-- * The 'tvPosterPath' field is an incomplete URL. To construct a
-- complete URL you'll need to use the 'Configuration' type and the
-- 'tvPosterURLs' helper function.
data TV = TV
{ tvID :: ItemID
-- ^ TheMovieDB unique ID.

, tvName :: Text
-- ^ The name of the TV series.

, tvOverview :: Text
-- ^ Short description of the TV series.

, tvGenres :: [Genre]
-- ^ List of 'Genre's.

, tvPopularity :: Double
-- ^ Popularity ranking.

, tvPosterPath :: Text
-- ^ Incomplete URL for poster image. See 'tvPosterURLs'.

, tvFirstAirDate :: Maybe Day
-- ^ Air date for first episode.

, tvLastAirDate :: Maybe Day
-- ^ Air date for last episode.

, tvNumberOfSeasons :: Int
-- ^ Number of seasons for the TV series.

, tvNumberOfEpisodes :: Int
-- ^ Total number of episodes for all seasons.

, tvSeasons :: [Season]
-- ^ Information about each season.
--
-- The number of elements in this list may not match
-- 'tvNumberOfSeasons'. Information about special episodes and
-- unreleased episodes are usually kept in a 'Season' listed as
-- season 0. Therefore, the first element in this list might not
-- be season 1.

} deriving (Eq, Show)

--------------------------------------------------------------------------------
instance Ord TV where
compare a b = tvID a `compare` tvID b

--------------------------------------------------------------------------------
instance FromJSON TV where
parseJSON (Object v) =
TV <$> v .: "id"
<*> v .: "name"
<*> v .:? "overview" .!= ""
<*> v .:? "genres" .!= []
<*> v .:? "popularity" .!= 0.0
<*> v .:? "poster_path" .!= ""
<*> v .:: "first_air_date"
<*> v .:: "last_air_date"
<*> v .:? "number_of_seasons" .!= 0
<*> v .:? "number_of_episodes" .!= 0
<*> v .:? "seasons" .!= []
parseJSON v = typeMismatch "TV" v

--------------------------------------------------------------------------------
-- | Return a list of URLs for all possible TV posters.
tvPosterURLs :: Configuration -> TV -> [Text]
tvPosterURLs c m = posterURLs c (tvPosterPath m)

+ 15
- 0
vendor/themoviedb/test/Main.hs View File

@@ -0,0 +1,15 @@
--------------------------------------------------------------------------------
module Main (main) where

--------------------------------------------------------------------------------
import qualified MovieTest as M
import qualified TVTest as T
import Test.Tasty

--------------------------------------------------------------------------------
tests :: TestTree
tests = testGroup "Tests" [ M.tests, T.tests ]

--------------------------------------------------------------------------------
main :: IO ()
main = defaultMain tests

+ 73
- 0
vendor/themoviedb/test/MovieTest.hs View File

@@ -0,0 +1,73 @@
{-# LANGUAGE OverloadedStrings #-}

--------------------------------------------------------------------------------
module MovieTest (tests) where

--------------------------------------------------------------------------------
import Test.Tasty
import Test.Tasty.HUnit
import TestHelper

--------------------------------------------------------------------------------
import qualified Data.Text as T
import Network.API.TheMovieDB
import Network.API.TheMovieDB.Internal.TheMovieDB

--------------------------------------------------------------------------------
testSearchMovie :: Assertion
testSearchMovie = do
movies <- fakeTMDB "test/search-good.json" (searchMovies T.empty)
assertEqual "length" 8 (length movies)

--------------------------------------------------------------------------------
testMoviePosterURLs :: Assertion
testMoviePosterURLs = do
cfg <- fakeTMDB "test/config-good.json" config
movie <- fakeTMDB "test/movie-good.json" (fetchMovie 0)
let urls = moviePosterURLs cfg movie
poster = "http://cf2.imgobject.com/t/p/w92/pTpxQB1N0waaSc3OSn0e9oc8kx9.jpg"
assertEqual "length" 6 (length urls)
assertEqual "url" poster (head urls)

--------------------------------------------------------------------------------
goodMovieFieldsTest :: Assertion
goodMovieFieldsTest = do
movie <- fakeTMDB "test/movie-good.json" (fetchMovie 0)
assertEqual "movieID" 105 (movieID movie)
assertEqual "movieTitle" "Back to the Future" (movieTitle movie)
assertBool "movieOverview" $ "Eighties teenager" `T.isPrefixOf` movieOverview movie
assertEqual "movieGenres" 4 (length $ movieGenres movie)
assertEqual "moviePopularity" 80329.688 $ moviePopularity movie
assertEqual "moviePosterPath" "/pTpxQB1N0waaSc3OSn0e9oc8kx9.jpg" $ moviePosterPath movie
assertEqual "movieReleaseDate" (mkDay 1985 7 3) (movieReleaseDate movie)
assertBool "movieAdult" $ not (movieAdult movie)
assertEqual "movieIMDB" "tt0088763" $ movieIMDB movie
assertEqual "movieRunTime" 116 $ movieRunTime movie

--------------------------------------------------------------------------------
badMovieJSONTest :: Assertion
badMovieJSONTest = do
result <- runTheMovieDBWithRequestFunction
(fileRequest "test/movie-bad.json") (fetchMovie 0)

case result of
Left (ResponseParseError _ _) -> return ()
_ -> assertFailure "JSON should have been bad"

--------------------------------------------------------------------------------
shouldHaveNetworkErrorTest :: Assertion
shouldHaveNetworkErrorTest = do
result <- runTheMovieDBWithRequestFunction fakeNetworkError (fetchMovie 0)
case result of
Left (ServiceError _) -> return ()
_ -> assertFailure "should have network error"

--------------------------------------------------------------------------------
tests :: TestTree
tests = testGroup "Movies"
[ testCase "All movie fields are parsed" goodMovieFieldsTest
, testCase "Failure with bad JSON" badMovieJSONTest
, testCase "Propagate network failure" shouldHaveNetworkErrorTest
, testCase "Searching movies" testSearchMovie
, testCase "Movie poster URLs" testMoviePosterURLs
]

+ 78
- 0
vendor/themoviedb/test/TVTest.hs View File

@@ -0,0 +1,78 @@
{-# LANGUAGE OverloadedStrings #-}

--------------------------------------------------------------------------------
module TVTest (tests) where

--------------------------------------------------------------------------------
import Test.Tasty
import Test.Tasty.HUnit
import TestHelper

--------------------------------------------------------------------------------
import qualified Data.Text as T
import Network.API.TheMovieDB

--------------------------------------------------------------------------------
testTVBasicFields :: TV -> Assertion
testTVBasicFields tv = do
assertEqual "id" 1437 (tvID tv)
assertEqual "name" "Firefly" (tvName tv)
assertEqual "poster" "/mWNadwBZIx8NyEw4smGftYtHHrE.jpg" (tvPosterPath tv)
assertEqual "aired" (mkDay 2002 12 20) (tvFirstAirDate tv)

--------------------------------------------------------------------------------
testSearchTV :: Assertion
testSearchTV = do
tvs <- fakeTMDB "test/search-tv-good.json" (searchTV T.empty)
assertEqual "length" 1 (length tvs)
mapM_ testTVBasicFields tvs

--------------------------------------------------------------------------------
testFetchTV :: Assertion
testFetchTV = do
tv <- fakeTMDB "test/tv-good.json" (fetchTV 0)
testTVBasicFields tv
assertEqual "genres" 2 (length $ tvGenres tv)
assertEqual "seasons" 1 (tvNumberOfSeasons tv)
assertEqual "episodes" 13 (tvNumberOfEpisodes tv)
assertEqual "season len" 2 (length $ tvSeasons tv)

--------------------------------------------------------------------------------
testFetchSeason :: Assertion
testFetchSeason = do
season <- fakeTMDB "test/season-good.json" (fetchTVSeason 0 0)
assertEqual "length" 14 (length $ seasonEpisodes season)

--------------------------------------------------------------------------------
testSeasonPoster :: Assertion
testSeasonPoster = do
cfg <- fakeTMDB "test/config-good.json" config
season <- fakeTMDB "test/season-good.json" (fetchTVSeason 0 0)

let expect = "http://cf2.imgobject.com/t/p/w92/2dxsbVMoxsYH0Pta2mbFjF7mhHr.jpg"
urls = seasonPosterURLs cfg season

assertEqual "length" 6 (length urls)
assertEqual "poster" expect (head urls)

--------------------------------------------------------------------------------
testTVPoster :: Assertion
testTVPoster = do
cfg <- fakeTMDB "test/config-good.json" config
tv <- fakeTMDB "test/tv-good.json" (fetchTV 0)

let expect = "http://cf2.imgobject.com/t/p/w92/mWNadwBZIx8NyEw4smGftYtHHrE.jpg"
urls = tvPosterURLs cfg tv

assertEqual "length" 6 (length urls)
assertEqual "poster" expect (head urls)

--------------------------------------------------------------------------------
tests :: TestTree
tests = testGroup "TV"
[ testCase "Search fields" testSearchTV
, testCase "Fetch fields" testFetchTV
, testCase "Season fields" testFetchSeason
, testCase "Season Poster" testSeasonPoster
, testCase "TV Poster" testTVPoster
]

+ 42
- 0
vendor/themoviedb/test/TestHelper.hs View File

@@ -0,0 +1,42 @@
--------------------------------------------------------------------------------
module TestHelper
( fakeTMDB
, fileRequest
, fakeNetworkError
, mkDay
) where

--------------------------------------------------------------------------------
import Control.Applicative
import qualified Data.ByteString.Lazy as B
import Data.Time (Day (..), fromGregorian)
import Network.API.TheMovieDB.Internal.TheMovieDB
import Network.API.TheMovieDB.Internal.Types
import Test.Tasty.HUnit

--------------------------------------------------------------------------------
-- The following is a kludge to avoid the "redundant import" warning
-- when using GHC >= 7.10.x. This should be removed after we decide
-- to stop supporting GHC < 7.10.x.
import Prelude

--------------------------------------------------------------------------------
fakeTMDB :: FilePath -> TheMovieDB a -> IO a
fakeTMDB path m = do
result <- runTheMovieDBWithRequestFunction (fileRequest path) m

case result of
Left e -> assertFailure (show e) >> fail (show e)
Right a -> return a

--------------------------------------------------------------------------------
fileRequest :: FilePath -> RequestFunction
fileRequest path _ _ = Right <$> B.readFile path

--------------------------------------------------------------------------------
fakeNetworkError :: RequestFunction
fakeNetworkError _ _ = return $ Left $ ServiceError "fake outage"

--------------------------------------------------------------------------------
mkDay :: Integer -> Int -> Int -> Maybe Day
mkDay y m d = Just (fromGregorian y m d)

+ 1
- 0
vendor/themoviedb/test/config-good.json View File

@@ -0,0 +1 @@
{"images":{"base_url":"http://cf2.imgobject.com/t/p/","secure_base_url":"https://d1zm4mmpsrckwj.cloudfront.net/t/p/","poster_sizes":["w92","w154","w185","w342","w500","original"],"backdrop_sizes":["w300","w780","w1280","original"],"profile_sizes":["w45","w185","h632","original"],"logo_sizes":["w45","w92","w154","w185","w300","w500","original"]},"change_keys":["adult","also_known_as","alternative_titles","biography","birthday","budget","cast","character_names","crew","deathday","general","genres","homepage","images","imdb_id","name","original_title","overview","plot_keywords","production_companies","production_countries","releases","revenue","runtime","spoken_languages","status","tagline","title","trailers","translations"]}

+ 1
- 0
vendor/themoviedb/test/movie-bad.json View File

@@ -0,0 +1 @@
{"adult":1,"backdrop_path":"/x4N74cycZvKu5k3KDERJay4ajR3.jpg","belongs_to_collection":{"id":264,"name":"Back to the Future Collection","poster_path":"/qdVjh8PWGWqbssVqdwZIgr7Ckts.jpg","backdrop_path":"/c9C9Pg2QctyjZHRmS0P8rZg1OTA.jpg"},"budget":19000000,"genres":[{"id":12,"name":"Adventure"},{"id":35,"name":"Comedy"},{"id":878,"name":"Science Fiction"},{"id":10751,"name":"Family"}],"homepage":"http://www.bttfmovie.com/","id":105,"imdb_id":"tt0088763","original_title":"Back to the Future","overview":"Eighties teenager Marty McFly is accidentally sent back in time to 1955, inadvertently disrupting his parents' first meeting and attracting his mother's romantic interest. Marty must repair the damage to history by rekindling his parents' romance and - with the help of his eccentric inventor friend Doc Brown - returning to 1985.","popularity":80329.688,"poster_path":"/pTpxQB1N0waaSc3OSn0e9oc8kx9.jpg","production_companies":[{"name":"Universal Pictures","id":33},{"name":"Amblin Entertainment","id":56}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"1985-07-03","revenue":381109762,"runtime":116,"spoken_languages":[{"iso_639_1":"en","name":"English"}],"status":"Released","tagline":"He's the only kid ever to get into trouble before he was born.","title":"Back to the Future","vote_average":8.9,"vote_count":123}

+ 1
- 0
vendor/themoviedb/test/movie-good.json View File

@@ -0,0 +1 @@
{"adult":false,"backdrop_path":"/x4N74cycZvKu5k3KDERJay4ajR3.jpg","belongs_to_collection":{"id":264,"name":"Back to the Future Collection","poster_path":"/qdVjh8PWGWqbssVqdwZIgr7Ckts.jpg","backdrop_path":"/c9C9Pg2QctyjZHRmS0P8rZg1OTA.jpg"},"budget":19000000,"genres":[{"id":12,"name":"Adventure"},{"id":35,"name":"Comedy"},{"id":878,"name":"Science Fiction"},{"id":10751,"name":"Family"}],"homepage":"http://www.bttfmovie.com/","id":105,"imdb_id":"tt0088763","original_title":"Back to the Future","overview":"Eighties teenager Marty McFly is accidentally sent back in time to 1955, inadvertently disrupting his parents' first meeting and attracting his mother's romantic interest. Marty must repair the damage to history by rekindling his parents' romance and - with the help of his eccentric inventor friend Doc Brown - returning to 1985.","popularity":80329.688,"poster_path":"/pTpxQB1N0waaSc3OSn0e9oc8kx9.jpg","production_companies":[{"name":"Universal Pictures","id":33},{"name":"Amblin Entertainment","id":56}],"production_countries":[{"iso_3166_1":"US","name":"United States of America"}],"release_date":"1985-07-03","revenue":381109762,"runtime":116,"spoken_languages":[{"iso_639_1":"en","name":"English"}],"status":"Released","tagline":"He's the only kid ever to get into trouble before he was born.","title":"Back to the Future","vote_average":8.9,"vote_count":123}

+ 1
- 0
vendor/themoviedb/test/search-good.json View File

@@ -0,0 +1 @@
{"page":1,"results":[{"adult":false,"backdrop_path":"/x4N74cycZvKu5k3KDERJay4ajR3.jpg","id":105,"original_title":"Back to the Future","release_date":"1985-07-03","poster_path":"/pTpxQB1N0waaSc3OSn0e9oc8kx9.jpg","popularity":80329.688,"title":"Back to the Future","vote_average":8.9,"vote_count":123},{"adult":false,"backdrop_path":"/snLFUFzWUZCdYkAbhZlaGJxiY3I.jpg","id":165,"original_title":"Back to the Future Part II","release_date":"1989-11-20","poster_path":"/k5dzvCQkXU2CAhLtlj9BHE7xmyK.jpg","popularity":11893.083,"title":"Back to the Future Part II","vote_average":8.4,"vote_count":56},{"adult":false,"backdrop_path":"/pP2a4MBQbIeZMbErBWMjxTT5Npb.jpg","id":196,"original_title":"Back to the Future Part III","release_date":"1990-05-25","poster_path":"/6DmgPTZYaug7QNDjOhUDWyjOQDl.jpg","popularity":11975.265,"title":"Back to the Future Part III","vote_average":8.4,"vote_count":59},{"adult":false,"backdrop_path":"/9gSVZIxWvFoEo03WylTHDSzpUvf.jpg","id":20803,"original_title":"Иван Васильевич меняет профессию","release_date":"","poster_path":"/f1y86qb0GAcUn0Vc7TQzglePxj8.jpg","popularity":0.576,"title":"Ivan Vasilievich: Back to the Future","vote_average":8.8,"vote_count":3},{"adult":false,"backdrop_path":"/4ag7bLf1edaEKuxKDQ5WB820PJw.jpg","id":12889,"original_title":"Futurama: The Beast with a Billion Backs","release_date":"2008-06-24","poster_path":"/8d1ljps74inNnsSP36iRjFpMbT2.jpg","popularity":3.424,"title":"Futurama: The Beast with a Billion Backs","vote_average":7.6,"vote_count":4},{"adult":false,"backdrop_path":null,"id":48499,"original_title":"Back to the Future Part 2 Behind-the-Scenes Special Presentation","release_date":"1989-01-01","poster_path":null,"popularity":0.011,"title":"Back to the Future Part 2 Behind-the-Scenes Special Presentation","vote_average":0.0,"vote_count":0},{"adult":false,"backdrop_path":null,"id":48501,"original_title":"Back to the Future: Making the Trilogy","release_date":"2002-01-01","poster_path":null,"popularity":0.01,"title":"Back to the Future: Making the Trilogy","vote_average":0.0,"vote_count":0},{"adult":false,"backdrop_path":null,"id":113268,"original_title":"The Secrets of the Back to the Future Trilogy","release_date":"1990-06-12","poster_path":"/sXxrpdsuyDDam1Jk2OSKTTEubXR.jpg","popularity":0.006,"title":"The Secrets of the Back to the Future Trilogy","vote_average":0.0,"vote_count":0}],"total_pages":1,"total_results":8}

+ 1
- 0
vendor/themoviedb/test/search-tv-good.json View File

@@ -0,0 +1 @@
{"page":1,"results":[{"backdrop_path":"/qlJB8bkK1JXAQ0m02OYS1ArS6DZ.jpg","id":1437,"original_name":"Firefly","first_air_date":"2002-12-20","origin_country":["US"],"poster_path":"/mWNadwBZIx8NyEw4smGftYtHHrE.jpg","popularity":2.61700779681977,"name":"Firefly","vote_average":8.9,"vote_count":55}],"total_pages":1,"total_results":2}

+ 1
- 0
vendor/themoviedb/test/season-good.json
File diff suppressed because it is too large
View File


+ 1
- 0
vendor/themoviedb/test/tv-good.json View File

@@ -0,0 +1 @@
{"backdrop_path":"/qlJB8bkK1JXAQ0m02OYS1ArS6DZ.jpg","created_by":[{"id":12891,"name":"Joss Whedon","profile_path":"/n2x16sVDgj46PabFgJ0jvgjqxWl.jpg"}],"episode_run_time":[45,60,42,44],"first_air_date":"2002-12-20","genres":[{"id":18,"name":"Drama"},{"id":10765,"name":"Sci-Fi & Fantasy"}],"homepage":"","id":1437,"in_production":false,"languages":["en"],"last_air_date":"2002-12-13","name":"Firefly","networks":[{"id":19,"name":"Fox Broadcasting Company"}],"number_of_episodes":13,"number_of_seasons":1,"origin_country":["US"],"original_language":"en","original_name":"Firefly","overview":"Firefly is an American space western drama television series created by writer and director Joss Whedon, under his Mutant Enemy Productions label. The series is set in the year 2517, after the arrival of humans in a new star system, and follows the adventures of the renegade crew of Serenity, a \"Firefly-class\" spaceship. The ensemble cast portrays the nine characters who live on Serenity. Whedon pitched the show as \"nine people looking into the blackness of space and seeing nine different things\".\n\nThe show explores the lives of a group of people who fought on the losing side of a civil war and others who now make a living on the outskirts of society, as part of the pioneer culture that exists on the fringes of their star system. In this future, the only two surviving superpowers, the United States and China, fused to form the central federal government, called the Alliance, resulting in the fusion of the two cultures. According to Whedon's vision, \"nothing will change in the future: technology will advance, but we will still have the same political, moral, and ethical problems as today\".","popularity":2.61700779681977,"poster_path":"/mWNadwBZIx8NyEw4smGftYtHHrE.jpg","production_companies":[],"seasons":[{"air_date":"2005-09-30","episode_count":4,"id":3847,"poster_path":"/oMy3GEeWT14LRjTTFWwlc4uQld1.jpg","season_number":0},{"air_date":"2002-12-20","episode_count":14,"id":3846,"poster_path":"/2dxsbVMoxsYH0Pta2mbFjF7mhHr.jpg","season_number":1}],"status":"Ended","type":"Scripted","vote_average":8.9,"vote_count":55}

+ 116
- 0
vendor/themoviedb/themoviedb.cabal View File

@@ -0,0 +1,116 @@
--------------------------------------------------------------------------------
name: themoviedb
version: 1.1.1.0
synopsis: Haskell API bindings for http://themoviedb.org
homepage: http://github.com/pjones/themoviedb
bug-reports: http://github.com/pjones/themoviedb/issues
license: MIT
license-file: LICENSE
author: Peter Jones <pjones@devalot.com>
maintainer: Peter Jones <pjones@devalot.com>
copyright: Copyright: (c) 2012-2015 Peter Jones
category: Network, API
stability: experimental
tested-with: GHC == 7.8.4, GHC == 7.10.1
build-type: Simple
cabal-version: >=1.10
description: This library provides functions for retrieving metadata
from the <http://TheMovieDB.org> API. Documentation
can be found in the "Network.API.TheMovieDB" module.

--------------------------------------------------------------------------------
extra-source-files:
CHANGES
README.md
TODO.org
test/*.json

--------------------------------------------------------------------------------
source-repository head
type: git
location: git://github.com/pjones/themoviedb.git

--------------------------------------------------------------------------------
flag maintainer
description: Enable settings for the package maintainer.
manual: True
default: False

--------------------------------------------------------------------------------
library
exposed-modules:
Network.API.TheMovieDB
Network.API.TheMovieDB.Actions
Network.API.TheMovieDB.Internal.Configuration
Network.API.TheMovieDB.Internal.Date
Network.API.TheMovieDB.Internal.HTTP
Network.API.TheMovieDB.Internal.SearchResults
Network.API.TheMovieDB.Internal.TheMovieDB
Network.API.TheMovieDB.Internal.Types
Network.API.TheMovieDB.Types.Episode
Network.API.TheMovieDB.Types.Genre
Network.API.TheMovieDB.Types.Movie
Network.API.TheMovieDB.Types.Season
Network.API.TheMovieDB.Types.TV

default-language: Haskell2010
hs-source-dirs: src
ghc-options: -Wall -fwarn-incomplete-uni-patterns

if flag(maintainer)
ghc-options: -Werror
ghc-prof-options: -prof -auto-all

build-depends: aeson >= 0.6 && < 0.10
, base >= 4.6 && < 5.0
, binary >= 0.7 && < 0.8
, bytestring >= 0.9 && < 0.11
, either >= 4.3 && < 4.5
, http-client >= 0.4 && < 0.5
, http-client-tls >= 0.2.2 && < 0.3
, http-types >= 0.8 && < 0.9
, mtl >= 2.1 && < 2.3
, text >= 0.11 && < 1.3
, text-binary >= 0.1 && < 0.3
, time >= 1.2 && < 1.6
, time-locale-compat >= 0.1 && < 0.2
, transformers >= 0.3 && < 0.5

--------------------------------------------------------------------------------
executable tmdb
default-language: Haskell2010
hs-source-dirs: example
main-is: Main.hs

ghc-options: -Wall -fwarn-incomplete-uni-patterns

if flag(maintainer)
ghc-options: -Werror

build-depends: base
, text
, themoviedb
, time
, time-locale-compat
, transformers

--------------------------------------------------------------------------------
test-suite test
type: exitcode-stdio-1.0
default-language: Haskell2010
hs-source-dirs: test
main-is: Main.hs
other-modules: TestHelper MovieTest TVTest

ghc-options: -Wall -fwarn-incomplete-uni-patterns

if flag(maintainer)
ghc-options: -Werror

build-depends: base
, bytestring
, tasty >= 0.10 && < 0.11
, tasty-hunit >= 0.9 && < 0.10
, text
, themoviedb
, time

Loading…
Cancel
Save