62 lines
1.8 KiB
Go
62 lines
1.8 KiB
Go
package api
|
||
|
||
import (
|
||
"errors"
|
||
"net/url"
|
||
"regexp"
|
||
"strings"
|
||
)
|
||
|
||
var (
|
||
youtubeIDRE = regexp.MustCompile(`^[A-Za-z0-9_-]{11}$`)
|
||
rutubeIDRE = regexp.MustCompile(`^[a-f0-9]{32}$`)
|
||
errVideoURL = errors.New("video url")
|
||
)
|
||
|
||
// embedVideoURL приводит ссылку на видеоотзыв к адресу для встраивания.
|
||
// Адрес попадает в src у iframe, поэтому пропускаем только YouTube и Rutube:
|
||
// произвольная ссылка (например, javascript:) выполнилась бы на странице сайта.
|
||
func embedVideoURL(raw string) (string, error) {
|
||
raw = strings.TrimSpace(raw)
|
||
if raw == "" {
|
||
return "", nil
|
||
}
|
||
u, err := url.Parse(raw)
|
||
if err != nil || (u.Scheme != "https" && u.Scheme != "http") {
|
||
return "", errVideoURL
|
||
}
|
||
host := strings.TrimPrefix(strings.ToLower(u.Hostname()), "www.")
|
||
host = strings.TrimPrefix(host, "m.")
|
||
parts := strings.Split(strings.Trim(u.Path, "/"), "/")
|
||
|
||
youtube := func(id string) (string, error) {
|
||
if !youtubeIDRE.MatchString(id) {
|
||
return "", errVideoURL
|
||
}
|
||
return "https://www.youtube.com/embed/" + id, nil
|
||
}
|
||
switch host {
|
||
case "youtu.be":
|
||
return youtube(parts[0])
|
||
case "youtube.com", "youtube-nocookie.com":
|
||
switch {
|
||
case len(parts) == 1 && parts[0] == "watch":
|
||
return youtube(u.Query().Get("v"))
|
||
case len(parts) == 2 && (parts[0] == "embed" || parts[0] == "shorts" || parts[0] == "live"):
|
||
return youtube(parts[1])
|
||
}
|
||
case "rutube.ru":
|
||
// rutube.ru/video/<id>/ и rutube.ru/play/embed/<id>
|
||
id := ""
|
||
if len(parts) == 2 && parts[0] == "video" {
|
||
id = parts[1]
|
||
} else if len(parts) == 3 && parts[0] == "play" && parts[1] == "embed" {
|
||
id = parts[2]
|
||
}
|
||
if rutubeIDRE.MatchString(id) {
|
||
return "https://rutube.ru/play/embed/" + id, nil
|
||
}
|
||
}
|
||
return "", errVideoURL
|
||
}
|