Current section
Files
Jump to
Current section
Files
lib/broadcast.ex
defmodule Broadcast do
@moduledoc """
Broadcast to multiple social media domains simultaneously through a unified interface.
"""
@doc """
Posts a given status message to both Mastodon and Bluesky platforms.
## Parameters
The function takes a map containing the necessary parameters for posting:
* `:status` - a string representing the status message to be posted.
* `:mastodon_access_token` - the access token for the Mastodon account for authentication.
* `:bluesky_handle` - the handle (username) of the Bluesky account to post the status.
* `:bluesky_password` - the password for the Bluesky account for authentication.
## Examples
iex> post_all(%{
...> status: "Hello World!",
...> mastodon_access_token: "your_mastodon_token",
...> bluesky_handle: "your_bluesky_handle",
...> bluesky_password: "your_bluesky_password"
...> })
{:ok, [mastodon_result, bluesky_result]}
"""
def post_all(
%{
status: status,
mastodon_access_token: mastodon_access_token,
bluesky_handle: bluesky_handle,
bluesky_password: bluesky_password
}
) do
mastodon_result = post_mastodon_status(mastodon_access_token, status)
bluesky_result = post_bluesky_status(bluesky_handle, bluesky_password, status)
{:ok, [mastodon_result, bluesky_result]}
end
@doc """
Posts a status update to the Mastodon social media platform.
## Parameters
* `access_token` - The bearer token used for authentication with the Mastodon API.
* `status` - The string representing the status update to be posted.
## Examples
iex> post_mastodon_status("your_access_token", "Hello, Mastodon!")
{:ok, response}
"""
def post_mastodon_status(access_token, status) do
base_url = "https://mastodon.social/api/v1/statuses"
headers = [
{"Authorization", "Bearer #{access_token}"},
{"Idempotency-Key", status},
{"Content-Type", "application/json"}
]
params = %{"status" => status}
post(base_url, params, headers)
end
@doc """
Posts a status update to the Bluesky social network.
## Parameters
* `handle`: a string representing the user identifier on the Bluesky platform.
* `password`: a string containing the user password for authentication.
* `status`: a string representing the status update to be posted.
## Examples
iex> post_bluesky_status("your_user_handle", "your_password", "Hello, Mastodon!")
{:ok, response}
"""
def post_bluesky_status(handle, password, status) do
# authenticate
response =
post(
"https://bsky.social/xrpc/com.atproto.server.createSession",
%{
"identifier" => handle,
"password" => password
},
[{"Content-Type", "application/json"}]
)
case response do
{:ok, raw} ->
json = raw |> Jason.decode!()
access_token = json |> Map.get("accessJwt")
# post the status
post(
"https://bsky.social/xrpc/com.atproto.repo.createRecord",
%{
"repo" => handle,
"collection" => "app.bsky.feed.post",
"record" => %{
"text" => status,
"createdAt" => datetime_now()
}
},
[
{"Authorization", "Bearer #{access_token}"},
{"Content-Type", "application/json"}
]
)
{:error, _raw} ->
response
end
end
# private helpers
defp datetime_now do
(DateTime.utc_now()
|> DateTime.to_iso8601()
|> String.split(".")
|> List.first()) <> "Z"
end
defp post(url, params, headers) do
case HTTPoison.post(url, Jason.encode!(params), headers) do
{:ok, %HTTPoison.Response{status_code: 200, body: response_body}} ->
{:ok, response_body}
{:ok, %HTTPoison.Response{status_code: status_code, body: response_body}} ->
{:error, "Unexpected Response:\n Status code: #{status_code}\n #{response_body}"}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, "HTTP error: #{reason}"}
end
end
end