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") }