MyanmarSwe commited on
Commit
3816526
·
verified ·
1 Parent(s): 3e8e235

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +44 -28
main.py CHANGED
@@ -28,6 +28,7 @@ ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/5
28
  MEDIAFIRE_CACHE = {}
29
  CACHE_TTL = 3600
30
 
 
31
  client = httpx.AsyncClient(
32
  timeout=httpx.Timeout(60.0, read=None),
33
  follow_redirects=True,
@@ -79,20 +80,17 @@ async def download_proxy(request: Request, url: str, key: str = None):
79
  # --- MediaFire Section ---
80
  if "mediafire.com" in clean_url:
81
  target_link = None
82
-
83
- # 1. Check Cache
84
  cached = MEDIAFIRE_CACHE.get(clean_url)
 
85
  if cached and (current_time - cached['time']) < CACHE_TTL:
86
  target_link = cached['link']
87
 
88
- # 2. Fetch New Link if not cached
89
  if not target_link:
90
  try:
91
  headers = {'User-Agent': ua.random}
92
  async with httpx.AsyncClient(headers=headers, follow_redirects=True, timeout=30.0) as temp_client:
93
  r = await temp_client.get(clean_url)
94
  if r.status_code == 200:
95
- # Regex for direct link
96
  match = re.search(r"https?://download[0-9]+\.mediafire\.com/[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+/[^\s'\"]+", r.text)
97
  if match:
98
  target_link = match.group(0).replace('"', '').replace("'", "")
@@ -104,13 +102,12 @@ async def download_proxy(request: Request, url: str, key: str = None):
104
  if target_link:
105
  if target_link.startswith("//"): target_link = f"https:{target_link}"
106
  MEDIAFIRE_CACHE[clean_url] = {'link': target_link, 'time': current_time}
107
- except Exception as e:
108
- print(f"Scraper Error: {e}")
109
 
110
  if target_link:
111
  return await stream_file(target_link, range_header, filename)
112
  else:
113
- raise HTTPException(status_code=404, detail="MediaFire link could not be resolved.")
114
 
115
  # --- Google Drive Section ---
116
  elif "drive.google.com" in clean_url:
@@ -126,37 +123,60 @@ async def download_proxy(request: Request, url: str, key: str = None):
126
  api_link = f"https://www.googleapis.com/drive/v3/files/{file_id}?alt=media"
127
  headers = {"Authorization": f"Bearer {token}"}
128
  if range_header: headers['Range'] = range_header
 
 
129
  try:
130
- # Use stream=True to handle large video files
131
- r = await client.get(api_link, headers=headers, stream=True)
132
- if r.status_code in [200, 206]:
133
- return await process_response(r, filename)
134
- await r.aclose()
135
  except: continue
136
 
137
- # Public Fallback
138
  public_url = f"https://drive.google.com/uc?export=download&id={file_id}"
139
  return await stream_file(public_url, range_header, filename)
140
 
141
  else:
142
  return await stream_file(clean_url, range_header, filename)
143
 
144
- async def stream_file(target_url, range_header, filename):
145
  headers = {'User-Agent': ua.random}
146
  if range_header: headers['Range'] = range_header
 
147
 
 
148
  try:
149
- # Request with stream=True
150
- r = await client.get(target_url, headers=headers, stream=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
- # If MediaFire returns HTML (Error), raise exception to retry or show error
153
- if "text/html" in r.headers.get("Content-Type", "").lower():
154
  await r.aclose()
155
- raise HTTPException(status_code=415, detail="MediaFire blocked the request. Try again.")
156
 
157
  return await process_response(r, filename)
158
- except HTTPException:
159
- raise
160
  except Exception as e:
161
  print(f"Stream Error: {e}")
162
  raise HTTPException(status_code=500, detail=str(e))
@@ -166,22 +186,18 @@ async def process_response(r, filename):
166
  if not mime_type or 'application' in mime_type:
167
  mime_type = 'video/mp4' if filename.lower().endswith('.mp4') else 'video/x-matroska'
168
 
169
- # Essential Headers for Resume and Seeking
170
  res_headers = {
171
  'Content-Type': mime_type,
172
  'Accept-Ranges': 'bytes',
173
  'Content-Disposition': f'inline; filename="{urllib.parse.quote(filename)}"',
174
  'Cache-Control': 'no-cache'
175
  }
176
-
177
- if 'content-length' in r.headers:
178
- res_headers['Content-Length'] = r.headers['content-length']
179
- if 'content-range' in r.headers:
180
- res_headers['Content-Range'] = r.headers['content-range']
181
 
182
  async def stream_generator():
183
  try:
184
- async for chunk in r.aiter_bytes(chunk_size=131072): # 128KB chunks
185
  yield chunk
186
  finally:
187
  await r.aclose()
 
28
  MEDIAFIRE_CACHE = {}
29
  CACHE_TTL = 3600
30
 
31
+ # Global Client
32
  client = httpx.AsyncClient(
33
  timeout=httpx.Timeout(60.0, read=None),
34
  follow_redirects=True,
 
80
  # --- MediaFire Section ---
81
  if "mediafire.com" in clean_url:
82
  target_link = None
 
 
83
  cached = MEDIAFIRE_CACHE.get(clean_url)
84
+
85
  if cached and (current_time - cached['time']) < CACHE_TTL:
86
  target_link = cached['link']
87
 
 
88
  if not target_link:
89
  try:
90
  headers = {'User-Agent': ua.random}
91
  async with httpx.AsyncClient(headers=headers, follow_redirects=True, timeout=30.0) as temp_client:
92
  r = await temp_client.get(clean_url)
93
  if r.status_code == 200:
 
94
  match = re.search(r"https?://download[0-9]+\.mediafire\.com/[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+/[^\s'\"]+", r.text)
95
  if match:
96
  target_link = match.group(0).replace('"', '').replace("'", "")
 
102
  if target_link:
103
  if target_link.startswith("//"): target_link = f"https:{target_link}"
104
  MEDIAFIRE_CACHE[clean_url] = {'link': target_link, 'time': current_time}
105
+ except: pass
 
106
 
107
  if target_link:
108
  return await stream_file(target_link, range_header, filename)
109
  else:
110
+ raise HTTPException(status_code=404, detail="MediaFire direct link not found.")
111
 
112
  # --- Google Drive Section ---
113
  elif "drive.google.com" in clean_url:
 
123
  api_link = f"https://www.googleapis.com/drive/v3/files/{file_id}?alt=media"
124
  headers = {"Authorization": f"Bearer {token}"}
125
  if range_header: headers['Range'] = range_header
126
+
127
+ # Google Drive API Stream
128
  try:
129
+ return await stream_file(api_link, range_header, filename, extra_headers=headers)
 
 
 
 
130
  except: continue
131
 
 
132
  public_url = f"https://drive.google.com/uc?export=download&id={file_id}"
133
  return await stream_file(public_url, range_header, filename)
134
 
135
  else:
136
  return await stream_file(clean_url, range_header, filename)
137
 
138
+ async def stream_file(target_url, range_header, filename, extra_headers=None):
139
  headers = {'User-Agent': ua.random}
140
  if range_header: headers['Range'] = range_header
141
+ if extra_headers: headers.update(extra_headers)
142
 
143
+ # Correct Way to Stream with HTTPX
144
  try:
145
+ # We use a context manager to ensure the request is properly handled
146
+ async def response_streamer():
147
+ async with client.stream("GET", target_url, headers=headers) as r:
148
+ if r.status_code >= 400:
149
+ yield b"Error accessing file"
150
+ return
151
+
152
+ mime_type, _ = mimetypes.guess_type(filename)
153
+ if not mime_type or 'application' in mime_type:
154
+ mime_type = 'video/mp4' if filename.lower().endswith('.mp4') else 'video/x-matroska'
155
+
156
+ # Headers for Resume/Seek
157
+ res_headers = {
158
+ 'Content-Type': mime_type,
159
+ 'Accept-Ranges': 'bytes',
160
+ 'Content-Disposition': f'inline; filename="{urllib.parse.quote(filename)}"',
161
+ 'Cache-Control': 'no-cache'
162
+ }
163
+ if 'content-length' in r.headers: res_headers['Content-Length'] = r.headers['content-length']
164
+ if 'content-range' in r.headers: res_headers['Content-Range'] = r.headers['content-range']
165
+
166
+ # Note: StreamingResponse requires the generator to be passed,
167
+ # but we need to send headers first. So we use a nested approach.
168
+ # Since FastAPI's StreamingResponse needs an async iterator:
169
+
170
+ # ပြန်လည်ပြင်ဆင်��ားသော Stream Logic
171
+ req = client.build_request("GET", target_url, headers=headers)
172
+ r = await client.send(req, stream=True)
173
 
174
+ if "text/html" in r.headers.get("Content-Type", "").lower() and r.status_code == 200:
 
175
  await r.aclose()
176
+ raise HTTPException(status_code=415, detail="MediaFire Blocked (HTML received)")
177
 
178
  return await process_response(r, filename)
179
+
 
180
  except Exception as e:
181
  print(f"Stream Error: {e}")
182
  raise HTTPException(status_code=500, detail=str(e))
 
186
  if not mime_type or 'application' in mime_type:
187
  mime_type = 'video/mp4' if filename.lower().endswith('.mp4') else 'video/x-matroska'
188
 
 
189
  res_headers = {
190
  'Content-Type': mime_type,
191
  'Accept-Ranges': 'bytes',
192
  'Content-Disposition': f'inline; filename="{urllib.parse.quote(filename)}"',
193
  'Cache-Control': 'no-cache'
194
  }
195
+ if 'content-length' in r.headers: res_headers['Content-Length'] = r.headers['content-length']
196
+ if 'content-range' in r.headers: res_headers['Content-Range'] = r.headers['content-range']
 
 
 
197
 
198
  async def stream_generator():
199
  try:
200
+ async for chunk in r.aiter_bytes(chunk_size=131072):
201
  yield chunk
202
  finally:
203
  await r.aclose()