68 lines
1.4 KiB
Go
68 lines
1.4 KiB
Go
package internal
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"sort"
|
|
|
|
"royalroadupdates/internal/formatter"
|
|
"royalroadupdates/internal/pocketbase"
|
|
"royalroadupdates/internal/royalroad"
|
|
)
|
|
|
|
// Config holds the compile-time settings for the application.
|
|
type Config struct {
|
|
PBURL string
|
|
}
|
|
|
|
// App orchestrates the full pipeline.
|
|
type App struct {
|
|
pocketbase *pocketbase.Client
|
|
scraper *royalroad.Scraper
|
|
outW io.Writer
|
|
errW io.Writer
|
|
}
|
|
|
|
// New creates a new App with the given configuration.
|
|
func New(cfg Config) *App {
|
|
return &App{
|
|
pocketbase: pocketbase.New(cfg.PBURL),
|
|
scraper: royalroad.NewScraper(),
|
|
outW: os.Stdout,
|
|
errW: os.Stderr,
|
|
}
|
|
}
|
|
|
|
// Run executes the full pipeline and outputs results.
|
|
func (a *App) Run(ctx context.Context, jsonOutput bool) error {
|
|
urls, err := a.pocketbase.GetBookmarkURLs(ctx)
|
|
if err != nil {
|
|
return fmt.Errorf("fetching bookmarks: %w", err)
|
|
}
|
|
|
|
var results []royalroad.Story
|
|
for _, u := range urls {
|
|
story, err := a.scraper.FetchStory(ctx, u)
|
|
if err != nil {
|
|
continue // silently skip
|
|
}
|
|
results = append(results, story)
|
|
}
|
|
|
|
sort.Slice(results, func(i, j int) bool {
|
|
return results[i].DateModified.After(results[j].DateModified)
|
|
})
|
|
|
|
if jsonOutput {
|
|
if err := formatter.PrintJSON(a.outW, results); err != nil {
|
|
return fmt.Errorf("encoding JSON: %w", err)
|
|
}
|
|
} else {
|
|
formatter.PrintTable(a.outW, results)
|
|
}
|
|
|
|
return nil
|
|
}
|