Current section
Files
Jump to
Current section
Files
src/telega@file.erl
-module(telega@file).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/telega/file.gleam").
-export([from_string/1, from_file/1, from_file_with_name/2, from_bytes/2, read_file/1, to_json_value/1, requires_multipart/1, get_attach_name/1, to_multipart_file/1, get_file_info/2, download_by_path/2, download_file/2, download_to_file/3]).
-export_type([media_input/0, multipart_file/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" File handling utilities for Telegram Bot API\n"
" Provides types and functions for working with files in media uploads\n"
).
-type media_input() :: {url, binary()} |
{file_id, binary()} |
{local_file, binary(), binary()} |
{bytes, bitstring(), binary(), binary()}.
-type multipart_file() :: {multipart_file,
binary(),
binary(),
bitstring(),
gleam@option:option(binary())}.
-file("src/telega/file.gleam", 33).
?DOC(" Creates a MediaInput from a string that could be URL or file ID\n").
-spec from_string(binary()) -> media_input().
from_string(Value) ->
case {gleam_stdlib:string_starts_with(Value, <<"http://"/utf8>>),
gleam_stdlib:string_starts_with(Value, <<"https://"/utf8>>)} of
{true, _} ->
{url, Value};
{_, true} ->
{url, Value};
{_, _} ->
{file_id, Value}
end.
-file("src/telega/file.gleam", 44).
?DOC(" Creates a MediaInput from a local file path\n").
-spec from_file(binary()) -> media_input().
from_file(Path) ->
Attach_name = <<"file_"/utf8,
(gleam@string:replace(Path, <<"/"/utf8>>, <<"_"/utf8>>))/binary>>,
{local_file, Path, Attach_name}.
-file("src/telega/file.gleam", 50).
?DOC(" Creates a MediaInput from a local file path with custom attach name\n").
-spec from_file_with_name(binary(), binary()) -> media_input().
from_file_with_name(Path, Attach_name) ->
{local_file, Path, Attach_name}.
-file("src/telega/file.gleam", 55).
?DOC(" Creates a MediaInput from bytes\n").
-spec from_bytes(bitstring(), binary()) -> media_input().
from_bytes(Data, Filename) ->
Attach_name = <<"bytes_"/utf8, Filename/binary>>,
{bytes, Data, Filename, Attach_name}.
-file("src/telega/file.gleam", 61).
?DOC(" Reads a file and creates a MediaInput with its contents\n").
-spec read_file(binary()) -> {ok, media_input()} |
{error, simplifile:file_error()}.
read_file(Path) ->
gleam@result:'try'(
simplifile_erl:read_bits(Path),
fun(Data) ->
Filename = case gleam@string:split(Path, <<"/"/utf8>>) of
[] ->
<<"file"/utf8>>;
Parts ->
case gleam@list:last(Parts) of
{ok, Name} ->
Name;
{error, _} ->
<<"file"/utf8>>
end
end,
{ok, from_bytes(Data, Filename)}
end
).
-file("src/telega/file.gleam", 77).
?DOC(
" Gets the string representation for JSON encoding\n"
" For local files and bytes, returns the attach:// reference\n"
).
-spec to_json_value(media_input()) -> binary().
to_json_value(Input) ->
case Input of
{url, Url} ->
Url;
{file_id, Id} ->
Id;
{local_file, _, Attach_name} ->
<<"attach://"/utf8, Attach_name/binary>>;
{bytes, _, _, Attach_name@1} ->
<<"attach://"/utf8, Attach_name@1/binary>>
end.
-file("src/telega/file.gleam", 87).
?DOC(" Checks if this MediaInput requires multipart upload\n").
-spec requires_multipart(media_input()) -> boolean().
requires_multipart(Input) ->
case Input of
{local_file, _, _} ->
true;
{bytes, _, _, _} ->
true;
{url, _} ->
false;
{file_id, _} ->
false
end.
-file("src/telega/file.gleam", 95).
?DOC(" Gets the attach name if this is a local file or bytes\n").
-spec get_attach_name(media_input()) -> gleam@option:option(binary()).
get_attach_name(Input) ->
case Input of
{local_file, _, Name} ->
{some, Name};
{bytes, _, _, Name} ->
{some, Name};
_ ->
none
end.
-file("src/telega/file.gleam", 158).
?DOC(" Simple MIME type detection based on file extension\n").
-spec detect_mime_type(binary()) -> gleam@option:option(binary()).
detect_mime_type(Filename) ->
Extension = case gleam@string:split(Filename, <<"."/utf8>>) of
[] ->
<<""/utf8>>;
Parts ->
case gleam@list:last(Parts) of
{ok, Ext} ->
string:lowercase(Ext);
{error, _} ->
<<""/utf8>>
end
end,
case Extension of
<<"jpg"/utf8>> ->
{some, <<"image/jpeg"/utf8>>};
<<"jpeg"/utf8>> ->
{some, <<"image/jpeg"/utf8>>};
<<"png"/utf8>> ->
{some, <<"image/png"/utf8>>};
<<"gif"/utf8>> ->
{some, <<"image/gif"/utf8>>};
<<"webp"/utf8>> ->
{some, <<"image/webp"/utf8>>};
<<"mp4"/utf8>> ->
{some, <<"video/mp4"/utf8>>};
<<"avi"/utf8>> ->
{some, <<"video/x-msvideo"/utf8>>};
<<"mkv"/utf8>> ->
{some, <<"video/x-matroska"/utf8>>};
<<"webm"/utf8>> ->
{some, <<"video/webm"/utf8>>};
<<"mp3"/utf8>> ->
{some, <<"audio/mpeg"/utf8>>};
<<"ogg"/utf8>> ->
{some, <<"audio/ogg"/utf8>>};
<<"wav"/utf8>> ->
{some, <<"audio/wav"/utf8>>};
<<"pdf"/utf8>> ->
{some, <<"application/pdf"/utf8>>};
<<"zip"/utf8>> ->
{some, <<"application/zip"/utf8>>};
<<"json"/utf8>> ->
{some, <<"application/json"/utf8>>};
<<"xml"/utf8>> ->
{some, <<"application/xml"/utf8>>};
_ ->
none
end.
-file("src/telega/file.gleam", 117).
?DOC(" Converts MediaInput to MultipartFile for upload\n").
-spec to_multipart_file(media_input()) -> {ok,
gleam@option:option(multipart_file())} |
{error, simplifile:file_error()}.
to_multipart_file(Input) ->
case Input of
{url, _} ->
{ok, none};
{file_id, _} ->
{ok, none};
{local_file, Path, Attach_name} ->
gleam@result:'try'(
simplifile_erl:read_bits(Path),
fun(Content) ->
Filename = case gleam@string:split(Path, <<"/"/utf8>>) of
[] ->
<<"file"/utf8>>;
Parts ->
case gleam@list:last(Parts) of
{ok, Name} ->
Name;
{error, _} ->
<<"file"/utf8>>
end
end,
{ok,
{some,
{multipart_file,
Attach_name,
Filename,
Content,
detect_mime_type(Filename)}}}
end
);
{bytes, Data, Filename@1, Attach_name@1} ->
{ok,
{some,
{multipart_file,
Attach_name@1,
Filename@1,
Data,
detect_mime_type(Filename@1)}}}
end.
-file("src/telega/file.gleam", 261).
?DOC(" Gets file information without downloading\n").
-spec get_file_info(telega@client:telegram_client(), binary()) -> {ok,
telega@model@types:file()} |
{error, binary()}.
get_file_info(Client, File_id) ->
_pipe = telega@api:get_file(Client, File_id),
gleam@result:map_error(
_pipe,
fun(E) ->
<<"Failed to get file info: "/utf8,
(gleam@string:inspect(E))/binary>>
end
).
-file("src/telega/file.gleam", 270).
?DOC(" Builds the full URL for downloading a file from Telegram\n").
-spec build_file_url(telega@client:telegram_client(), binary()) -> binary().
build_file_url(Client, File_path) ->
Api_url = telega@client:get_api_url(Client),
Base_url = case Api_url of
<<"https://api.telegram.org/bot"/utf8>> ->
<<"https://api.telegram.org/file"/utf8>>;
Custom ->
case gleam_stdlib:string_ends_with(Custom, <<"/bot"/utf8>>) of
true ->
<<(gleam@string:drop_end(Custom, 4))/binary, "/file"/utf8>>;
false ->
<<Custom/binary, "/file"/utf8>>
end
end,
<<<<<<<<Base_url/binary, "/bot"/utf8>>/binary,
(telega@client:get_token(Client))/binary>>/binary,
"/"/utf8>>/binary,
File_path/binary>>.
-file("src/telega/file.gleam", 213).
?DOC(
" Downloads a file using its file_path from the File object.\n"
"\n"
" Requires a `FetchBitsClient` to be configured on the client\n"
" (via `client.set_fetch_bits_client`). Adapter packages like\n"
" `telega_httpc` configure this automatically.\n"
).
-spec download_by_path(telega@client:telegram_client(), binary()) -> {ok,
bitstring()} |
{error, binary()}.
download_by_path(Client, File_path) ->
Url = build_file_url(Client, File_path),
gleam@result:'try'(case telega@client:get_fetch_bits_client(Client) of
{some, F} ->
{ok, F};
none ->
{error,
<<"No FetchBitsClient configured. Use client.set_fetch_bits_client or an adapter like telega_httpc that provides one."/utf8>>}
end, fun(Fetch_bits) ->
gleam@result:'try'(
begin
_pipe = gleam@http@request:to(Url),
gleam@result:map_error(
_pipe,
fun(_) ->
<<"Failed to build request for: "/utf8, Url/binary>>
end
)
end,
fun(Req) ->
Bits_req = gleam@http@request:set_body(Req, <<>>),
gleam@result:'try'(
begin
_pipe@1 = Fetch_bits(Bits_req),
gleam@result:map_error(
_pipe@1,
fun(E) ->
<<<<<<"Failed to download file from: "/utf8,
Url/binary>>/binary,
" — "/utf8>>/binary,
(gleam@string:inspect(E))/binary>>
end
)
end,
fun(Resp) -> case erlang:element(2, Resp) of
200 ->
{ok, erlang:element(4, Resp)};
Status ->
{error,
<<"Download failed with status: "/utf8,
(erlang:integer_to_binary(Status))/binary>>}
end end
)
end
)
end).
-file("src/telega/file.gleam", 191).
?DOC(
" Downloads a file from Telegram servers\n"
" First gets the file path using getFile API, then downloads the actual file\n"
).
-spec download_file(telega@client:telegram_client(), binary()) -> {ok,
bitstring()} |
{error, binary()}.
download_file(Client, File_id) ->
gleam@result:'try'(
begin
_pipe = telega@api:get_file(Client, File_id),
gleam@result:map_error(
_pipe,
fun(E) ->
<<"Failed to get file info: "/utf8,
(gleam@string:inspect(E))/binary>>
end
)
end,
fun(File_info) -> case erlang:element(5, File_info) of
none ->
{error, <<"File path not available"/utf8>>};
{some, Path} ->
download_by_path(Client, Path)
end end
).
-file("src/telega/file.gleam", 249).
?DOC(" Downloads a file and saves it to disk\n").
-spec download_to_file(telega@client:telegram_client(), binary(), binary()) -> {ok,
nil} |
{error, binary()}.
download_to_file(Client, File_id, Save_path) ->
gleam@result:'try'(
download_file(Client, File_id),
fun(Content) -> _pipe = simplifile_erl:write_bits(Save_path, Content),
gleam@result:map_error(
_pipe,
fun(E) ->
<<"Failed to save file: "/utf8,
(gleam@string:inspect(E))/binary>>
end
) end
).