Spaces:
Sleeping
Sleeping
AdityaAdaki
commited on
Commit
·
63fc423
1
Parent(s):
c071803
bug fixes1
Browse files- app.py +75 -8
- static/js/main.js +29 -6
app.py
CHANGED
@@ -20,6 +20,7 @@ import asyncio
|
|
20 |
from flask_compress import Compress
|
21 |
from flask_caching import Cache
|
22 |
import hashlib
|
|
|
23 |
|
24 |
# Create uploads directory in the static folder instead of using tempfile
|
25 |
UPLOAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'uploads')
|
@@ -56,6 +57,16 @@ logger = logging.getLogger(__name__)
|
|
56 |
|
57 |
THREAD_POOL = ThreadPoolExecutor(max_workers=8)
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
def allowed_file(filename):
|
60 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
61 |
|
@@ -110,17 +121,19 @@ def index():
|
|
110 |
return render_template('index.html', title="Soundscape - 3D Music Visualizer")
|
111 |
|
112 |
def cleanup_old_files():
|
|
|
113 |
while True:
|
114 |
current_time = datetime.now()
|
115 |
files_to_delete = []
|
116 |
|
117 |
-
#
|
118 |
for filename, timestamp in file_timestamps.items():
|
119 |
if current_time - timestamp > FILE_LIFETIME:
|
120 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
121 |
try:
|
122 |
if os.path.exists(filepath):
|
123 |
os.remove(filepath)
|
|
|
124 |
files_to_delete.append(filename)
|
125 |
except Exception as e:
|
126 |
logger.error(f"Error deleting file {filename}: {str(e)}")
|
@@ -128,6 +141,28 @@ def cleanup_old_files():
|
|
128 |
# Remove deleted files from timestamps
|
129 |
for filename in files_to_delete:
|
130 |
file_timestamps.pop(filename, None)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
time.sleep(300) # Check every 5 minutes
|
133 |
|
@@ -160,6 +195,17 @@ def serve_static(filename):
|
|
160 |
def upload_file():
|
161 |
logger.info('Upload request received')
|
162 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
163 |
if 'files[]' not in request.files:
|
164 |
logger.warning('No files in request')
|
165 |
return jsonify({'success': False, 'error': 'No files uploaded'}), 400
|
@@ -184,27 +230,26 @@ def upload_file():
|
|
184 |
|
185 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
186 |
|
187 |
-
# Use buffered write for faster file saving
|
188 |
with open(filepath, 'wb') as f:
|
189 |
while True:
|
190 |
-
chunk = file.read(8192)
|
191 |
if not chunk:
|
192 |
break
|
193 |
f.write(chunk)
|
194 |
|
195 |
file_timestamps[filename] = datetime.now()
|
|
|
|
|
196 |
|
197 |
-
# Process metadata in parallel
|
198 |
metadata = extract_metadata(filepath)
|
199 |
-
|
200 |
-
# Invalidate cache if needed
|
201 |
invalidate_metadata_cache(filepath)
|
202 |
|
203 |
return {
|
204 |
'filename': file.filename,
|
205 |
'success': True,
|
206 |
'filepath': f'/static/uploads/{filename}',
|
207 |
-
'metadata': metadata
|
|
|
208 |
}
|
209 |
return {
|
210 |
'filename': file.filename,
|
@@ -225,7 +270,8 @@ def upload_file():
|
|
225 |
|
226 |
return jsonify({
|
227 |
'success': True,
|
228 |
-
'files': results
|
|
|
229 |
})
|
230 |
|
231 |
@app.route('/static/uploads/<filename>')
|
@@ -252,5 +298,26 @@ def add_header(response):
|
|
252 |
def invalidate_metadata_cache(filepath):
|
253 |
cache.delete_memoized(extract_metadata, filepath)
|
254 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
if __name__ == '__main__':
|
256 |
app.run(host='0.0.0.0', port=7860)
|
|
|
20 |
from flask_compress import Compress
|
21 |
from flask_caching import Cache
|
22 |
import hashlib
|
23 |
+
from uuid import uuid4
|
24 |
|
25 |
# Create uploads directory in the static folder instead of using tempfile
|
26 |
UPLOAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'uploads')
|
|
|
57 |
|
58 |
THREAD_POOL = ThreadPoolExecutor(max_workers=8)
|
59 |
|
60 |
+
# Track files by session
|
61 |
+
session_files = {}
|
62 |
+
INACTIVE_SESSION_TIMEOUT = 3600 # 1 hour in seconds
|
63 |
+
|
64 |
+
def get_session_id():
|
65 |
+
"""Generate or retrieve session ID from request"""
|
66 |
+
if 'X-Session-ID' in request.headers:
|
67 |
+
return request.headers['X-Session-ID']
|
68 |
+
return str(uuid4())
|
69 |
+
|
70 |
def allowed_file(filename):
|
71 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
72 |
|
|
|
121 |
return render_template('index.html', title="Soundscape - 3D Music Visualizer")
|
122 |
|
123 |
def cleanup_old_files():
|
124 |
+
"""Enhanced cleanup that handles both time-based and session-based cleanup"""
|
125 |
while True:
|
126 |
current_time = datetime.now()
|
127 |
files_to_delete = []
|
128 |
|
129 |
+
# Cleanup files by age
|
130 |
for filename, timestamp in file_timestamps.items():
|
131 |
if current_time - timestamp > FILE_LIFETIME:
|
132 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
133 |
try:
|
134 |
if os.path.exists(filepath):
|
135 |
os.remove(filepath)
|
136 |
+
logger.info(f"Deleted old file: {filename}")
|
137 |
files_to_delete.append(filename)
|
138 |
except Exception as e:
|
139 |
logger.error(f"Error deleting file {filename}: {str(e)}")
|
|
|
141 |
# Remove deleted files from timestamps
|
142 |
for filename in files_to_delete:
|
143 |
file_timestamps.pop(filename, None)
|
144 |
+
|
145 |
+
# Cleanup files by session
|
146 |
+
inactive_sessions = []
|
147 |
+
current_timestamp = time.time()
|
148 |
+
|
149 |
+
for session_id, session_data in session_files.items():
|
150 |
+
last_access = session_data.get('last_access', 0)
|
151 |
+
if current_timestamp - last_access > INACTIVE_SESSION_TIMEOUT:
|
152 |
+
# Delete all files for this session
|
153 |
+
for filename in session_data.get('files', []):
|
154 |
+
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
155 |
+
try:
|
156 |
+
if os.path.exists(filepath):
|
157 |
+
os.remove(filepath)
|
158 |
+
logger.info(f"Deleted session file: {filename}")
|
159 |
+
except Exception as e:
|
160 |
+
logger.error(f"Error deleting session file {filename}: {str(e)}")
|
161 |
+
inactive_sessions.append(session_id)
|
162 |
+
|
163 |
+
# Remove inactive sessions
|
164 |
+
for session_id in inactive_sessions:
|
165 |
+
session_files.pop(session_id, None)
|
166 |
|
167 |
time.sleep(300) # Check every 5 minutes
|
168 |
|
|
|
195 |
def upload_file():
|
196 |
logger.info('Upload request received')
|
197 |
|
198 |
+
session_id = get_session_id()
|
199 |
+
|
200 |
+
if session_id not in session_files:
|
201 |
+
session_files[session_id] = {
|
202 |
+
'files': [],
|
203 |
+
'last_access': time.time()
|
204 |
+
}
|
205 |
+
|
206 |
+
# Update last access time
|
207 |
+
session_files[session_id]['last_access'] = time.time()
|
208 |
+
|
209 |
if 'files[]' not in request.files:
|
210 |
logger.warning('No files in request')
|
211 |
return jsonify({'success': False, 'error': 'No files uploaded'}), 400
|
|
|
230 |
|
231 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
232 |
|
|
|
233 |
with open(filepath, 'wb') as f:
|
234 |
while True:
|
235 |
+
chunk = file.read(8192)
|
236 |
if not chunk:
|
237 |
break
|
238 |
f.write(chunk)
|
239 |
|
240 |
file_timestamps[filename] = datetime.now()
|
241 |
+
# Track file with session
|
242 |
+
session_files[session_id]['files'].append(filename)
|
243 |
|
|
|
244 |
metadata = extract_metadata(filepath)
|
|
|
|
|
245 |
invalidate_metadata_cache(filepath)
|
246 |
|
247 |
return {
|
248 |
'filename': file.filename,
|
249 |
'success': True,
|
250 |
'filepath': f'/static/uploads/{filename}',
|
251 |
+
'metadata': metadata,
|
252 |
+
'session_id': session_id # Return session ID to client
|
253 |
}
|
254 |
return {
|
255 |
'filename': file.filename,
|
|
|
270 |
|
271 |
return jsonify({
|
272 |
'success': True,
|
273 |
+
'files': results,
|
274 |
+
'session_id': session_id
|
275 |
})
|
276 |
|
277 |
@app.route('/static/uploads/<filename>')
|
|
|
298 |
def invalidate_metadata_cache(filepath):
|
299 |
cache.delete_memoized(extract_metadata, filepath)
|
300 |
|
301 |
+
# Add endpoint to explicitly end session
|
302 |
+
@app.route('/end-session', methods=['POST'])
|
303 |
+
def end_session():
|
304 |
+
session_id = request.headers.get('X-Session-ID')
|
305 |
+
if session_id and session_id in session_files:
|
306 |
+
# Delete all files for this session
|
307 |
+
for filename in session_files[session_id].get('files', []):
|
308 |
+
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
309 |
+
try:
|
310 |
+
if os.path.exists(filepath):
|
311 |
+
os.remove(filepath)
|
312 |
+
logger.info(f"Deleted session file: {filename}")
|
313 |
+
except Exception as e:
|
314 |
+
logger.error(f"Error deleting session file {filename}: {str(e)}")
|
315 |
+
|
316 |
+
# Remove session data
|
317 |
+
session_files.pop(session_id, None)
|
318 |
+
return jsonify({'success': True, 'message': 'Session ended and files cleaned up'})
|
319 |
+
|
320 |
+
return jsonify({'success': False, 'error': 'Session not found'}), 404
|
321 |
+
|
322 |
if __name__ == '__main__':
|
323 |
app.run(host='0.0.0.0', port=7860)
|
static/js/main.js
CHANGED
@@ -1310,12 +1310,9 @@ async function handleFiles(files) {
|
|
1310 |
const response = await fetch('/upload', {
|
1311 |
method: 'POST',
|
1312 |
body: formData,
|
1313 |
-
|
1314 |
-
|
1315 |
-
|
1316 |
-
if (progressFill) progressFill.style.width = percentComplete + '%';
|
1317 |
-
if (progressText) progressText.textContent = Math.round(percentComplete) + '%';
|
1318 |
-
}
|
1319 |
});
|
1320 |
|
1321 |
if (!response.ok) {
|
@@ -1372,6 +1369,12 @@ async function handleFiles(files) {
|
|
1372 |
item.classList.toggle('active', i === currentTrackIndex);
|
1373 |
});
|
1374 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1375 |
} else {
|
1376 |
console.error('Upload failed:', data.error);
|
1377 |
showError(data.error || 'Upload failed');
|
@@ -1455,4 +1458,24 @@ function setupVolumeControl() {
|
|
1455 |
document.addEventListener('DOMContentLoaded', () => {
|
1456 |
// ... other initialization code ...
|
1457 |
setupVolumeControl();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1458 |
});
|
|
|
1310 |
const response = await fetch('/upload', {
|
1311 |
method: 'POST',
|
1312 |
body: formData,
|
1313 |
+
headers: sessionId ? {
|
1314 |
+
'X-Session-ID': sessionId
|
1315 |
+
} : {}
|
|
|
|
|
|
|
1316 |
});
|
1317 |
|
1318 |
if (!response.ok) {
|
|
|
1369 |
item.classList.toggle('active', i === currentTrackIndex);
|
1370 |
});
|
1371 |
}
|
1372 |
+
|
1373 |
+
// Store session ID if we got one
|
1374 |
+
if (data.session_id) {
|
1375 |
+
sessionId = data.session_id;
|
1376 |
+
localStorage.setItem('audioSessionId', sessionId);
|
1377 |
+
}
|
1378 |
} else {
|
1379 |
console.error('Upload failed:', data.error);
|
1380 |
showError(data.error || 'Upload failed');
|
|
|
1458 |
document.addEventListener('DOMContentLoaded', () => {
|
1459 |
// ... other initialization code ...
|
1460 |
setupVolumeControl();
|
1461 |
+
});
|
1462 |
+
|
1463 |
+
// Add session management
|
1464 |
+
let sessionId = localStorage.getItem('audioSessionId');
|
1465 |
+
|
1466 |
+
// Add cleanup on page unload
|
1467 |
+
window.addEventListener('beforeunload', async () => {
|
1468 |
+
if (sessionId) {
|
1469 |
+
try {
|
1470 |
+
await fetch('/end-session', {
|
1471 |
+
method: 'POST',
|
1472 |
+
headers: {
|
1473 |
+
'X-Session-ID': sessionId
|
1474 |
+
}
|
1475 |
+
});
|
1476 |
+
localStorage.removeItem('audioSessionId');
|
1477 |
+
} catch (error) {
|
1478 |
+
console.error('Error ending session:', error);
|
1479 |
+
}
|
1480 |
+
}
|
1481 |
});
|