✨ Support pagination when list

This commit is contained in:
OpenWaygate committed 2025-09-14 19:24:31 +08:00
1 parent 5bf60ff2f1
commit a74fca8ce7
21 files changed
+343 -206

No files matched your search

+26 -11
View File
@@ -27,14 +27,14 @@ type activity struct {
RegionCode string `yaml:"region_code" json:"region_code"`
}
type Activity interface {
type Activity[T any] interface {
List([]string, string, string, io.Writer) error
Get([]string) ([]*youtube.Activity, error)
Get([]string) ([]*T, error)
}
type Option func(*activity)
func NewActivity(opts ...Option) Activity {
func NewActivity(opts ...Option) Activity[youtube.Activity] {
a := &activity{}
for _, opt := range opts {
@@ -58,9 +58,8 @@ func (a *activity) Get(parts []string) ([]*youtube.Activity, error) {
call = call.Mine(*a.Mine)
}
call.MaxResults(a.MaxResults)
if a.PublishedAfter != "" {
// TODO: update call
call.PublishedAfter(a.PublishedAfter)
}
@@ -72,19 +71,35 @@ func (a *activity) Get(parts []string) ([]*youtube.Activity, error) {
call.RegionCode(a.RegionCode)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetActivity, err)
var items []*youtube.Activity
pageToken := ""
for a.MaxResults > 0 {
call = call.MaxResults(min(a.MaxResults, pkg.PerPage))
a.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetActivity, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (a *activity) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
activities, err := a.Get(parts)
if err != nil {
if err != nil && activities == nil {
return err
}
@@ -109,7 +124,7 @@ func (a *activity) List(
)
}
}
return nil
return err
}
func WithChannelId(channelId string) Option {
+14 -10
View File
@@ -41,18 +41,18 @@ type caption struct {
Tlang string `yaml:"tlang" json:"tlang"`
}
type Caption interface {
Get(parts []string) ([]*youtube.Caption, error)
List(parts []string, output string, s string, writer io.Writer) error
Insert(output string, s string, writer io.Writer) error
Update(output string, s string, writer io.Writer) error
Delete(writer io.Writer) error
Download(writer io.Writer) error
type Caption[T youtube.Caption] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
Delete(io.Writer) error
Download(io.Writer) error
}
type Option func(*caption)
func NewCation(opts ...Option) Caption {
func NewCation(opts ...Option) Caption[youtube.Caption] {
c := &caption{}
for _, opt := range opts {
opt(c)
@@ -112,7 +112,9 @@ func (c *caption) List(
return nil
}
func (c *caption) Insert(output string, jpath string, writer io.Writer) error {
func (c *caption) Insert(
output string, jpath string, writer io.Writer,
) error {
file, err := pkg.Root.Open(c.File)
if err != nil {
return errors.Join(errInsertCaption, err)
@@ -159,7 +161,9 @@ func (c *caption) Insert(output string, jpath string, writer io.Writer) error {
return nil
}
func (c *caption) Update(output string, jpath string, writer io.Writer) error {
func (c *caption) Update(
output string, jpath string, writer io.Writer,
) error {
captions, err := c.Get([]string{"snippet"})
if err != nil {
return errors.Join(errUpdateCaption, err)
+24 -19
View File
@@ -39,15 +39,15 @@ type channel struct {
Title string `yaml:"title" json:"title"`
}
type Channel interface {
type Channel[T youtube.Channel] interface {
List([]string, string, string, io.Writer) error
Update(string, string, io.Writer) error
Get([]string) ([]*youtube.Channel, error)
Get([]string) ([]*T, error)
}
type Option func(*channel)
func NewChannel(opts ...Option) Channel {
func NewChannel(opts ...Option) Channel[youtube.Channel] {
c := &channel{}
for _, opt := range opts {
@@ -62,54 +62,59 @@ func (c *channel) Get(parts []string) ([]*youtube.Channel, error) {
if c.CategoryId != "" {
call = call.CategoryId(c.CategoryId)
}
if c.ForHandle != "" {
call = call.ForHandle(c.ForHandle)
}
if c.ForUsername != "" {
call = call.ForUsername(c.ForUsername)
}
if c.Hl != "" {
call = call.Hl(c.Hl)
}
if len(c.IDs) > 0 {
call = call.Id(c.IDs...)
}
if c.ManagedByMe != nil {
call = call.ManagedByMe(*c.ManagedByMe)
}
call = call.MaxResults(c.MaxResults)
if c.Mine != nil {
call = call.Mine(*c.Mine)
}
if c.MySubscribers != nil {
call = call.MySubscribers(*c.MySubscribers)
}
if c.OnBehalfOfContentOwner != "" {
call = call.OnBehalfOfContentOwner(c.OnBehalfOfContentOwner)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetChannel, err)
var items []*youtube.Channel
pageToken := ""
for c.MaxResults > 0 {
call = call.MaxResults(min(c.MaxResults, pkg.PerPage))
c.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetChannel, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (c *channel) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
channels, err := c.Get(parts)
if err != nil {
if err != nil && channels == nil {
return err
}
@@ -131,7 +136,7 @@ func (c *channel) List(
)
}
}
return nil
return err
}
func (c *channel) Update(output string, jpath string, writer io.Writer) error {
+3 -3
View File
@@ -26,8 +26,8 @@ type channelSection struct {
OnBehalfOfContentOwner string `yaml:"on_behalf_of_content_owner" json:"on_behalf_of_content_owner"`
}
type ChannelSection interface {
Get([]string) ([]*youtube.ChannelSection, error)
type ChannelSection[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Delete(writer io.Writer) error
// Update()
@@ -36,7 +36,7 @@ type ChannelSection interface {
type Option func(*channelSection)
func NewChannelSection(opts ...Option) ChannelSection {
func NewChannelSection(opts ...Option) ChannelSection[youtube.ChannelSection] {
cs := &channelSection{}
for _, opt := range opts {
+25 -14
View File
@@ -38,8 +38,8 @@ type comment struct {
ViewerRating string `yaml:"viewer_rating" json:"viewer_rating"`
}
type Comment interface {
Get([]string) ([]*youtube.Comment, error)
type Comment[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
@@ -50,7 +50,7 @@ type Comment interface {
type Option func(*comment)
func NewComment(opts ...Option) Comment {
func NewComment(opts ...Option) Comment[youtube.Comment] {
c := &comment{}
for _, opt := range opts {
@@ -62,34 +62,45 @@ func NewComment(opts ...Option) Comment {
func (c *comment) Get(parts []string) ([]*youtube.Comment, error) {
call := service.Comments.List(parts)
if c.IDs[0] != "" {
call = call.Id(c.IDs...)
}
call = call.MaxResults(c.MaxResults)
if c.ParentId != "" {
call = call.ParentId(c.ParentId)
}
if c.TextFormat != "" {
call = call.TextFormat(c.TextFormat)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetComment, err)
var items []*youtube.Comment
pageToken := ""
for c.MaxResults > 0 {
call = call.MaxResults(min(c.MaxResults, pkg.PerPage))
c.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetComment, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (c *comment) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
comments, err := c.Get(parts)
if err != nil {
if err != nil && comments == nil {
return err
}
@@ -114,7 +125,7 @@ func (c *comment) List(
)
}
}
return nil
return err
}
func (c *comment) Insert(output string, jpath string, writer io.Writer) error {
+25 -19
View File
@@ -33,15 +33,15 @@ type commentThread struct {
VideoId string `yaml:"video_id" json:"video_id"`
}
type CommentThread interface {
Get([]string) ([]*youtube.CommentThread, error)
type CommentThread[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Insert(output string, s string, writer io.Writer) error
}
type Option func(*commentThread)
func NewCommentThread(opts ...Option) CommentThread {
func NewCommentThread(opts ...Option) CommentThread[youtube.CommentThread] {
c := &commentThread{}
for _, opt := range opts {
@@ -53,54 +53,60 @@ func NewCommentThread(opts ...Option) CommentThread {
func (c *commentThread) Get(parts []string) ([]*youtube.CommentThread, error) {
call := service.CommentThreads.List(parts)
if len(c.IDs) > 0 {
call = call.Id(c.IDs...)
}
if c.AllThreadsRelatedToChannelId != "" {
call = call.AllThreadsRelatedToChannelId(c.AllThreadsRelatedToChannelId)
}
if c.ChannelId != "" {
call = call.ChannelId(c.ChannelId)
}
call = call.MaxResults(c.MaxResults)
if c.ModerationStatus != "" {
call = call.ModerationStatus(c.ModerationStatus)
}
if c.Order != "" {
call = call.Order(c.Order)
}
if c.SearchTerms != "" {
call = call.SearchTerms(c.SearchTerms)
}
if c.TextFormat != "" {
call = call.TextFormat(c.TextFormat)
}
if c.VideoId != "" {
call = call.VideoId(c.VideoId)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetCommentThread, err)
var items []*youtube.CommentThread
pageToken := ""
for c.MaxResults > 0 {
call = call.MaxResults(min(c.MaxResults, pkg.PerPage))
c.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetCommentThread, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (c *commentThread) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
commentThreads, err := c.Get(parts)
if err != nil {
if err != nil && commentThreads == nil {
return err
}
@@ -126,7 +132,7 @@ func (c *commentThread) List(
)
}
}
return nil
return err
}
func (c *commentThread) Insert(
+6 -4
View File
@@ -20,14 +20,14 @@ type i18nLanguage struct {
Hl string `yaml:"hl" json:"hl"`
}
type I18nLanguage interface {
Get([]string) ([]*youtube.I18nLanguage, error)
type I18nLanguage[T youtube.I18nLanguage] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
}
type Option func(*i18nLanguage)
func NewI18nLanguage(opts ...Option) I18nLanguage {
func NewI18nLanguage(opts ...Option) I18nLanguage[youtube.I18nLanguage] {
i := &i18nLanguage{}
for _, opt := range opts {
@@ -37,7 +37,9 @@ func NewI18nLanguage(opts ...Option) I18nLanguage {
return i
}
func (i *i18nLanguage) Get(parts []string) ([]*youtube.I18nLanguage, error) {
func (i *i18nLanguage) Get(parts []string) (
[]*youtube.I18nLanguage, error,
) {
call := service.I18nLanguages.List(parts)
if i.Hl != "" {
call = call.Hl(i.Hl)
+3 -3
View File
@@ -20,14 +20,14 @@ type i18nRegion struct {
Hl string `yaml:"hl" json:"hl"`
}
type I18nRegion interface {
Get([]string) ([]*youtube.I18nRegion, error)
type I18nRegion[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
}
type Option func(*i18nRegion)
func NewI18nRegion(opts ...Option) I18nRegion {
func NewI18nRegion(opts ...Option) I18nRegion[youtube.I18nRegion] {
i := &i18nRegion{}
for _, opt := range opts {
+4
View File
@@ -4,6 +4,10 @@ import (
"io"
)
type Getter[T any] interface {
Get([]string) ([]*T, error)
}
type Lister interface {
List([]string, string, string, io.Writer) error
}
+25 -10
View File
@@ -24,14 +24,14 @@ type member struct {
Mode string `yaml:"mode" json:"mode"`
}
type Member interface {
type Member[T any] interface {
List([]string, string, string, io.Writer) error
Get([]string) ([]*youtube.Member, error)
Get([]string) ([]*T, error)
}
type Option func(*member)
func NewMember(opts ...Option) Member {
func NewMember(opts ...Option) Member[youtube.Member] {
m := &member{}
for _, opt := range opts {
@@ -49,24 +49,39 @@ func (m *member) Get(parts []string) ([]*youtube.Member, error) {
if m.HasAccessToLevel != "" {
call = call.HasAccessToLevel(m.HasAccessToLevel)
}
call = call.MaxResults(m.MaxResults)
if m.Mode != "" {
call = call.Mode(m.Mode)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetMember, err)
var items []*youtube.Member
pageToken := ""
for m.MaxResults > 0 {
call = call.MaxResults(min(m.MaxResults, pkg.PerPage))
m.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetMember, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (m *member) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
members, err := m.Get(parts)
if err != nil {
if err != nil && members == nil {
return err
}
@@ -91,7 +106,7 @@ func (m *member) List(
)
}
}
return nil
return err
}
func WithMemberChannelId(channelId string) Option {
+3 -3
View File
@@ -18,14 +18,14 @@ var (
type membershipsLevel struct{}
type MembershipsLevel interface {
type MembershipsLevel[T any] interface {
List([]string, string, string, io.Writer) error
Get([]string) ([]*youtube.MembershipsLevel, error)
Get([]string) ([]*T, error)
}
type Option func(*membershipsLevel)
func NewMembershipsLevel(opts ...Option) MembershipsLevel {
func NewMembershipsLevel(opts ...Option) MembershipsLevel[youtube.MembershipsLevel] {
m := &membershipsLevel{}
for _, opt := range opts {
+25 -10
View File
@@ -37,17 +37,17 @@ type playlist struct {
OnBehalfOfContentOwnerChannel string `yaml:"on_behalf_of_content_owner_channel" json:"on_behalf_of_content_owner_channel"`
}
type Playlist interface {
type Playlist[T any] interface {
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
Delete(io.Writer) error
Get([]string) ([]*youtube.Playlist, error)
Get([]string) ([]*T, error)
}
type Option func(*playlist)
func NewPlaylist(opts ...Option) Playlist {
func NewPlaylist(opts ...Option) Playlist[youtube.Playlist] {
p := &playlist{}
for _, opt := range opts {
@@ -69,7 +69,6 @@ func (p *playlist) Get(parts []string) ([]*youtube.Playlist, error) {
if p.Mine != nil {
call = call.Mine(*p.Mine)
}
call = call.MaxResults(p.MaxResults)
if p.OnBehalfOfContentOwner != "" {
call = call.OnBehalfOfContentOwner(p.OnBehalfOfContentOwner)
}
@@ -77,19 +76,35 @@ func (p *playlist) Get(parts []string) ([]*youtube.Playlist, error) {
call = call.OnBehalfOfContentOwnerChannel(p.OnBehalfOfContentOwnerChannel)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetPlaylist, err)
var items []*youtube.Playlist
pageToken := ""
for p.MaxResults > 0 {
call = call.MaxResults(min(p.MaxResults, pkg.PerPage))
p.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetPlaylist, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (p *playlist) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
playlists, err := p.Get(parts)
if err != nil {
if err != nil && playlists == nil {
return err
}
@@ -109,7 +124,7 @@ func (p *playlist) List(
tb.AppendRow(table.Row{pl.Id, pl.Snippet.ChannelId, pl.Snippet.Title})
}
}
return nil
return err
}
func (p *playlist) Insert(output string, jpath string, writer io.Writer) error {
+25 -11
View File
@@ -36,8 +36,8 @@ type playlistImage struct {
OnBehalfOfContentOwnerChannel string `yaml:"on_behalf_of_content_owner_channel" json:"on_behalf_of_content_owner_channel"`
}
type PlaylistImage interface {
Get([]string) ([]*youtube.PlaylistImage, error)
type PlaylistImage[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
@@ -46,7 +46,7 @@ type PlaylistImage interface {
type Option func(*playlistImage)
func NewPlaylistImage(opts ...Option) PlaylistImage {
func NewPlaylistImage(opts ...Option) PlaylistImage[youtube.PlaylistImage] {
pi := &playlistImage{}
for _, opt := range opts {
opt(pi)
@@ -57,7 +57,6 @@ func NewPlaylistImage(opts ...Option) PlaylistImage {
func (pi *playlistImage) Get(parts []string) ([]*youtube.PlaylistImage, error) {
call := service.PlaylistImages.List()
call = call.Part(parts...)
if pi.Parent != "" {
call = call.Parent(pi.Parent)
}
@@ -67,21 +66,36 @@ func (pi *playlistImage) Get(parts []string) ([]*youtube.PlaylistImage, error) {
if pi.OnBehalfOfContentOwnerChannel != "" {
call = call.OnBehalfOfContentOwnerChannel(pi.OnBehalfOfContentOwnerChannel)
}
call = call.MaxResults(pi.MaxResults)
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetPlaylistImage, err)
var items []*youtube.PlaylistImage
pageToken := ""
for pi.MaxResults > 0 {
call = call.MaxResults(min(pi.MaxResults, pkg.PerPage))
pi.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetPlaylistImage, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (pi *playlistImage) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
playlistImages, err := pi.Get(parts)
if err != nil {
if err != nil && playlistImages == nil {
return err
}
@@ -103,7 +117,7 @@ func (pi *playlistImage) List(
)
}
}
return nil
return err
}
func (pi *playlistImage) Insert(
+26 -10
View File
@@ -38,17 +38,17 @@ type playlistItem struct {
OnBehalfOfContentOwner string `yaml:"on_behalf_of_content_owner" json:"on_behalf_of_content_owner"`
}
type PlaylistItem interface {
type PlaylistItem[T any] interface {
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
Delete(io.Writer) error
Get([]string) ([]*youtube.PlaylistItem, error)
Get([]string) ([]*T, error)
}
type Option func(*playlistItem)
func NewPlaylistItem(opts ...Option) PlaylistItem {
func NewPlaylistItem(opts ...Option) PlaylistItem[youtube.PlaylistItem] {
p := &playlistItem{}
for _, opt := range opts {
@@ -72,20 +72,36 @@ func (pi *playlistItem) Get(parts []string) ([]*youtube.PlaylistItem, error) {
if pi.VideoId != "" {
call = call.VideoId(pi.VideoId)
}
call = call.MaxResults(pi.MaxResults)
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetPlaylistItem, err)
var items []*youtube.PlaylistItem
pageToken := ""
for pi.MaxResults > 0 {
call = call.MaxResults(min(pi.MaxResults, pkg.PerPage))
pi.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetPlaylistItem, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (pi *playlistItem) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
playlistItems, err := pi.Get(parts)
if err != nil {
if err != nil && playlistItems == nil {
return err
}
@@ -118,7 +134,7 @@ func (pi *playlistItem) List(
)
}
}
return nil
return err
}
func (pi *playlistItem) Insert(
+25 -38
View File
@@ -49,14 +49,14 @@ type search struct {
VideoType string `yaml:"video_type" json:"video_type"`
}
type Search interface {
Get([]string) ([]*youtube.SearchResult, error)
type Search[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
}
type Option func(*search)
func NewSearch(opts ...Option) Search {
func NewSearch(opts ...Option) Search[youtube.SearchResult] {
s := &search{}
for _, opt := range opts {
@@ -71,130 +71,117 @@ func (s *search) Get(parts []string) ([]*youtube.SearchResult, error) {
if s.ChannelId != "" {
call.ChannelId(s.ChannelId)
}
if s.ChannelType != "" {
call.ChannelType(s.ChannelType)
}
if s.EventType != "" {
call.EventType(s.EventType)
}
if s.ForContentOwner != nil {
call.ForContentOwner(*s.ForContentOwner)
}
if s.ForDeveloper != nil {
call.ForDeveloper(*s.ForDeveloper)
}
if s.ForMine != nil {
call.ForMine(*s.ForMine)
}
if s.Location != "" {
call.Location(s.Location)
}
if s.LocationRadius != "" {
call.LocationRadius(s.LocationRadius)
}
call.MaxResults(s.MaxResults)
if s.OnBehalfOfContentOwner != "" {
call.OnBehalfOfContentOwner(s.OnBehalfOfContentOwner)
}
if s.Order != "" {
call.Order(s.Order)
}
if s.PublishedAfter != "" {
call.PublishedAfter(s.PublishedAfter)
}
if s.PublishedBefore != "" {
call.PublishedBefore(s.PublishedBefore)
}
if s.Q != "" {
call.Q(s.Q)
}
if s.RegionCode != "" {
call.RegionCode(s.RegionCode)
}
if s.RelevanceLanguage != "" {
call.RelevanceLanguage(s.RelevanceLanguage)
}
if s.SafeSearch != "" {
call.SafeSearch(s.SafeSearch)
}
if s.TopicId != "" {
call.TopicId(s.TopicId)
}
if len(s.Types) > 0 {
call.Type(s.Types...)
}
if s.VideoCaption != "" {
call.VideoCaption(s.VideoCaption)
}
if s.VideoCategoryId != "" {
call.VideoCategoryId(s.VideoCategoryId)
}
if s.VideoDefinition != "" {
call.VideoDefinition(s.VideoDefinition)
}
if s.VideoDimension != "" {
call.VideoDimension(s.VideoDimension)
}
if s.VideoDuration != "" {
call.VideoDuration(s.VideoDuration)
}
if s.VideoEmbeddable != "" {
call.VideoEmbeddable(s.VideoEmbeddable)
}
if s.VideoLicense != "" {
call.VideoLicense(s.VideoLicense)
}
if s.VideoPaidProductPlacement != "" {
call.VideoPaidProductPlacement(s.VideoPaidProductPlacement)
}
if s.VideoSyndicated != "" {
call.VideoSyndicated(s.VideoSyndicated)
}
if s.VideoType != "" {
call.VideoType(s.VideoType)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetSearch, err)
var items []*youtube.SearchResult
pageToken := ""
for s.MaxResults > 0 {
call = call.MaxResults(min(s.MaxResults, pkg.PerPage))
s.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetSearch, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (s *search) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
results, err := s.Get(parts)
if err != nil {
if err != nil && results == nil {
return err
}
@@ -225,7 +212,7 @@ func (s *search) List(
)
}
}
return nil
return err
}
func WithChannelId(channelId string) Option {
+26 -13
View File
@@ -36,8 +36,8 @@ type subscription struct {
Title string `yaml:"title" json:"title"`
}
type Subscription interface {
Get([]string) ([]*youtube.Subscription, error)
type Subscription[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Delete(io.Writer) error
@@ -45,7 +45,7 @@ type Subscription interface {
type Option func(*subscription)
func NewSubscription(opts ...Option) Subscription {
func NewSubscription(opts ...Option) Subscription[youtube.Subscription] {
s := &subscription{}
for _, opt := range opts {
@@ -66,8 +66,6 @@ func (s *subscription) Get(parts []string) ([]*youtube.Subscription, error) {
if s.ForChannelId != "" {
call = call.ForChannelId(s.ForChannelId)
}
call = call.MaxResults(s.MaxResults)
if s.Mine != nil {
call = call.Mine(*s.Mine)
}
@@ -77,7 +75,6 @@ func (s *subscription) Get(parts []string) ([]*youtube.Subscription, error) {
if s.MySubscribers != nil {
call = call.MySubscribers(*s.MySubscribers)
}
if s.OnBehalfOfContentOwner != "" {
call = call.OnBehalfOfContentOwner(s.OnBehalfOfContentOwner)
}
@@ -88,20 +85,36 @@ func (s *subscription) Get(parts []string) ([]*youtube.Subscription, error) {
call = call.Order(s.Order)
}
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetSubscription, err)
var items []*youtube.Subscription
pageToken := ""
for s.MaxResults > 0 {
call = call.MaxResults(min(s.MaxResults, pkg.PerPage))
s.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetSubscription, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (s *subscription) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
subscriptions, err := s.Get(parts)
if err != nil {
return errors.Join(errGetSubscription, err)
if err != nil && subscriptions == nil {
return err
}
switch output {
@@ -133,7 +146,7 @@ func (s *subscription) List(
)
}
}
return nil
return err
}
func (s *subscription) Insert(
+26 -11
View File
@@ -22,14 +22,14 @@ type superChatEvent struct {
MaxResults int64 `yaml:"max_results" json:"max_results"`
}
type SuperChatEvent interface {
Get([]string) ([]*youtube.SuperChatEvent, error)
type SuperChatEvent[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
}
type Option func(*superChatEvent)
func NewSuperChatEvent(opts ...Option) SuperChatEvent {
func NewSuperChatEvent(opts ...Option) SuperChatEvent[youtube.SuperChatEvent] {
s := &superChatEvent{}
for _, opt := range opts {
@@ -44,22 +44,37 @@ func (s *superChatEvent) Get(parts []string) ([]*youtube.SuperChatEvent, error)
if s.Hl != "" {
call = call.Hl(s.Hl)
}
call = call.MaxResults(s.MaxResults)
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetSuperChatEvent, err)
var items []*youtube.SuperChatEvent
pageToken := ""
for s.MaxResults > 0 {
call = call.MaxResults(min(s.MaxResults, pkg.PerPage))
s.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetSuperChatEvent, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (s *superChatEvent) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
events, err := s.Get(parts)
if err != nil {
return errors.Join(errGetSuperChatEvent, err)
if err != nil && events == nil {
return err
}
switch output {
@@ -83,7 +98,7 @@ func (s *superChatEvent) List(
)
}
}
return nil
return err
}
func WithHl(hl string) Option {
+1 -1
View File
@@ -7,7 +7,7 @@ import (
const (
PartsUsage = "Comma separated parts"
MRUsage = "The maximum number of items that should be returned"
MRUsage = "The maximum number of items that should be returned, 0 for no limit"
TableUsage = "json, yaml, or table"
SilentUsage = "json, yaml, or silent"
JPUsage = "JSONPath expression to filter the output"
+25 -10
View File
@@ -64,7 +64,7 @@ type video struct {
OnBehalfOfContentOwnerChannel string `yaml:"on_behalf_of_content_owner_channel" json:"on_behalf_of_content_owner_channel"`
}
type Video interface {
type Video[T any] interface {
List([]string, string, string, io.Writer) error
Insert(string, string, io.Writer) error
Update(string, string, io.Writer) error
@@ -72,12 +72,12 @@ type Video interface {
GetRating(string, string, io.Writer) error
Delete(io.Writer) error
ReportAbuse(io.Writer) error
Get([]string) ([]*youtube.Video, error)
Get([]string) ([]*T, error)
}
type Option func(*video)
func NewVideo(opts ...Option) Video {
func NewVideo(opts ...Option) Video[youtube.Video] {
v := &video{}
for _, opt := range opts {
@@ -119,21 +119,36 @@ func (v *video) Get(parts []string) ([]*youtube.Video, error) {
if v.OnBehalfOfContentOwner != "" {
call = call.OnBehalfOfContentOwner(v.OnBehalfOfContentOwner)
}
call = call.MaxResults(v.MaxResults)
res, err := call.Do()
if err != nil {
return nil, errors.Join(errGetVideo, err)
var items []*youtube.Video
pageToken := ""
for v.MaxResults > 0 {
call = call.MaxResults(min(v.MaxResults, pkg.PerPage))
v.MaxResults -= pkg.PerPage
if pageToken != "" {
call = call.PageToken(pageToken)
}
res, err := call.Do()
if err != nil {
return items, errors.Join(errGetVideo, err)
}
items = append(items, res.Items...)
pageToken = res.NextPageToken
if pageToken == "" || len(res.Items) == 0 {
break
}
}
return res.Items, nil
return items, nil
}
func (v *video) List(
parts []string, output string, jpath string, writer io.Writer,
) error {
videos, err := v.Get(parts)
if err != nil {
if err != nil && videos == nil {
return err
}
@@ -159,7 +174,7 @@ func (v *video) List(
)
}
}
return nil
return err
}
func (v *video) Insert(output string, jpath string, writer io.Writer) error {
@@ -20,14 +20,14 @@ type videoAbuseReportReason struct {
Hl string `yaml:"hl" json:"hl"`
}
type VideoAbuseReportReason interface {
Get([]string) ([]*youtube.VideoAbuseReportReason, error)
type VideoAbuseReportReason[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
}
type Option func(*videoAbuseReportReason)
func NewVideoAbuseReportReason(opt ...Option) VideoAbuseReportReason {
func NewVideoAbuseReportReason(opt ...Option) VideoAbuseReportReason[youtube.VideoAbuseReportReason] {
va := &videoAbuseReportReason{}
for _, o := range opt {
o(va)
+3 -3
View File
@@ -22,14 +22,14 @@ type videoCategory struct {
RegionCode string `yaml:"region_code" json:"region_code"`
}
type VideoCategory interface {
Get([]string) ([]*youtube.VideoCategory, error)
type VideoCategory[T any] interface {
Get([]string) ([]*T, error)
List([]string, string, string, io.Writer) error
}
type Option func(*videoCategory)
func NewVideoCategory(opt ...Option) VideoCategory {
func NewVideoCategory(opt ...Option) VideoCategory[youtube.VideoCategory] {
vc := &videoCategory{}
for _, o := range opt {
o(vc)