MyanmarSwe commited on
Commit
0f196fd
·
verified ·
1 Parent(s): 440ede7

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +74 -94
main.py CHANGED
@@ -6,7 +6,6 @@ import httpx
6
  import random
7
  import asyncio
8
  import urllib.parse
9
- import mimetypes
10
  from bs4 import BeautifulSoup
11
  from fastapi import FastAPI, HTTPException, Request
12
  from fastapi.responses import StreamingResponse
@@ -26,7 +25,7 @@ ua = UserAgent(fallback='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/5
26
 
27
  # Global Async Client
28
  client = httpx.AsyncClient(
29
- timeout=httpx.Timeout(60.0, read=None),
30
  follow_redirects=True,
31
  limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
32
  )
@@ -61,120 +60,101 @@ async def download_proxy(request: Request, url: str, key: str = None):
61
  if key != ACCESS_KEY:
62
  raise HTTPException(status_code=403, detail="Access Denied")
63
 
64
- clean_url = urllib.parse.unquote(url)
65
- while "%" in clean_url:
66
- prev_url = clean_url
67
- clean_url = urllib.parse.unquote(clean_url)
68
- if prev_url == clean_url: break
69
 
70
- # ဖိုင်နာမည်ကို URL ထဲမှ ကြိုတင်ထုတ်ယူထားခြင်း (Media Type သိရှိနိုင်ရန်)
71
- filename = clean_url.split('/')[-1] if '/' in clean_url else "video.mp4"
72
  range_header = request.headers.get('range')
73
 
74
- # --- MediaFire ---
75
- if "mediafire.com" in clean_url:
76
- try:
77
- browser_headers = {
78
- 'User-Agent': ua.random,
79
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
80
- 'Referer': 'https://www.mediafire.com/',
81
- }
82
-
83
- r = await client.get(clean_url, headers=browser_headers)
84
- if r.status_code != 200:
85
- raise HTTPException(status_code=r.status_code, detail="MediaFire page access denied")
86
-
87
- target_link = None
88
- # Direct link ရှာခြင်း
89
- match = re.search(r"https?://download[0-9]+\.mediafire\.com/[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+/[^\s'\"]+", r.text)
90
- if match:
91
- target_link = match.group(0).replace('"', '').replace("'", "")
92
-
93
- if not target_link:
94
- soup = BeautifulSoup(r.text, 'html.parser')
95
- btn = soup.find('a', {'id': 'downloadButton'})
96
- if btn and btn.get('href'):
97
- target_link = btn.get('href')
98
-
99
- if target_link:
100
- if target_link.startswith("//"): target_link = f"https:{target_link}"
101
- elif target_link.startswith("/"): target_link = f"https://www.mediafire.com{target_link}"
102
-
103
- if not target_link:
104
- raise HTTPException(status_code=404, detail="Direct link not found")
105
-
106
- return await stream_file(target_link, range_header, filename, referer=clean_url)
107
 
108
- except Exception as e:
109
- raise HTTPException(status_code=500, detail=str(e))
 
 
 
 
 
 
110
 
111
  # --- Google Drive ---
112
- elif "drive.google.com" in clean_url:
113
- file_id = get_google_file_id(clean_url)
114
- if not file_id:
115
- raise HTTPException(status_code=400, detail="Invalid Google Drive Link")
116
-
117
- accounts = get_all_service_accounts()
118
- random.shuffle(accounts)
119
-
120
- for account in accounts:
121
- token = await get_token_for_account(account)
122
- if not token: continue
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
- try:
127
- req = client.build_request("GET", api_link, headers=headers)
128
- r = await client.send(req, stream=True)
129
- if r.status_code in [200, 206]:
130
- return await process_response(r, filename)
131
- await r.aclose()
132
- except: continue
133
 
134
- public_url = f"https://drive.google.com/uc?export=download&id={file_id}"
135
- return await stream_file(public_url, range_header, filename)
 
 
 
 
 
136
 
137
- else:
138
- return await stream_file(clean_url, range_header, filename)
 
139
 
140
- async def stream_file(target_url, range_header, filename, referer=None):
141
  headers = {'User-Agent': ua.random}
142
  if range_header: headers['Range'] = range_header
143
- if referer: headers['Referer'] = referer
144
 
145
  try:
146
  req = client.build_request("GET", target_url, headers=headers)
147
  r = await client.send(req, stream=True)
148
- if r.status_code >= 400:
149
- await r.aclose()
150
- raise HTTPException(status_code=r.status_code, detail="Remote server rejected")
151
- return await process_response(r, filename)
152
  except Exception as e:
 
153
  raise HTTPException(status_code=500, detail=str(e))
154
 
155
- async def process_response(r, filename):
156
- # MIME type ခန့်မှန်းခြင်း
157
- mime_type, _ = mimetypes.guess_type(filename)
158
- if not mime_type or mime_type == 'application/octet-stream':
159
- if filename.endswith('.mkv'): mime_type = 'video/x-matroska'
160
- elif filename.endswith('.mp4'): mime_type = 'video/mp4'
161
- else: mime_type = r.headers.get('content-type', 'video/mp4')
162
-
163
- safe_headers = [
164
- 'content-length', 'content-range', 'accept-ranges', 'cache-control'
165
- ]
166
- response_headers = {n: v for n, v in r.headers.items() if n.lower() in safe_headers}
167
 
168
- # nPlayer အတွက် မရှိမဖြစ်လိုအပ်ချက်များ
169
  response_headers['Accept-Ranges'] = 'bytes'
170
- response_headers['Content-Type'] = mime_type
171
- # filename အတိအကျကို header ထဲထည့်ပေးခြင်း
172
- encoded_filename = urllib.parse.quote(filename)
173
- response_headers['Content-Disposition'] = f'inline; filename="{encoded_filename}"; filename*=UTF-8\'\'{encoded_filename}'
 
 
174
 
175
  async def stream_generator():
176
  try:
177
- async for chunk in r.aiter_bytes(chunk_size=262144):
178
  yield chunk
179
  finally:
180
  await r.aclose()
@@ -183,7 +163,7 @@ async def process_response(r, filename):
183
  stream_generator(),
184
  status_code=r.status_code,
185
  headers=response_headers,
186
- media_type=mime_type
187
  )
188
 
189
  if __name__ == "__main__":
 
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
 
25
 
26
  # Global Async Client
27
  client = httpx.AsyncClient(
28
+ timeout=httpx.Timeout(30.0, read=None),
29
  follow_redirects=True,
30
  limits=httpx.Limits(max_connections=100, max_keepalive_connections=20)
31
  )
 
60
  if key != ACCESS_KEY:
61
  raise HTTPException(status_code=403, detail="Access Denied")
62
 
63
+ # Double encoded ဖြစ်နေသော URL များကို ရှင်းလင်းရန်
64
+ url = urllib.parse.unquote(url)
 
 
 
65
 
 
 
66
  range_header = request.headers.get('range')
67
 
68
+ # --- MediaFire & Others ---
69
+ if "drive.google.com" not in url:
70
+ target_link = None
71
+ headers = {'User-Agent': ua.random, 'Accept-Language': 'en-US,en;q=0.9'}
72
+
73
+ if "mediafire.com" in url:
74
+ try:
75
+ headers['Referer'] = 'https://www.mediafire.com/'
76
+ r = await client.get(url, headers=headers)
77
+
78
+ # Regex ဖြင့် Direct Link ကို ရှာဖွေခြင်း
79
+ match = re.search(r'href="(https?://[a-zA-Z0-9-]+\.mediafire\.com/download/[^"]+)"', r.text)
80
+ if match:
81
+ target_link = match.group(1)
82
+ else:
83
+ soup = BeautifulSoup(r.text, 'html.parser')
84
+ btn = soup.find('a', {'id': 'downloadButton'})
85
+ if btn and btn.get('href'):
86
+ # ပေးလာတဲ့ href မှာ https:// မပါရင် မူလ URL နဲ့ ပေါင်းပြီး အပြည့်အစုံဖြစ်အောင် ပြုလုပ်ခြင်း
87
+ target_link = urllib.parse.urljoin(url, btn.get('href'))
88
+ except Exception as e:
89
+ print(f"MediaFire Error: {e}")
90
+
91
+ elif "dropbox.com" in url:
92
+ target_link = url.replace("?dl=0", "").split("?")[0] + "?dl=1"
 
 
 
 
 
 
 
 
93
 
94
+ elif "1drv.ms" in url or "onedrive.live.com" in url:
95
+ encoded_url = base64.b64encode(bytes(url, 'utf-8')).decode('utf-8').replace('=', '').replace('/', '_').replace('+', '-')
96
+ target_link = f"https://api.onedrive.com/v1.0/shares/u!{encoded_url}/root/content"
97
+
98
+ if not target_link:
99
+ raise HTTPException(status_code=400, detail="Could not resolve direct link")
100
+
101
+ return await stream_file(target_link, range_header)
102
 
103
  # --- Google Drive ---
104
+ file_id = get_google_file_id(url)
105
+ if not file_id:
106
+ raise HTTPException(status_code=400, detail="Invalid Google Drive Link")
107
+
108
+ accounts = get_all_service_accounts()
109
+ random.shuffle(accounts)
110
+
111
+ for account in accounts:
112
+ token = await get_token_for_account(account)
113
+ if not token: continue
114
+
115
+ api_link = f"https://www.googleapis.com/drive/v3/files/{file_id}?alt=media"
116
+ headers = {"Authorization": f"Bearer {token}"}
117
+ if range_header: headers['Range'] = range_header
 
 
 
 
 
 
 
118
 
119
+ try:
120
+ req = client.build_request("GET", api_link, headers=headers)
121
+ r = await client.send(req, stream=True)
122
+ if r.status_code in [200, 206]:
123
+ return await process_response(r)
124
+ await r.aclose()
125
+ except: continue
126
 
127
+ # Public Fallback
128
+ public_url = f"https://drive.google.com/uc?export=download&id={file_id}"
129
+ return await stream_file(public_url, range_header)
130
 
131
+ async def stream_file(target_url, range_header):
132
  headers = {'User-Agent': ua.random}
133
  if range_header: headers['Range'] = range_header
 
134
 
135
  try:
136
  req = client.build_request("GET", target_url, headers=headers)
137
  r = await client.send(req, stream=True)
138
+ return await process_response(r)
 
 
 
139
  except Exception as e:
140
+ print(f"Stream Error for {target_url}: {e}")
141
  raise HTTPException(status_code=500, detail=str(e))
142
 
143
+ async def process_response(r):
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
 
 
147
  response_headers['Accept-Ranges'] = 'bytes'
148
+ if 'Content-Length' in r.headers:
149
+ response_headers['Content-Length'] = r.headers['Content-Length']
150
+ if 'Content-Range' in r.headers:
151
+ response_headers['Content-Range'] = r.headers['Content-Range']
152
+
153
+ response_headers['Content-Disposition'] = 'attachment'
154
 
155
  async def stream_generator():
156
  try:
157
+ async for chunk in r.aiter_bytes(chunk_size=131072):
158
  yield chunk
159
  finally:
160
  await r.aclose()
 
163
  stream_generator(),
164
  status_code=r.status_code,
165
  headers=response_headers,
166
+ media_type='application/octet-stream'
167
  )
168
 
169
  if __name__ == "__main__":