MyanmarSwe commited on
Commit
63fa4d7
·
verified ·
1 Parent(s): fef82ba

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +24 -12
main.py CHANGED
@@ -5,6 +5,7 @@ import base64
5
  import httpx
6
  import random
7
  import asyncio
 
8
  from bs4 import BeautifulSoup
9
  from fastapi import FastAPI, HTTPException, Request
10
  from fastapi.responses import StreamingResponse
@@ -22,16 +23,16 @@ ACCESS_KEY = os.getenv("ACCESS_KEY", "0000")
22
  SERVICE_ACCOUNT_JSON_STR = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")
23
  ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
24
 
25
- # Global Async Client: Video ကျော်ကြည့်တဲ့အခါ Connection အသစ်တွေ မြန်မြန်ဆောက်နိုင်ဖို့
26
  client = httpx.AsyncClient(
27
- timeout=httpx.Timeout(20.0, read=None),
28
  follow_redirects=True,
29
  limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
30
  )
31
 
32
  @app.get("/")
33
  async def index():
34
- return {"Online"}
35
 
36
  def get_all_service_accounts():
37
  if not SERVICE_ACCOUNT_JSON_STR: return []
@@ -44,7 +45,7 @@ async def get_token_for_account(cred_dict):
44
  try:
45
  scopes = ['https://www.googleapis.com/auth/drive.readonly']
46
  creds = service_account.Credentials.from_service_account_info(cred_dict, scopes=scopes)
47
- # Token refresh ကို thread ထဲမှာ run ပါတယ် (Google library က sync ဖြစ်လို့)
48
  loop = asyncio.get_event_loop()
49
  auth_req = google.auth.transport.requests.Request()
50
  await loop.run_in_executor(None, creds.refresh, auth_req)
@@ -60,6 +61,9 @@ async def download_proxy(request: Request, url: str, key: str = None):
60
  if key != ACCESS_KEY:
61
  raise HTTPException(status_code=403, detail="Access Denied")
62
 
 
 
 
63
  range_header = request.headers.get('range')
64
 
65
  # --- MediaFire & Others ---
@@ -71,8 +75,9 @@ async def download_proxy(request: Request, url: str, key: str = None):
71
  try:
72
  headers['Referer'] = 'https://www.mediafire.com/'
73
  r = await client.get(url, headers=headers)
74
- # Regex ဖြင့် Direct Link ကို အမြန်ဆုံး ရှာဖွေခြင်း
75
- match = re.search(r'href="(https?://download[^"]+)"', r.text)
 
76
  if match:
77
  target_link = match.group(1)
78
  else:
@@ -111,7 +116,6 @@ async def download_proxy(request: Request, url: str, key: str = None):
111
  if range_header: headers['Range'] = range_header
112
 
113
  try:
114
- # Stream mode ဖြင့် ချိတ်ဆက်ခြင်း
115
  req = client.build_request("GET", api_link, headers=headers)
116
  r = await client.send(req, stream=True)
117
  if r.status_code in [200, 206]:
@@ -132,10 +136,11 @@ async def stream_file(target_url, range_header):
132
  r = await client.send(req, stream=True)
133
  return await process_response(r)
134
  except Exception as e:
 
135
  raise HTTPException(status_code=500, detail=str(e))
136
 
137
  async def process_response(r):
138
- # မူလလာတဲ့ content-disposition ကို ဖယ်ထုတ်ဖို့ excluded ထဲ ထည့်လိုက်ပါမယ်
139
  excluded = ['content-encoding', 'content-length', 'transfer-encoding', 'connection', 'content-disposition']
140
  response_headers = {n: v for n, v in r.headers.items() if n.lower() not in excluded}
141
 
@@ -146,15 +151,22 @@ async def process_response(r):
146
  if 'Content-Range' in r.headers:
147
  response_headers['Content-Range'] = r.headers['Content-Range']
148
 
149
- # --- Direct Download ဖြစ်စေရန် ပြင်ဆင်ချက် ---
150
- # content-disposition ကို attachment လို့ သတ်မှတ်ပေးလိုက်ရင် browser က တန်း download လုပ်ပါလိမ့်မယ်
151
  response_headers['Content-Disposition'] = 'attachment'
152
 
 
 
 
 
 
 
 
 
153
  return StreamingResponse(
154
- r.aiter_bytes(chunk_size=131072), # 128KB chunks for perfect buffering
155
  status_code=r.status_code,
156
  headers=response_headers,
157
- media_type='application/octet-stream' # stream အနေနဲ့ တန်းဆွဲဖို့ application/octet-stream ပြောင်းလိုက်ပါတယ်
158
  )
159
 
160
  if __name__ == "__main__":
 
5
  import httpx
6
  import random
7
  import asyncio
8
+ import urllib.parse
9
  from bs4 import BeautifulSoup
10
  from fastapi import FastAPI, HTTPException, Request
11
  from fastapi.responses import StreamingResponse
 
23
  SERVICE_ACCOUNT_JSON_STR = os.getenv("GOOGLE_SERVICE_ACCOUNT_JSON")
24
  ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36')
25
 
26
+ # Global Async Client
27
  client = httpx.AsyncClient(
28
+ timeout=httpx.Timeout(30.0, read=None), # Timeout ကို 30 စက္ကန့်အထိ တိုးပေးထားပါတယ်
29
  follow_redirects=True,
30
  limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
31
  )
32
 
33
  @app.get("/")
34
  async def index():
35
+ return {"status": "Online"}
36
 
37
  def get_all_service_accounts():
38
  if not SERVICE_ACCOUNT_JSON_STR: return []
 
45
  try:
46
  scopes = ['https://www.googleapis.com/auth/drive.readonly']
47
  creds = service_account.Credentials.from_service_account_info(cred_dict, scopes=scopes)
48
+ # Token refresh ကို thread ထဲမှာ run ပါတယ်
49
  loop = asyncio.get_event_loop()
50
  auth_req = google.auth.transport.requests.Request()
51
  await loop.run_in_executor(None, creds.refresh, auth_req)
 
61
  if key != ACCESS_KEY:
62
  raise HTTPException(status_code=403, detail="Access Denied")
63
 
64
+ # Double encoded ဖြစ်နေသော URL များကို ရှင်းလင်းရန်
65
+ url = urllib.parse.unquote(url)
66
+
67
  range_header = request.headers.get('range')
68
 
69
  # --- MediaFire & Others ---
 
75
  try:
76
  headers['Referer'] = 'https://www.mediafire.com/'
77
  r = await client.get(url, headers=headers)
78
+
79
+ # Regex ဖြင့် Direct Link ကို ရှာဖွေခြင်း (ပိုမိုတိကျစေရန် ပြင်ထားသည်)
80
+ match = re.search(r'href="(https?://[a-zA-Z0-9-]+\.mediafire\.com/download/[^"]+)"', r.text)
81
  if match:
82
  target_link = match.group(1)
83
  else:
 
116
  if range_header: headers['Range'] = range_header
117
 
118
  try:
 
119
  req = client.build_request("GET", api_link, headers=headers)
120
  r = await client.send(req, stream=True)
121
  if r.status_code in [200, 206]:
 
136
  r = await client.send(req, stream=True)
137
  return await process_response(r)
138
  except Exception as e:
139
+ print(f"Stream Error for {target_url}: {e}")
140
  raise HTTPException(status_code=500, detail=str(e))
141
 
142
  async def process_response(r):
143
+ # မူလလာတဲ့ content-disposition ကို ဖယ်ထုတ်ဖို့ excluded ထဲ ထည့်ပါမယ်
144
  excluded = ['content-encoding', 'content-length', 'transfer-encoding', 'connection', 'content-disposition']
145
  response_headers = {n: v for n, v in r.headers.items() if n.lower() not in excluded}
146
 
 
151
  if 'Content-Range' in r.headers:
152
  response_headers['Content-Range'] = r.headers['Content-Range']
153
 
154
+ # Direct Download ဖြစ်စေရန်
 
155
  response_headers['Content-Disposition'] = 'attachment'
156
 
157
+ # Connection များကို Memory Leak မဖြစ်စေဘဲ သေချာပိတ်ပေးမည့် Generator
158
+ async def stream_generator():
159
+ try:
160
+ async for chunk in r.aiter_bytes(chunk_size=131072): # 128KB chunks
161
+ yield chunk
162
+ finally:
163
+ await r.aclose()
164
+
165
  return StreamingResponse(
166
+ stream_generator(),
167
  status_code=r.status_code,
168
  headers=response_headers,
169
+ media_type='application/octet-stream'
170
  )
171
 
172
  if __name__ == "__main__":