wilooper commited on
Commit
352f44f
·
1 Parent(s): 99038e8
Files changed (1) hide show
  1. app.py +106 -51
app.py CHANGED
@@ -2,47 +2,44 @@ import os
2
  import uuid
3
  import time
4
  import shutil
5
- import threading
 
6
  from fastapi import FastAPI, UploadFile, File, Form, HTTPException
7
  from fastapi.responses import FileResponse, HTMLResponse
8
- from fastapi.staticfiles import StaticFiles
9
- import pyshorteners
10
-
11
- app = FastAPI()
12
 
13
  # Configuration
14
  UPLOAD_DIR = "temp_storage"
15
  PORT = 7860
16
  os.makedirs(UPLOAD_DIR, exist_ok=True)
17
 
18
- # Helper to shorten links
19
- def shorten_url(long_url):
20
- try:
21
- s = pyshorteners.Shortener()
22
- return s.tinyurl.short(long_url)
23
- except:
24
- return long_url # Fallback to long URL if shortening fails
25
-
26
  # Background task to clean up expired files
27
- def cleanup_task():
28
  while True:
29
  now = time.time()
30
- for subdir in os.listdir(UPLOAD_DIR):
31
- path = os.path.join(UPLOAD_DIR, subdir)
32
- if os.path.isdir(path):
33
- # Check metadata file for expiration
34
- meta_path = os.path.join(path, "expiry.txt")
35
- if os.path.exists(meta_path):
36
- with open(meta_path, "r") as f:
37
- expiry_time = float(f.read())
38
- if now > expiry_time:
39
- shutil.rmtree(path)
40
- print(f"[*] Expired and deleted: {subdir}")
41
- time.sleep(60) # Run every minute
42
-
43
- @app.on_event("startup")
44
- async def startup_event():
45
- threading.Thread(target=cleanup_task, daemon=True).start()
 
 
 
 
 
 
 
 
46
 
47
  @app.post("/upload")
48
  async def upload_file(
@@ -66,15 +63,13 @@ async def upload_file(
66
  with open(os.path.join(save_path, "expiry.txt"), "w") as f:
67
  f.write(str(expiry_timestamp))
68
 
69
- # Generate Link
70
- long_link = f"{base_url.rstrip('/')}/download/{file_id}/{file.filename}"
71
- short_link = shorten_url(long_link)
72
 
73
  return {
74
  "status": "success",
75
- "short_link": short_link,
76
- "expires_in_hours": expiry_hours,
77
- "uid": file_id
78
  }
79
 
80
  @app.get("/download/{uid}/{filename}")
@@ -87,24 +82,84 @@ async def download_file(uid: str, filename: str):
87
  @app.get("/", response_class=HTMLResponse)
88
  async def main_page():
89
  return """
 
90
  <html>
91
- <head><title>File Tunnel</title></head>
92
- <body style="font-family: sans-serif; display: flex; flex-direction: column; align-items: center; padding-top: 50px;">
93
- <h2>Temporary File Tunnel</h2>
94
- <form action="/upload" method="post" enctype="multipart/form-data" style="border: 1px solid #ccc; padding: 20px; border-radius: 8px;">
95
- <input type="file" name="file" required><br><br>
96
- <label>Expire in (hours, max 24):</label><br>
97
- <input type="number" name="expiry_hours" value="2" step="0.5" max="24"><br><br>
98
- <input type="hidden" name="base_url" id="base_url">
99
- <button type="submit">Generate Secure Link</button>
100
- </form>
101
- <script>
102
- document.getElementById('base_url').value = window.location.origin;
103
- </script>
104
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
105
  </html>
106
  """
107
 
108
  if __name__ == "__main__":
109
  import uvicorn
110
- uvicorn.run(app, host="0.0.0.0", port=PORT)
 
2
  import uuid
3
  import time
4
  import shutil
5
+ import asyncio
6
+ from contextlib import asynccontextmanager
7
  from fastapi import FastAPI, UploadFile, File, Form, HTTPException
8
  from fastapi.responses import FileResponse, HTMLResponse
 
 
 
 
9
 
10
  # Configuration
11
  UPLOAD_DIR = "temp_storage"
12
  PORT = 7860
13
  os.makedirs(UPLOAD_DIR, exist_ok=True)
14
 
 
 
 
 
 
 
 
 
15
  # Background task to clean up expired files
16
+ async def cleanup_task():
17
  while True:
18
  now = time.time()
19
+ if os.path.exists(UPLOAD_DIR):
20
+ for subdir in os.listdir(UPLOAD_DIR):
21
+ path = os.path.join(UPLOAD_DIR, subdir)
22
+ if os.path.isdir(path):
23
+ meta_path = os.path.join(path, "expiry.txt")
24
+ if os.path.exists(meta_path):
25
+ with open(meta_path, "r") as f:
26
+ expiry_time = float(f.read())
27
+ if now > expiry_time:
28
+ shutil.rmtree(path)
29
+ print(f"[*] Expired and deleted: {subdir}")
30
+ await asyncio.sleep(60)
31
+
32
+ # Lifespan handler (Replaces on_event)
33
+ @asynccontextmanager
34
+ async def lifespan(app: FastAPI):
35
+ # Startup logic
36
+ loop = asyncio.get_event_loop()
37
+ task = loop.create_task(cleanup_task())
38
+ yield
39
+ # Shutdown logic
40
+ task.cancel()
41
+
42
+ app = FastAPI(lifespan=lifespan)
43
 
44
  @app.post("/upload")
45
  async def upload_file(
 
63
  with open(os.path.join(save_path, "expiry.txt"), "w") as f:
64
  f.write(str(expiry_timestamp))
65
 
66
+ # Generate direct link (TinyURL removed)
67
+ direct_link = f"{base_url.rstrip('/')}/download/{file_id}/{file.filename}"
 
68
 
69
  return {
70
  "status": "success",
71
+ "link": direct_link,
72
+ "expires_in_hours": expiry_hours
 
73
  }
74
 
75
  @app.get("/download/{uid}/{filename}")
 
82
  @app.get("/", response_class=HTMLResponse)
83
  async def main_page():
84
  return """
85
+ <!DOCTYPE html>
86
  <html>
87
+ <head>
88
+ <title>File Tunnel</title>
89
+ <meta name="viewport" content="width=device-width, initial-scale=1">
90
+ <style>
91
+ body { font-family: -apple-system, sans-serif; display: flex; flex-direction: column; align-items: center; padding: 20px; background: #f4f4f9; }
92
+ .card { background: white; padding: 2rem; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); width: 100%; max-width: 400px; }
93
+ input, button { width: 100%; margin: 10px 0; padding: 10px; border-radius: 6px; border: 1px solid #ccc; box-sizing: border-box; }
94
+ button { background: #007bff; color: white; border: none; cursor: pointer; font-weight: bold; }
95
+ #progress-container { width: 100%; background: #eee; border-radius: 10px; display: none; margin: 15px 0; }
96
+ #progress-bar { width: 0%; height: 10px; background: #28a745; border-radius: 10px; transition: width 0.2s; }
97
+ #result { margin-top: 15px; word-break: break-all; padding: 10px; background: #e9ecef; border-radius: 6px; display: none; }
98
+ </style>
99
+ </head>
100
+ <body>
101
+ <div class="card">
102
+ <h2>File Tunnel</h2>
103
+ <input type="file" id="fileInput">
104
+ <label>Expiry (Hours, max 24):</label>
105
+ <input type="number" id="expiryInput" value="2" step="0.5" max="24">
106
+ <button onclick="uploadFile()" id="uploadBtn">Generate Link</button>
107
+
108
+ <div id="progress-container">
109
+ <div id="progress-bar"></div>
110
+ </div>
111
+
112
+ <div id="result"></div>
113
+ </div>
114
+
115
+ <script>
116
+ function uploadFile() {
117
+ const fileInput = document.getElementById('fileInput');
118
+ const expiryInput = document.getElementById('expiryInput');
119
+ const resultDiv = document.getElementById('result');
120
+ const progContainer = document.getElementById('progress-container');
121
+ const progBar = document.getElementById('progress-bar');
122
+ const btn = document.getElementById('uploadBtn');
123
+
124
+ if (!fileInput.files[0]) return alert("Select a file first!");
125
+
126
+ const formData = new FormData();
127
+ formData.append("file", fileInput.files[0]);
128
+ formData.append("expiry_hours", expiryInput.value);
129
+ formData.append("base_url", window.location.origin);
130
+
131
+ const xhr = new XMLHttpRequest();
132
+ xhr.open("POST", "/upload", true);
133
+
134
+ progContainer.style.display = "block";
135
+ resultDiv.style.display = "none";
136
+ btn.disabled = true;
137
+
138
+ xhr.upload.onprogress = (e) => {
139
+ if (e.lengthComputable) {
140
+ const percent = (e.loaded / e.total) * 100;
141
+ progBar.style.width = percent + "%";
142
+ }
143
+ };
144
+
145
+ xhr.onload = () => {
146
+ btn.disabled = false;
147
+ const res = JSON.parse(xhr.responseText);
148
+ if (xhr.status === 200) {
149
+ resultDiv.style.display = "block";
150
+ resultDiv.innerHTML = `<strong>Link Generated:</strong><br><a href="${res.link}" target="_blank">${res.link}</a><br><br><small>Expires in ${res.expires_in_hours}h</small>`;
151
+ } else {
152
+ alert("Upload failed.");
153
+ }
154
+ };
155
+
156
+ xhr.send(formData);
157
+ }
158
+ </script>
159
+ </body>
160
  </html>
161
  """
162
 
163
  if __name__ == "__main__":
164
  import uvicorn
165
+ uvicorn.run(app, host="0.0.0.0", port=7860)