Use url.1440.news for shorter URLs (28 chars vs 32)
- Changed short URL format from app.1440.news/r/{code} to url.1440.news/{code}
- Added Traefik routing for url.1440.news domain
- Root handler checks Host header to route url.1440.news requests
- Legacy /r/ path still supported for backwards compatibility
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
+33
-6
@@ -240,11 +240,35 @@ func (c *Crawler) StartDashboard(addr string) error {
|
|||||||
c.handleDashboard(w, r)
|
c.handleDashboard(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
// URL shortener redirect handler
|
// URL shortener redirect handler (legacy /r/ path)
|
||||||
http.HandleFunc("/r/", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/r/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
c.handleRedirect(w, r)
|
c.handleRedirect(w, r)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Root handler for url.1440.news short URLs
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
host := r.Host
|
||||||
|
// Strip port if present
|
||||||
|
if idx := strings.Index(host, ":"); idx != -1 {
|
||||||
|
host = host[:idx]
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is url.1440.news, treat path as short code
|
||||||
|
if host == "url.1440.news" {
|
||||||
|
c.handleRedirect(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, redirect to dashboard for root path
|
||||||
|
if r.URL.Path == "/" {
|
||||||
|
http.Redirect(w, r, "/dashboard", http.StatusFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unknown path
|
||||||
|
http.NotFound(w, r)
|
||||||
|
})
|
||||||
|
|
||||||
http.HandleFunc("/api/stats", func(w http.ResponseWriter, r *http.Request) {
|
http.HandleFunc("/api/stats", func(w http.ResponseWriter, r *http.Request) {
|
||||||
c.handleAPIStats(w, r)
|
c.handleAPIStats(w, r)
|
||||||
})
|
})
|
||||||
@@ -2235,15 +2259,18 @@ func (c *Crawler) handleAPIStats(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// handleRedirect handles short URL redirects
|
// handleRedirect handles short URL redirects
|
||||||
|
// Supports both /r/{code} (legacy) and /{code} (for url.1440.news)
|
||||||
func (c *Crawler) handleRedirect(w http.ResponseWriter, r *http.Request) {
|
func (c *Crawler) handleRedirect(w http.ResponseWriter, r *http.Request) {
|
||||||
// Extract code from path: /r/{code}
|
|
||||||
path := r.URL.Path
|
path := r.URL.Path
|
||||||
if !strings.HasPrefix(path, "/r/") {
|
var code string
|
||||||
http.NotFound(w, r)
|
|
||||||
return
|
// Support both /r/{code} and /{code} formats
|
||||||
|
if strings.HasPrefix(path, "/r/") {
|
||||||
|
code = strings.TrimPrefix(path, "/r/")
|
||||||
|
} else {
|
||||||
|
code = strings.TrimPrefix(path, "/")
|
||||||
}
|
}
|
||||||
|
|
||||||
code := strings.TrimPrefix(path, "/r/")
|
|
||||||
if code == "" {
|
if code == "" {
|
||||||
http.NotFound(w, r)
|
http.NotFound(w, r)
|
||||||
return
|
return
|
||||||
|
|||||||
+8
-4
@@ -21,18 +21,22 @@ services:
|
|||||||
- atproto
|
- atproto
|
||||||
labels:
|
labels:
|
||||||
- "traefik.enable=true"
|
- "traefik.enable=true"
|
||||||
# Production: HTTPS with Let's Encrypt
|
# Production: HTTPS with Let's Encrypt for app.1440.news
|
||||||
- "traefik.http.routers.app-1440-news.rule=Host(`app.1440.news`)"
|
- "traefik.http.routers.app-1440-news.rule=Host(`app.1440.news`)"
|
||||||
- "traefik.http.routers.app-1440-news.entrypoints=https"
|
- "traefik.http.routers.app-1440-news.entrypoints=https"
|
||||||
- "traefik.http.routers.app-1440-news.tls.certresolver=letsencrypt-dns"
|
- "traefik.http.routers.app-1440-news.tls.certresolver=letsencrypt-dns"
|
||||||
# Production: HTTP to HTTPS redirect
|
# Production: HTTPS for url.1440.news (URL shortener)
|
||||||
- "traefik.http.routers.app-1440-news-redirect.rule=Host(`app.1440.news`)"
|
- "traefik.http.routers.url-1440-news.rule=Host(`url.1440.news`)"
|
||||||
|
- "traefik.http.routers.url-1440-news.entrypoints=https"
|
||||||
|
- "traefik.http.routers.url-1440-news.tls.certresolver=letsencrypt-dns"
|
||||||
|
# Production: HTTP to HTTPS redirect for both domains
|
||||||
|
- "traefik.http.routers.app-1440-news-redirect.rule=Host(`app.1440.news`) || Host(`url.1440.news`)"
|
||||||
- "traefik.http.routers.app-1440-news-redirect.entrypoints=http"
|
- "traefik.http.routers.app-1440-news-redirect.entrypoints=http"
|
||||||
- "traefik.http.routers.app-1440-news-redirect.middlewares=https-redirect"
|
- "traefik.http.routers.app-1440-news-redirect.middlewares=https-redirect"
|
||||||
- "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
|
- "traefik.http.middlewares.https-redirect.redirectscheme.scheme=https"
|
||||||
- "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"
|
- "traefik.http.middlewares.https-redirect.redirectscheme.permanent=true"
|
||||||
# Local development: HTTP only
|
# Local development: HTTP only
|
||||||
- "traefik.http.routers.app-1440-news-local.rule=Host(`app.1440.localhost`)"
|
- "traefik.http.routers.app-1440-news-local.rule=Host(`app.1440.localhost`) || Host(`url.1440.localhost`)"
|
||||||
- "traefik.http.routers.app-1440-news-local.entrypoints=http"
|
- "traefik.http.routers.app-1440-news-local.entrypoints=http"
|
||||||
# Shared service
|
# Shared service
|
||||||
- "traefik.http.services.app-1440-news.loadbalancer.server.port=4321"
|
- "traefik.http.services.app-1440-news.loadbalancer.server.port=4321"
|
||||||
|
|||||||
+2
-2
@@ -162,13 +162,13 @@ func (c *Crawler) RecordClick(code string, r *http.Request) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetShortURLForPost returns the short URL string for use in posts
|
// GetShortURLForPost returns the short URL string for use in posts
|
||||||
// Format: https://app.1440.news/r/{code}
|
// Format: https://url.1440.news/{code}
|
||||||
func (c *Crawler) GetShortURLForPost(originalURL string, itemID *int64, feedURL string) (string, error) {
|
func (c *Crawler) GetShortURLForPost(originalURL string, itemID *int64, feedURL string) (string, error) {
|
||||||
shortURL, err := c.CreateShortURL(originalURL, itemID, feedURL)
|
shortURL, err := c.CreateShortURL(originalURL, itemID, feedURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("https://app.1440.news/r/%s", shortURL.Code), nil
|
return fmt.Sprintf("https://url.1440.news/%s", shortURL.Code), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClickStats returns click statistics for a short URL
|
// GetClickStats returns click statistics for a short URL
|
||||||
|
|||||||
Reference in New Issue
Block a user