PageRenderTime 33ms CodeModel.GetById 7ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/modules/mod_twitter/filters/filter_twitter.erl

http://github.com/zotonic/zotonic
Erlang | 153 lines | 114 code | 20 blank | 19 comment | 0 complexity | 0e64ecf338876d39ac449404c02aeaa6 MD5 | raw file
  1%% @author Arjan Scherpenisse <arjan@scherpenisse.net>
  2%% @copyright 2010-2012 Arjan Scherpenisse
  3%% @doc 'twitter' filter, make a tweet from twitter look nice
  4
  5%% Copyright 2010-2012 Arjan Scherpenisse
  6%%
  7%% Licensed under the Apache License, Version 2.0 (the "License");
  8%% you may not use this file except in compliance with the License.
  9%% You may obtain a copy of the License at
 10%% 
 11%%     http://www.apache.org/licenses/LICENSE-2.0
 12%% 
 13%% Unless required by applicable law or agreed to in writing, software
 14%% distributed under the License is distributed on an "AS IS" BASIS,
 15%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16%% See the License for the specific language governing permissions and
 17%% limitations under the License.
 18
 19-module(filter_twitter).
 20-export([
 21    twitter/2,
 22    twitter/3
 23]).
 24
 25%% Number of characters for truncating an url
 26-define(URL_TRUNCATE, 50).
 27
 28
 29twitter(undefined, _Context) -> undefined;
 30twitter(<<"<p>", _/binary>> = Input, _Context) -> Input;
 31twitter(Input, Context) when is_list(Input) ->
 32    twitter(z_convert:to_binary(Input), Context);
 33twitter(Input, Context) when is_binary(Input) -> iolist_to_binary(twitter1(Input, 0, [], Context));
 34twitter(Input, _Context) -> Input.
 35
 36%% @doc filter with options, only option for now: url_location (follows url shorteners)
 37twitter(Input, Options, Context) ->
 38    twitter1(Input, 0, Options, Context).
 39    
 40
 41twitter1(Input, Index, Opts, Context) when is_binary(Input) ->
 42    case Input of
 43        <<Pre:Index/binary, "http://", Post/binary>> ->  [Pre, twitter1_url(<<"http://">>, Post, 0, Opts, Context)];
 44        <<Pre:Index/binary, "https://", Post/binary>> -> [Pre, twitter1_url(<<"https://">>, Post, 0, Opts, Context)];
 45        <<Pre:Index/binary, "ftp://", Post/binary>> ->   [Pre, twitter1_url(<<"ftp://">>, Post, 0, Opts, Context)];
 46        <<Pre:Index/binary, "ftps://", Post/binary>> ->  [Pre, twitter1_url(<<"ftps://">>, Post, 0, Opts, Context)];
 47        <<Pre:Index/binary, "mailto:", Post/binary>> ->  [Pre, twitter1_url(<<"mailto:">>, Post, 0, Opts, Context)];
 48        <<Pre:Index/binary, $&, $#, Post/binary>> ->     [Pre, $&, $#, twitter1(Post, 0, Opts, Context)];
 49        <<Pre:Index/binary, $@, Post/binary>> ->         [Pre, twitter1_at(Post, 0, Opts, Context)];
 50        <<Pre:Index/binary, $#, Post/binary>> ->         [Pre, twitter1_hash(Post, 0, Opts, Context)];
 51        <<_:Index/binary, _/binary>> -> twitter1(Input, Index + 1, Opts, Context);
 52        _ -> Input
 53    end.
 54
 55twitter1_url(Pre, Input, Index, Opts, Context) ->
 56    case Input of
 57        <<_:Index/binary, "&#38;", _/binary>> ->
 58            twitter1_url(Pre, Input, Index + 5, Opts, Context);
 59        <<_:Index/binary, "&amp;", _/binary>> ->
 60            twitter1_url(Pre, Input, Index + 5, Opts, Context);
 61        <<Url:Index/binary, Char, Post/binary>> ->
 62            case Char /= $& andalso z_url:url_valid_char(Char) of
 63                true ->  twitter1_url(Pre, Input, Index + 1, Opts, Context);
 64                false -> twitter1_url_anchor(Pre, Url, <<Char, Post/binary>>, Opts, Context)
 65            end;
 66        <<Url:Index/binary>> ->
 67            twitter1_url_anchor(Pre, Url, <<>>, Opts, Context);
 68        _ ->
 69            Input
 70    end.
 71
 72    twitter1_url_anchor(Pre, <<>>, Post, Opts, Context) ->
 73        [Pre, twitter1(Post, 0, Opts, Context)];
 74    twitter1_url_anchor(Pre, Url, Post, Opts, Context) ->
 75        Length1 = size(Url) - 1,
 76        <<Url1:Length1/binary,LastChar>> = Url,
 77        Html = case is_url_truncatable(LastChar) of
 78                  true -> [ twitter1_url_html(Pre, Url1, Opts), LastChar];
 79                  false -> twitter1_url_html(Pre, Url, Opts)
 80               end,
 81        [Html, twitter1(Post, 0, Opts, Context)].
 82
 83
 84    % Create the html link, follow the url to remove any url shortener.
 85    twitter1_url_html(Pre, Url, Opts) ->
 86        case proplists:get_value(url_location, Opts, false) of
 87            true -> 
 88                Url2 = z_url:location(<<Pre/binary,Url/binary>>),
 89                Text = z_string:truncate(z_url:remove_protocol(Url2), ?URL_TRUNCATE),
 90                ["<a href=\"", Url2, "\">", Text, "</a>"];
 91            false ->
 92                ["<a href=\"", Pre, Url, "\">", Url, "</a>"]
 93        end.
 94
 95
 96    is_url_truncatable($.) -> true;
 97    is_url_truncatable($;) -> true;
 98    is_url_truncatable($#) -> true;
 99    is_url_truncatable($,) -> true;
100    is_url_truncatable($') -> true;
101    is_url_truncatable($") -> true;
102    is_url_truncatable($?) -> true;
103    is_url_truncatable($!) -> true;
104    is_url_truncatable($/) -> true;
105    is_url_truncatable($+) -> true;
106    is_url_truncatable($%) -> true;
107    is_url_truncatable(_) -> false.
108
109
110twitter1_at(Input, Index, Opts, Context) ->
111    case Input of
112        <<Name:Index/binary, Char, Post/binary>> when not(Char >= $a andalso Char =< $z
113                                                          orelse
114                                                          Char >= $A andalso Char =< $Z
115                                                          orelse
116                                                          Char >= $0 andalso Char =< $9
117                                                          orelse Char =:= $_ orelse Char =:= $.
118                                                         ) ->
119            Html = twitter_at_url(Name),
120            [Html, twitter1(<<Char, Post/binary>>, 0, Opts, Context)];
121        <<Name:Index/binary>> ->
122            twitter_at_url(Name);
123        <<_:Index/binary, _/binary>> ->
124            twitter1_at(Input, Index + 1, Opts, Context);
125        _ ->
126            Input
127    end.
128
129twitter_at_url(Name) ->
130    ["<a href=\"http://twitter.com/", Name, "\">@", Name, "</a>"].
131
132twitter1_hash(Input, Index, Opts, Context) ->
133    case Input of
134        <<Name:Index/binary, Char, Post/binary>> when not(Char >= $a andalso Char =< $z
135                                                          orelse
136                                                          Char >= $A andalso Char =< $Z
137                                                          orelse
138                                                          Char >= $0 andalso Char =< $9
139                                                          orelse Char =:= $_ orelse Char =:= $.
140                                                         ) ->
141            Html = twitter_hash_url(Name),
142            [[Html, Char], twitter1(Post, 0, Opts, Context)];
143        <<Name:Index/binary>> ->
144            twitter_hash_url(Name);
145        <<_:Index/binary, _/binary>>  ->
146            twitter1_hash(Input, Index + 1, Opts, Context);
147        _ ->
148            Input
149    end.
150
151twitter_hash_url(Hash) ->
152    ["<a href=\"http://twitter.com/#search?q=%23", Hash, "\">#", Hash, "</a>"].
153