Adds internal/reddit package with a Fetcher interface and Client implementation backed by go-reddit/v2. Handles hot/top/rising/new sort variants with correct option types per the library API.
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package reddit
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/vartanbeno/go-reddit/v2/reddit"
|
|
|
|
"somegit.dev/vikingowl/reddit-reader/internal/domain"
|
|
)
|
|
|
|
// Fetcher is the interface for fetching posts from a subreddit.
|
|
type Fetcher interface {
|
|
FetchPosts(ctx context.Context, subreddit, sort string, limit int) ([]domain.Post, error)
|
|
}
|
|
|
|
// Client wraps the go-reddit client behind the Fetcher interface.
|
|
type Client struct {
|
|
rc *reddit.Client
|
|
}
|
|
|
|
// NewClient creates an authenticated Reddit API client.
|
|
func NewClient(clientID, clientSecret, username, password string) (*Client, error) {
|
|
rc, err := reddit.NewClient(reddit.Credentials{
|
|
ID: clientID,
|
|
Secret: clientSecret,
|
|
Username: username,
|
|
Password: password,
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create reddit client: %w", err)
|
|
}
|
|
return &Client{rc: rc}, nil
|
|
}
|
|
|
|
// FetchPosts retrieves posts from the given subreddit using the specified sort order.
|
|
// Supported sort values: "hot", "top", "rising", and anything else defaults to "new".
|
|
func (c *Client) FetchPosts(ctx context.Context, subreddit, sort string, limit int) ([]domain.Post, error) {
|
|
listOpts := &reddit.ListOptions{Limit: limit}
|
|
listPostOpts := &reddit.ListPostOptions{ListOptions: *listOpts}
|
|
|
|
var posts []*reddit.Post
|
|
var err error
|
|
|
|
switch sort {
|
|
case "hot":
|
|
posts, _, err = c.rc.Subreddit.HotPosts(ctx, subreddit, listOpts)
|
|
case "top":
|
|
posts, _, err = c.rc.Subreddit.TopPosts(ctx, subreddit, listPostOpts)
|
|
case "rising":
|
|
posts, _, err = c.rc.Subreddit.RisingPosts(ctx, subreddit, listOpts)
|
|
default:
|
|
posts, _, err = c.rc.Subreddit.NewPosts(ctx, subreddit, listOpts)
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("fetch %s/%s: %w", subreddit, sort, err)
|
|
}
|
|
|
|
result := make([]domain.Post, len(posts))
|
|
for i, p := range posts {
|
|
var created time.Time
|
|
if p.Created != nil {
|
|
created = p.Created.Time
|
|
}
|
|
result[i] = domain.Post{
|
|
ID: p.FullID,
|
|
Subreddit: p.SubredditName,
|
|
Title: p.Title,
|
|
Author: p.Author,
|
|
URL: p.URL,
|
|
SelfText: p.Body,
|
|
Score: p.Score,
|
|
CreatedUTC: created,
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|