albumup commited on
Commit
0f7a742
·
verified ·
1 Parent(s): bff639b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +93 -97
app.py CHANGED
@@ -14,12 +14,14 @@ app = FastAPI()
14
 
15
  DENO_API_URL = "https://dataerrr99.deno.dev"
16
 
17
- async def save_album_to_db(album_name: str, album_id: str):
18
  async with httpx.AsyncClient() as client:
19
  try:
20
  response = await client.post(DENO_API_URL, json={
21
  "albumName": album_name,
22
- "albumLink": album_id
 
 
23
  })
24
  return response.json()
25
  except Exception as e:
@@ -35,9 +37,6 @@ async def get_albums_from_db():
35
  print(f"Error fetching from DB: {str(e)}")
36
  return {"data": []}
37
 
38
- # In-memory storage for albums
39
- albums = {}
40
-
41
  HTML_CONTENT = """
42
  <!DOCTYPE html>
43
  <html lang="en">
@@ -46,42 +45,41 @@ HTML_CONTENT = """
46
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
47
  <title>File Upload</title>
48
  <style>
49
- .container {{
50
  max-width: 800px;
51
  margin: 0 auto;
52
  padding: 20px;
53
- }}
54
- .upload-form {{
55
  margin-bottom: 20px;
56
  padding: 20px;
57
  border: 1px solid #ddd;
58
  border-radius: 5px;
59
- }}
60
- .preview {{
61
  margin-top: 20px;
62
- }}
63
- .search-form {{
64
  margin: 20px 0;
65
  padding: 20px;
66
  border: 1px solid #ddd;
67
  border-radius: 5px;
68
- }}
69
- .album-list {{
70
  margin-top: 20px;
71
- }}
72
- .album-item {{
73
  padding: 10px;
74
  border: 1px solid #ddd;
75
  margin-bottom: 10px;
76
  border-radius: 5px;
77
- }}
78
  </style>
79
  </head>
80
  <body>
81
  <div class="container">
82
  <h1>File Upload & Album Management</h1>
83
 
84
- <!-- Search Albums -->
85
  <div class="search-form">
86
  <h2>Search Albums</h2>
87
  <form action="/search" method="get">
@@ -90,7 +88,6 @@ HTML_CONTENT = """
90
  </form>
91
  </div>
92
 
93
- <!-- Single File Upload -->
94
  <div class="upload-form">
95
  <h2>Single File Upload</h2>
96
  <form action="/upload" method="post" enctype="multipart/form-data">
@@ -99,7 +96,6 @@ HTML_CONTENT = """
99
  </form>
100
  </div>
101
 
102
- <!-- Album Upload -->
103
  <div class="upload-form">
104
  <h2>Create Album</h2>
105
  <form action="/album/create" method="post" enctype="multipart/form-data">
@@ -121,30 +117,30 @@ ALBUM_VIEW_HTML = """
121
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
122
  <title>Album View - {album_name}</title>
123
  <style>
124
- .container {{
125
  max-width: 800px;
126
  margin: 0 auto;
127
  padding: 20px;
128
- }}
129
- .file-grid {{
130
  display: grid;
131
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
132
  gap: 20px;
133
- }}
134
- .file-item {{
135
  border: 1px solid #ddd;
136
  padding: 10px;
137
  text-align: center;
138
  border-radius: 5px;
139
- }}
140
- .download-all {{
141
  margin: 20px 0;
142
- }}
143
- .back-link {{
144
  margin-bottom: 20px;
145
  display: block;
146
- }}
147
- .button {{
148
  display: inline-block;
149
  padding: 8px 16px;
150
  background-color: #007bff;
@@ -152,11 +148,11 @@ ALBUM_VIEW_HTML = """
152
  text-decoration: none;
153
  border-radius: 4px;
154
  margin: 5px;
155
- }}
156
- .button:hover {{
157
  background-color: #0056b3;
158
- }}
159
- .preview-container {{
160
  margin-bottom: 10px;
161
  max-width: 100%;
162
  height: 200px;
@@ -166,18 +162,18 @@ ALBUM_VIEW_HTML = """
166
  justify-content: center;
167
  background-color: #f8f9fa;
168
  border-radius: 4px;
169
- }}
170
- .preview-container img {{
171
  max-width: 100%;
172
  max-height: 100%;
173
  object-fit: contain;
174
- }}
175
- .preview-container video {{
176
  max-width: 100%;
177
  max-height: 100%;
178
  object-fit: contain;
179
- }}
180
- .modal {{
181
  display: none;
182
  position: fixed;
183
  z-index: 1000;
@@ -187,15 +183,15 @@ ALBUM_VIEW_HTML = """
187
  height: 100%;
188
  background-color: rgba(0,0,0,0.9);
189
  overflow: auto;
190
- }}
191
- .modal-content {{
192
  margin: auto;
193
  display: block;
194
  max-width: 90%;
195
  max-height: 90vh;
196
  margin-top: 50px;
197
- }}
198
- .close {{
199
  position: absolute;
200
  right: 35px;
201
  top: 15px;
@@ -203,39 +199,39 @@ ALBUM_VIEW_HTML = """
203
  font-size: 40px;
204
  font-weight: bold;
205
  cursor: pointer;
206
- }}
207
  </style>
208
  <script>
209
- function openModal(url) {{
210
  const modal = document.getElementById('previewModal');
211
  const modalContent = document.getElementById('modalContent');
212
  const contentType = getContentType(url);
213
 
214
- if (contentType === 'image') {{
215
- modalContent.innerHTML = `<img src="${{url}}" style="max-width:100%;max-height:90vh;">`;
216
- }} else if (contentType === 'video') {{
217
  modalContent.innerHTML = `<video controls style="max-width:100%;max-height:90vh;">
218
- <source src="${{url}}" type="video/mp4">
219
  Your browser does not support the video tag.
220
  </video>`;
221
- }}
222
 
223
  modal.style.display = 'block';
224
- }}
225
 
226
- function closeModal() {{
227
  const modal = document.getElementById('previewModal');
228
  modal.style.display = 'none';
229
  const modalContent = document.getElementById('modalContent');
230
  modalContent.innerHTML = '';
231
- }}
232
 
233
- function getContentType(url) {{
234
  const ext = url.split('.').pop().toLowerCase();
235
  if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(ext)) return 'image';
236
  if (['mp4', 'webm', 'ogg'].includes(ext)) return 'video';
237
  return 'other';
238
- }}
239
  </script>
240
  </head>
241
  <body>
@@ -250,7 +246,6 @@ ALBUM_VIEW_HTML = """
250
  </div>
251
  </div>
252
 
253
- <!-- Modal for previews -->
254
  <div id="previewModal" class="modal" onclick="closeModal()">
255
  <span class="close">&times;</span>
256
  <div id="modalContent" class="modal-content">
@@ -268,22 +263,22 @@ SEARCH_RESULTS_HTML = """
268
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
269
  <title>Search Results</title>
270
  <style>
271
- .container {{
272
  max-width: 800px;
273
  margin: 0 auto;
274
  padding: 20px;
275
- }}
276
- .album-item {{
277
  border: 1px solid #ddd;
278
  padding: 15px;
279
  margin-bottom: 15px;
280
  border-radius: 5px;
281
- }}
282
- .back-link {{
283
  margin-bottom: 20px;
284
  display: block;
285
- }}
286
- .button {{
287
  display: inline-block;
288
  padding: 8px 16px;
289
  background-color: #007bff;
@@ -291,10 +286,10 @@ SEARCH_RESULTS_HTML = """
291
  text-decoration: none;
292
  border-radius: 4px;
293
  margin: 5px;
294
- }}
295
- .button:hover {{
296
  background-color: #0056b3;
297
- }}
298
  </style>
299
  </head>
300
  <body>
@@ -325,23 +320,19 @@ async def index():
325
 
326
  @app.get("/search", response_class=HTMLResponse)
327
  async def search_albums(query: str = ""):
328
- query = query.lower()
329
- db_albums = await get_albums_from_db()
330
-
331
- matching_albums = {
332
- album['link']: albums[album['link']]
333
- for album in db_albums['data']
334
- if album['link'] in albums and query in album['name'].lower()
335
- }
336
 
337
  results_html = ""
338
- for album_id, album in matching_albums.items():
339
  results_html += f"""
340
  <div class="album-item">
341
  <h3>{album['name']}</h3>
342
- <p>Created: {album['created_at']}</p>
343
- <p>Files: {len(album['files'])}</p>
344
- <a href="/album/{album_id}" class="button">View Album</a>
345
  </div>
346
  """
347
 
@@ -377,27 +368,25 @@ async def create_album(
377
  'uploaded_at': datetime.now().isoformat()
378
  })
379
 
380
- albums[album_id] = {
381
- 'name': album_name,
382
- 'created_at': datetime.now().isoformat(),
383
- 'files': album_files
384
- }
385
-
386
- # Save to Deno KV database
387
- await save_album_to_db(album_name, album_id)
388
-
389
  base_url = str(request.base_url).rstrip('/')
390
  return RedirectResponse(url=f"{base_url}/album/{album_id}", status_code=303)
391
 
392
  @app.get("/album/{album_id}", response_class=HTMLResponse)
393
  async def view_album(album_id: str):
394
- if album_id not in albums:
 
 
 
 
 
 
 
395
  return "Album not found", 404
396
 
397
- album = albums[album_id]
398
  file_list_html = ""
399
-
400
- for file in album['files']:
401
  file_url = f"/upload/{file['path']}"
402
  file_type = get_file_type(file['filename'])
403
 
@@ -441,7 +430,14 @@ async def view_album(album_id: str):
441
 
442
  @app.get("/album/{album_id}/download")
443
  async def download_album(album_id: str):
444
- if album_id not in albums:
 
 
 
 
 
 
 
445
  return {"error": "Album not found"}, 404
446
 
447
  import io
@@ -449,7 +445,7 @@ async def download_album(album_id: str):
449
 
450
  zip_buffer = io.BytesIO()
451
  with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
452
- for file in albums[album_id]['files']:
453
  response = requests.get(f"https://replicate.delivery/pbxt/{file['path']}")
454
  zip_file.writestr(file['filename'], response.content)
455
 
@@ -459,7 +455,7 @@ async def download_album(album_id: str):
459
  io.BytesIO(zip_buffer.getvalue()),
460
  media_type="application/zip",
461
  headers={
462
- "Content-Disposition": f"attachment; filename={albums[album_id]['name']}.zip"
463
  }
464
  )
465
 
@@ -514,4 +510,4 @@ async def retry_upload(upload_url, file_content, content_type, max_retries=5):
514
 
515
  if __name__ == "__main__":
516
  import uvicorn
517
- uvicorn.run(app, host="0.0.0.0", port=8000)
 
14
 
15
  DENO_API_URL = "https://dataerrr99.deno.dev"
16
 
17
+ async def save_album_to_db(album_name: str, album_id: str, files: list):
18
  async with httpx.AsyncClient() as client:
19
  try:
20
  response = await client.post(DENO_API_URL, json={
21
  "albumName": album_name,
22
+ "albumLink": album_id,
23
+ "files": files,
24
+ "createdAt": datetime.now().isoformat()
25
  })
26
  return response.json()
27
  except Exception as e:
 
37
  print(f"Error fetching from DB: {str(e)}")
38
  return {"data": []}
39
 
 
 
 
40
  HTML_CONTENT = """
41
  <!DOCTYPE html>
42
  <html lang="en">
 
45
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
46
  <title>File Upload</title>
47
  <style>
48
+ .container {
49
  max-width: 800px;
50
  margin: 0 auto;
51
  padding: 20px;
52
+ }
53
+ .upload-form {
54
  margin-bottom: 20px;
55
  padding: 20px;
56
  border: 1px solid #ddd;
57
  border-radius: 5px;
58
+ }
59
+ .preview {
60
  margin-top: 20px;
61
+ }
62
+ .search-form {
63
  margin: 20px 0;
64
  padding: 20px;
65
  border: 1px solid #ddd;
66
  border-radius: 5px;
67
+ }
68
+ .album-list {
69
  margin-top: 20px;
70
+ }
71
+ .album-item {
72
  padding: 10px;
73
  border: 1px solid #ddd;
74
  margin-bottom: 10px;
75
  border-radius: 5px;
76
+ }
77
  </style>
78
  </head>
79
  <body>
80
  <div class="container">
81
  <h1>File Upload & Album Management</h1>
82
 
 
83
  <div class="search-form">
84
  <h2>Search Albums</h2>
85
  <form action="/search" method="get">
 
88
  </form>
89
  </div>
90
 
 
91
  <div class="upload-form">
92
  <h2>Single File Upload</h2>
93
  <form action="/upload" method="post" enctype="multipart/form-data">
 
96
  </form>
97
  </div>
98
 
 
99
  <div class="upload-form">
100
  <h2>Create Album</h2>
101
  <form action="/album/create" method="post" enctype="multipart/form-data">
 
117
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
118
  <title>Album View - {album_name}</title>
119
  <style>
120
+ .container {
121
  max-width: 800px;
122
  margin: 0 auto;
123
  padding: 20px;
124
+ }
125
+ .file-grid {
126
  display: grid;
127
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
128
  gap: 20px;
129
+ }
130
+ .file-item {
131
  border: 1px solid #ddd;
132
  padding: 10px;
133
  text-align: center;
134
  border-radius: 5px;
135
+ }
136
+ .download-all {
137
  margin: 20px 0;
138
+ }
139
+ .back-link {
140
  margin-bottom: 20px;
141
  display: block;
142
+ }
143
+ .button {
144
  display: inline-block;
145
  padding: 8px 16px;
146
  background-color: #007bff;
 
148
  text-decoration: none;
149
  border-radius: 4px;
150
  margin: 5px;
151
+ }
152
+ .button:hover {
153
  background-color: #0056b3;
154
+ }
155
+ .preview-container {
156
  margin-bottom: 10px;
157
  max-width: 100%;
158
  height: 200px;
 
162
  justify-content: center;
163
  background-color: #f8f9fa;
164
  border-radius: 4px;
165
+ }
166
+ .preview-container img {
167
  max-width: 100%;
168
  max-height: 100%;
169
  object-fit: contain;
170
+ }
171
+ .preview-container video {
172
  max-width: 100%;
173
  max-height: 100%;
174
  object-fit: contain;
175
+ }
176
+ .modal {
177
  display: none;
178
  position: fixed;
179
  z-index: 1000;
 
183
  height: 100%;
184
  background-color: rgba(0,0,0,0.9);
185
  overflow: auto;
186
+ }
187
+ .modal-content {
188
  margin: auto;
189
  display: block;
190
  max-width: 90%;
191
  max-height: 90vh;
192
  margin-top: 50px;
193
+ }
194
+ .close {
195
  position: absolute;
196
  right: 35px;
197
  top: 15px;
 
199
  font-size: 40px;
200
  font-weight: bold;
201
  cursor: pointer;
202
+ }
203
  </style>
204
  <script>
205
+ function openModal(url) {
206
  const modal = document.getElementById('previewModal');
207
  const modalContent = document.getElementById('modalContent');
208
  const contentType = getContentType(url);
209
 
210
+ if (contentType === 'image') {
211
+ modalContent.innerHTML = `<img src="${url}" style="max-width:100%;max-height:90vh;">`;
212
+ } else if (contentType === 'video') {
213
  modalContent.innerHTML = `<video controls style="max-width:100%;max-height:90vh;">
214
+ <source src="${url}" type="video/mp4">
215
  Your browser does not support the video tag.
216
  </video>`;
217
+ }
218
 
219
  modal.style.display = 'block';
220
+ }
221
 
222
+ function closeModal() {
223
  const modal = document.getElementById('previewModal');
224
  modal.style.display = 'none';
225
  const modalContent = document.getElementById('modalContent');
226
  modalContent.innerHTML = '';
227
+ }
228
 
229
+ function getContentType(url) {
230
  const ext = url.split('.').pop().toLowerCase();
231
  if (['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(ext)) return 'image';
232
  if (['mp4', 'webm', 'ogg'].includes(ext)) return 'video';
233
  return 'other';
234
+ }
235
  </script>
236
  </head>
237
  <body>
 
246
  </div>
247
  </div>
248
 
 
249
  <div id="previewModal" class="modal" onclick="closeModal()">
250
  <span class="close">&times;</span>
251
  <div id="modalContent" class="modal-content">
 
263
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
264
  <title>Search Results</title>
265
  <style>
266
+ .container {
267
  max-width: 800px;
268
  margin: 0 auto;
269
  padding: 20px;
270
+ }
271
+ .album-item {
272
  border: 1px solid #ddd;
273
  padding: 15px;
274
  margin-bottom: 15px;
275
  border-radius: 5px;
276
+ }
277
+ .back-link {
278
  margin-bottom: 20px;
279
  display: block;
280
+ }
281
+ .button {
282
  display: inline-block;
283
  padding: 8px 16px;
284
  background-color: #007bff;
 
286
  text-decoration: none;
287
  border-radius: 4px;
288
  margin: 5px;
289
+ }
290
+ .button:hover {
291
  background-color: #0056b3;
292
+ }
293
  </style>
294
  </head>
295
  <body>
 
320
 
321
  @app.get("/search", response_class=HTMLResponse)
322
  async def search_albums(query: str = ""):
323
+ db_data = await get_albums_from_db()
324
+ matching_albums = [
325
+ album for album in db_data['data']
326
+ if query.lower() in album['name'].lower()
327
+ ]
 
 
 
328
 
329
  results_html = ""
330
+ for album in matching_albums:
331
  results_html += f"""
332
  <div class="album-item">
333
  <h3>{album['name']}</h3>
334
+ <p>Created: {album['createdAt']}</p>
335
+ <a href="/album/{album['albumLink']}" class="button">View Album</a>
 
336
  </div>
337
  """
338
 
 
368
  'uploaded_at': datetime.now().isoformat()
369
  })
370
 
371
+ await save_album_to_db(album_name, album_id, album_files)
372
+
 
 
 
 
 
 
 
373
  base_url = str(request.base_url).rstrip('/')
374
  return RedirectResponse(url=f"{base_url}/album/{album_id}", status_code=303)
375
 
376
  @app.get("/album/{album_id}", response_class=HTMLResponse)
377
  async def view_album(album_id: str):
378
+ db_data = await get_albums_from_db()
379
+ album = None
380
+ for a in db_data['data']:
381
+ if a['albumLink'] == album_id:
382
+ album = a
383
+ break
384
+
385
+ if not album:
386
  return "Album not found", 404
387
 
 
388
  file_list_html = ""
389
+ for file in album.get('files', []):
 
390
  file_url = f"/upload/{file['path']}"
391
  file_type = get_file_type(file['filename'])
392
 
 
430
 
431
  @app.get("/album/{album_id}/download")
432
  async def download_album(album_id: str):
433
+ db_data = await get_albums_from_db()
434
+ album = None
435
+ for a in db_data['data']:
436
+ if a['albumLink'] == album_id:
437
+ album = a
438
+ break
439
+
440
+ if not album:
441
  return {"error": "Album not found"}, 404
442
 
443
  import io
 
445
 
446
  zip_buffer = io.BytesIO()
447
  with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zip_file:
448
+ for file in album['files']:
449
  response = requests.get(f"https://replicate.delivery/pbxt/{file['path']}")
450
  zip_file.writestr(file['filename'], response.content)
451
 
 
455
  io.BytesIO(zip_buffer.getvalue()),
456
  media_type="application/zip",
457
  headers={
458
+ "Content-Disposition": f"attachment; filename={album['name']}.zip"
459
  }
460
  )
461
 
 
510
 
511
  if __name__ == "__main__":
512
  import uvicorn
513
+ uvicorn.run(app, host="0.0.0.0", port=8000)