diff --git a/go/twitterchiver/viewer/templates/index.html b/go/twitterchiver/viewer/templates/index.html
index 47f1dff292..a2a7120411 100644
--- a/go/twitterchiver/viewer/templates/index.html
+++ b/go/twitterchiver/viewer/templates/index.html
@@ -7,3 +7,14 @@
{{.Username}} ({{.TweetCount}} tweets, latest tweet at {{.LatestTweet}})
{{end}}
+Stats
+
+ - Tweets
+ - {{.TotalTweets}} tweets ({{.TimelineTweets}} on timeline)
+
+ - Unfetched Media
+ - {{.UnfetchedMedia}}
+
+ - Unfetched Related
+ - {{.UnfetchedRelated}}
+
diff --git a/go/twitterchiver/viewer/viewer.go b/go/twitterchiver/viewer/viewer.go
index 54041781c1..a8bdb7669f 100644
--- a/go/twitterchiver/viewer/viewer.go
+++ b/go/twitterchiver/viewer/viewer.go
@@ -110,7 +110,34 @@ func main() {
user := userFromContext(ctx)
twitterAccounts := userMapping[user]
- rows, err := pool.Query(ctx, "SELECT ua.username, COUNT(uat.tweetid) tweet_count, (SELECT CAST(object->>'created_at' AS timestamp with time zone) FROM tweets WHERE id=MAX(uat.tweetid)) latest_tweet FROM user_accounts ua LEFT JOIN user_accounts_tweets uat ON uat.userid=ua.userid WHERE ua.username = ANY($1::text[]) GROUP BY 1 ORDER BY 1", twitterAccounts)
+ var allTweets, timelineTweets, unfetchedMedia, unfetchedRelated int
+
+ if err := pool.QueryRow(ctx, `
+SELECT
+ (SELECT COUNT(id) FROM tweets) all_tweets,
+ (SELECT COUNT(DISTINCT tweetid) FROM user_accounts_tweets WHERE on_timeline) timeline_tweets,
+ (SELECT COUNT(id) FROM tweets WHERE NOT fetched_media) not_fetched_media,
+ (SELECT COUNT(id) FROM tweets WHERE NOT fetched_related_tweets) not_fetched_related
+`).Scan(&allTweets, &timelineTweets, &unfetchedMedia, &unfetchedRelated); err != nil {
+ writeError(rw, http.StatusInternalServerError, "querying stats", err)
+ return
+ }
+
+ rows, err := pool.Query(ctx, `
+SELECT
+ ua.username,
+ COUNT(uat.tweetid) tweet_count,
+ (SELECT CAST(object->>'created_at' AS timestamp with time zone) FROM tweets WHERE id=MAX(uat.tweetid)) latest_tweet
+FROM
+ user_accounts ua
+LEFT JOIN
+ user_accounts_tweets uat ON uat.userid=ua.userid
+WHERE 1=1
+ AND ua.username = ANY($1::text[])
+ AND uat.on_timeline
+GROUP BY 1
+ORDER BY 1
+`, twitterAccounts)
if err != nil {
writeError(rw, http.StatusInternalServerError, "querying database", err)
return
@@ -135,11 +162,19 @@ func main() {
rows.Close()
indexTmpl.Execute(rw, struct {
- Username string
- TwitterAccounts []twitterData
+ Username string
+ TwitterAccounts []twitterData
+ TotalTweets int
+ TimelineTweets int
+ UnfetchedMedia int
+ UnfetchedRelated int
}{
- Username: user,
- TwitterAccounts: tds,
+ Username: user,
+ TwitterAccounts: tds,
+ TotalTweets: allTweets,
+ TimelineTweets: timelineTweets,
+ UnfetchedMedia: unfetchedMedia,
+ UnfetchedRelated: unfetchedRelated,
})
})
isAllowedToSee := func(ctx context.Context, twitterUser string) bool {