about summary refs log tree commit diff
path: root/pkgs/profpatsch/query-album-streams/last-fm-api.nix
blob: 920c2bfb2c91d9b75e693a850196177248e20494 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
{ pkgs, getBins, writeExecline, writeHaskellInterpret }:
let

  lib = pkgs.lib;
  bins = getBins pkgs.httpie [ "http" ];

  develop = true;

  writeHaskell = name: { interpret ? false, withPackages }:
    if interpret
    then writeHaskellInterpret name { inherit withPackages; }
    else pkgs.writers.writeHaskell name { libraries = withPackages pkgs.haskellPackages; };

  # see https://hackage.haskell.org/package/aeson-schema-0.4.1.2/docs/Data-Aeson-Schema-Types.html#t:Schema
  # for the schema format.
  # The input is a json-encoding of that via quasi-quoter.
  json-schema-validator = name: schema: writeHaskell name {
    withPackages = hps: [ (pkgs.haskell.lib.doJailbreak (pkgs.haskell.lib.markUnbroken hps.aeson-schema)) hps.aeson ];
    interpret = develop;
  } ''
    {-# language QuasiQuotes #-}
    import qualified Data.ByteString.Lazy as BS
    import Data.Aeson (eitherDecode')
    import Data.Aeson.Schema
    import System.Exit (die, exitSuccess)

    main :: IO ()
    main = do
      stdin <- BS.getContents
      case (eitherDecode' stdin) of
        Left errs ->  die errs
        Right json -> do
          let val = validate mempty schema json
          if val == []
          then BS.putStr stdin >> exitSuccess
          else die (show val)

    schema :: Schema ()
    schema = [schemaQQ| ${lib.generators.toJSON {} schema} |]
  '';

  query-lastFm-album = writeExecline "query-lastFm-album" { readNArgs = 2; } [
    bins.http
      "GET"
      "https://ws.audioscrobbler.com/2.0/"
      "--"
      "api_key==\${1}"
      "method==album.search"
      "album==\${2}"
      "format==json"
  ];

  schema = {
    obj = { required ? true }: propsMap: {
      type = "object";
      inherit required;
      properties = propsMap;
    };

    arr = { required ? true }: itemsSchema: {
      type = "array";
      inherit required;
      items = itemsSchema;
    };
  };

  validator = json-schema-validator "last-fm-album-output" (with schema; obj {} {
    results = obj {} {
      albummatches = obj {} {
        album = arr {} (obj {} {
          name = { type = "string"; };
          artist = { type = "string"; };
        });
      };
    };
  });

  query-and-validate = writeExecline "validate-lastfm-album-response" { } [
    "pipeline" [ query-lastFm-album "$@" ]
    "if" [ validator ]
  ];


# in validator
in {
  inherit query-lastFm-album validator query-and-validate;
}