-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathembed.go
More file actions
125 lines (100 loc) · 3.36 KB
/
Copy pathembed.go
File metadata and controls
125 lines (100 loc) · 3.36 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package embed
import (
"fmt"
"net/url"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
)
// Option is a functional option type for this extension.
type Option func(*embedExtension)
type embedExtension struct{}
// New returns a new Embed extension.
func New(opts ...Option) goldmark.Extender {
e := &embedExtension{}
for _, opt := range opts {
opt(e)
}
return e
}
func (e *embedExtension) Extend(m goldmark.Markdown) {
m.Parser().AddOptions(
parser.WithASTTransformers(
util.Prioritized(defaultASTTransformer, 500),
),
)
m.Renderer().AddOptions(
renderer.WithNodeRenderers(
util.Prioritized(NewHTMLRenderer(), 500),
),
)
}
type astTransformer struct{}
var defaultASTTransformer = &astTransformer{}
func (a *astTransformer) Transform(node *ast.Document, reader text.Reader, pc parser.Context) {
replaceImages := func(n ast.Node, entering bool) (ast.WalkStatus, error) {
if !entering {
return ast.WalkContinue, nil
}
if n.Kind() != ast.KindImage {
return ast.WalkContinue, nil
}
img := n.(*ast.Image)
// parse the url
u, err := url.Parse(string(img.Destination))
if err != nil {
msg := ast.NewString([]byte(fmt.Sprintf("<!-- %s -->", err)))
msg.SetCode(true)
n.Parent().InsertAfter(n.Parent(), n, msg)
return ast.WalkContinue, nil
}
if u.Host == "www.youtube.com" && u.Path == "/watch" {
// if YouTube
v := u.Query().Get("v")
if v == "" {
return ast.WalkContinue, nil
}
youtube := NewYouTube(img, v)
n.Parent().ReplaceChild(n.Parent(), n, youtube)
} else if u.Host == "vimeo.com" {
// if Vimeo
// remove the '/' from url
path := u.Path[1:]
vimeo := NewVimeo(img, path)
n.Parent().ReplaceChild(n.Parent(), n, vimeo)
}
return ast.WalkContinue, nil
}
ast.Walk(node, replaceImages)
}
// HTMLRenderer struct is a renderer.NodeRenderer implementation for the extension.
type HTMLRenderer struct{}
// NewHTMLRenderer builds a new HTMLRenderer with given options and returns it.
func NewHTMLRenderer() renderer.NodeRenderer {
r := &HTMLRenderer{}
return r
}
// RegisterFuncs implements NodeRenderer.RegisterFuncs.
func (r *HTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) {
reg.Register(KindYouTube, r.renderYouTubeVideo)
reg.Register(KindVimeo, r.renderVimeoVideo)
}
func (r *HTMLRenderer) renderYouTubeVideo(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
return ast.WalkContinue, nil
}
youtube := node.(*YouTube)
w.Write([]byte(`<iframe width="560" height="315" src="https://www.youtube.com/embed/` + youtube.Video + `" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>`))
return ast.WalkContinue, nil
}
func (r *HTMLRenderer) renderVimeoVideo(w util.BufWriter, source []byte, node ast.Node, entering bool) (ast.WalkStatus, error) {
if entering {
return ast.WalkContinue, nil
}
vimeo := node.(*Vimeo)
w.Write([]byte(`<iframe src="https://player.vimeo.com/video/` + vimeo.Video + `?&badge=0&autopause=0&player_id=0" width="724" height="404" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>`))
return ast.WalkContinue, nil
}