1
0
mirror of https://github.com/mxpv/podsync.git synced 2024-05-11 05:55:04 +00:00

Use context in YouTube builder

This commit is contained in:
Maksym Pavlenko
2019-10-29 14:52:19 -07:00
parent fc9942baf6
commit b22d2dccdb
5 changed files with 35 additions and 29 deletions

View File

@ -33,7 +33,7 @@ func (u *Updater) Update(ctx context.Context, feed *config.Feed) error {
}
// Query API to get episodes
result, err := provider.Build(feed)
result, err := provider.Build(ctx, feed)
if err != nil {
return err
}
@ -47,7 +47,7 @@ func (u *Updater) Update(ctx context.Context, feed *config.Feed) error {
// Save XML to disk
xmlName := fmt.Sprintf("%s.xml", result.ItemID)
xmlPath := filepath.Join(u.config.Server.DataDir, xmlName)
if err := ioutil.WriteFile(xmlPath, []byte(podcast.String()), 600); err != nil {
if err := ioutil.WriteFile(xmlPath, []byte(podcast.String()), 0600); err != nil {
return errors.Wrapf(err, "failed to write XML feed to disk")
}

View File

@ -1,6 +1,7 @@
package builder
import (
"context"
"errors"
"github.com/mxpv/podsync/pkg/config"
@ -13,5 +14,5 @@ var (
)
type Builder interface {
Build(cfg *config.Feed) (*model.Feed, error)
Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error)
}

View File

@ -158,7 +158,7 @@ func (v *VimeoBuilder) queryVideos(getVideos getVideosFunc, feed *model.Feed) er
}
}
func (v *VimeoBuilder) Build(cfg *config.Feed) (*model.Feed, error) {
func (v *VimeoBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error) {
info, err := link.Parse(cfg.URL)
if err != nil {
return nil, err

View File

@ -1,6 +1,7 @@
package builder
import (
"context"
"fmt"
"net/http"
"sort"
@ -38,7 +39,7 @@ 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(linkType link.Type, id string, parts string) (*youtube.Channel, error) {
func (yt *YouTubeBuilder) listChannels(ctx context.Context, linkType link.Type, id string, parts string) (*youtube.Channel, error) {
req := yt.client.Channels.List(parts)
switch linkType {
@ -50,7 +51,7 @@ func (yt *YouTubeBuilder) listChannels(linkType link.Type, id string, parts stri
return nil, errors.New("unsupported link type")
}
resp, err := req.Do(yt.key)
resp, err := req.Context(ctx).Do(yt.key)
if err != nil {
return nil, errors.Wrapf(err, "failed to query channel")
}
@ -65,7 +66,7 @@ func (yt *YouTubeBuilder) listChannels(linkType link.Type, id string, parts stri
// Cost: 3 units (call method: 1, snippet: 2)
// See https://developers.google.com/youtube/v3/docs/playlists/list#part
func (yt *YouTubeBuilder) listPlaylists(id, channelID string, parts string) (*youtube.Playlist, error) {
func (yt *YouTubeBuilder) listPlaylists(ctx context.Context, id, channelID string, parts string) (*youtube.Playlist, error) {
req := yt.client.Playlists.List(parts)
if id != "" {
@ -74,7 +75,7 @@ func (yt *YouTubeBuilder) listPlaylists(id, channelID string, parts string) (*yo
req = req.ChannelId(channelID)
}
resp, err := req.Do(yt.key)
resp, err := req.Context(ctx).Do(yt.key)
if err != nil {
return nil, errors.Wrapf(err, "failed to query playlist")
}
@ -89,13 +90,13 @@ func (yt *YouTubeBuilder) listPlaylists(id, channelID string, parts string) (*yo
// Cost: 3 units (call: 1, snippet: 2)
// See https://developers.google.com/youtube/v3/docs/playlistItems/list#part
func (yt *YouTubeBuilder) listPlaylistItems(itemID string, pageToken string) ([]*youtube.PlaylistItem, string, error) {
func (yt *YouTubeBuilder) listPlaylistItems(ctx context.Context, itemID string, pageToken string) ([]*youtube.PlaylistItem, string, error) {
req := yt.client.PlaylistItems.List("id,snippet").MaxResults(maxYoutubeResults).PlaylistId(itemID)
if pageToken != "" {
req = req.PageToken(pageToken)
}
resp, err := req.Do(yt.key)
resp, err := req.Context(ctx).Do(yt.key)
if err != nil {
return nil, "", errors.Wrap(err, "failed to query playlist items")
}
@ -141,11 +142,11 @@ func (yt *YouTubeBuilder) selectThumbnail(snippet *youtube.ThumbnailDetails, qua
return snippet.Default.Url
}
func (yt *YouTubeBuilder) GetVideoCount(info *link.Info) (uint64, error) {
func (yt *YouTubeBuilder) GetVideoCount(ctx context.Context, info *link.Info) (uint64, error) {
switch info.LinkType {
case link.TypeChannel, link.TypeUser:
// Cost: 3 units
if channel, err := yt.listChannels(info.LinkType, info.ItemID, "id,statistics"); err != nil {
if channel, err := yt.listChannels(ctx, info.LinkType, info.ItemID, "id,statistics"); err != nil {
return 0, err
} else { // nolint:golint
return channel.Statistics.VideoCount, nil
@ -153,7 +154,7 @@ func (yt *YouTubeBuilder) GetVideoCount(info *link.Info) (uint64, error) {
case link.TypePlaylist:
// Cost: 3 units
if playlist, err := yt.listPlaylists(info.ItemID, "", "id,contentDetails"); err != nil {
if playlist, err := yt.listPlaylists(ctx, info.ItemID, "", "id,contentDetails"); err != nil {
return 0, err
} else { // nolint:golint
return uint64(playlist.ContentDetails.ItemCount), nil
@ -164,7 +165,7 @@ func (yt *YouTubeBuilder) GetVideoCount(info *link.Info) (uint64, error) {
}
}
func (yt *YouTubeBuilder) queryFeed(feed *model.Feed, info *link.Info) error {
func (yt *YouTubeBuilder) queryFeed(ctx context.Context, feed *model.Feed, info *link.Info) error {
var (
thumbnails *youtube.ThumbnailDetails
)
@ -172,7 +173,7 @@ func (yt *YouTubeBuilder) queryFeed(feed *model.Feed, info *link.Info) error {
switch info.LinkType {
case link.TypeChannel, link.TypeUser:
// Cost: 5 units for channel or user
channel, err := yt.listChannels(info.LinkType, info.ItemID, "id,snippet,contentDetails")
channel, err := yt.listChannels(ctx, info.LinkType, info.ItemID, "id,snippet,contentDetails")
if err != nil {
return err
}
@ -200,7 +201,7 @@ func (yt *YouTubeBuilder) queryFeed(feed *model.Feed, info *link.Info) error {
case link.TypePlaylist:
// Cost: 3 units for playlist
playlist, err := yt.listPlaylists(info.ItemID, "", "id,snippet")
playlist, err := yt.listPlaylists(ctx, info.ItemID, "", "id,snippet")
if err != nil {
return err
}
@ -258,14 +259,14 @@ func (yt *YouTubeBuilder) getSize(duration int64, feed *model.Feed) int64 {
// Cost: 5 units (call: 1, snippet: 2, contentDetails: 2)
// See https://developers.google.com/youtube/v3/docs/videos/list#part
func (yt *YouTubeBuilder) queryVideoDescriptions(playlist map[string]*youtube.PlaylistItemSnippet, feed *model.Feed) error {
func (yt *YouTubeBuilder) queryVideoDescriptions(ctx context.Context, playlist map[string]*youtube.PlaylistItemSnippet, feed *model.Feed) error {
// Make the list of video ids
ids := make([]string, 0, len(playlist))
for _, s := range playlist {
ids = append(ids, s.ResourceId.VideoId)
}
req, err := yt.client.Videos.List("id,snippet,contentDetails").Id(strings.Join(ids, ",")).Do(yt.key)
req, err := yt.client.Videos.List("id,snippet,contentDetails").Id(strings.Join(ids, ",")).Context(ctx).Do(yt.key)
if err != nil {
return errors.Wrap(err, "failed to query video descriptions")
}
@ -326,14 +327,14 @@ func (yt *YouTubeBuilder) queryVideoDescriptions(playlist map[string]*youtube.Pl
}
// Cost: (3 units + 5 units) * X pages = 8 units per page
func (yt *YouTubeBuilder) queryItems(feed *model.Feed) error {
func (yt *YouTubeBuilder) queryItems(ctx context.Context, feed *model.Feed) error {
var (
token string
count int
)
for {
items, pageToken, err := yt.listPlaylistItems(feed.ItemID, token)
items, pageToken, err := yt.listPlaylistItems(ctx, feed.ItemID, token)
if err != nil {
return err
}
@ -352,7 +353,7 @@ func (yt *YouTubeBuilder) queryItems(feed *model.Feed) error {
}
// Query video descriptions from the list of ids
if err := yt.queryVideoDescriptions(snippets, feed); err != nil {
if err := yt.queryVideoDescriptions(ctx, snippets, feed); err != nil {
return err
}
@ -362,7 +363,7 @@ func (yt *YouTubeBuilder) queryItems(feed *model.Feed) error {
}
}
func (yt *YouTubeBuilder) Build(cfg *config.Feed) (*model.Feed, error) {
func (yt *YouTubeBuilder) Build(ctx context.Context, cfg *config.Feed) (*model.Feed, error) {
info, err := link.Parse(cfg.URL)
if err != nil {
return nil, err
@ -380,11 +381,11 @@ func (yt *YouTubeBuilder) Build(cfg *config.Feed) (*model.Feed, error) {
}
// Query general information about feed (title, description, lang, etc)
if err := yt.queryFeed(feed, &info); err != nil {
if err := yt.queryFeed(ctx, feed, &info); err != nil {
return nil, err
}
if err := yt.queryItems(feed); err != nil {
if err := yt.queryItems(ctx, feed); err != nil {
return nil, err
}

View File

@ -1,6 +1,7 @@
package builder
import (
"context"
"os"
"testing"
@ -11,7 +12,10 @@ import (
"github.com/mxpv/podsync/pkg/link"
)
var ytKey = os.Getenv("YOUTUBE_TEST_API_KEY")
var (
testCtx = context.Background()
ytKey = os.Getenv("YOUTUBE_TEST_API_KEY")
)
func TestYT_QueryChannel(t *testing.T) {
if ytKey == "" {
@ -21,11 +25,11 @@ func TestYT_QueryChannel(t *testing.T) {
builder, err := NewYouTubeBuilder(ytKey)
require.NoError(t, err)
channel, err := builder.listChannels(link.TypeChannel, "UC2yTVSttx7lxAOAzx1opjoA", "id")
channel, err := builder.listChannels(testCtx, link.TypeChannel, "UC2yTVSttx7lxAOAzx1opjoA", "id")
require.NoError(t, err)
require.Equal(t, "UC2yTVSttx7lxAOAzx1opjoA", channel.Id)
channel, err = builder.listChannels(link.TypeUser, "fxigr1", "id")
channel, err = builder.listChannels(testCtx, link.TypeUser, "fxigr1", "id")
require.NoError(t, err)
require.Equal(t, "UCr_fwF-n-2_olTYd-m3n32g", channel.Id)
}
@ -49,7 +53,7 @@ func TestYT_BuildFeed(t *testing.T) {
for _, addr := range urls {
t.Run(addr, func(t *testing.T) {
feed, err := builder.Build(&config.Feed{URL: addr})
feed, err := builder.Build(testCtx, &config.Feed{URL: addr})
require.NoError(t, err)
assert.NotEmpty(t, feed.Title)
@ -91,7 +95,7 @@ func TestYT_GetVideoCount(t *testing.T) {
for _, f := range feeds {
feed := f
t.Run(f.ItemID, func(t *testing.T) {
count, err := builder.GetVideoCount(feed)
count, err := builder.GetVideoCount(testCtx, feed)
assert.NoError(t, err)
assert.NotZero(t, count)
})