dongsii's picture
Update main.go
25c2902 verified
Raw
History Blame Contribute Delete
7.77 kB
package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"net/url"
"os"
"time"
)
const PORT = ":7860"
// Response structure untuk error
type ErrorResponse struct {
Error string `json:"error"`
Message string `json:"message"`
URL string `json:"url,omitempty"`
Example string `json:"example,omitempty"`
}
// Response structure untuk test
type TestResponse struct {
Message string `json:"message"`
Original string `json:"original"`
Encoded string `json:"encoded"`
TestURL string `json:"test_url"`
TestWithReferer string `json:"test_with_referer"`
}
// Health response
type HealthResponse struct {
Status string `json:"status"`
Message string `json:"message"`
Timestamp string `json:"timestamp"`
}
func main() {
// Setup router
http.HandleFunc("/", homeHandler)
// 🔥 GABUNGKAN HANDLER UNTUK /proxy-video (GET + OPTIONS)
http.HandleFunc("/proxy-video", func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions {
setCORSHeaders(w)
w.WriteHeader(http.StatusOK)
return
}
proxyVideoHandler(w, r)
})
http.HandleFunc("/test", testHandler)
http.HandleFunc("/health", healthHandler)
// Start server
log.Printf("[PROXY] Server running at http://localhost%s", PORT)
log.Printf("[VIDEO] Usage: http://localhost%s/proxy-video?u=ENCODED_URL", PORT)
log.Printf("[TEST] Test: http://localhost%s/test", PORT)
log.Printf("[INFO] Example with referer: /proxy-video?u=ENCODED_URL&referer=https://vid30s.com/")
if err := http.ListenAndServe(PORT, nil); err != nil {
log.Fatal("[ERROR] Server error:", err)
}
}
// HOME HALAMAN UTAMA (HTML FORM) - Baca dari file
func homeHandler(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
// Baca file template.html
htmlContent, err := os.ReadFile("template.html")
if err != nil {
log.Printf("[ERROR] Failed to read template: %v", err)
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return
}
fmt.Fprint(w, string(htmlContent))
}
// MAIN PROXY HANDLER
func proxyVideoHandler(w http.ResponseWriter, r *http.Request) {
// Hanya GET yang diterima (OPTIONS sudah di-handle di atas)
if r.Method != http.MethodGet {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
videoURL := r.URL.Query().Get("u")
if videoURL == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(ErrorResponse{
Error: "Missing parameter",
Message: "Please provide video URL with ?u= parameter",
Example: "/proxy-video?u=https://example.com/video.mp4",
})
return
}
decodedURL, err := url.QueryUnescape(videoURL)
if err != nil {
decodedURL = videoURL
}
parsedURL, err := url.Parse(decodedURL)
if err != nil || parsedURL.Scheme == "" || parsedURL.Host == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(ErrorResponse{
Error: "Invalid URL",
Message: "Please provide a valid URL",
})
return
}
log.Printf("[LINK] New request for: %s", decodedURL)
referer := r.URL.Query().Get("referer")
if referer == "" {
referer = fmt.Sprintf("%s://%s/", parsedURL.Scheme, parsedURL.Host)
}
origin := r.URL.Query().Get("origin")
if origin == "" {
origin = fmt.Sprintf("%s://%s", parsedURL.Scheme, parsedURL.Host)
}
userAgent := r.URL.Query().Get("ua")
if userAgent == "" {
userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
}
accept := r.URL.Query().Get("accept")
if accept == "" {
accept = "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5"
}
rangeHeader := r.Header.Get("Range")
if rangeHeader == "" {
rangeHeader = "bytes=0-"
}
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
req, err := http.NewRequestWithContext(ctx, "GET", decodedURL, nil)
if err != nil {
log.Printf("[ERROR] Error creating request: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(ErrorResponse{
Error: "Request creation failed",
Message: err.Error(),
URL: decodedURL,
})
return
}
req.Header.Set("Referer", referer)
req.Header.Set("Origin", origin)
req.Header.Set("User-Agent", userAgent)
req.Header.Set("Accept", accept)
req.Header.Set("Accept-Language", "en-US,en;q=0.9")
req.Header.Set("Accept-Encoding", "gzip, deflate, br")
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Range", rangeHeader)
log.Printf("[SEND] Forwarding to: %s", parsedURL.Host)
client := &http.Client{
Timeout: 60 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return nil
},
}
resp, err := client.Do(req)
if err != nil {
log.Printf("[ERROR] Proxy error: %v", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(ErrorResponse{
Error: "Proxy error",
Message: err.Error(),
URL: decodedURL,
})
return
}
defer resp.Body.Close()
log.Printf("[RECV] Response status: %d", resp.StatusCode)
forwardHeaders := []string{
"Content-Type",
"Content-Length",
"Accept-Ranges",
"Content-Range",
"ETag",
"Last-Modified",
}
for _, header := range forwardHeaders {
if value := resp.Header.Get(header); value != "" {
w.Header().Set(header, value)
}
}
setCORSHeaders(w)
w.WriteHeader(resp.StatusCode)
_, err = io.Copy(w, resp.Body)
if err != nil {
log.Printf("[ERROR] Streaming error: %v", err)
}
}
// TEST ENDPOINT
func testHandler(w http.ResponseWriter, r *http.Request) {
testURL := "https://vidoycdn.b-cdn.net/dqYoJcz0BB-r0gaEycmpl?token=SsO2H5sCmonrqwz5NigK3w&expires=1782138064"
encodedURL := url.QueryEscape(testURL)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(TestResponse{
Message: "Test your proxy with these URLs",
Original: testURL,
Encoded: encodedURL,
TestURL: fmt.Sprintf("/proxy-video?u=%s", encodedURL),
TestWithReferer: fmt.Sprintf("/proxy-video?u=%s&referer=https://vid30s.com/", encodedURL),
})
}
// HEALTH CHECK
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(HealthResponse{
Status: "OK",
Message: "Proxy server is running",
Timestamp: time.Now().Format(time.RFC3339),
})
}
// SET CORS HEADERS
func setCORSHeaders(w http.ResponseWriter) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Range, Content-Type")
}