223 lines
7.9 KiB
Go
223 lines
7.9 KiB
Go
package server
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/gorilla/mux"
|
|
"github.com/iwasforcedtobehere/gomeme/internal/meme"
|
|
)
|
|
|
|
// Server represents our meme server
|
|
type Server struct {
|
|
generator *meme.Generator
|
|
}
|
|
|
|
// New creates a new server instance
|
|
func New() *Server {
|
|
return &Server{
|
|
generator: meme.NewGenerator(),
|
|
}
|
|
}
|
|
|
|
// Routes sets up all the HTTP routes
|
|
func (s *Server) Routes() http.Handler {
|
|
r := mux.NewRouter()
|
|
|
|
// Static files
|
|
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("web/static/"))))
|
|
|
|
// Web interface
|
|
r.HandleFunc("/", s.homeHandler).Methods("GET")
|
|
r.HandleFunc("/generate", s.generateWebHandler).Methods("POST")
|
|
|
|
// API endpoints
|
|
api := r.PathPrefix("/api/v1").Subrouter()
|
|
api.HandleFunc("/memes", s.generateAPIHandler).Methods("POST")
|
|
api.HandleFunc("/memes/{id}", s.getMemeHandler).Methods("GET")
|
|
api.HandleFunc("/templates", s.getTemplatesHandler).Methods("GET")
|
|
api.HandleFunc("/health", s.healthHandler).Methods("GET")
|
|
|
|
return r
|
|
}
|
|
|
|
// homeHandler serves the main page
|
|
func (s *Server) homeHandler(w http.ResponseWriter, r *http.Request) {
|
|
html := `<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>GoMeme - Because Manual Meme Making is for Peasants</title>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<style>
|
|
body { font-family: 'Comic Sans MS', cursive; background: linear-gradient(45deg, #ff6b6b, #4ecdc4); margin: 0; padding: 20px; }
|
|
.container { max-width: 800px; margin: 0 auto; background: white; border-radius: 15px; padding: 30px; box-shadow: 0 10px 30px rgba(0,0,0,0.2); }
|
|
h1 { color: #333; text-align: center; font-size: 2.5em; margin-bottom: 10px; }
|
|
.subtitle { text-align: center; color: #666; font-size: 1.2em; margin-bottom: 30px; }
|
|
.form-group { margin-bottom: 20px; }
|
|
label { display: block; margin-bottom: 5px; font-weight: bold; color: #333; }
|
|
input, select, textarea { width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 5px; font-size: 16px; }
|
|
button { background: #ff6b6b; color: white; padding: 15px 30px; border: none; border-radius: 5px; font-size: 18px; cursor: pointer; width: 100%; }
|
|
button:hover { background: #ff5252; }
|
|
.footer { text-align: center; margin-top: 30px; color: #666; font-style: italic; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>🎭 GoMeme Generator</h1>
|
|
<p class="subtitle">Automated meme production because who has time for manual labor?</p>
|
|
|
|
<form action="/generate" method="POST">
|
|
<div class="form-group">
|
|
<label for="template">Meme Template:</label>
|
|
<select id="template" name="template" required>
|
|
<option value="drake">Drake Pointing</option>
|
|
<option value="distracted">Distracted Boyfriend</option>
|
|
<option value="woman_yelling">Woman Yelling at Cat</option>
|
|
<option value="change_my_mind">Change My Mind</option>
|
|
<option value="this_is_fine">This is Fine</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="top_text">Top Text:</label>
|
|
<textarea id="top_text" name="top_text" rows="2" placeholder="Enter your brilliant top text here..."></textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="bottom_text">Bottom Text:</label>
|
|
<textarea id="bottom_text" name="bottom_text" rows="2" placeholder="Enter your even more brilliant bottom text here..."></textarea>
|
|
</div>
|
|
|
|
<button type="submit">Generate This Fucking Masterpiece</button>
|
|
</form>
|
|
|
|
<div class="footer">
|
|
<p>Built with Go, goroutines, and a healthy dose of sarcasm 🚀</p>
|
|
<p><a href="/api/v1/health" style="color: #666;">API Health Check</a> | <a href="/api/v1/templates" style="color: #666;">Available Templates</a></p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>`
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
fmt.Fprint(w, html)
|
|
}
|
|
|
|
// generateWebHandler handles web form submissions
|
|
func (s *Server) generateWebHandler(w http.ResponseWriter, r *http.Request) {
|
|
if err := r.ParseForm(); err != nil {
|
|
http.Error(w, "Failed to parse form", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
req := meme.GenerateRequest{
|
|
Template: r.FormValue("template"),
|
|
TopText: r.FormValue("top_text"),
|
|
BottomText: r.FormValue("bottom_text"),
|
|
}
|
|
|
|
result, err := s.generator.Generate(req)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to generate meme: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Return HTML with the generated meme
|
|
html := fmt.Sprintf(`<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>Your Meme is Ready!</title>
|
|
<meta charset="UTF-8">
|
|
<style>
|
|
body { font-family: 'Comic Sans MS', cursive; background: linear-gradient(45deg, #ff6b6b, #4ecdc4); margin: 0; padding: 20px; text-align: center; }
|
|
.container { max-width: 600px; margin: 0 auto; background: white; border-radius: 15px; padding: 30px; }
|
|
img { max-width: 100%%; border-radius: 10px; box-shadow: 0 5px 15px rgba(0,0,0,0.3); }
|
|
.buttons { margin-top: 20px; }
|
|
.btn { display: inline-block; padding: 10px 20px; margin: 5px; background: #4ecdc4; color: white; text-decoration: none; border-radius: 5px; }
|
|
.btn:hover { background: #26a69a; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>🎉 Your Meme is Ready!</h1>
|
|
<img src="/static/generated/%s" alt="Generated Meme">
|
|
<div class="buttons">
|
|
<a href="/" class="btn">Create Another Masterpiece</a>
|
|
<a href="/static/generated/%s" class="btn" download>Download This Beauty</a>
|
|
</div>
|
|
<p><strong>Share URL:</strong> <code>%s</code></p>
|
|
</div>
|
|
</body>
|
|
</html>`, result.Filename, result.Filename, result.ShareURL)
|
|
|
|
w.Header().Set("Content-Type", "text/html")
|
|
fmt.Fprint(w, html)
|
|
}
|
|
|
|
// generateAPIHandler handles API meme generation requests
|
|
func (s *Server) generateAPIHandler(w http.ResponseWriter, r *http.Request) {
|
|
var req meme.GenerateRequest
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid JSON", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
result, err := s.generator.Generate(req)
|
|
if err != nil {
|
|
http.Error(w, fmt.Sprintf("Failed to generate meme: %v", err), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(result)
|
|
}
|
|
|
|
// getMemeHandler retrieves a specific meme by ID
|
|
func (s *Server) getMemeHandler(w http.ResponseWriter, r *http.Request) {
|
|
vars := mux.Vars(r)
|
|
id := vars["id"]
|
|
|
|
// Convert string ID to int for demo purposes
|
|
memeID, err := strconv.Atoi(id)
|
|
if err != nil {
|
|
http.Error(w, "Invalid meme ID", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
meme, err := s.generator.GetMeme(memeID)
|
|
if err != nil {
|
|
http.Error(w, "Meme not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(meme)
|
|
}
|
|
|
|
// getTemplatesHandler returns available meme templates
|
|
func (s *Server) getTemplatesHandler(w http.ResponseWriter, r *http.Request) {
|
|
templates := s.generator.GetTemplates()
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"templates": templates,
|
|
"count": len(templates),
|
|
})
|
|
}
|
|
|
|
// healthHandler provides health check endpoint
|
|
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
|
response := map[string]interface{}{
|
|
"status": "healthy",
|
|
"message": "GoMeme is alive and ready to generate some fucking awesome memes!",
|
|
"timestamp": "2025-09-12T00:00:00Z",
|
|
"version": "1.0.0",
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(response)
|
|
} |