Skip to content

Commit d9f748a

Browse files
wolfogresilverwindlunny
authored
Support asciicast files as new markup (#22448)
Support [asciicast files](https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md) as a new markup via [asciinema-player](https://github.com/asciinema/asciinema-player). For more on asciinema, see the [introduction](https://asciinema.org/). So users can use asciinema recorder to generate an asciicast file (or you can download a sample file from https://asciinema.org/a/335480.cast?dl=1), then upload it to Gitea and play it on Gitea. Snapshots: <details> ## Upload asciicast files <img width="1134" alt="image" src="https://user-images.githubusercontent.com/9418365/212461061-cc2c7181-0e14-4534-af55-1ec60a639fd1.png"> ## Open an asciicast file <img width="1137" alt="image" src="https://user-images.githubusercontent.com/9418365/212461090-a3b5141f-4894-430d-a2b4-ea257801a0ed.png"> ## Play it <img width="1144" alt="image" src="https://user-images.githubusercontent.com/9418365/212461157-4e82db69-0e41-471d-928f-ac1fe0737105.png"> ## Copy contents from the "video" <img width="1145" alt="image" src="https://user-images.githubusercontent.com/9418365/212461286-211612bc-15d6-427a-89a9-6abff5c6a0a5.png"> ## View the source <img width="1140" alt="image" src="https://user-images.githubusercontent.com/9418365/212461187-05473b2d-ba3d-4072-84a6-4aa1e7d82182.png"> </details> Known issue: Don't support the [v1 version asciicast files](https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v1.md), it's a poorly designed version, it does not specify the file extension and uses `*.json` usually, so it's impossible to recognize the files. Co-authored-by: silverwind <[email protected]> Co-authored-by: Lunny Xiao <[email protected]>
1 parent de484e8 commit d9f748a

File tree

9 files changed

+173
-0
lines changed

9 files changed

+173
-0
lines changed

main.go

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"code.gitea.io/gitea/modules/setting"
1818

1919
// register supported doc types
20+
_ "code.gitea.io/gitea/modules/markup/asciicast"
2021
_ "code.gitea.io/gitea/modules/markup/console"
2122
_ "code.gitea.io/gitea/modules/markup/csv"
2223
_ "code.gitea.io/gitea/modules/markup/markdown"

modules/markup/asciicast/asciicast.go

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package asciicast
5+
6+
import (
7+
"fmt"
8+
"io"
9+
"net/url"
10+
"regexp"
11+
12+
"code.gitea.io/gitea/modules/markup"
13+
"code.gitea.io/gitea/modules/setting"
14+
)
15+
16+
func init() {
17+
markup.RegisterRenderer(Renderer{})
18+
}
19+
20+
// Renderer implements markup.Renderer for asciicast files.
21+
// See https://github.com/asciinema/asciinema/blob/develop/doc/asciicast-v2.md
22+
type Renderer struct{}
23+
24+
// Name implements markup.Renderer
25+
func (Renderer) Name() string {
26+
return "asciicast"
27+
}
28+
29+
// Extensions implements markup.Renderer
30+
func (Renderer) Extensions() []string {
31+
return []string{".cast"}
32+
}
33+
34+
const (
35+
playerClassName = "asciinema-player-container"
36+
playerSrcAttr = "data-asciinema-player-src"
37+
)
38+
39+
// SanitizerRules implements markup.Renderer
40+
func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
41+
return []setting.MarkupSanitizerRule{
42+
{Element: "div", AllowAttr: "class", Regexp: regexp.MustCompile(playerClassName)},
43+
{Element: "div", AllowAttr: playerSrcAttr},
44+
}
45+
}
46+
47+
// Render implements markup.Renderer
48+
func (Renderer) Render(ctx *markup.RenderContext, _ io.Reader, output io.Writer) error {
49+
rawURL := fmt.Sprintf("%s/%s/%s/raw/%s/%s",
50+
setting.AppSubURL,
51+
url.PathEscape(ctx.Metas["user"]),
52+
url.PathEscape(ctx.Metas["repo"]),
53+
ctx.Metas["BranchNameSubURL"],
54+
url.PathEscape(ctx.RelativePath),
55+
)
56+
57+
_, err := io.WriteString(output, fmt.Sprintf(
58+
`<div class="%s" %s="%s"></div>`,
59+
playerClassName,
60+
playerSrcAttr,
61+
rawURL,
62+
))
63+
return err
64+
}

package-lock.json

+76
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"@primer/octicons": "17.10.0",
1717
"@vue/compiler-sfc": "3.2.45",
1818
"add-asset-webpack-plugin": "2.0.1",
19+
"asciinema-player": "3.0.1",
1920
"css-loader": "6.7.3",
2021
"dropzone": "6.0.0-beta.2",
2122
"easymde": "2.18.0",

web_src/js/markup/asciicast.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export async function renderAsciinemaPlayer() {
2+
const els = document.querySelectorAll('.asciinema-player-container');
3+
if (!els.length) return;
4+
5+
const player = await import(/* webpackChunkName: "asciinema-player" */'asciinema-player');
6+
7+
for (const el of els) {
8+
player.create(el.getAttribute('data-asciinema-player-src'), el, {
9+
// poster (a preview frame) to display until the playback is started.
10+
// Set it to 1 hour (also means the end if the video is shorter) to make the preview frame show more.
11+
poster: 'npt:1:0:0',
12+
});
13+
}
14+
}

web_src/js/markup/content.js

+2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import {renderMermaid} from './mermaid.js';
22
import {renderMath} from './math.js';
33
import {renderCodeCopy} from './codecopy.js';
4+
import {renderAsciinemaPlayer} from './asciicast.js';
45
import {initMarkupTasklist} from './tasklist.js';
56

67
// code that runs for all markup content
78
export function initMarkupContent() {
89
renderMermaid();
910
renderMath();
1011
renderCodeCopy();
12+
renderAsciinemaPlayer();
1113
}
1214

1315
// code that only runs for comments

web_src/less/_repository.less

+4
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,10 @@
470470
pre {
471471
overflow: auto;
472472
}
473+
474+
.asciicast {
475+
padding: 5px !important;
476+
}
473477
}
474478

475479
.sidebar {

web_src/less/index.less

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
@import "./markup/content.less";
1414
@import "./markup/codecopy.less";
1515
@import "./code/linebutton.less";
16+
@import "./markup/asciicast.less";
1617

1718
@import "./chroma/base.less";
1819
@import "./chroma/light.less";

web_src/less/markup/asciicast.less

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@import "../asciinema-player/dist/bundle/asciinema-player.css";
2+
3+
.asciinema-player-container {
4+
width: 100%;
5+
height: auto;
6+
}
7+
8+
.asciinema-terminal {
9+
overflow: hidden !important;
10+
}

0 commit comments

Comments
 (0)