Source file Plugin_movie.ml
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
open Calculon
open Lwt.Infix
open CCFun
let get_body uri =
Lwt_preemptive.detach
(fun () ->
Curly.run ~args:["-L"]
Curly.(Request.make ~url:(Uri.to_string uri) ~meth:`GET ()))
()
>>= function
| Ok {Curly.Response. body;_ } -> Lwt.return body
| Error e -> Lwt.fail (Failure (Format.asprintf "%a" Curly.Error.pp e))
type query =
| Movie of string
| Serie of string
let query_movie s = Movie s
let query_serie s = Serie s
let api_prefix = Uri.of_string "http://omdbapi.com/"
let make_search_uri query =
let title, kind =
match query with
| Movie title -> title, "movie"
| Serie title -> title, "series"
in
Uri.add_query_params' api_prefix ["v", "1"; "r", "json"; "s", title; "type", kind ]
let make_get_uri id =
Uri.add_query_params' api_prefix ["v", "1"; "r", "json"; "i", id ]
let parse_search body =
try
Movie_j.search_result_of_string body
with exn ->
Printf.printf "invalid imdb search response (%s) : %S" (Printexc.to_string exn) body;
{ Movie_t.results = []; count = 0 }
let parse_get body =
try
CCOpt.pure @@ Movie_j.query_entry_of_string body
with exn ->
Printf.printf "invalid imdb query response (%s) : %S" (Printexc.to_string exn) body;
None
let search query =
make_search_uri query |> get_body >|=
parse_search
let get_infos id =
make_get_uri id |> get_body >|= parse_get
let ellipsis n s =
if String.length s > n then begin
try
let last = String.rindex_from s n ' ' in
let s = Bytes.sub (Bytes.of_string s) 0 (last + 4) in
Bytes.blit_string "... " 0 s last 4;
Bytes.to_string s
with Not_found ->
CCString.take n s
end else
s
let make_imdb_url id =
String.concat "/" ["http://www.imdb.com/title"; id ]
let show_result ?buffer (title, r) =
let open Printf in
let open CCOpt in
let open Movie_t in
let buffer = get_lazy (fun () -> Buffer.create 10) buffer in
Buffer.clear buffer;
bprintf buffer "%S " (ellipsis 50 title);
iter (bprintf buffer "(%d) ") r.year;
bprintf buffer "- %.1f " r.rating;
iter (Buffer.add_string buffer % ellipsis 150) r.plot;
Buffer.add_string buffer @@ make_imdb_url r.id;
Buffer.contents buffer
let title { Movie_t.s_title; _ } = s_title
let get_id { Movie_t.s_id; _ } = s_id
let refine_results ?(n=3) results =
results.Movie_t.results |>
CCList.filter (CCOpt.is_some % title) |>
CCList.take n |>
CCList.map get_id |>
Lwt_list.filter_map_p get_infos
let format_seq ?n results =
let buffer = Buffer.create 100 in
let title { Movie_t.title; _ } = title in
refine_results ?n results >>= fun results ->
results |>
CCList.filter_map (fun r -> CCOpt.map (flip CCPair.make r) @@ title r) |>
CCList.map (show_result ~buffer) |>
Lwt.return
let mk_movie_cmd cmd q_of_str =
Command.make_simple_l
~descr:"look for movies/series" ~prio:10 ~cmd
(fun _ s ->
String.trim s |>
q_of_str |>
search >>=
format_seq
)
let cmd_film = mk_movie_cmd "film" query_movie
let cmd_serie = mk_movie_cmd "serie" query_serie
let plugin =
[ cmd_film;
cmd_serie;
] |> Plugin.of_cmds