diff --git a/pkg/db/badger_test.go b/pkg/db/badger_test.go index 68a7511e..1b0b99b2 100644 --- a/pkg/db/badger_test.go +++ b/pkg/db/badger_test.go @@ -11,7 +11,6 @@ import ( "github.com/stretchr/testify/require" "github.com/mxpv/podsync/pkg/config" - "github.com/mxpv/podsync/pkg/link" "github.com/mxpv/podsync/pkg/model" ) @@ -188,8 +187,8 @@ func getFeed() *model.Feed { return &model.Feed{ ID: "1", ItemID: "2", - LinkType: link.TypeChannel, - Provider: link.ProviderVimeo, + LinkType: model.TypeChannel, + Provider: model.ProviderVimeo, CreatedAt: time.Now().UTC(), LastAccess: time.Now().UTC(), ExpirationTime: time.Now().UTC().Add(1 * time.Hour), diff --git a/pkg/feed/common.go b/pkg/feed/common.go index 935dbee1..eca7be6b 100644 --- a/pkg/feed/common.go +++ b/pkg/feed/common.go @@ -6,7 +6,6 @@ import ( "github.com/pkg/errors" "github.com/mxpv/podsync/pkg/config" - "github.com/mxpv/podsync/pkg/link" "github.com/mxpv/podsync/pkg/model" ) @@ -20,15 +19,15 @@ func New(ctx context.Context, cfg *config.Feed, tokens config.Tokens) (Builder, err error ) - info, err := link.Parse(cfg.URL) + info, err := ParseURL(cfg.URL) if err != nil { return nil, err } switch info.Provider { - case link.ProviderYoutube: + case model.ProviderYoutube: provider, err = NewYouTubeBuilder(tokens.YouTube) - case link.ProviderVimeo: + case model.ProviderVimeo: provider, err = NewVimeoBuilder(ctx, tokens.Vimeo) default: return nil, errors.Errorf("unsupported provider %q", info.Provider) diff --git a/pkg/link/url.go b/pkg/feed/url.go similarity index 77% rename from pkg/link/url.go rename to pkg/feed/url.go index 9a2c3acb..5566f198 100644 --- a/pkg/link/url.go +++ b/pkg/feed/url.go @@ -1,27 +1,29 @@ -package link +package feed import ( "net/url" "strings" "github.com/pkg/errors" + + "github.com/mxpv/podsync/pkg/model" ) -func Parse(link string) (Info, error) { +func ParseURL(link string) (model.Info, error) { parsed, err := parseURL(link) if err != nil { - return Info{}, err + return model.Info{}, err } - info := Info{} + info := model.Info{} if strings.HasSuffix(parsed.Host, "youtube.com") { kind, id, err := parseYoutubeURL(parsed) if err != nil { - return Info{}, err + return model.Info{}, err } - info.Provider = ProviderYoutube + info.Provider = model.ProviderYoutube info.LinkType = kind info.ItemID = id @@ -31,17 +33,17 @@ func Parse(link string) (Info, error) { if strings.HasSuffix(parsed.Host, "vimeo.com") { kind, id, err := parseVimeoURL(parsed) if err != nil { - return Info{}, err + return model.Info{}, err } - info.Provider = ProviderVimeo + info.Provider = model.ProviderVimeo info.LinkType = kind info.ItemID = id return info, nil } - return Info{}, errors.New("unsupported URL host") + return model.Info{}, errors.New("unsupported URL host") } func parseURL(link string) (*url.URL, error) { @@ -57,13 +59,13 @@ func parseURL(link string) (*url.URL, error) { return parsed, nil } -func parseYoutubeURL(parsed *url.URL) (Type, string, error) { +func parseYoutubeURL(parsed *url.URL) (model.Type, string, error) { path := parsed.EscapedPath() // https://www.youtube.com/playlist?list=PLCB9F975ECF01953C // https://www.youtube.com/watch?v=rbCbho7aLYw&list=PLMpEfaKcGjpWEgNtdnsvLX6LzQL0UC0EM if strings.HasPrefix(path, "/playlist") || strings.HasPrefix(path, "/watch") { - kind := TypePlaylist + kind := model.TypePlaylist id := parsed.Query().Get("list") if id != "" { @@ -76,7 +78,7 @@ func parseYoutubeURL(parsed *url.URL) (Type, string, error) { // - https://www.youtube.com/channel/UC5XPnUk8Vvv_pWslhwom6Og // - https://www.youtube.com/channel/UCrlakW-ewUT8sOod6Wmzyow/videos if strings.HasPrefix(path, "/channel") { - kind := TypeChannel + kind := model.TypeChannel parts := strings.Split(parsed.EscapedPath(), "/") if len(parts) <= 2 { return "", "", errors.New("invalid youtube channel link") @@ -92,7 +94,7 @@ func parseYoutubeURL(parsed *url.URL) (Type, string, error) { // - https://www.youtube.com/user/fxigr1 if strings.HasPrefix(path, "/user") { - kind := TypeUser + kind := model.TypeUser parts := strings.Split(parsed.EscapedPath(), "/") if len(parts) <= 2 { @@ -110,23 +112,23 @@ func parseYoutubeURL(parsed *url.URL) (Type, string, error) { return "", "", errors.New("unsupported link format") } -func parseVimeoURL(parsed *url.URL) (Type, string, error) { +func parseVimeoURL(parsed *url.URL) (model.Type, string, error) { parts := strings.Split(parsed.EscapedPath(), "/") if len(parts) <= 1 { return "", "", errors.New("invalid vimeo link path") } - var kind Type + var kind model.Type switch parts[1] { case "groups": - kind = TypeGroup + kind = model.TypeGroup case "channels": - kind = TypeChannel + kind = model.TypeChannel default: - kind = TypeUser + kind = model.TypeUser } - if kind == TypeGroup || kind == TypeChannel { + if kind == model.TypeGroup || kind == model.TypeChannel { if len(parts) <= 2 { return "", "", errors.New("invalid channel link") } @@ -139,7 +141,7 @@ func parseVimeoURL(parsed *url.URL) (Type, string, error) { return kind, id, nil } - if kind == TypeUser { + if kind == model.TypeUser { id := parts[1] if id == "" { return "", "", errors.New("invalid id") diff --git a/pkg/link/url_test.go b/pkg/feed/url_test.go similarity index 85% rename from pkg/link/url_test.go rename to pkg/feed/url_test.go index 4c7dd8d6..5b09a801 100644 --- a/pkg/link/url_test.go +++ b/pkg/feed/url_test.go @@ -1,23 +1,25 @@ -package link +package feed import ( "net/url" "testing" "github.com/stretchr/testify/require" + + "github.com/mxpv/podsync/pkg/model" ) func TestParseYoutubeURL_Playlist(t *testing.T) { link, _ := url.ParseRequestURI("https://www.youtube.com/playlist?list=PLCB9F975ECF01953C") kind, id, err := parseYoutubeURL(link) require.NoError(t, err) - require.Equal(t, TypePlaylist, kind) + require.Equal(t, model.TypePlaylist, kind) require.Equal(t, "PLCB9F975ECF01953C", id) link, _ = url.ParseRequestURI("https://www.youtube.com/watch?v=rbCbho7aLYw&list=PLMpEfaKcGjpWEgNtdnsvLX6LzQL0UC0EM") kind, id, err = parseYoutubeURL(link) require.NoError(t, err) - require.Equal(t, TypePlaylist, kind) + require.Equal(t, model.TypePlaylist, kind) require.Equal(t, "PLMpEfaKcGjpWEgNtdnsvLX6LzQL0UC0EM", id) } @@ -25,13 +27,13 @@ func TestParseYoutubeURL_Channel(t *testing.T) { link, _ := url.ParseRequestURI("https://www.youtube.com/channel/UC5XPnUk8Vvv_pWslhwom6Og") kind, id, err := parseYoutubeURL(link) require.NoError(t, err) - require.Equal(t, TypeChannel, kind) + require.Equal(t, model.TypeChannel, kind) require.Equal(t, "UC5XPnUk8Vvv_pWslhwom6Og", id) link, _ = url.ParseRequestURI("https://www.youtube.com/channel/UCrlakW-ewUT8sOod6Wmzyow/videos") kind, id, err = parseYoutubeURL(link) require.NoError(t, err) - require.Equal(t, TypeChannel, kind) + require.Equal(t, model.TypeChannel, kind) require.Equal(t, "UCrlakW-ewUT8sOod6Wmzyow", id) } @@ -39,7 +41,7 @@ func TestParseYoutubeURL_User(t *testing.T) { link, _ := url.ParseRequestURI("https://youtube.com/user/fxigr1") kind, id, err := parseYoutubeURL(link) require.NoError(t, err) - require.Equal(t, TypeUser, kind) + require.Equal(t, model.TypeUser, kind) require.Equal(t, "fxigr1", id) } @@ -57,25 +59,25 @@ func TestParseVimeoURL_Group(t *testing.T) { link, _ := url.ParseRequestURI("https://vimeo.com/groups/109") kind, id, err := parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeGroup, kind) + require.Equal(t, model.TypeGroup, kind) require.Equal(t, "109", id) link, _ = url.ParseRequestURI("http://vimeo.com/groups/109") kind, id, err = parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeGroup, kind) + require.Equal(t, model.TypeGroup, kind) require.Equal(t, "109", id) link, _ = url.ParseRequestURI("http://www.vimeo.com/groups/109") kind, id, err = parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeGroup, kind) + require.Equal(t, model.TypeGroup, kind) require.Equal(t, "109", id) link, _ = url.ParseRequestURI("https://vimeo.com/groups/109/videos/") kind, id, err = parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeGroup, kind) + require.Equal(t, model.TypeGroup, kind) require.Equal(t, "109", id) } @@ -83,13 +85,13 @@ func TestParseVimeoURL_Channel(t *testing.T) { link, _ := url.ParseRequestURI("https://vimeo.com/channels/staffpicks") kind, id, err := parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeChannel, kind) + require.Equal(t, model.TypeChannel, kind) require.Equal(t, "staffpicks", id) link, _ = url.ParseRequestURI("http://vimeo.com/channels/staffpicks/146224925") kind, id, err = parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeChannel, kind) + require.Equal(t, model.TypeChannel, kind) require.Equal(t, "staffpicks", id) } @@ -97,7 +99,7 @@ func TestParseVimeoURL_User(t *testing.T) { link, _ := url.ParseRequestURI("https://vimeo.com/awhitelabelproduct") kind, id, err := parseVimeoURL(link) require.NoError(t, err) - require.Equal(t, TypeUser, kind) + require.Equal(t, model.TypeUser, kind) require.Equal(t, "awhitelabelproduct", id) } diff --git a/pkg/feed/vimeo.go b/pkg/feed/vimeo.go index 6184cba2..758debc6 100644 --- a/pkg/feed/vimeo.go +++ b/pkg/feed/vimeo.go @@ -11,7 +11,6 @@ import ( "golang.org/x/oauth2" "github.com/mxpv/podsync/pkg/config" - "github.com/mxpv/podsync/pkg/link" "github.com/mxpv/podsync/pkg/model" ) @@ -160,7 +159,7 @@ func (v *VimeoBuilder) queryVideos(getVideos getVideosFunc, feed *model.Feed) er } func (v *VimeoBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error) { - info, err := link.Parse(cfg.URL) + info, err := ParseURL(cfg.URL) if err != nil { return nil, err } @@ -175,7 +174,7 @@ func (v *VimeoBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed UpdatedAt: time.Now().UTC(), } - if info.LinkType == link.TypeChannel { + if info.LinkType == model.TypeChannel { if err := v.queryChannel(feed); err != nil { return nil, err } @@ -187,7 +186,7 @@ func (v *VimeoBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed return feed, nil } - if info.LinkType == link.TypeGroup { + if info.LinkType == model.TypeGroup { if err := v.queryGroup(feed); err != nil { return nil, err } @@ -199,7 +198,7 @@ func (v *VimeoBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed return feed, nil } - if info.LinkType == link.TypeUser { + if info.LinkType == model.TypeUser { if err := v.queryUser(feed); err != nil { return nil, err } diff --git a/pkg/feed/build.go b/pkg/feed/xml.go similarity index 100% rename from pkg/feed/build.go rename to pkg/feed/xml.go diff --git a/pkg/feed/youtube.go b/pkg/feed/youtube.go index a927712b..b0d400f6 100644 --- a/pkg/feed/youtube.go +++ b/pkg/feed/youtube.go @@ -14,7 +14,6 @@ import ( "google.golang.org/api/youtube/v3" "github.com/mxpv/podsync/pkg/config" - "github.com/mxpv/podsync/pkg/link" "github.com/mxpv/podsync/pkg/model" ) @@ -39,13 +38,13 @@ type YouTubeBuilder struct { // Cost: 5 units (call method: 1, snippet: 2, contentDetails: 2) // See https://developers.google.com/youtube/v3/docs/channels/list#part -func (yt *YouTubeBuilder) listChannels(ctx context.Context, linkType link.Type, id string, parts string) (*youtube.Channel, error) { +func (yt *YouTubeBuilder) listChannels(ctx context.Context, linkType model.Type, id string, parts string) (*youtube.Channel, error) { req := yt.client.Channels.List(parts) switch linkType { - case link.TypeChannel: + case model.TypeChannel: req = req.Id(id) - case link.TypeUser: + case model.TypeUser: req = req.ForUsername(id) default: return nil, errors.New("unsupported link type") @@ -148,9 +147,9 @@ func (yt *YouTubeBuilder) selectThumbnail(snippet *youtube.ThumbnailDetails, qua return snippet.Default.Url } -func (yt *YouTubeBuilder) GetVideoCount(ctx context.Context, info *link.Info) (uint64, error) { +func (yt *YouTubeBuilder) GetVideoCount(ctx context.Context, info *model.Info) (uint64, error) { switch info.LinkType { - case link.TypeChannel, link.TypeUser: + case model.TypeChannel, model.TypeUser: // Cost: 3 units if channel, err := yt.listChannels(ctx, info.LinkType, info.ItemID, "id,statistics"); err != nil { return 0, err @@ -158,7 +157,7 @@ func (yt *YouTubeBuilder) GetVideoCount(ctx context.Context, info *link.Info) (u return channel.Statistics.VideoCount, nil } - case link.TypePlaylist: + case model.TypePlaylist: // Cost: 3 units if playlist, err := yt.listPlaylists(ctx, info.ItemID, "", "id,contentDetails"); err != nil { return 0, err @@ -171,13 +170,13 @@ func (yt *YouTubeBuilder) GetVideoCount(ctx context.Context, info *link.Info) (u } } -func (yt *YouTubeBuilder) queryFeed(ctx context.Context, feed *model.Feed, info *link.Info) error { +func (yt *YouTubeBuilder) queryFeed(ctx context.Context, feed *model.Feed, info *model.Info) error { var ( thumbnails *youtube.ThumbnailDetails ) switch info.LinkType { - case link.TypeChannel, link.TypeUser: + case model.TypeChannel, model.TypeUser: // Cost: 5 units for channel or user channel, err := yt.listChannels(ctx, info.LinkType, info.ItemID, "id,snippet,contentDetails") if err != nil { @@ -205,7 +204,7 @@ func (yt *YouTubeBuilder) queryFeed(ctx context.Context, feed *model.Feed, info thumbnails = channel.Snippet.Thumbnails - case link.TypePlaylist: + case model.TypePlaylist: // Cost: 3 units for playlist playlist, err := yt.listPlaylists(ctx, info.ItemID, "", "id,snippet") if err != nil { @@ -369,7 +368,7 @@ func (yt *YouTubeBuilder) queryItems(ctx context.Context, feed *model.Feed) erro } func (yt *YouTubeBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error) { - info, err := link.Parse(cfg.URL) + info, err := ParseURL(cfg.URL) if err != nil { return nil, err } diff --git a/pkg/feed/youtube_test.go b/pkg/feed/youtube_test.go index 80069de0..2c2483c3 100644 --- a/pkg/feed/youtube_test.go +++ b/pkg/feed/youtube_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/mxpv/podsync/pkg/config" - "github.com/mxpv/podsync/pkg/link" + "github.com/mxpv/podsync/pkg/model" ) var ( @@ -25,11 +25,11 @@ func TestYT_QueryChannel(t *testing.T) { builder, err := NewYouTubeBuilder(ytKey) require.NoError(t, err) - channel, err := builder.listChannels(testCtx, link.TypeChannel, "UC2yTVSttx7lxAOAzx1opjoA", "id") + channel, err := builder.listChannels(testCtx, model.TypeChannel, "UC2yTVSttx7lxAOAzx1opjoA", "id") require.NoError(t, err) require.Equal(t, "UC2yTVSttx7lxAOAzx1opjoA", channel.Id) - channel, err = builder.listChannels(testCtx, link.TypeUser, "fxigr1", "id") + channel, err = builder.listChannels(testCtx, model.TypeUser, "fxigr1", "id") require.NoError(t, err) require.Equal(t, "UCr_fwF-n-2_olTYd-m3n32g", channel.Id) } @@ -83,13 +83,13 @@ func TestYT_GetVideoCount(t *testing.T) { builder, err := NewYouTubeBuilder(ytKey) require.NoError(t, err) - feeds := []*link.Info{ - {Provider: link.ProviderYoutube, LinkType: link.TypeUser, ItemID: "fxigr1"}, - {Provider: link.ProviderYoutube, LinkType: link.TypeChannel, ItemID: "UCupvZG-5ko_eiXAupbDfxWw"}, - {Provider: link.ProviderYoutube, LinkType: link.TypePlaylist, ItemID: "PLF7tUDhGkiCk_Ne30zu7SJ9gZF9R9ZruE"}, - {Provider: link.ProviderYoutube, LinkType: link.TypeChannel, ItemID: "UCK9lZ2lHRBgx2LOcqPifukA"}, - {Provider: link.ProviderYoutube, LinkType: link.TypeUser, ItemID: "WylsaLive"}, - {Provider: link.ProviderYoutube, LinkType: link.TypePlaylist, ItemID: "PLUVl5pafUrBydT_gsCjRGeCy0hFHloec8"}, + feeds := []*model.Info{ + {Provider: model.ProviderYoutube, LinkType: model.TypeUser, ItemID: "fxigr1"}, + {Provider: model.ProviderYoutube, LinkType: model.TypeChannel, ItemID: "UCupvZG-5ko_eiXAupbDfxWw"}, + {Provider: model.ProviderYoutube, LinkType: model.TypePlaylist, ItemID: "PLF7tUDhGkiCk_Ne30zu7SJ9gZF9R9ZruE"}, + {Provider: model.ProviderYoutube, LinkType: model.TypeChannel, ItemID: "UCK9lZ2lHRBgx2LOcqPifukA"}, + {Provider: model.ProviderYoutube, LinkType: model.TypeUser, ItemID: "WylsaLive"}, + {Provider: model.ProviderYoutube, LinkType: model.TypePlaylist, ItemID: "PLUVl5pafUrBydT_gsCjRGeCy0hFHloec8"}, } for _, f := range feeds { diff --git a/pkg/model/feed.go b/pkg/model/feed.go index d8a64a44..35f57fba 100644 --- a/pkg/model/feed.go +++ b/pkg/model/feed.go @@ -2,8 +2,6 @@ package model import ( "time" - - "github.com/mxpv/podsync/pkg/link" ) // Quality to use when downloading episodes @@ -37,24 +35,24 @@ type Episode struct { } type Feed struct { - ID string `json:"feed_id"` - ItemID string `json:"item_id"` - LinkType link.Type `json:"link_type"` // Either group, channel or user - Provider link.Provider `json:"provider"` // Youtube or Vimeo - CreatedAt time.Time `json:"created_at"` - LastAccess time.Time `json:"last_access"` - ExpirationTime time.Time `json:"expiration_time"` - Format Format `json:"format"` - Quality Quality `json:"quality"` - PageSize int `json:"page_size"` - CoverArt string `json:"cover_art"` - Title string `json:"title"` - Description string `json:"description"` - PubDate time.Time `json:"pub_date"` - Author string `json:"author"` - ItemURL string `json:"item_url"` // Platform specific URL - Episodes []*Episode `json:"-"` // Array of episodes - UpdatedAt time.Time `json:"updated_at"` + ID string `json:"feed_id"` + ItemID string `json:"item_id"` + LinkType Type `json:"link_type"` // Either group, channel or user + Provider Provider `json:"provider"` // Youtube or Vimeo + CreatedAt time.Time `json:"created_at"` + LastAccess time.Time `json:"last_access"` + ExpirationTime time.Time `json:"expiration_time"` + Format Format `json:"format"` + Quality Quality `json:"quality"` + PageSize int `json:"page_size"` + CoverArt string `json:"cover_art"` + Title string `json:"title"` + Description string `json:"description"` + PubDate time.Time `json:"pub_date"` + Author string `json:"author"` + ItemURL string `json:"item_url"` // Platform specific URL + Episodes []*Episode `json:"-"` // Array of episodes + UpdatedAt time.Time `json:"updated_at"` } type EpisodeStatus string diff --git a/pkg/link/info.go b/pkg/model/link.go similarity index 96% rename from pkg/link/info.go rename to pkg/model/link.go index 05367e2b..4a84e9a4 100644 --- a/pkg/link/info.go +++ b/pkg/model/link.go @@ -1,4 +1,4 @@ -package link +package model type Type string