From f277f1d5147943b11412fef021c0ee8a4ac84a5f Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Sun, 13 Aug 2023 15:54:06 +0200 Subject: [PATCH 01/19] Fix display of recording metadata when OS is known while term/shell are not --- .../templates/recording/show.html.heex | 8 ++------ lib/asciinema_web/views/recording_view.ex | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/lib/asciinema_web/templates/recording/show.html.heex b/lib/asciinema_web/templates/recording/show.html.heex index f33c8cdfc..a1a2171b9 100644 --- a/lib/asciinema_web/templates/recording/show.html.heex +++ b/lib/asciinema_web/templates/recording/show.html.heex @@ -114,13 +114,9 @@
- <% os = os_info(@asciicast) %> - <% term = term_info(@asciicast) %> - <% shell = shell_info(@asciicast) %> - - <%= if Enum.any?([os, term, shell]) do %> + <%= if m = metadata(@asciicast) do %> - <.terminal_solid_icon /> <%= Enum.join([os, term, shell], " ◆ ") %> + <.terminal_solid_icon /> <%= m %> <% end %> diff --git a/lib/asciinema_web/views/recording_view.ex b/lib/asciinema_web/views/recording_view.ex index ff5876749..985aba56d 100644 --- a/lib/asciinema_web/views/recording_view.ex +++ b/lib/asciinema_web/views/recording_view.ex @@ -170,7 +170,16 @@ defmodule AsciinemaWeb.RecordingView do |> Enum.join(";") end - def os_info(asciicast) do + def metadata(asciicast) do + items = [os_info(asciicast), term_info(asciicast), shell_info(asciicast)] + + case Enum.filter(items, & &1) do + [] -> nil + items -> Enum.join(items, " ◆ ") + end + end + + defp os_info(asciicast) do os_from_user_agent(asciicast) || os_from_uname(asciicast) end @@ -199,13 +208,13 @@ defmodule AsciinemaWeb.RecordingView do end end - def shell_info(asciicast) do + defp shell_info(asciicast) do if asciicast.shell do Path.basename("#{asciicast.shell}") end end - def term_info(asciicast) do + defp term_info(asciicast) do asciicast.terminal_type end From 48ed91d6328bcd11be7502ac0a1f5ac644985770 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Mon, 14 Aug 2023 11:36:14 +0200 Subject: [PATCH 02/19] Add Repo.transact/2 Thanks https://tomkonidas.com/repo-transact/ ! --- lib/asciinema.ex | 5 +++-- lib/asciinema/repo.ex | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/asciinema.ex b/lib/asciinema.ex index 8390db369..78a2ce9a9 100644 --- a/lib/asciinema.ex +++ b/lib/asciinema.ex @@ -31,12 +31,13 @@ defmodule Asciinema do defdelegate verify_login_token(token), to: Accounts def merge_accounts(src_user, dst_user) do - Repo.transaction(fn -> + Repo.transact(fn -> Recordings.reassign_asciicasts(src_user.id, dst_user.id) Streaming.reassign_live_streams(src_user.id, dst_user.id) Accounts.reassign_api_tokens(src_user.id, dst_user.id) Accounts.delete_user!(src_user) - Accounts.get_user(dst_user.id) + + {:ok, Accounts.get_user(dst_user.id)} end) end diff --git a/lib/asciinema/repo.ex b/lib/asciinema/repo.ex index 43bcd6017..c1bc9b35d 100644 --- a/lib/asciinema/repo.ex +++ b/lib/asciinema/repo.ex @@ -5,6 +5,20 @@ defmodule Asciinema.Repo do use Scrivener, page_size: 10 + def transact(fun, opts \\ []) do + transaction( + fn -> + case fun.() do + {:ok, value} -> value + :ok -> :transaction_commited + {:error, reason} -> rollback(reason) + :error -> rollback(:transaction_rollback_error) + end + end, + opts + ) + end + def count(query) do aggregate(query, :count, :id) end From 187b21af6acbe32875f67913920f88737ac96f8f Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Mon, 14 Aug 2023 11:49:07 +0200 Subject: [PATCH 03/19] Function rename --- lib/asciinema/recordings.ex | 4 ++-- lib/asciinema_web/controllers/live_stream_controller.ex | 2 +- lib/asciinema_web/controllers/recording_controller.ex | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/asciinema/recordings.ex b/lib/asciinema/recordings.ex index 396bc8992..b79859981 100644 --- a/lib/asciinema/recordings.ex +++ b/lib/asciinema/recordings.ex @@ -37,7 +37,7 @@ defmodule Asciinema.Recordings do |> Repo.preload(:user) end - def public_asciicasts(%{asciicasts: _} = owner, limit \\ 4) do + def list_public_asciicasts(%{asciicasts: _} = owner, limit \\ 4) do owner |> Ecto.assoc(:asciicasts) |> filter(:public) @@ -47,7 +47,7 @@ defmodule Asciinema.Recordings do |> Repo.all() end - def other_public_asciicasts(asciicast, limit \\ 4) do + def list_other_public_asciicasts(asciicast, limit \\ 4) do Asciicast |> filter({asciicast.user_id, :public}) |> where([a], a.id != ^asciicast.id) diff --git a/lib/asciinema_web/controllers/live_stream_controller.ex b/lib/asciinema_web/controllers/live_stream_controller.ex index 10254b23a..62c127f48 100644 --- a/lib/asciinema_web/controllers/live_stream_controller.ex +++ b/lib/asciinema_web/controllers/live_stream_controller.ex @@ -19,7 +19,7 @@ defmodule AsciinemaWeb.LiveStreamController do player_opts: player_opts(params), actions: stream_actions(stream, current_user), user_is_self: user_is_self, - author_asciicasts: Recordings.public_asciicasts(stream.user) + author_asciicasts: Recordings.list_public_asciicasts(stream.user) ) end diff --git a/lib/asciinema_web/controllers/recording_controller.ex b/lib/asciinema_web/controllers/recording_controller.ex index e10d1605f..814f7f22c 100644 --- a/lib/asciinema_web/controllers/recording_controller.ex +++ b/lib/asciinema_web/controllers/recording_controller.ex @@ -63,7 +63,7 @@ defmodule AsciinemaWeb.RecordingController do asciicast: asciicast, player_opts: player_opts(conn.params), actions: asciicast_actions(asciicast, conn.assigns.current_user), - author_asciicasts: Recordings.other_public_asciicasts(asciicast) + author_asciicasts: Recordings.list_other_public_asciicasts(asciicast) ) end end From 6fe204e0c6b6a4c1d563ca53a401158b7533652d Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Mon, 14 Aug 2023 12:09:05 +0200 Subject: [PATCH 04/19] Add Asciinema.delete_user!/1 --- lib/asciinema.ex | 11 +++++++++++ lib/asciinema/accounts.ex | 3 +++ lib/asciinema/recordings.ex | 8 ++++++++ lib/asciinema/streaming.ex | 6 ++++++ test/asciinema_test.exs | 11 +++++++++++ 5 files changed, 39 insertions(+) diff --git a/lib/asciinema.ex b/lib/asciinema.ex index 78a2ce9a9..3c07c87db 100644 --- a/lib/asciinema.ex +++ b/lib/asciinema.ex @@ -41,6 +41,17 @@ defmodule Asciinema do end) end + def delete_user!(user) do + result = + Repo.transact(fn -> + Recordings.delete_asciicasts(user) + Streaming.delete_live_streams(user) + Accounts.delete_user!(user) + end) + + with {:ok, _} <- result, do: :ok + end + defdelegate get_live_stream(id_or_owner), to: Streaming def recording_gc_days do diff --git a/lib/asciinema/accounts.ex b/lib/asciinema/accounts.ex index 27dabe53c..32a2522c5 100644 --- a/lib/asciinema/accounts.ex +++ b/lib/asciinema/accounts.ex @@ -304,6 +304,9 @@ defmodule Asciinema.Accounts do end def delete_user!(%User{} = user) do + Repo.delete_all(assoc(user, :api_tokens)) Repo.delete!(user) + + :ok end end diff --git a/lib/asciinema/recordings.ex b/lib/asciinema/recordings.ex index b79859981..59395a989 100644 --- a/lib/asciinema/recordings.ex +++ b/lib/asciinema/recordings.ex @@ -492,6 +492,14 @@ defmodule Asciinema.Recordings do end end + def delete_asciicasts(%{asciicasts: _} = owner) do + for a <- Repo.all(Ecto.assoc(owner, :asciicasts)) do + {:ok, _} = delete_asciicast(a) + end + + :ok + end + def update_snapshot(%Asciicast{} = asciicast) do cols = asciicast.cols_override || asciicast.cols rows = asciicast.rows_override || asciicast.rows diff --git a/lib/asciinema/streaming.ex b/lib/asciinema/streaming.ex index 1efa879b6..8e981e9f1 100644 --- a/lib/asciinema/streaming.ex +++ b/lib/asciinema/streaming.ex @@ -111,6 +111,12 @@ defmodule Asciinema.Streaming do end end + def delete_live_streams(%{live_streams: _} = owner) do + Repo.delete_all(Ecto.assoc(owner, :live_streams)) + + :ok + end + def reassign_live_streams(src_user_id, dst_user_id) do from(s in LiveStream, where: s.user_id == ^src_user_id) |> Repo.update_all(set: [user_id: dst_user_id, updated_at: Timex.now()]) diff --git a/test/asciinema_test.exs b/test/asciinema_test.exs index 88d63a102..13d292a4e 100644 --- a/test/asciinema_test.exs +++ b/test/asciinema_test.exs @@ -93,4 +93,15 @@ defmodule AsciinemaTest do assert {:ok, %{id: ^id2}} = Asciinema.merge_accounts(user1, user2) end end + + describe "delete_user!/1" do + test "succeeds" do + user = insert(:user) + insert(:asciicast, user: user) + insert(:api_token, user: user) + insert(:live_stream, user: user) + + assert :ok = Asciinema.delete_user!(user) + end + end end From ee98fe402c7c08203d0885f31893eb2709a6b989 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Aug 2023 14:24:48 +0200 Subject: [PATCH 05/19] Upgrade js player to "next" tag --- assets/package-lock.json | 8 ++++---- assets/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/package-lock.json b/assets/package-lock.json index 52c772349..00f40bb0b 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -8,7 +8,7 @@ "devDependencies": { "@babel/core": "^7.21.0", "@babel/preset-env": "^7.20.2", - "asciinema-player": "^3.5.0", + "asciinema-player": "next", "babel-loader": "^8.3.0", "bootstrap": "^4.5.0", "copy-webpack-plugin": "^11.0.0", @@ -2298,9 +2298,9 @@ } }, "node_modules/asciinema-player": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.5.0.tgz", - "integrity": "sha512-o4B2AscBuCZo4+JB9TBGrfZ7GQL99wsbm08WwmuNJTPd1lyLQJq8wgacnBsdvb2sC0K875ScYr8T5XmfeH/6dg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.6.0.tgz", + "integrity": "sha512-+cScxWtyam4PBS3qv2o9n6MmF1qY8mbCMZScw3y8oEIZiyaa2busEPdUxcsI562+yyJSzzl8hnnNccna1HPhKw==", "dev": true, "dependencies": { "@babel/runtime": "^7.21.0", diff --git a/assets/package.json b/assets/package.json index 914b20005..6883d628e 100644 --- a/assets/package.json +++ b/assets/package.json @@ -12,7 +12,7 @@ "devDependencies": { "@babel/core": "^7.21.0", "@babel/preset-env": "^7.20.2", - "asciinema-player": "^3.5.0", + "asciinema-player": "next", "babel-loader": "^8.3.0", "bootstrap": "^4.5.0", "copy-webpack-plugin": "^11.0.0", From dcef909ac801fccbe055de95a7499dc9937661a9 Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Aug 2023 14:48:28 +0200 Subject: [PATCH 06/19] Handle new terminal resize events --- assets/js/app.js | 3 ++- assets/js/player.js | 10 ++++++++++ lib/asciinema/streaming/parser/json.ex | 5 +++++ .../controllers/live_stream/show.html.heex | 15 ++++++--------- .../templates/recording/show.html.heex | 5 +++++ 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/assets/js/app.js b/assets/js/app.js index 19d243bda..84a2e8157 100644 --- a/assets/js/app.js +++ b/assets/js/app.js @@ -3,9 +3,10 @@ import css from '../css/app.scss'; import $ from 'jquery'; import "bootstrap"; import "phoenix_html"; -import { createPlayer } from './player'; +import { createPlayer, cinemaHeight } from './player'; window.createPlayer = createPlayer; +window.cinemaHeight = cinemaHeight; $(function() { $('input[data-behavior=focus]:first').focus().select(); diff --git a/assets/js/player.js b/assets/js/player.js index ad4e4902a..14e2740ef 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -15,3 +15,13 @@ export function createPlayer(src, container, opts) { return create(src, container, opts); } } + +const CONTAINER_VERTICAL_PADDING = 2 * 4; +const APPROX_CHAR_WIDTH = 7; +const APPROX_CHAR_HEIGHT = 16; + +export function cinemaHeight(cols, rows) { + const ratio = (rows * APPROX_CHAR_HEIGHT) / (cols * APPROX_CHAR_WIDTH); + const height = Math.round(CONTAINER_VERTICAL_PADDING + 100 * ratio); + return `${height}vw`; +} diff --git a/lib/asciinema/streaming/parser/json.ex b/lib/asciinema/streaming/parser/json.ex index b0ad75969..1b0530e9e 100644 --- a/lib/asciinema/streaming/parser/json.ex +++ b/lib/asciinema/streaming/parser/json.ex @@ -37,6 +37,11 @@ defmodule Asciinema.Streaming.Parser.Json do {:ok, [feed: {time, data}], state} end + def handle_message([time, "r", data], state) when is_number(time) and is_binary(data) do + [cols, rows] = String.split(data, "x") + {:ok, [feed: {time, "\x1b[8;#{rows};#{cols}t"}], state} + end + def handle_message([time, type, data], state) when is_number(time) and is_binary(type) and is_binary(data) do {:ok, [], state} diff --git a/lib/asciinema_web/controllers/live_stream/show.html.heex b/lib/asciinema_web/controllers/live_stream/show.html.heex index 317bffe09..f1aa39899 100644 --- a/lib/asciinema_web/controllers/live_stream/show.html.heex +++ b/lib/asciinema_web/controllers/live_stream/show.html.heex @@ -205,14 +205,11 @@ script -f -O live.pipe { ...opts, fit: 'both', logger: console } ); - const containerVerticalPadding = 2 * 4; - const approxCharWidth = 7; - const approxCharHeight = 16; - - player.addEventListener('reset', ({ cols, rows }) => { - const ratio = (rows * approxCharHeight) / (cols * approxCharWidth); - const height = Math.round(containerVerticalPadding + 100 * ratio); - container.style.height = `${height}vw`; - }); + function resizeCinema({ cols, rows }) { + container.style.height = window.cinemaHeight(cols, rows); + } + + player.addEventListener('reset', resizeCinema); + player.addEventListener('resize', resizeCinema); }); diff --git a/lib/asciinema_web/templates/recording/show.html.heex b/lib/asciinema_web/templates/recording/show.html.heex index a1a2171b9..ee41e2a4c 100644 --- a/lib/asciinema_web/templates/recording/show.html.heex +++ b/lib/asciinema_web/templates/recording/show.html.heex @@ -171,6 +171,7 @@ From 29cf7e0ffbd744e453d1ebe76133e05db4745dfd Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Aug 2023 15:22:20 +0200 Subject: [PATCH 07/19] Save producer parser in db, for stats --- lib/asciinema/application.ex | 2 ++ lib/asciinema/streaming/live_stream.ex | 1 + lib/asciinema/streaming/parser.ex | 6 +++--- lib/asciinema_web/live_stream_producer_socket.ex | 9 +++++++++ .../20230817131250_add_parser_to_live_streams.exs | 11 +++++++++++ 5 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 priv/repo/migrations/20230817131250_add_parser_to_live_streams.exs diff --git a/lib/asciinema/application.ex b/lib/asciinema/application.ex index ad5b58ed4..fa8604335 100644 --- a/lib/asciinema/application.ex +++ b/lib/asciinema/application.ex @@ -14,6 +14,8 @@ defmodule Asciinema.Application do # List all child processes to be supervised children = [ + # Start task supervisor + {Task.Supervisor, name: Asciinema.TaskSupervisor}, # Start cluster supervisor {Cluster.Supervisor, [topologies, [name: Asciinema.ClusterSupervisor]]}, # Start the PubSub system diff --git a/lib/asciinema/streaming/live_stream.ex b/lib/asciinema/streaming/live_stream.ex index e5660b683..20dcc9f30 100644 --- a/lib/asciinema/streaming/live_stream.ex +++ b/lib/asciinema/streaming/live_stream.ex @@ -18,6 +18,7 @@ defmodule Asciinema.Streaming.LiveStream do field :current_viewer_count, :integer field :peak_viewer_count, :integer field :buffer_time, :float + field :parser, :string timestamps() diff --git a/lib/asciinema/streaming/parser.ex b/lib/asciinema/streaming/parser.ex index 9d61fb098..e6848ae3b 100644 --- a/lib/asciinema/streaming/parser.ex +++ b/lib/asciinema/streaming/parser.ex @@ -5,7 +5,7 @@ defmodule Asciinema.Streaming.Parser do alias Asciinema.Streaming.Parser - def get(:raw), do: %{impl: Parser.Raw, state: Parser.Raw.init()} - def get(:alis), do: %{impl: Parser.Alis, state: Parser.Alis.init()} - def get(:json), do: %{impl: Parser.Json, state: Parser.Json.init()} + def get(:raw), do: %{impl: Parser.Raw, name: "raw", state: Parser.Raw.init()} + def get(:alis), do: %{impl: Parser.Alis, name: "alis", state: Parser.Alis.init()} + def get(:json), do: %{impl: Parser.Json, name: "json", state: Parser.Json.init()} end diff --git a/lib/asciinema_web/live_stream_producer_socket.ex b/lib/asciinema_web/live_stream_producer_socket.ex index 43b94229b..c066449c9 100644 --- a/lib/asciinema_web/live_stream_producer_socket.ex +++ b/lib/asciinema_web/live_stream_producer_socket.ex @@ -126,6 +126,7 @@ defmodule AsciinemaWeb.LiveStreamProducerSocket do Logger.info("producer/#{state.stream_id}: reset (#{cols}x#{rows})") state = ensure_server(state) + save_parser(state.stream_id, state.parser.name) with :ok <- LiveStreamServer.reset(state.stream_id, {cols, rows}, init, time) do {:ok, state} @@ -233,6 +234,14 @@ defmodule AsciinemaWeb.LiveStreamProducerSocket do end end + defp save_parser(stream_id, parser_name) do + Task.Supervisor.start_child(Asciinema.TaskSupervisor, fn -> + stream_id + |> Streaming.get_live_stream() + |> Streaming.update_live_stream(parser: parser_name) + end) + end + defp config(key, default) do Application.get_env(:asciinema, :"live_stream_producer_#{key}", default) end diff --git a/priv/repo/migrations/20230817131250_add_parser_to_live_streams.exs b/priv/repo/migrations/20230817131250_add_parser_to_live_streams.exs new file mode 100644 index 000000000..d1eb0dffe --- /dev/null +++ b/priv/repo/migrations/20230817131250_add_parser_to_live_streams.exs @@ -0,0 +1,11 @@ +defmodule Asciinema.Repo.Migrations.AddParserToLiveStreams do + use Ecto.Migration + + def change do + alter table(:live_streams) do + add :parser, :string + end + + create index(:live_streams, [:parser]) + end +end From 6115f18e078c00f2e09a8644396a36d41358bfbb Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Aug 2023 15:35:26 +0200 Subject: [PATCH 08/19] Add missing return in custom font loading code path --- assets/js/player.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/js/player.js b/assets/js/player.js index 14e2740ef..b1f13d87c 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -6,7 +6,7 @@ export function createPlayer(src, container, opts) { document.fonts.load(`1em ${opts.customTerminalFontFamily}`).then(() => { console.log(`loaded font ${opts.customTerminalFontFamily}`); - create(src, container, opts); + return create(src, container, opts); }).catch(error => { console.log(`failed to load font ${opts.customTerminalFontFamily}`, error); return create(src, container, opts); From 51dbf2a4af5ab33cd3025b656e8b8a4f2b7aa30b Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Aug 2023 15:43:58 +0200 Subject: [PATCH 09/19] npx update-browserslist-db@latest --- assets/package-lock.json | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/assets/package-lock.json b/assets/package-lock.json index 00f40bb0b..de57ccb11 100644 --- a/assets/package-lock.json +++ b/assets/package-lock.json @@ -2538,9 +2538,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001451", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz", - "integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==", + "version": "1.0.30001521", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001521.tgz", + "integrity": "sha512-fnx1grfpEOvDGH+V17eccmNjucGUnCbP6KL+l5KqBIerp26WK/+RQ7CIDE37KGJjaPyqWXXlFUyKiWmvdNNKmQ==", "dev": true, "funding": [ { @@ -2550,6 +2550,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, From db468494f67214628085e9783806c611c830fead Mon Sep 17 00:00:00 2001 From: Marcin Kulik Date: Thu, 17 Aug 2023 15:52:09 +0200 Subject: [PATCH 10/19] Proper fix for adding player event listeners when custom font used --- assets/js/player.js | 2 +- lib/asciinema_web/controllers/live_stream/show.html.heex | 4 ++-- lib/asciinema_web/templates/recording/show.html.heex | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/js/player.js b/assets/js/player.js index b1f13d87c..cec5c40eb 100644 --- a/assets/js/player.js +++ b/assets/js/player.js @@ -4,7 +4,7 @@ export function createPlayer(src, container, opts) { if (opts.customTerminalFontFamily) { opts.terminalFontFamily = `${opts.customTerminalFontFamily},Consolas,Menlo,'Bitstream Vera Sans Mono',monospace,'Powerline Symbols'`; - document.fonts.load(`1em ${opts.customTerminalFontFamily}`).then(() => { + return document.fonts.load(`1em ${opts.customTerminalFontFamily}`).then(() => { console.log(`loaded font ${opts.customTerminalFontFamily}`); return create(src, container, opts); }).catch(error => { diff --git a/lib/asciinema_web/controllers/live_stream/show.html.heex b/lib/asciinema_web/controllers/live_stream/show.html.heex index f1aa39899..5c19e5e0d 100644 --- a/lib/asciinema_web/controllers/live_stream/show.html.heex +++ b/lib/asciinema_web/controllers/live_stream/show.html.heex @@ -195,11 +195,11 @@ script -f -O live.pipe