dongsii commited on
Commit
05a470b
Β·
verified Β·
1 Parent(s): 1a72d9e

Update main.go

Browse files
Files changed (1) hide show
  1. main.go +132 -65
main.go CHANGED
@@ -1,84 +1,151 @@
1
  package main
2
 
3
  import (
4
- "log"
5
- "net/http"
6
- "net/url"
7
- "os"
8
- "time"
 
9
  )
10
 
11
  func main() {
12
- port := "7860"
13
- if p := os.Getenv("PORT"); p != "" {
14
- port = p
15
- }
 
 
 
16
 
17
- http.HandleFunc("/query_text", videoProxy)
18
-
19
- log.Println("πŸš€ Go video proxy running on :" + port)
20
- log.Fatal(http.ListenAndServe(":"+port, nil))
21
  }
22
 
23
- func videoProxy(w http.ResponseWriter, r *http.Request) {
24
- rawURL := r.URL.Query().Get("url")
25
- if rawURL == "" {
26
- http.Error(w, "missing ?url parameter", http.StatusBadRequest)
27
- return
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- parsed, err := url.Parse(rawURL)
31
- if err != nil {
32
- http.Error(w, "invalid url", http.StatusBadRequest)
33
- return
34
- }
35
 
36
- client := &http.Client{
37
- Timeout: 0, // streaming
38
- }
 
 
 
 
 
 
 
 
 
39
 
40
- req, err := http.NewRequest("GET", parsed.String(), nil)
41
- if err != nil {
42
- http.Error(w, "request error", 500)
43
- return
44
- }
45
 
46
- // πŸ”₯ PENTING: samakan header dengan fetch script
47
- req.Header.Set("User-Agent", "Mozilla/5.0")
48
- req.Header.Set("Accept", "*/*")
49
- req.Header.Set("Connection", "keep-alive")
50
- req.Header.Set("Referer", "https://dood.video/")
51
 
52
- resp, err := client.Do(req)
53
- if err != nil {
54
- http.Error(w, "fetch error", 500)
55
- return
56
- }
57
- defer resp.Body.Close()
58
 
59
- // forward headers
60
- for k, v := range resp.Header {
61
- for _, vv := range v {
62
- w.Header().Add(k, vv)
63
- }
64
- }
 
 
 
 
 
 
 
 
 
65
 
66
- w.Header().Set("Access-Control-Allow-Origin", "*")
67
- w.Header().Set("Cache-Control", "no-store")
68
- w.WriteHeader(resp.StatusCode)
 
 
 
 
 
69
 
70
- // stream body
71
- buf := make([]byte, 32*1024)
72
- for {
73
- n, err := resp.Body.Read(buf)
74
- if n > 0 {
75
- _, _ = w.Write(buf[:n])
76
- w.(http.Flusher).Flush()
77
- }
78
- if err != nil {
79
- break
80
- }
81
- }
82
 
83
- log.Println("β–Ά stream done:", time.Now())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  }
 
1
  package main
2
 
3
  import (
4
+ "fmt"
5
+ "io"
6
+ "log"
7
+ "net/http"
8
+ "strings"
9
+ "time"
10
  )
11
 
12
  func main() {
13
+ // Handler untuk proxy video
14
+ http.HandleFunc("/proxy", proxyHandler)
15
+
16
+ // Serve HTML generator
17
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
18
+ http.ServeFile(w, r, "index.html")
19
+ })
20
 
21
+ log.Println("πŸš€ Server running on :7860")
22
+ log.Println("πŸ“‘ Proxy endpoint: http://localhost:7860/proxy")
23
+ log.Println("🌐 CORS enabled for all origins")
24
+ log.Fatal(http.ListenAndServe(":7860", nil))
25
  }
26
 
27
+ func proxyHandler(w http.ResponseWriter, r *http.Request) {
28
+ // ============ CORS HEADERS ============
29
+ // Allow all origins untuk remote upload
30
+ w.Header().Set("Access-Control-Allow-Origin", "*")
31
+ w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
32
+ w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With, Range")
33
+ w.Header().Set("Access-Control-Expose-Headers", "Content-Length, Content-Range, Content-Disposition, Accept-Ranges")
34
+ w.Header().Set("Access-Control-Allow-Credentials", "true")
35
+ w.Header().Set("Access-Control-Max-Age", "86400") // 24 jam cache preflight
36
+
37
+ // Handle preflight OPTIONS request
38
+ if r.Method == "OPTIONS" {
39
+ w.WriteHeader(http.StatusOK)
40
+ return
41
+ }
42
+
43
+ // ============ PARSE PARAMETERS ============
44
+ query := r.URL.Query()
45
+ videoParam := query.Get("video")
46
+ exp := query.Get("exp")
47
+ sig := query.Get("sig")
48
+ videoType := query.Get("type") // "mp4" atau "null"
49
+ domain := query.Get("d") // domain CDN, misal: cdn.xvdhsy.pro
50
 
51
+ if videoParam == "" || exp == "" || sig == "" || domain == "" {
52
+ http.Error(w, "Missing parameters: video, exp, sig, d required", http.StatusBadRequest)
53
+ return
54
+ }
 
55
 
56
+ // ============ REKONSTRUKSI URL ============
57
+ // Hapus .mp4 dari video parameter
58
+ videoId := strings.TrimSuffix(videoParam, ".mp4")
59
+
60
+ // Pastikan domain tidak memiliki protocol
61
+ domain = strings.TrimPrefix(domain, "http://")
62
+ domain = strings.TrimPrefix(domain, "https://")
63
+ domain = strings.TrimSuffix(domain, "/")
64
+
65
+ // Rekonstruksi URL asli
66
+ // Format: https://{domain}/{videoId}?exp={exp}&sig={sig}
67
+ originalURL := fmt.Sprintf("https://%s/%s?exp=%s&sig=%s", domain, videoId, exp, sig)
68
 
69
+ log.Printf("πŸ“₯ Proxy request: %s -> %s", r.URL.String(), originalURL)
 
 
 
 
70
 
71
+ // ============ BUAT REQUEST ============
72
+ client := &http.Client{
73
+ Timeout: 120 * time.Second, // Timeout lebih lama untuk video besar
74
+ }
 
75
 
76
+ req, err := http.NewRequest("GET", originalURL, nil)
77
+ if err != nil {
78
+ http.Error(w, "Failed to create request", http.StatusInternalServerError)
79
+ return
80
+ }
 
81
 
82
+ // Set headers untuk request ke CDN
83
+ req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
84
+ req.Header.Set("Accept", "*/*")
85
+ req.Header.Set("Accept-Encoding", "gzip, deflate, br")
86
+ req.Header.Set("Accept-Language", "en-US,en;q=0.9")
87
+ req.Header.Set("Connection", "keep-alive")
88
+ req.Header.Set("Sec-Fetch-Dest", "video")
89
+ req.Header.Set("Sec-Fetch-Mode", "cors")
90
+ req.Header.Set("Sec-Fetch-Site", "cross-site")
91
+
92
+ // Copy Range header untuk support streaming
93
+ if rangeHeader := r.Header.Get("Range"); rangeHeader != "" {
94
+ req.Header.Set("Range", rangeHeader)
95
+ log.Printf("πŸ“Š Range request: %s", rangeHeader)
96
+ }
97
 
98
+ // ============ EKSEKUSI REQUEST ============
99
+ resp, err := client.Do(req)
100
+ if err != nil {
101
+ log.Printf("❌ Error fetching video: %v", err)
102
+ http.Error(w, "Failed to fetch video", http.StatusInternalServerError)
103
+ return
104
+ }
105
+ defer resp.Body.Close()
106
 
107
+ log.Printf("βœ… Response status: %s, Content-Length: %s", resp.Status, resp.Header.Get("Content-Length"))
 
 
 
 
 
 
 
 
 
 
 
108
 
109
+ // ============ SET RESPONSE HEADERS ============
110
+ // CORS headers (already set above)
111
+
112
+ // Content Type untuk video
113
+ contentType := resp.Header.Get("Content-Type")
114
+ if contentType == "" || !strings.Contains(contentType, "video") {
115
+ contentType = "video/mp4"
116
+ }
117
+ w.Header().Set("Content-Type", contentType)
118
+
119
+ // Support range requests (streaming & seeking)
120
+ w.Header().Set("Accept-Ranges", "bytes")
121
+
122
+ // Copy Content-Length jika ada
123
+ if resp.Header.Get("Content-Length") != "" {
124
+ w.Header().Set("Content-Length", resp.Header.Get("Content-Length"))
125
+ }
126
+
127
+ // Set Content-Disposition berdasarkan parameter type
128
+ filename := videoId
129
+ if videoType == "mp4" {
130
+ filename = videoId + ".mp4"
131
+ }
132
+ // Gunakan attachment agar bisa di-download oleh remote upload
133
+ w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename))
134
+
135
+ // Cache control untuk performance
136
+ w.Header().Set("Cache-Control", "public, max-age=86400")
137
+
138
+ // Support untuk Doodstream & platform sejenis
139
+ w.Header().Set("X-Content-Type-Options", "nosniff")
140
+ w.Header().Set("X-Frame-Options", "SAMEORIGIN")
141
+
142
+ // ============ KIRIM RESPONSE ============
143
+ // Copy status code
144
+ w.WriteHeader(resp.StatusCode)
145
+
146
+ // Copy body dengan buffering untuk performance
147
+ buffer := make([]byte, 32*1024) // 32KB buffer
148
+ io.CopyBuffer(w, resp.Body, buffer)
149
+
150
+ log.Printf("βœ… Stream completed for: %s", videoId)
151
  }