2020-04-20 21:02:05 -07:00
|
|
|
package builder
|
2017-08-13 14:50:59 -07:00
|
|
|
|
|
|
|
import (
|
|
|
|
"net/url"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
2020-04-18 14:52:15 -07:00
|
|
|
|
|
|
|
"github.com/mxpv/podsync/pkg/model"
|
2017-08-13 14:50:59 -07:00
|
|
|
)
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
func ParseURL(link string) (model.Info, error) {
|
2019-10-29 14:38:29 -07:00
|
|
|
parsed, err := parseURL(link)
|
2017-08-13 14:50:59 -07:00
|
|
|
if err != nil {
|
2020-04-18 14:52:15 -07:00
|
|
|
return model.Info{}, err
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
info := model.Info{}
|
2017-08-13 14:50:59 -07:00
|
|
|
|
|
|
|
if strings.HasSuffix(parsed.Host, "youtube.com") {
|
|
|
|
kind, id, err := parseYoutubeURL(parsed)
|
|
|
|
if err != nil {
|
2020-04-18 14:52:15 -07:00
|
|
|
return model.Info{}, err
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
info.Provider = model.ProviderYoutube
|
2019-10-29 12:50:06 -07:00
|
|
|
info.LinkType = kind
|
|
|
|
info.ItemID = id
|
2017-08-13 14:50:59 -07:00
|
|
|
|
2019-10-29 12:50:06 -07:00
|
|
|
return info, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if strings.HasSuffix(parsed.Host, "vimeo.com") {
|
|
|
|
kind, id, err := parseVimeoURL(parsed)
|
|
|
|
if err != nil {
|
2020-04-18 14:52:15 -07:00
|
|
|
return model.Info{}, err
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
info.Provider = model.ProviderVimeo
|
2019-10-29 12:50:06 -07:00
|
|
|
info.LinkType = kind
|
|
|
|
info.ItemID = id
|
2017-08-13 14:50:59 -07:00
|
|
|
|
2019-10-29 12:50:06 -07:00
|
|
|
return info, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2021-10-02 21:32:46 -04:00
|
|
|
if strings.HasSuffix(parsed.Host, "soundcloud.com") {
|
|
|
|
kind, id, err := parseSoundcloudURL(parsed)
|
|
|
|
if err != nil {
|
|
|
|
return model.Info{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
info.Provider = model.ProviderSoundcloud
|
|
|
|
info.LinkType = kind
|
|
|
|
info.ItemID = id
|
|
|
|
|
|
|
|
return info, nil
|
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
return model.Info{}, errors.New("unsupported URL host")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-10-29 14:38:29 -07:00
|
|
|
func parseURL(link string) (*url.URL, error) {
|
|
|
|
if !strings.HasPrefix(link, "http") {
|
|
|
|
link = "https://" + link
|
|
|
|
}
|
|
|
|
|
|
|
|
parsed, err := url.Parse(link)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrapf(err, "failed to parse url: %s", link)
|
|
|
|
}
|
|
|
|
|
|
|
|
return parsed, nil
|
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
func parseYoutubeURL(parsed *url.URL) (model.Type, string, error) {
|
2017-08-13 14:50:59 -07:00
|
|
|
path := parsed.EscapedPath()
|
|
|
|
|
|
|
|
// https://www.youtube.com/playlist?list=PLCB9F975ECF01953C
|
2017-10-23 16:52:21 -07:00
|
|
|
// https://www.youtube.com/watch?v=rbCbho7aLYw&list=PLMpEfaKcGjpWEgNtdnsvLX6LzQL0UC0EM
|
|
|
|
if strings.HasPrefix(path, "/playlist") || strings.HasPrefix(path, "/watch") {
|
2020-04-18 14:52:15 -07:00
|
|
|
kind := model.TypePlaylist
|
2017-08-13 14:50:59 -07:00
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
id := parsed.Query().Get("list")
|
2017-08-13 14:50:59 -07:00
|
|
|
if id != "" {
|
2019-01-07 20:47:59 -08:00
|
|
|
return kind, id, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid playlist link")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// - https://www.youtube.com/channel/UC5XPnUk8Vvv_pWslhwom6Og
|
|
|
|
// - https://www.youtube.com/channel/UCrlakW-ewUT8sOod6Wmzyow/videos
|
|
|
|
if strings.HasPrefix(path, "/channel") {
|
2020-04-18 14:52:15 -07:00
|
|
|
kind := model.TypeChannel
|
2017-08-13 14:50:59 -07:00
|
|
|
parts := strings.Split(parsed.EscapedPath(), "/")
|
|
|
|
if len(parts) <= 2 {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid youtube channel link")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
id := parts[2]
|
2017-08-13 14:50:59 -07:00
|
|
|
if id == "" {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid id")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return kind, id, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// - https://www.youtube.com/user/fxigr1
|
|
|
|
if strings.HasPrefix(path, "/user") {
|
2020-04-18 14:52:15 -07:00
|
|
|
kind := model.TypeUser
|
2017-08-13 14:50:59 -07:00
|
|
|
|
|
|
|
parts := strings.Split(parsed.EscapedPath(), "/")
|
|
|
|
if len(parts) <= 2 {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid user link")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
id := parts[2]
|
2017-08-13 14:50:59 -07:00
|
|
|
if id == "" {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid id")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return kind, id, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("unsupported link format")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
func parseVimeoURL(parsed *url.URL) (model.Type, string, error) {
|
2017-08-13 14:50:59 -07:00
|
|
|
parts := strings.Split(parsed.EscapedPath(), "/")
|
|
|
|
if len(parts) <= 1 {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid vimeo link path")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
var kind model.Type
|
2019-01-07 20:47:59 -08:00
|
|
|
switch parts[1] {
|
|
|
|
case "groups":
|
2020-04-18 14:52:15 -07:00
|
|
|
kind = model.TypeGroup
|
2019-01-07 20:47:59 -08:00
|
|
|
case "channels":
|
2020-04-18 14:52:15 -07:00
|
|
|
kind = model.TypeChannel
|
2019-01-07 20:47:59 -08:00
|
|
|
default:
|
2020-04-18 14:52:15 -07:00
|
|
|
kind = model.TypeUser
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
if kind == model.TypeGroup || kind == model.TypeChannel {
|
2017-08-13 14:50:59 -07:00
|
|
|
if len(parts) <= 2 {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid channel link")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
id := parts[2]
|
2017-08-13 14:50:59 -07:00
|
|
|
if id == "" {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid id")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return kind, id, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2020-04-18 14:52:15 -07:00
|
|
|
if kind == model.TypeUser {
|
2019-01-07 20:47:59 -08:00
|
|
|
id := parts[1]
|
2017-08-13 14:50:59 -07:00
|
|
|
if id == "" {
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("invalid id")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return kind, id, nil
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 20:47:59 -08:00
|
|
|
return "", "", errors.New("unsupported link format")
|
2017-08-13 14:50:59 -07:00
|
|
|
}
|
2021-10-02 21:32:46 -04:00
|
|
|
|
|
|
|
func parseSoundcloudURL(parsed *url.URL) (model.Type, string, error) {
|
|
|
|
parts := strings.Split(parsed.EscapedPath(), "/")
|
|
|
|
if len(parts) <= 3 {
|
|
|
|
return "", "", errors.New("invald soundcloud link path")
|
|
|
|
}
|
|
|
|
|
|
|
|
var kind model.Type
|
|
|
|
|
|
|
|
// - https://soundcloud.com/user/sets/example-set
|
|
|
|
switch parts[2] {
|
|
|
|
case "sets":
|
|
|
|
kind = model.TypePlaylist
|
|
|
|
default:
|
|
|
|
return "", "", errors.New("invalid soundcloud url, missing sets")
|
|
|
|
}
|
|
|
|
|
|
|
|
id := parts[3]
|
|
|
|
|
|
|
|
return kind, id, nil
|
|
|
|
}
|