Files
vikingowl a11206b980 feat(reddit): Fetcher interface and go-reddit wrapper
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.
2026-04-03 11:54:34 +02:00

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
}