responsive video iframe

This commit is contained in:
Nazar Kanaev 2021-05-13 21:42:34 +01:00
parent da267a56ef
commit 28f08ad42a
4 changed files with 66 additions and 4 deletions

View File

@ -360,6 +360,27 @@ select.form-control:not([multiple]):not([size]) {
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
.content .video-wrapper {
position: relative;
display: block;
width: 100%;
overflow: hidden;
}
.content .video-wrapper::before {
display: block;
padding-top: 56.25%; /* 16x9 aspect ratio */
content: "";
}
.content .video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.content pre { .content pre {
overflow-x: auto; overflow-x: auto;
color: inherit; color: inherit;

View File

@ -58,19 +58,31 @@ func Sanitize(baseURL, input string) string {
attrNames, htmlAttributes := sanitizeAttributes(baseURL, tagName, token.Attr) attrNames, htmlAttributes := sanitizeAttributes(baseURL, tagName, token.Attr)
if hasRequiredAttributes(tagName, attrNames) { if hasRequiredAttributes(tagName, attrNames) {
wrap := isVideoIframe(token)
if wrap {
buffer.WriteString(`<div class="video-wrapper">`)
}
if len(attrNames) > 0 { if len(attrNames) > 0 {
buffer.WriteString("<" + tagName + " " + htmlAttributes + ">") buffer.WriteString("<" + tagName + " " + htmlAttributes + ">")
} else { } else {
buffer.WriteString("<" + tagName + ">") buffer.WriteString("<" + tagName + ">")
} }
if wrap {
buffer.WriteString("</iframe></div>")
} else {
tagStack = append(tagStack, tagName) tagStack = append(tagStack, tagName)
} }
}
} else if isBlockedTag(tagName) { } else if isBlockedTag(tagName) {
blacklistedTagDepth++ blacklistedTagDepth++
} }
case html.EndTagToken: case html.EndTagToken:
tagName := token.Data tagName := token.Data
if tagName == "iframe" {
continue
}
if isValidTag(tagName) && inList(tagName, tagStack) { if isValidTag(tagName) && inList(tagName, tagStack) {
buffer.WriteString(fmt.Sprintf("</%s>", tagName)) buffer.WriteString(fmt.Sprintf("</%s>", tagName))
} else if isBlockedTag(tagName) { } else if isBlockedTag(tagName) {
@ -417,3 +429,22 @@ func isValidDataAttribute(value string) bool {
} }
return false return false
} }
func isVideoIframe(token html.Token) bool {
videoWhitelist := map[string]bool{
"player.bilibili.com": true,
"player.vimeo.com": true,
"www.dailymotion.com": true,
"www.youtube-nocookie.com": true,
"www.youtube.com": true,
}
if token.Data == "iframe" {
for _, attr := range token.Attr {
if attr.Key == "src" {
domain := htmlutil.URLDomain(attr.Val)
return videoWhitelist[domain]
}
}
}
return false
}

View File

@ -175,7 +175,7 @@ func TestInvalidIFrame(t *testing.T) {
func TestIFrameWithChildElements(t *testing.T) { func TestIFrameWithChildElements(t *testing.T) {
input := `<iframe src="https://www.youtube.com/"><p>test</p></iframe>` input := `<iframe src="https://www.youtube.com/"><p>test</p></iframe>`
expected := `<iframe src="https://www.youtube.com/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>` expected := `<div class="video-wrapper"><iframe src="https://www.youtube.com/" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe></div>`
output := Sanitize("http://example.com/", input) output := Sanitize("http://example.com/", input)
if expected != output { if expected != output {
@ -255,7 +255,7 @@ func TestEspaceAttributes(t *testing.T) {
func TestReplaceIframeURL(t *testing.T) { func TestReplaceIframeURL(t *testing.T) {
input := `<iframe src="https://player.vimeo.com/video/123456?title=0&amp;byline=0"></iframe>` input := `<iframe src="https://player.vimeo.com/video/123456?title=0&amp;byline=0"></iframe>`
expected := `<iframe src="https://player.vimeo.com/video/123456?title=0&amp;byline=0" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe>` expected := `<div class="video-wrapper"><iframe src="https://player.vimeo.com/video/123456?title=0&amp;byline=0" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe></div>`
output := Sanitize("http://example.org/", input) output := Sanitize("http://example.org/", input)
if expected != output { if expected != output {
@ -292,3 +292,13 @@ func TestReplaceStyle(t *testing.T) {
t.Errorf(`Wrong output: "%s" != "%s"`, expected, output) t.Errorf(`Wrong output: "%s" != "%s"`, expected, output)
} }
} }
func TestWrapYoutubeIFrames(t *testing.T) {
input := `<iframe src="https://www.youtube.com/embed/foobar"></iframe>`
expected := `<div class="video-wrapper"><iframe src="https://www.youtube.com/embed/foobar" sandbox="allow-scripts allow-same-origin allow-popups" loading="lazy"></iframe></div>`
output := Sanitize("http://example.org/", input)
if expected != output {
t.Errorf("Wrong output:\nwant: %v\nhave: %v", expected, output)
}
}

View File

@ -417,7 +417,7 @@ func (s *Server) handlePageCrawl(c *router.Context) {
if content := silo.VideoIFrame(url); content != "" { if content := silo.VideoIFrame(url); content != "" {
c.JSON(http.StatusOK, map[string]string{ c.JSON(http.StatusOK, map[string]string{
"content": content, "content": sanitizer.Sanitize(url, content),
}) })
return return
} }