Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
ku1ik committed Nov 3, 2024
2 parents 24b5040 + f08ab26 commit 64a9184
Show file tree
Hide file tree
Showing 23 changed files with 272 additions and 230 deletions.
8 changes: 4 additions & 4 deletions assets/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"asciinema-player": "3.8.0",
"asciinema-player": "3.8.1",
"babel-loader": "^8.3.0",
"bootstrap": "^4.5.0",
"copy-webpack-plugin": "^11.0.0",
Expand Down
4 changes: 0 additions & 4 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ config :asciinema, Asciinema.Repo,
pool: Ecto.Adapters.SQL.Sandbox,
pool_size: 10

if db_url = System.get_env("TEST_DATABASE_URL") do
System.put_env("DATABASE_URL", db_url)
end

# In test we don't send emails.
config :asciinema, Asciinema.Emails.Mailer, adapter: Swoosh.Adapters.Test

Expand Down
3 changes: 2 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
devShells.default = pkgs.mkShell {
nativeBuildInputs = with pkgs; [
otp.elixir_1_14
otp.elixir-ls
nodejs_18
(rust-bin.stable."1.78.0".default)
(rust-bin.stable."1.78.0".default.override { extensions = [ "rust-src" "rust-analyzer" ]; })
inotify-tools
librsvg
];
Expand Down
16 changes: 13 additions & 3 deletions lib/asciinema/recordings/snapshot.ex
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,13 @@ defmodule Asciinema.Recordings.Snapshot do
case {k, v} do
{"fg", c} when is_number(c) and c < 8 -> "3#{c}"
{"fg", c} when is_number(c) -> "38;5;#{c}"
{"fg", "rgb(" <> _} -> "38;2;#{parse_rgb(v)}"
{"fg", "#" <> _} -> "38;2;#{parse_hex_color(v)}"
{"fg", "rgb(" <> _} -> "38;2;#{parse_rgb_color(v)}"
{"fg", [r, g, b]} -> "38;2;#{r};#{g};#{b}"
{"bg", c} when is_number(c) and c < 8 -> "4#{c}"
{"bg", c} when is_number(c) -> "48;5;#{c}"
{"bg", "rgb(" <> _} -> "48;2;#{parse_rgb(v)}"
{"bg", "#" <> _} -> "48;2;#{parse_hex_color(v)}"
{"bg", "rgb(" <> _} -> "48;2;#{parse_rgb_color(v)}"
{"bg", [r, g, b]} -> "48;2;#{r};#{g};#{b}"
{"bold", true} -> "1"
{"faint", true} -> "2"
Expand All @@ -200,7 +202,15 @@ defmodule Asciinema.Recordings.Snapshot do

defp sgr_params([]), do: []

defp parse_rgb("rgb(" <> c) do
defp parse_hex_color(<<"#", r::binary-size(2), g::binary-size(2), b::binary-size(2)>>) do
r = String.to_integer(r, 16)
g = String.to_integer(g, 16)
b = String.to_integer(b, 16)

"#{r};#{g};#{b}"
end

defp parse_rgb_color("rgb(" <> c) do
c
|> String.slice(0, String.length(c) - 1)
|> String.split(",")
Expand Down
8 changes: 4 additions & 4 deletions lib/asciinema_web.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ defmodule AsciinemaWeb do

import Plug.Conn
import AsciinemaWeb.Gettext
import AsciinemaWeb.Router.Helpers.Extra
import AsciinemaWeb.UrlHelpers

import AsciinemaWeb.Authentication,
only: [require_current_user: 2, log_in: 2, log_out: 1, get_basic_auth: 1]
Expand Down Expand Up @@ -118,7 +118,7 @@ defmodule AsciinemaWeb do
import AsciinemaWeb.ErrorHelpers
alias AsciinemaWeb.Router.Helpers, as: Routes

import AsciinemaWeb.Router.Helpers.Extra
import AsciinemaWeb.UrlHelpers
import AsciinemaWeb.ApplicationView

# Routes generation with the ~p sigil
Expand All @@ -131,7 +131,7 @@ defmodule AsciinemaWeb do
use Phoenix.Component
import Phoenix.View
import AsciinemaWeb.ApplicationView
import AsciinemaWeb.Router.Helpers.Extra
import AsciinemaWeb.UrlHelpers

# Include general helpers for rendering HTML
unquote(html_helpers())
Expand Down Expand Up @@ -159,7 +159,7 @@ defmodule AsciinemaWeb do
def json do
quote do
import AsciinemaWeb.ErrorHelpers
import AsciinemaWeb.Router.Helpers.Extra
import AsciinemaWeb.UrlHelpers

# Routes generation with the ~p sigil
unquote(verified_routes())
Expand Down
13 changes: 10 additions & 3 deletions lib/asciinema_web/controllers/api/live_stream_controller.ex
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
defmodule AsciinemaWeb.Api.LiveStreamController do
use AsciinemaWeb, :controller
alias Asciinema.{Accounts, Streaming}
alias AsciinemaWeb.Router.Helpers.Extra, as: Routes
alias AsciinemaWeb.UrlHelpers

plug :accepts, ~w(json)
plug :authenticate

def show(conn, params) do
id = params["id"]
get_stream(conn, params["id"])
end

def create(conn, _params) do
# TODO add mode (config option) where new streams are actually created here
get_stream(conn, nil)
end

defp get_stream(conn, id) do
if stream = Streaming.get_live_stream(conn.assigns.current_user, id) do
json(conn, %{
url: url(~p"/s/#{stream}"),
ws_producer_url: Routes.ws_producer_url(stream)
ws_producer_url: UrlHelpers.ws_producer_url(stream)
})
else
conn
Expand Down
2 changes: 1 addition & 1 deletion lib/asciinema_web/controllers/recording_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ defmodule AsciinemaWeb.RecordingController do
conn
|> put_layout("simple.html")
|> render("gif.html",
file_url: asciicast_file_url(conn, asciicast),
file_url: asciicast_file_url(asciicast),
asciicast_id: asciicast.id
)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/asciinema_web/controllers/session_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,6 @@ defmodule AsciinemaWeb.SessionController do
conn
|> log_out()
|> put_flash(:info, "See you later!")
|> redirect(to: root_path())
|> redirect(to: ~p"/")
end
end
2 changes: 1 addition & 1 deletion lib/asciinema_web/controllers/username_html/new.html.heex
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<br />

<p>
Every asciinema user gets a profile page at <a href="#"><%= root_url() %>/~<strong>username</strong></a>.
Every asciinema user gets a profile page at <a href="#"><%= url(~p"/") %>/~<strong>username</strong></a>.
</p>

<.form :let={f} for={@changeset} action={~p"/username"} class="username-form" method="post">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule AsciinemaWeb.TrailingFormat do
defmodule AsciinemaWeb.Plug.TrailingFormat do
@known_exts ["js", "json", "cast", "txt", "svg", "png", "gif", "xml"]

def init(opts), do: opts
Expand Down
93 changes: 11 additions & 82 deletions lib/asciinema_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,12 @@ defmodule AsciinemaWeb.Router do
end

pipeline :asciicast do
plug AsciinemaWeb.TrailingFormat
plug AsciinemaWeb.Plug.TrailingFormat
plug :accepts, ["html", "js", "json", "cast", "txt", "svg", "png", "gif"]
plug :format_specific_plugs
plug :put_secure_browser_headers
end

defp format_specific_plugs(conn, []) do
format_specific_plugs(conn, Phoenix.Controller.get_format(conn))
end

defp format_specific_plugs(conn, "html") do
conn
|> fetch_session([])
|> fetch_flash([])
|> protect_from_forgery([])
|> AsciinemaWeb.Plug.Authn.call([])
end

defp format_specific_plugs(conn, _other), do: conn

pipeline :oembed do
plug :accepts, ["json", "xml"]
plug :put_secure_browser_headers
Expand Down Expand Up @@ -97,6 +83,7 @@ defmodule AsciinemaWeb.Router do

scope "/api", AsciinemaWeb.Api, as: :api do
post "/asciicasts", RecordingController, :create
post "/streams", LiveStreamController, :create

scope "/user" do
get "/stream", LiveStreamController, :show
Expand All @@ -110,76 +97,18 @@ defmodule AsciinemaWeb.Router do
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
end

defmodule AsciinemaWeb.Router.Helpers.Extra do
alias AsciinemaWeb.Router.Helpers, as: H
alias AsciinemaWeb.Endpoint

def root_path do
Endpoint.path("/")
end

def root_url do
Endpoint.url()
end

def profile_path(_conn, user) do
profile_path(user)
end

def profile_path(%Plug.Conn{} = conn) do
profile_path(conn.assigns.current_user)
end

def profile_path(%{id: id, username: username}) do
if username do
Endpoint.path("/~#{username}")
else
Endpoint.path("/u/#{id}")
end
end

def profile_url(user) do
Endpoint.url() <> profile_path(user)
end

def asciicast_file_path(conn, asciicast) do
H.recording_path(conn, :show, asciicast) <> "." <> ext(asciicast)
end

def asciicast_file_url(asciicast) do
asciicast_file_url(AsciinemaWeb.Endpoint, asciicast)
end

def asciicast_file_url(conn, asciicast) do
H.recording_url(conn, :show, asciicast) <> "." <> ext(asciicast)
end

@http_to_ws %{"http" => "ws", "https" => "wss"}

def ws_producer_url(stream) do
uri = Endpoint.struct_url()
scheme = @http_to_ws[uri.scheme]
path = "/ws/S/#{stream.producer_token}"

to_string(%{uri | scheme: scheme, path: path})
defp format_specific_plugs(conn, []) do
format_specific_plugs(conn, Phoenix.Controller.get_format(conn))
end

def ws_public_url(stream) do
uri = Endpoint.struct_url()
scheme = @http_to_ws[uri.scheme]
param = Phoenix.Param.to_param(stream)
path = "/ws/s/#{param}"

to_string(%{uri | scheme: scheme, path: path})
defp format_specific_plugs(conn, "html") do
conn
|> fetch_session([])
|> fetch_flash([])
|> protect_from_forgery([])
|> AsciinemaWeb.Plug.Authn.call([])
end

defp ext(asciicast) do
case asciicast.version do
0 -> "json"
1 -> "json"
_ -> "cast"
end
end
defp format_specific_plugs(conn, _other), do: conn
end
2 changes: 1 addition & 1 deletion lib/asciinema_web/templates/layout/_header.html.heex
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<header>
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href={root_path()}>
<a class="navbar-brand" href={~p"/"}>
<img src={Routes.static_path(@conn, "/images/logo-red.svg")} />
</a>

Expand Down
57 changes: 57 additions & 0 deletions lib/asciinema_web/url_helpers.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
defmodule AsciinemaWeb.UrlHelpers do
use Phoenix.VerifiedRoutes,
endpoint: AsciinemaWeb.Endpoint,
router: AsciinemaWeb.Router

alias AsciinemaWeb.Endpoint

def profile_path(_conn, user), do: profile_path(user)

def profile_path(%Plug.Conn{} = conn), do: profile_path(conn.assigns.current_user)

def profile_path(%{id: id, username: username}) do
if username do
~p"/~#{username}"
else
~p"/u/#{id}"
end
end

def profile_url(user) do
Endpoint.url() <> profile_path(user)
end

def asciicast_file_path(asciicast) do
~p"/a/#{asciicast}" <> "." <> ext(asciicast)
end

def asciicast_file_url(asciicast) do
url(~p"/a/#{asciicast}") <> "." <> ext(asciicast)
end

defp ext(asciicast) do
case asciicast.version do
1 -> "json"
2 -> "cast"
end
end

@http_to_ws %{"http" => "ws", "https" => "wss"}

def ws_producer_url(stream) do
uri = Endpoint.struct_url()
scheme = @http_to_ws[uri.scheme]
path = "/ws/S/#{stream.producer_token}"

to_string(%{uri | scheme: scheme, path: path})
end

def ws_public_url(stream) do
uri = Endpoint.struct_url()
scheme = @http_to_ws[uri.scheme]
param = Phoenix.Param.to_param(stream)
path = "/ws/s/#{param}"

to_string(%{uri | scheme: scheme, path: path})
end
end
4 changes: 0 additions & 4 deletions lib/asciinema_web/views/media_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,6 @@ defmodule AsciinemaWeb.MediaView do
profile_path(user)
end

def author_profile_url(%{user: user}) do
profile_url(user)
end

def theme_options do
for theme <- Themes.terminal_themes() do
{Themes.display_name(theme), theme}
Expand Down
Loading

0 comments on commit 64a9184

Please sign in to comment.