summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-24 22:45:46 +0300
committerPaul Buetow <paul@buetow.org>2025-09-24 22:45:46 +0300
commit970b9b3754f2798f234f99c54f161acb4931b3b7 (patch)
treef8b1af179e59ab05bc749dc20892e59f382dbde7
parent16ce1d306f89f44974eb033056bc65c1be9a5f8a (diff)
add --stats flag
-rw-r--r--internal/config/args.go1
-rw-r--r--internal/config/config_test.go2
-rw-r--r--internal/main.go9
-rw-r--r--internal/schedule/schedule.go2
-rw-r--r--internal/schedule/stats.go25
-rw-r--r--internal/schedule/stats_test.go46
6 files changed, 56 insertions, 29 deletions
diff --git a/internal/config/args.go b/internal/config/args.go
index d1a23b9..be7353b 100644
--- a/internal/config/args.go
+++ b/internal/config/args.go
@@ -26,6 +26,7 @@ type Args struct {
GemtexterEnable bool
GeminiCapsules []string
ComposeMode bool
+ StatsOnly bool
}
func (a *Args) ParsePlatforms(platformStrs string) error {
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
index 5aed307..adecc18 100644
--- a/internal/config/config_test.go
+++ b/internal/config/config_test.go
@@ -187,4 +187,4 @@ func TestIsPausedCurrentTime(t *testing.T) {
if paused {
t.Errorf("Expected not to be paused for past dates, but got true")
}
-} \ No newline at end of file
+}
diff --git a/internal/main.go b/internal/main.go
index 1e7d023..9bc0507 100644
--- a/internal/main.go
+++ b/internal/main.go
@@ -10,6 +10,7 @@ import (
"time"
"codeberg.org/snonux/gos/internal/config"
+ "codeberg.org/snonux/gos/internal/schedule"
)
func Main(composeModeDefault bool) {
@@ -31,6 +32,7 @@ func Main(composeModeDefault bool) {
geminiSummaryFor := flag.String("geminiSummaryFor", "", "Generate a summary in Gemini Gemtext format, format is coma separated string of months, e.g. 202410,202411")
geminiCapsules := flag.String("geminiCapsules", "foo.zone", "Comma sepaeated list Gemini capsules. Used by geminiEnable to detect Gemtext links")
gemtexterEnable := flag.Bool("gemtexterEnable", false, "Add special Gemtexter (the static site generator) tags to the Gemini Gemtext summary")
+ statsOnly := flag.Bool("stats", false, "Print statistics for all social networks and exit")
flag.Parse()
conf, err := config.New(configPath, *composeMode)
@@ -54,6 +56,7 @@ func Main(composeModeDefault bool) {
GemtexterEnable: *gemtexterEnable,
GeminiCapsules: strings.Split(*geminiCapsules, ","),
ComposeMode: *composeMode,
+ StatsOnly: *statsOnly,
}
if *geminiSummaryFor != "" {
args.GeminiSummaryFor = strings.Split(*geminiSummaryFor, ",")
@@ -68,6 +71,12 @@ func Main(composeModeDefault bool) {
return
}
+ if args.StatsOnly {
+ // Call the new function to print all stats
+ schedule.PrintAllStats(args)
+ return // Exit after printing stats
+ }
+
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
diff --git a/internal/schedule/schedule.go b/internal/schedule/schedule.go
index bf86bcc..0e3e8b3 100644
--- a/internal/schedule/schedule.go
+++ b/internal/schedule/schedule.go
@@ -23,7 +23,7 @@ var (
func Run(args config.Args, platform platforms.Platform) (entry.Entry, error) {
dir := fmt.Sprintf("%s/db/platforms/%s", args.GosDir, platform.String())
- stats, err := newStats(dir, args.Lookback, args.Target, args.PauseDays, args.MaxDaysQueued, args.Config)
+ stats, err := newStats(args.GosDir, platform.String(), args.Lookback, args.Target, args.PauseDays, args.MaxDaysQueued, args.Config)
if err != nil {
return entry.Zero, err
}
diff --git a/internal/schedule/stats.go b/internal/schedule/stats.go
index b0f35d1..55d5f8c 100644
--- a/internal/schedule/stats.go
+++ b/internal/schedule/stats.go
@@ -32,7 +32,8 @@ type stats struct {
pauseDays int
}
-func newStats(dir string, lookback time.Duration, target, pauseDays, maxQueuedDays int, cfg config.Config) (stats, error) {
+func newStats(gosDir string, platformName string, lookback time.Duration, target, pauseDays, maxQueuedDays int, cfg config.Config) (stats, error) {
+ dir := filepath.Join(gosDir, "db", "platforms", strings.ToLower(platformName))
s := stats{postsPerDayTarget: float64(target) / 7, pauseDays: pauseDays}
if err := s.gatherPostedStats(dir, pastTime(lookback), cfg); err != nil {
@@ -50,10 +51,10 @@ func newStats(dir string, lookback time.Duration, target, pauseDays, maxQueuedDa
}
newTarget := s.postsPerDayTarget + add
- colour.Infoln("Increasing posts per day target", s.postsPerDayTarget, "by", add, "to", newTarget)
+ colour.Infoln(platformName, "- Increasing posts per day target", s.postsPerDayTarget, "by", add, "to", newTarget)
s.postsPerDayTarget = newTarget
- colour.Infoln("Decreasing pause days from", s.pauseDays, "to", s.pauseDays-1)
+ colour.Infoln(platformName, "- Decreasing pause days from", s.pauseDays, "to", s.pauseDays-1)
s.pauseDays--
}
@@ -115,7 +116,7 @@ func (s *stats) gatherPostedStats(dir string, lookbackTime time.Time, cfg config
since := now.Sub(oldest)
s.sinceDays = since.Abs().Hours() / 24.0
-
+
// Subtract paused days from the calculation period
pausedDays := calculatePausedDays(oldest, now, cfg)
activeDays := s.sinceDays - pausedDays
@@ -225,3 +226,19 @@ func minTime(a, b time.Time) time.Time {
}
return b
}
+
+func PrintAllStats(args config.Args) {
+ for platformName := range args.Platforms {
+ platform, err := platforms.New(platformName)
+ if err != nil {
+ colour.Warnln("Error creating platform for", platformName, ":", err)
+ continue
+ }
+ s, err := newStats(args.GosDir, platformName, args.Lookback, args.Target, args.PauseDays, args.MaxDaysQueued, args.Config)
+ if err != nil {
+ colour.Warnln("Error gathering stats for", platformName, ":", err)
+ continue
+ }
+ s.RenderTable(platform)
+ }
+}
diff --git a/internal/schedule/stats_test.go b/internal/schedule/stats_test.go
index af71222..7751212 100644
--- a/internal/schedule/stats_test.go
+++ b/internal/schedule/stats_test.go
@@ -21,44 +21,44 @@ func TestGatherPostedStats(t *testing.T) {
// Create test posted files with different timestamps
now := time.Now()
testFiles := []struct {
- filename string
- content string
+ filename string
+ content string
timestamp time.Time
}{
{
// Posted entry from 5 days ago
- filename: "post1.txt." + now.AddDate(0, 0, -5).Format(timestamp.Format) + ".posted",
- content: "Test post 1",
+ filename: "post1.txt." + now.AddDate(0, 0, -5).Format(timestamp.Format) + ".posted",
+ content: "Test post 1",
timestamp: now.AddDate(0, 0, -5),
},
{
// Posted entry from 3 days ago
- filename: "post2.txt." + now.AddDate(0, 0, -3).Format(timestamp.Format) + ".posted",
- content: "Test post 2",
+ filename: "post2.txt." + now.AddDate(0, 0, -3).Format(timestamp.Format) + ".posted",
+ content: "Test post 2",
timestamp: now.AddDate(0, 0, -3),
},
{
// Posted entry from 1 day ago
- filename: "post3.txt." + now.AddDate(0, 0, -1).Format(timestamp.Format) + ".posted",
- content: "Test post 3",
+ filename: "post3.txt." + now.AddDate(0, 0, -1).Format(timestamp.Format) + ".posted",
+ content: "Test post 3",
timestamp: now.AddDate(0, 0, -1),
},
{
// Posted entry from 10 days ago (outside lookback period)
- filename: "old_post.txt." + now.AddDate(0, 0, -10).Format(timestamp.Format) + ".posted",
- content: "Old test post",
+ filename: "old_post.txt." + now.AddDate(0, 0, -10).Format(timestamp.Format) + ".posted",
+ content: "Old test post",
timestamp: now.AddDate(0, 0, -10),
},
{
// Queued entry (should be ignored)
- filename: "queued_post.txt." + now.AddDate(0, 0, -2).Format(timestamp.Format) + ".queued",
- content: "Queued post",
+ filename: "queued_post.txt." + now.AddDate(0, 0, -2).Format(timestamp.Format) + ".queued",
+ content: "Queued post",
timestamp: now.AddDate(0, 0, -2),
},
{
// Posted entry with .now. tag (should be ignored)
- filename: "now_post.now.txt." + now.AddDate(0, 0, -2).Format(timestamp.Format) + ".posted",
- content: "Now post",
+ filename: "now_post.now.txt." + now.AddDate(0, 0, -2).Format(timestamp.Format) + ".posted",
+ content: "Now post",
timestamp: now.AddDate(0, 0, -2),
},
}
@@ -74,7 +74,7 @@ func TestGatherPostedStats(t *testing.T) {
// Initialize stats and run gatherPostedStats
s := &stats{}
lookbackTime := now.AddDate(0, 0, -7) // 7 days lookback
- cfg := config.Config{} // Empty config (no pause)
+ cfg := config.Config{} // Empty config (no pause)
err = s.gatherPostedStats(tmpDir, lookbackTime, cfg)
if err != nil {
@@ -226,23 +226,23 @@ func TestGatherPostedStatsWithPause(t *testing.T) {
// Key test: postsPerDay should exclude the pause period
// Let's calculate this step by step:
-
+
// 1. Find the actual time range of our posts
oldestPost := now.AddDate(0, 0, -8)
-
+
// 2. Calculate paused days using our helper function
actualPausedDays := calculatePausedDays(oldestPost, now, cfg)
-
+
// 3. Calculate expected values
expectedActiveDays := s.sinceDays - actualPausedDays
expectedPostsPerDay := float64(expectedPosted) / expectedActiveDays
-
+
// Debug info for understanding the calculation
- // t.Logf("Debug: sinceDays=%.1f, actualPausedDays=%.1f, expectedActiveDays=%.1f",
+ // t.Logf("Debug: sinceDays=%.1f, actualPausedDays=%.1f, expectedActiveDays=%.1f",
// s.sinceDays, actualPausedDays, expectedActiveDays)
-
+
if s.postsPerDay < expectedPostsPerDay-0.01 || s.postsPerDay > expectedPostsPerDay+0.01 {
- t.Errorf("Expected postsPerDay≈%.2f (%.0f posts / %.1f active days), got postsPerDay=%.2f",
+ t.Errorf("Expected postsPerDay≈%.2f (%.0f posts / %.1f active days), got postsPerDay=%.2f",
expectedPostsPerDay, float64(expectedPosted), expectedActiveDays, s.postsPerDay)
}
}
@@ -316,4 +316,4 @@ func TestCalculatePausedDays(t *testing.T) {
}
})
}
-} \ No newline at end of file
+}