Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
ku1ik committed Apr 27, 2024
2 parents 1477c3e + ade2598 commit 2247493
Show file tree
Hide file tree
Showing 57 changed files with 1,104 additions and 543 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Notable features:
- visibility control for recordings: unlisted (secret) or public,
- editable recording metadata like title or long description (Markdown),
- configurable terminal themes and font families,
- ability to download pure text version (`.txt`) of a recording.
- ability to download plain text version (`.txt`) of a recording.

Refer to [asciinema server docs](https://docs.asciinema.org/manual/server/) for
further details.
Expand Down
12 changes: 12 additions & 0 deletions assets/css/_flash.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
section.flash {
max-height: 200px;
overflow: hidden;
transition: max-height 0.2s ease-out;

&.hidden {
max-height: 0px;
}

.container {
padding-top: 10px;
padding-bottom: 10px;
Expand All @@ -21,4 +29,8 @@ section.flash {
padding: 0;
border: 0;
border-radius: 0;

.close {
color: white;
}
}
14 changes: 13 additions & 1 deletion assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,20 @@ $(function() {
link.href = window.location.origin + window.location.pathname + '.txt';
})
});
});

document.querySelectorAll('#flash-notice button[data-behavior=close], #flash-alert button[data-behavior=close]').forEach(button => {
button.addEventListener('click', (e) => {
e.preventDefault();
e.target.closest('section').classList.add('hidden');
})
});

setTimeout(() => {
document.querySelectorAll('#flash-notice, #flash-alert').forEach(section => {
section.classList.add('hidden');
});
}, 5000);
});

import {Socket} from "phoenix";
import {LiveSocket} from "phoenix_live_view";
Expand Down
45 changes: 34 additions & 11 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.7.1-rc.2",
"asciinema-player": "3.7.2-rc.3",
"babel-loader": "^8.3.0",
"bootstrap": "^4.5.0",
"copy-webpack-plugin": "^11.0.0",
Expand Down
10 changes: 10 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ config :asciinema, Asciinema.Repo, migration_timestamps: [type: :naive_datetime_

# Configures the public endpoint
config :asciinema, AsciinemaWeb.Endpoint,
http: [
dispatch: [
{:_,
[
{"/ws/s/:public_token", AsciinemaWeb.LiveStreamConsumerSocket, []},
{"/ws/S/:producer_token", AsciinemaWeb.LiveStreamProducerSocket, []},
{:_, Plug.Cowboy.Handler, {AsciinemaWeb.Endpoint, []}}
]}
]
],
url: [host: "localhost"],
render_errors: [view: AsciinemaWeb.ErrorView, accepts: ~w(html json), layout: false],
live_view: [signing_salt: "F3BMP7k9SZ-Y2SMJ"],
Expand Down
1 change: 1 addition & 0 deletions lib/asciinema/accounts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ defmodule Asciinema.Accounts do
:name,
:username,
:theme_name,
:theme_prefer_original,
:terminal_font_family,
:asciicasts_private_by_default
])
Expand Down
1 change: 1 addition & 0 deletions lib/asciinema/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule Asciinema.Accounts.User do
field :name, :string
field :auth_token, :string
field :theme_name, :string
field :theme_prefer_original, :boolean, default: true
field :terminal_font_family, :string
field :asciicasts_private_by_default, :boolean, default: true
field :last_login_at, :utc_datetime_usec
Expand Down
20 changes: 13 additions & 7 deletions lib/asciinema/recordings.ex
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ defmodule Asciinema.Recordings do
)

with {:ok, metadata} <- extract_metadata(upload),
changeset = apply_metadata(changeset, metadata),
changeset = apply_metadata(changeset, metadata, user.theme_prefer_original),
{:ok, %Asciicast{} = asciicast} <- do_create_asciicast(changeset, upload) do
if asciicast.snapshot == nil do
:ok = SnapshotUpdater.update_snapshot(asciicast)
Expand Down Expand Up @@ -235,9 +235,15 @@ defmodule Asciinema.Recordings do
|> Enum.reduce(fn {t, _}, _prev_t -> t end)
end

defp apply_metadata(changeset, metadata) do
@hex_color_re ~r/^#[0-9a-f]{6}$/
@hex_palette_re ~r/^(#[0-9a-f]{6}:){7}((#[0-9a-f]{6}:){8})?#[0-9a-f]{6}$/

defp apply_metadata(changeset, metadata, prefer_original_theme) do
theme_name = if metadata[:theme_palette] && prefer_original_theme, do: "original"

changeset
|> put_change(:version, metadata.version)
|> put_change(:theme_name, theme_name)
|> cast(metadata, [
:duration,
:cols,
Expand All @@ -254,6 +260,9 @@ defmodule Asciinema.Recordings do
:title
])
|> validate_required([:duration, :cols, :rows])
|> validate_format(:theme_fg, @hex_color_re)
|> validate_format(:theme_bg, @hex_color_re)
|> validate_format(:theme_palette, @hex_palette_re)
end

defp decode_json(json) do
Expand Down Expand Up @@ -311,7 +320,7 @@ defmodule Asciinema.Recordings do
|> validate_number(:cols_override, greater_than: 0, less_than: 1024)
|> validate_number(:rows_override, greater_than: 0, less_than: 512)
|> validate_number(:idle_time_limit, greater_than_or_equal_to: 0.5)
|> validate_inclusion(:theme_name, Themes.terminal_themes())
|> validate_inclusion(:theme_name, Themes.terminal_themes() ++ ["original"])
|> validate_number(:terminal_line_height,
greater_than_or_equal_to: 1.0,
less_than_or_equal_to: 2.0
Expand Down Expand Up @@ -396,10 +405,7 @@ defmodule Asciinema.Recordings do

{lines, cursor}
|> Snapshot.new()
|> Map.get(:lines)
|> Enum.map(fn segments ->
Enum.map(segments, &Tuple.to_list/1)
end)
|> Snapshot.unwrap()
end

def title(asciicast) do
Expand Down
6 changes: 6 additions & 0 deletions lib/asciinema/recordings/snapshot.ex
Original file line number Diff line number Diff line change
Expand Up @@ -321,4 +321,10 @@ defmodule Asciinema.Recordings.Snapshot do

%{y: y, segments: Enum.reverse(segments)}
end

def unwrap(%__MODULE__{lines: lines}) do
Enum.map(lines, fn segments ->
Enum.map(segments, &Tuple.to_list/1)
end)
end
end
55 changes: 41 additions & 14 deletions lib/asciinema/streaming.ex
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,24 @@ defmodule Asciinema.Streaming do

def get_live_stream(id) when is_binary(id) do
stream =
cond do
String.match?(id, ~r/[[:alpha:]]/) ->
Repo.one(from(s in LiveStream, where: s.secret_token == ^id))

String.match?(id, ~r/^\d+$/) ->
id = String.to_integer(id)
Repo.one(from(s in LiveStream, where: s.private == false and s.id == ^id))

true ->
nil
if String.match?(id, ~r/[[:alpha:]]/) do
Repo.one(from(s in LiveStream, where: s.public_token == ^id))
end

Repo.preload(stream, :user)
end

def get_live_stream(%{live_streams: _} = owner) do
def get_live_stream(%{live_streams: _} = owner, nil) do
owner
|> Ecto.assoc(:live_streams)
|> first()
|> Repo.one()
end

def get_live_stream(%{live_streams: _} = owner, id) do
owner
|> Ecto.assoc(:live_streams)
|> where([s], like(s.public_token, ^"#{id}%"))
|> first()
|> Repo.one()
end
Expand All @@ -45,9 +45,35 @@ defmodule Asciinema.Streaming do
end
end

def list_public_live_streams(owner, limit \\ 4) do
owner
|> live_streams_q(limit)
|> where([s], not s.private)
|> Repo.all()
end

def list_all_live_streams(owner, limit \\ 4) do
owner
|> live_streams_q(limit)
|> Repo.all()
end

defp live_streams_q(%{live_streams: _} = owner, limit) do
owner
|> Ecto.assoc(:live_streams)
|> where([s], s.online)
|> order_by(desc: :last_started_at)
|> limit(^limit)
|> preload(:user)
end

def create_live_stream!(user) do
%LiveStream{}
|> change(secret_token: generate_secret_token(), producer_token: generate_producer_token())
|> change(
public_token: generate_public_token(),
producer_token: generate_producer_token(),
theme_prefer_original: user.theme_prefer_original
)
|> put_assoc(:user, user)
|> Repo.insert!()
end
Expand All @@ -61,6 +87,7 @@ defmodule Asciinema.Streaming do
:description,
:private,
:theme_name,
:theme_prefer_original,
:buffer_time,
:terminal_line_height,
:terminal_font_family
Expand Down Expand Up @@ -131,6 +158,6 @@ defmodule Asciinema.Streaming do
count
end

defp generate_producer_token, do: Crypto.random_token(25)
defp generate_secret_token, do: Crypto.random_token(25)
defp generate_public_token, do: Crypto.random_token(16)
defp generate_producer_token, do: Crypto.random_token(16)
end
12 changes: 4 additions & 8 deletions lib/asciinema/streaming/live_stream.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Asciinema.Streaming.LiveStream do
use Ecto.Schema

schema "live_streams" do
field :secret_token, :string
field :public_token, :string
field :producer_token, :string
field :private, :boolean, default: true
field :cols, :integer
Expand All @@ -16,25 +16,21 @@ defmodule Asciinema.Streaming.LiveStream do
field :theme_fg, :string
field :theme_bg, :string
field :theme_palette, :string
field :theme_prefer_original, :boolean, default: true
field :terminal_line_height, :float
field :terminal_font_family, :string
field :current_viewer_count, :integer
field :peak_viewer_count, :integer
field :buffer_time, :float
field :parser, :string
field :snapshot, Asciinema.Ecto.Type.JsonArray

timestamps()

belongs_to :user, Asciinema.Accounts.User
end

defimpl Phoenix.Param do
def to_param(%{private: true, secret_token: secret_token}) do
secret_token
end

def to_param(%{id: id}) do
Integer.to_string(id)
end
def to_param(stream), do: stream.public_token
end
end
Loading

0 comments on commit 2247493

Please sign in to comment.