Files
kevinandClaude Fable 5 da7a39c1c8 feat: implement comprehensive reading analytics system with bot detection
Features:
- Add article view tracking with automatic deduplication (per user/IP)
- Implement intelligent bot detection (35+ patterns: Google, Bing, Baidu, GPTBot, etc)
- Create admin analytics dashboard with statistics and filtering
- Display view count and comment count on article cards
- Add search-based article filter (replaced dropdown for scalability)

Analytics Dashboard:
- Global stats: total views, human/bot views, unique IPs/users
- Top 20 articles ranking with detailed metrics
- Detailed view records with time, article, user, IP, user-agent
- Filters: article title search, IP search, show/hide bots
- Pagination support (50 records per page)

Technical Implementation:
- Async view recording (non-blocking)
- Dual deduplication (application + database layer)
- Database indexes for performance optimization
- Batch query for comment counts
- Full i18n support (Chinese/English)

Files Added:
- models/article_view.go: View tracking model
- models/bot_detector.go: Bot detection logic
- handlers/admin_analytics.go: Analytics page handler
- templates/admin/analytics_views.html: Analytics UI
- test_analytics.sh: Testing script
- Documentation: implementation guide, usage guide, changelog

Files Modified:
- handlers/home.go: Add view recording and comment count queries
- models/db.go: Add ArticleView to auto-migration
- main.go: Add analytics routes
- i18n/i18n.go: Add 35+ translation keys
- templates/admin/dashboard.html: Add analytics entry link
- templates/pages/home.html: Display view/comment counts on cards

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-22 19:57:12 +08:00

39 lines
1.0 KiB
Go

package models
import (
"strings"
)
// botPatterns contains common bot/crawler/spider User-Agent patterns.
var botPatterns = []string{
"bot", "crawler", "spider", "scraper", "scraping",
"googlebot", "bingbot", "baiduspider", "yandexbot",
"duckduckbot", "slurp", "teoma", "ia_archiver",
"facebookexternalhit", "facebot", "twitterbot",
"whatsapp", "telegram", "slackbot", "discordbot",
"linkedinbot", "pinterestbot", "tumblr",
"semrushbot", "ahrefsbot", "mj12bot", "dotbot",
"archive.org_bot", "serpstatbot", "dataforseo",
"petalbot", "gptbot", "claudebot", "anthropic-ai",
"bytespider", "applebot", "seznambot",
"headless", "phantom", "selenium", "puppeteer",
}
// IsBot checks if the given User-Agent string matches known bot patterns.
// It performs a case-insensitive substring match against common bot identifiers.
func IsBot(userAgent string) bool {
if userAgent == "" {
return false
}
ua := strings.ToLower(userAgent)
for _, pattern := range botPatterns {
if strings.Contains(ua, pattern) {
return true
}
}
return false
}