Skip to content

Instantly share code, notes, and snippets.

@williamthome
Forked from mworrell/m_omdb.erl
Last active May 5, 2022 07:16
Show Gist options
  • Save williamthome/58b31fdfd252d12ae39db105aef44c11 to your computer and use it in GitHub Desktop.
Save williamthome/58b31fdfd252d12ae39db105aef44c11 to your computer and use it in GitHub Desktop.
Zotonic 1.0 - Template model for the OMDB movie database - source code to accompany the documentation
-module(m_omdb).
-behaviour(zotonic_model).
-export([
m_get/3
]).
-include_lib("zotonic_core/include/zotonic.hrl").
-define(API_URL, "http://www.omdbapi.com/?").
-spec m_get(Keys, Msg, Context) -> Return when
Keys :: list(),
Msg :: zotonic_model:opt_msg(),
Return :: zotonic_model:return(),
Context:: z:context().
% Syntax: m.omdb.api_url
m_get([ <<"api_url">> | Rest ], _Msg, _Context) ->
{ok, {z_convert:to_binary(?API_URL), Rest}};
% Syntax: m.omdb["tt0123456789"]
m_get([ <<"tt", _/binary>> = Id | Rest ], _Msg, _Context) ->
{ok, {fetch_data([ {id, Id} ]), Rest}};
% Syntax: m.omdb["some title"]
m_get([ Title | Rest ], _Msg, _Context) when is_binary(Title) ->
{ok, {fetch_data([ {id, Id} ]), Rest}};
% Syntax: m.omdb.sometype["tt0123456789"]
m_get([ Type, <<"tt", _/binary>> = Id | Rest ], _Msg, _Context)
when Type =:= <<"movies">>;
Type =:= <<"series">>;
Type =:= <<"episode">> ->
{ok, {fetch_data([ {type, Type}, {id, Id} ]), _Msg, Rest}};
% Syntax: m.omdb.sometype[QueryString]
m_get([ Type, QueryString | Rest ], _Msg, _Context)
when Type =:= <<"movies">>;
Type =:= <<"series">>;
Type =:= <<"episode">> ->
{ok, {fetch_data([ {type, Type}, {title, QueryString} ]), Rest}};
% Syntax: m.omdb[{query QueryParams}]
% For m.omdb[{query title="Dollhouse"}], Query is: [{title,"Dollhouse"}]
m_get([ {query, Query} | Rest ], _Msg, _Context) ->
{ok {fetch_data(Query), Rest}};
% Syntax: m.omdb.sometype[{query QueryParams}]
% For m.omdb.series[{query title="Dollhouse"}], Query is: [{title,"Dollhouse"}] and Q is: [{type,"series"}]
m_get([ Type, {query, Query} | Rest ], _Msg, _Context)
when Type =:= <<"movies">>;
Type =:= <<"series">>;
Type =:= <<"episode">> ->
{ok, {fetch_data([ {type, Type} | Query ]), Rest}}.
-spec fetch_data(Query) -> list() when Query:: list().
fetch_data([]) ->
[{error, "Params missing"}];
fetch_data(Query) ->
case proplists:is_defined(title, Query) or proplists:is_defined(id, Query) of
false -> [{error, "Param id or title missing"}];
true ->
QueryParts = lists:map(fun(Q) ->
make_query_string(Q)
end, Query),
Url = ?API_URL ++ string:join(QueryParts, "&"),
case get_page_body(Url) of
{error, Error} ->
[{error, Error}];
Json ->
{struct, JsonData} = mochijson2:decode(Json),
lists:map(fun(D) ->
convert_data_prop(D)
end, JsonData)
end
end.
%% Translate query params id, title and type into parameters that OMDB wants
-spec make_query_string({Key, Value}) -> string() when
Key:: atom(),
Value:: binary() | string() | atom().
make_query_string({id, Id}) ->
"i=" ++ z_url:url_encode(Id);
make_query_string({title, Title}) ->
"t=" ++ z_url:url_encode(Title);
make_query_string({type, Type}) ->
"type=" ++ z_url:url_encode(Type);
make_query_string(_) ->
"".
%% Translate binary keys to atoms
-spec convert_data_prop({Key, Value}) -> {atom(), string()} when
Key:: binary(),
Value:: binary().
convert_data_prop({Key, Value}) ->
{z_convert:to_atom(string:to_lower(z_convert:to_list(Key))), Value}.
get_page_body(Url) ->
case httpc:request(get, {Url, []}, [], []) of
{ok, {_, Headers, Body}} ->
case content_length(Headers) of
0 -> {error, "No content"};
_ -> Body
end;
Error ->
{error, Error}
end.
content_length(Headers) ->
list_to_integer(proplists:get_value("content-length", Headers, "0")).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment