albumup commited on
Commit
af3ffbb
·
verified ·
1 Parent(s): e401e54

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +450 -148
app.py CHANGED
@@ -66,7 +66,7 @@ def is_allowed_file_type(filename):
66
 
67
  @app.get("/", response_class=HTMLResponse)
68
  async def index():
69
- return f"""
70
  <!DOCTYPE html>
71
  <html lang="en">
72
  <head>
@@ -74,156 +74,222 @@ async def index():
74
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
75
  <title>File Upload</title>
76
  <style>
77
- body {{
78
- background-color: #121212;
79
- color: #e0e0e0;
80
- font-family: 'Helvetica Neue', Arial, sans-serif;
81
  margin: 0;
82
  padding: 0;
83
- }}
84
- .container {{
 
 
 
 
 
 
 
 
 
 
 
85
  max-width: 800px;
86
  margin: 0 auto;
87
- padding: 20px;
88
- }}
89
- h1 {{
90
- text-align: center;
91
- color: #fff;
92
- }}
93
- form {{
94
- display: flex;
95
- flex-direction: column;
96
- align-items: center;
97
- }}
98
- input, button {{
99
- margin: 10px 0;
100
- padding: 10px;
101
- border: none;
102
- border-radius: 5px;
103
- font-size: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
  outline: none;
105
- }}
106
- input[type="text"], input[type="file"] {{
107
- background-color: #222;
 
 
 
 
 
 
 
 
108
  color: #e0e0e0;
109
- }}
110
- input[type="checkbox"] {{
111
- margin-right: 5px;
112
- }}
113
- button {{
114
- background-color: #007bff;
115
- color: #fff;
116
  cursor: pointer;
117
- transition: background-color 0.3s ease;
118
- }}
119
- button:hover {{
120
- background-color: #0056b3;
121
- }}
122
- .progress-bar {{
123
  width: 100%;
124
  background-color: #333;
125
- border-radius: 5px;
 
126
  overflow: hidden;
127
- }}
128
- .progress-bar-inner {{
 
129
  width: 0%;
130
- height: 20px;
131
- background-color: #007bff;
132
- transition: width 0.3s ease;
133
- }}
134
- .private-checkbox {{
135
- display: flex;
136
- align-items: center;
137
- margin: 20px 0;
138
- }}
139
- .button {{
140
  display: inline-block;
141
- padding: 10px 20px;
142
- background-color: #007bff;
143
- color: #fff;
144
  text-decoration: none;
145
- border-radius: 5px;
146
- margin: 10px;
147
- transition: background-color 0.3s ease;
148
- }}
149
- .button:hover {{
150
- background-color: #0056b3;
151
- }}
152
- .search-form {{
 
 
 
 
 
 
153
  display: flex;
154
- margin-top: 20px;
155
- }}
156
- .search-form input {{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  flex: 1;
158
- margin-right: 10px;
159
- }}
160
- .search-results {{
161
- margin-top: 20px;
162
- }}
163
- .album-item {{
164
- background-color: #222;
165
- padding: 20px;
166
- border-radius: 5px;
167
- margin-bottom: 20px;
168
- }}
169
- .album-item h3 {{
170
- color: #fff;
171
- margin: 0;
172
- }}
173
- .album-item p {{
174
- color: #888;
175
- margin: 5px 0;
176
- }}
177
- @media (max-width: 600px) {{
178
- .container {{
179
- padding: 10px;
180
- }}
181
- input, button {{
182
- font-size: 14px;
183
- }}
184
- }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  </style>
186
  </head>
187
  <body>
188
  <div class="container">
189
  <h1>File Upload & Album Management</h1>
190
- <form action="/album/create" method="post" enctype="multipart/form-data" onsubmit="showProgressBar()">
191
- <input type="text" name="album_name" placeholder="Album Name" required>
192
- <input type="file" name="files" accept="*/*" multiple required>
193
- <div class="private-checkbox">
194
- <input type="checkbox" name="is_private">
195
- <label>Make this album private (exclude from search)</label>
196
- </div>
197
- <div class="progress-bar">
198
- <div class="progress-bar-inner" id="progressBar"></div>
199
- </div>
200
- <button type="submit">Create Album</button>
201
- </form>
202
- <h2>Single File Upload</h2>
203
- <a href="https://albumup-up1.hf.space/" class="button">Upload Single File</a>
204
- <h2>Search Albums</h2>
205
- <form class="search-form" action="/search" method="get">
206
- <input type="text" name="query" placeholder="Search by album name...">
207
- <button type="submit">Search</button>
208
- </form>
209
- <div class="search-results">
210
- <!-- Search results will be displayed here -->
 
 
 
 
 
211
  </div>
212
- <script>
213
- function showProgressBar() {{
214
- const progressBar = document.getElementById('progressBar');
215
- let width = 0;
216
- const interval = setInterval(() => {{
217
- if (width >= 100) {{
218
- clearInterval(interval);
219
- }} else {{
220
- width += 1;
221
- progressBar.style.width = width + '%';
222
- }}
223
- }}, 30);
224
- }}
225
- </script>
226
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  </body>
228
  </html>
229
  """
@@ -244,11 +310,43 @@ async def create_album(
244
  <meta charset="UTF-8">
245
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
246
  <title>Error</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  </head>
248
  <body>
249
- <h1>Error: Invalid File Type</h1>
250
- <p>The file '{file.filename}' is not allowed. Please upload it using the <a href="https://albumup-up1.hf.space/">Single File Upload</a>.</p>
251
- <a href="/" class="button">← Back to Home</a>
 
 
252
  </body>
253
  </html>
254
  """, status_code=400)
@@ -278,7 +376,6 @@ async def create_album(
278
  progress = math.floor((uploaded_files / total_files) * 100)
279
  print(f"Upload Progress: {progress}%")
280
 
281
- # Save to Deno KV database
282
  await save_album_to_db(album_name, album_id, album_files, is_private)
283
 
284
  base_url = str(request.base_url).rstrip('/')
@@ -288,10 +385,55 @@ async def create_album(
288
  async def view_album(album_id: str):
289
  album = await get_album_from_db(album_id)
290
  if not album or 'files' not in album:
291
- return "Album not found or invalid data", 404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
292
 
293
- file_list_html = ""
294
-
295
  for file in album['files']:
296
  file_url = f"/upload/{file['path']}"
297
  file_type = get_file_type(file['filename'])
@@ -323,8 +465,10 @@ async def view_album(album_id: str):
323
  <div class="file-item">
324
  {preview_html}
325
  <p>{file['filename']}</p>
326
- <a href="{file_url}" class="button" onclick="openModal('{file_url}'); return false;">View</a>
327
- <a href="{file_url}?download=true" class="button" target="_blank">Download</a>
 
 
328
  </div>
329
  """
330
 
@@ -335,12 +479,110 @@ async def view_album(album_id: str):
335
  <meta charset="UTF-8">
336
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
337
  <title>Album View - {album['albumName']}</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
338
  </head>
339
  <body>
340
- <h1>{album['albumName']}</h1>
341
- <a href="/album/{album_id}/download" class="button">Download All Files as ZIP</a>
342
- <div class="file-grid">
343
- {file_list_html}
 
 
 
 
344
  </div>
345
  </body>
346
  </html>
@@ -372,7 +614,6 @@ async def download_album(album_id: str):
372
  @app.get("/search", response_class=HTMLResponse)
373
  async def search_albums(query: str):
374
  db_albums = await get_albums_from_db()
375
- # Exclude private albums from search results
376
  matching_albums = [
377
  album for album in db_albums['data']
378
  if query.lower() in album.get('albumName', '').lower() and not album.get('isPrivate', False)
@@ -396,14 +637,75 @@ async def search_albums(query: str):
396
  <meta charset="UTF-8">
397
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
398
  <title>Search Results</title>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  </head>
400
  <body>
401
- <h1>Search Results</h1>
402
- <p>Found {len(matching_albums)} albums for "{query}"</p>
403
- <div class="search-results">
404
- {results_html}
 
 
 
405
  </div>
406
- <a href="/" class="button">← Back to Home</a>
407
  </body>
408
  </html>
409
  """
 
66
 
67
  @app.get("/", response_class=HTMLResponse)
68
  async def index():
69
+ return """
70
  <!DOCTYPE html>
71
  <html lang="en">
72
  <head>
 
74
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
75
  <title>File Upload</title>
76
  <style>
77
+ * {
 
 
 
78
  margin: 0;
79
  padding: 0;
80
+ box-sizing: border-box;
81
+ transition: all 0.2s ease-in-out;
82
+ }
83
+
84
+ body {
85
+ background-color: #121212;
86
+ color: rgba(255, 255, 255, 0.87);
87
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
88
+ line-height: 1.6;
89
+ padding: 2rem;
90
+ }
91
+
92
+ .container {
93
  max-width: 800px;
94
  margin: 0 auto;
95
+ padding: 2rem;
96
+ background-color: #1E1E1E;
97
+ border-radius: 12px;
98
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
99
+ }
100
+
101
+ h1, h2 {
102
+ color: #e0e0e0;
103
+ margin-bottom: 1.5rem;
104
+ font-weight: 600;
105
+ }
106
+
107
+ .upload-section {
108
+ background-color: #282828;
109
+ padding: 2rem;
110
+ border-radius: 8px;
111
+ margin-bottom: 2rem;
112
+ }
113
+
114
+ input[type="text"] {
115
+ width: 100%;
116
+ padding: 12px;
117
+ margin-bottom: 1rem;
118
+ background-color: #333;
119
+ border: 1px solid #404040;
120
+ border-radius: 6px;
121
+ color: #e0e0e0;
122
+ font-size: 1rem;
123
+ }
124
+
125
+ input[type="text"]:focus {
126
  outline: none;
127
+ border-color: #505050;
128
+ box-shadow: 0 0 0 2px rgba(224, 224, 224, 0.1);
129
+ }
130
+
131
+ input[type="file"] {
132
+ width: 100%;
133
+ padding: 12px;
134
+ margin-bottom: 1rem;
135
+ background-color: #333;
136
+ border: 1px solid #404040;
137
+ border-radius: 6px;
138
  color: #e0e0e0;
 
 
 
 
 
 
 
139
  cursor: pointer;
140
+ }
141
+
142
+ .progress-bar {
 
 
 
143
  width: 100%;
144
  background-color: #333;
145
+ border-radius: 6px;
146
+ margin: 1rem 0;
147
  overflow: hidden;
148
+ }
149
+
150
+ .progress-bar-inner {
151
  width: 0%;
152
+ height: 8px;
153
+ background-color: #4caf50;
154
+ border-radius: 6px;
155
+ transition: width 0.3s ease-in-out;
156
+ }
157
+
158
+ .button {
 
 
 
159
  display: inline-block;
160
+ padding: 12px 24px;
161
+ background-color: #404040;
162
+ color: #e0e0e0;
163
  text-decoration: none;
164
+ border-radius: 6px;
165
+ border: none;
166
+ font-size: 1rem;
167
+ cursor: pointer;
168
+ margin: 0.5rem;
169
+ transition: all 0.2s ease;
170
+ }
171
+
172
+ .button:hover {
173
+ background-color: #505050;
174
+ transform: translateY(-1px);
175
+ }
176
+
177
+ .private-checkbox {
178
  display: flex;
179
+ align-items: center;
180
+ margin: 1rem 0;
181
+ cursor: pointer;
182
+ }
183
+
184
+ .private-checkbox input[type="checkbox"] {
185
+ margin-right: 8px;
186
+ cursor: pointer;
187
+ }
188
+
189
+ .search-section {
190
+ margin-top: 2rem;
191
+ }
192
+
193
+ .search-form {
194
+ display: flex;
195
+ gap: 1rem;
196
+ }
197
+
198
+ .search-form input {
199
  flex: 1;
200
+ }
201
+
202
+ .file-grid {
203
+ display: grid;
204
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
205
+ gap: 1rem;
206
+ margin-top: 2rem;
207
+ }
208
+
209
+ .file-item {
210
+ background-color: #282828;
211
+ padding: 1rem;
212
+ border-radius: 8px;
213
+ transition: transform 0.2s ease;
214
+ }
215
+
216
+ .file-item:hover {
217
+ transform: translateY(-2px);
218
+ background-color: #333;
219
+ }
220
+
221
+ .preview-container {
222
+ width: 100%;
223
+ aspect-ratio: 1;
224
+ overflow: hidden;
225
+ border-radius: 6px;
226
+ margin-bottom: 0.5rem;
227
+ }
228
+
229
+ .preview-container img,
230
+ .preview-container video {
231
+ width: 100%;
232
+ height: 100%;
233
+ object-fit: cover;
234
+ }
235
+
236
+ @keyframes fadeIn {
237
+ from { opacity: 0; transform: translateY(10px); }
238
+ to { opacity: 1; transform: translateY(0); }
239
+ }
240
+
241
+ .container {
242
+ animation: fadeIn 0.3s ease-out;
243
+ }
244
  </style>
245
  </head>
246
  <body>
247
  <div class="container">
248
  <h1>File Upload & Album Management</h1>
249
+
250
+ <div class="upload-section">
251
+ <form action="/album/create" method="post" enctype="multipart/form-data" onsubmit="showProgressBar()">
252
+ <input type="text" name="album_name" placeholder="Enter album name..." required>
253
+ <input type="file" name="files" accept="*/*" multiple required>
254
+ <label class="private-checkbox">
255
+ <input type="checkbox" name="is_private">
256
+ <span>Make this album private</span>
257
+ </label>
258
+ <div class="progress-bar">
259
+ <div class="progress-bar-inner" id="progressBar"></div>
260
+ </div>
261
+ <button type="submit" class="button">Create Album</button>
262
+ </form>
263
+ </div>
264
+
265
+ <div class="search-section">
266
+ <h2>Search Albums</h2>
267
+ <form action="/search" method="get" class="search-form">
268
+ <input type="text" name="query" placeholder="Search albums..." required>
269
+ <button type="submit" class="button">Search</button>
270
+ </form>
271
+ </div>
272
+
273
+ <div style="text-align: center; margin-top: 2rem;">
274
+ <a href="https://albumup-up1.hf.space/" class="button">Upload Single File</a>
275
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  </div>
277
+
278
+ <script>
279
+ function showProgressBar() {
280
+ const progressBar = document.getElementById('progressBar');
281
+ progressBar.style.width = '0%';
282
+ let progress = 0;
283
+ const interval = setInterval(() => {
284
+ if (progress < 90) {
285
+ progress += 1;
286
+ progressBar.style.width = progress + '%';
287
+ } else {
288
+ clearInterval(interval);
289
+ }
290
+ }, 30);
291
+ }
292
+ </script>
293
  </body>
294
  </html>
295
  """
 
310
  <meta charset="UTF-8">
311
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
312
  <title>Error</title>
313
+ <style>
314
+ body {
315
+ background-color: #121212;
316
+ color: #e0e0e0;
317
+ font-family: -apple-system, system-ui, sans-serif;
318
+ padding: 2rem;
319
+ text-align: center;
320
+ }
321
+ .error-container {
322
+ background-color: #1E1E1E;
323
+ padding: 2rem;
324
+ border-radius: 12px;
325
+ max-width: 600px;
326
+ margin: 0 auto;
327
+ }
328
+ .button {
329
+ display: inline-block;
330
+ padding: 12px 24px;
331
+ background-color: #404040;
332
+ color: #e0e0e0;
333
+ text-decoration: none;
334
+ border-radius: 6px;
335
+ margin-top: 1rem;
336
+ transition: all 0.2s ease;
337
+ }
338
+ .button:hover {
339
+ background-color: #505050;
340
+ transform: translateY(-1px);
341
+ }
342
+ </style>
343
  </head>
344
  <body>
345
+ <div class="error-container">
346
+ <h1>Error: Invalid File Type</h1>
347
+ <p>The file '{file.filename}' is not allowed. Please upload it using the <a href="https://albumup-up1.hf.space/" style="color: #4caf50;">Single File Upload</a>.</p>
348
+ <a href="/" class="button">← Back to Home</a>
349
+ </div>
350
  </body>
351
  </html>
352
  """, status_code=400)
 
376
  progress = math.floor((uploaded_files / total_files) * 100)
377
  print(f"Upload Progress: {progress}%")
378
 
 
379
  await save_album_to_db(album_name, album_id, album_files, is_private)
380
 
381
  base_url = str(request.base_url).rstrip('/')
 
385
  async def view_album(album_id: str):
386
  album = await get_album_from_db(album_id)
387
  if not album or 'files' not in album:
388
+ return """
389
+ <!DOCTYPE html>
390
+ <html lang="en">
391
+ <head>
392
+ <meta charset="UTF-8">
393
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
394
+ <title>Album Not Found</title>
395
+ <style>
396
+ body {
397
+ background-color: #121212;
398
+ color: #e0e0e0;
399
+ font-family: -apple-system, system-ui, sans-serif;
400
+ padding: 2rem;
401
+ text-align: center;
402
+ }
403
+ .error-container {
404
+ background-color: #1E1E1E;
405
+ padding: 2rem;
406
+ border-radius: 12px;
407
+ max-width: 600px;
408
+ margin: 0 auto;
409
+ }
410
+ .button {
411
+ display: inline-block;
412
+ padding: 12px 24px;
413
+ background-color: #404040;
414
+ color: #e0e0e0;
415
+ text-decoration: none;
416
+ border-radius: 6px;
417
+ margin-top: 1rem;
418
+ transition: all 0.2s ease;
419
+ }
420
+ .button:hover {
421
+ background-color: #505050;
422
+ transform: translateY(-1px);
423
+ }
424
+ </style>
425
+ </head>
426
+ <body>
427
+ <div class="error-container">
428
+ <h1>Album Not Found</h1>
429
+ <p>The requested album could not be found or contains invalid data.</p>
430
+ <a href="/" class="button">← Back to Home</a>
431
+ </div>
432
+ </body>
433
+ </html>
434
+ """
435
 
436
+ file_list_html = ""
 
437
  for file in album['files']:
438
  file_url = f"/upload/{file['path']}"
439
  file_type = get_file_type(file['filename'])
 
465
  <div class="file-item">
466
  {preview_html}
467
  <p>{file['filename']}</p>
468
+ <div class="button-group">
469
+ <a href="{file_url}" class="button" onclick="openModal('{file_url}'); return false;">View</a>
470
+ <a href="{file_url}?download=true" class="button" target="_blank">Download</a>
471
+ </div>
472
  </div>
473
  """
474
 
 
479
  <meta charset="UTF-8">
480
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
481
  <title>Album View - {album['albumName']}</title>
482
+ <style>
483
+ body {{
484
+ background-color: #121212;
485
+ color: #e0e0e0;
486
+ font-family: -apple-system, system-ui, sans-serif;
487
+ padding: 2rem;
488
+ margin: 0;
489
+ }}
490
+
491
+ .container {{
492
+ max-width: 1200px;
493
+ margin: 0 auto;
494
+ padding: 2rem;
495
+ background-color: #1E1E1E;
496
+ border-radius: 12px;
497
+ }}
498
+
499
+ h1 {{
500
+ margin-bottom: 2rem;
501
+ color: #ffffff;
502
+ }}
503
+
504
+ .file-grid {{
505
+ display: grid;
506
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
507
+ gap: 1.5rem;
508
+ margin-top: 2rem;
509
+ }}
510
+
511
+ .file-item {{
512
+ background-color: #282828;
513
+ padding: 1rem;
514
+ border-radius: 8px;
515
+ transition: transform 0.2s ease;
516
+ }}
517
+
518
+ .file-item:hover {{
519
+ transform: translateY(-2px);
520
+ background-color: #333;
521
+ }}
522
+
523
+ .preview-container {{
524
+ width: 100%;
525
+ aspect-ratio: 1;
526
+ overflow: hidden;
527
+ border-radius: 6px;
528
+ margin-bottom: 1rem;
529
+ background-color: #1E1E1E;
530
+ }}
531
+
532
+ .preview-container img,
533
+ .preview-container video {{
534
+ width: 100%;
535
+ height: 100%;
536
+ object-fit: cover;
537
+ cursor: pointer;
538
+ }}
539
+
540
+ .button {{
541
+ display: inline-block;
542
+ padding: 8px 16px;
543
+ background-color: #404040;
544
+ color: #e0e0e0;
545
+ text-decoration: none;
546
+ border-radius: 6px;
547
+ margin: 0.25rem;
548
+ transition: all 0.2s ease;
549
+ }}
550
+
551
+ .button:hover {{
552
+ background-color: #505050;
553
+ transform: translateY(-1px);
554
+ }}
555
+
556
+ .button-group {{
557
+ display: flex;
558
+ justify-content: center;
559
+ gap: 0.5rem;
560
+ }}
561
+
562
+ .download-all {{
563
+ margin-bottom: 2rem;
564
+ text-align: center;
565
+ }}
566
+
567
+ @keyframes fadeIn {{
568
+ from {{ opacity: 0; transform: translateY(10px); }}
569
+ to {{ opacity: 1; transform: translateY(0); }}
570
+ }}
571
+
572
+ .container {{
573
+ animation: fadeIn 0.3s ease-out;
574
+ }}
575
+ </style>
576
  </head>
577
  <body>
578
+ <div class="container">
579
+ <h1>{album['albumName']}</h1>
580
+ <div class="download-all">
581
+ <a href="/album/{album_id}/download" class="button">Download All Files as ZIP</a>
582
+ </div>
583
+ <div class="file-grid">
584
+ {file_list_html}
585
+ </div>
586
  </div>
587
  </body>
588
  </html>
 
614
  @app.get("/search", response_class=HTMLResponse)
615
  async def search_albums(query: str):
616
  db_albums = await get_albums_from_db()
 
617
  matching_albums = [
618
  album for album in db_albums['data']
619
  if query.lower() in album.get('albumName', '').lower() and not album.get('isPrivate', False)
 
637
  <meta charset="UTF-8">
638
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
639
  <title>Search Results</title>
640
+ <style>
641
+ body {{
642
+ background-color: #121212;
643
+ color: #e0e0e0;
644
+ font-family: -apple-system, system-ui, sans-serif;
645
+ padding: 2rem;
646
+ margin: 0;
647
+ }}
648
+
649
+ .container {{
650
+ max-width: 800px;
651
+ margin: 0 auto;
652
+ padding: 2rem;
653
+ background-color: #1E1E1E;
654
+ border-radius: 12px;
655
+ }}
656
+
657
+ h1, h3 {{
658
+ color: #ffffff;
659
+ }}
660
+
661
+ .album-item {{
662
+ background-color: #282828;
663
+ padding: 1.5rem;
664
+ border-radius: 8px;
665
+ margin-bottom: 1rem;
666
+ transition: transform 0.2s ease;
667
+ }}
668
+
669
+ .album-item:hover {{
670
+ transform: translateY(-2px);
671
+ background-color: #333;
672
+ }}
673
+
674
+ .button {{
675
+ display: inline-block;
676
+ padding: 12px 24px;
677
+ background-color: #404040;
678
+ color: #e0e0e0;
679
+ text-decoration: none;
680
+ border-radius: 6px;
681
+ margin-top: 1rem;
682
+ transition: all 0.2s ease;
683
+ }}
684
+
685
+ .button:hover {{
686
+ background-color: #505050;
687
+ transform: translateY(-1px);
688
+ }}
689
+
690
+ @keyframes fadeIn {{
691
+ from {{ opacity: 0; transform: translateY(10px); }}
692
+ to {{ opacity: 1; transform: translateY(0); }}
693
+ }}
694
+
695
+ .container {{
696
+ animation: fadeIn 0.3s ease-out;
697
+ }}
698
+ </style>
699
  </head>
700
  <body>
701
+ <div class="container">
702
+ <h1>Search Results</h1>
703
+ <p>Found {len(matching_albums)} albums for "{query}"</p>
704
+ <div class="search-results">
705
+ {results_html}
706
+ </div>
707
+ <a href="/" class="button">← Back to Home</a>
708
  </div>
 
709
  </body>
710
  </html>
711
  """