Spaces:
Sleeping
Sleeping
AdityaAdaki
commited on
Commit
·
feee5aa
1
Parent(s):
25e8e76
bug fixes
Browse files- app.py +35 -28
- requirements.txt +2 -1
- static/js/main.js +12 -2
app.py
CHANGED
|
@@ -17,6 +17,7 @@ import logging
|
|
| 17 |
import base64
|
| 18 |
from concurrent.futures import ThreadPoolExecutor
|
| 19 |
import asyncio
|
|
|
|
| 20 |
|
| 21 |
# Create uploads directory in the static folder instead of using tempfile
|
| 22 |
UPLOAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'uploads')
|
|
@@ -38,19 +39,19 @@ file_timestamps = {}
|
|
| 38 |
logging.basicConfig(level=logging.INFO)
|
| 39 |
logger = logging.getLogger(__name__)
|
| 40 |
|
| 41 |
-
THREAD_POOL = ThreadPoolExecutor(max_workers=
|
| 42 |
|
| 43 |
def allowed_file(filename):
|
| 44 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
| 45 |
|
| 46 |
-
#
|
| 47 |
def extract_metadata(filepath):
|
| 48 |
try:
|
| 49 |
-
audio = File(filepath)
|
| 50 |
if audio is None:
|
| 51 |
return {}
|
| 52 |
|
| 53 |
-
#
|
| 54 |
metadata = {
|
| 55 |
'title': None,
|
| 56 |
'artist': 'Unknown Artist',
|
|
@@ -59,27 +60,17 @@ def extract_metadata(filepath):
|
|
| 59 |
|
| 60 |
# Get filename as fallback
|
| 61 |
original_filename = os.path.splitext(os.path.basename(filepath))[0]
|
| 62 |
-
|
| 63 |
-
original_filename = '_'.join(original_filename.split('_')[2:])
|
| 64 |
-
|
| 65 |
try:
|
| 66 |
-
#
|
| 67 |
if hasattr(audio.info, 'length'):
|
| 68 |
-
metadata['duration'] =
|
| 69 |
|
| 70 |
# Simplified tag extraction
|
| 71 |
-
if
|
| 72 |
-
metadata.
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
})
|
| 76 |
-
elif isinstance(audio, mutagen.mp3.MP3):
|
| 77 |
-
if audio.tags:
|
| 78 |
-
metadata.update({
|
| 79 |
-
'title': str(audio.tags.get('TIT2', original_filename)),
|
| 80 |
-
'artist': str(audio.tags.get('TPE1', 'Unknown Artist')),
|
| 81 |
-
})
|
| 82 |
-
|
| 83 |
except Exception as e:
|
| 84 |
logger.error(f"Error reading tags: {str(e)}")
|
| 85 |
metadata['title'] = original_filename
|
|
@@ -151,7 +142,6 @@ def upload_file():
|
|
| 151 |
}), 400
|
| 152 |
|
| 153 |
results = []
|
| 154 |
-
futures = []
|
| 155 |
|
| 156 |
def process_file(file):
|
| 157 |
try:
|
|
@@ -161,12 +151,20 @@ def upload_file():
|
|
| 161 |
filename = timestamp + filename
|
| 162 |
|
| 163 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
file_timestamps[filename] = datetime.now()
|
|
|
|
|
|
|
| 167 |
metadata = extract_metadata(filepath)
|
| 168 |
|
| 169 |
-
# Update the filepath to use relative URL
|
| 170 |
return {
|
| 171 |
'filename': file.filename,
|
| 172 |
'success': True,
|
|
@@ -186,10 +184,9 @@ def upload_file():
|
|
| 186 |
'error': 'Server error during upload'
|
| 187 |
}
|
| 188 |
|
| 189 |
-
# Process files in parallel
|
| 190 |
-
with THREAD_POOL:
|
| 191 |
-
|
| 192 |
-
results = [future.result() for future in futures]
|
| 193 |
|
| 194 |
return jsonify({
|
| 195 |
'success': True,
|
|
@@ -206,5 +203,15 @@ def cleanup():
|
|
| 206 |
|
| 207 |
atexit.register(cleanup)
|
| 208 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
if __name__ == '__main__':
|
| 210 |
app.run(host='0.0.0.0', port=7860)
|
|
|
|
| 17 |
import base64
|
| 18 |
from concurrent.futures import ThreadPoolExecutor
|
| 19 |
import asyncio
|
| 20 |
+
from flask_compress import Compress
|
| 21 |
|
| 22 |
# Create uploads directory in the static folder instead of using tempfile
|
| 23 |
UPLOAD_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'uploads')
|
|
|
|
| 39 |
logging.basicConfig(level=logging.INFO)
|
| 40 |
logger = logging.getLogger(__name__)
|
| 41 |
|
| 42 |
+
THREAD_POOL = ThreadPoolExecutor(max_workers=8) # Increased from 4 to 8
|
| 43 |
|
| 44 |
def allowed_file(filename):
|
| 45 |
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
| 46 |
|
| 47 |
+
# Optimize metadata extraction
|
| 48 |
def extract_metadata(filepath):
|
| 49 |
try:
|
| 50 |
+
audio = File(filepath, easy=True) # Added easy=True for faster loading
|
| 51 |
if audio is None:
|
| 52 |
return {}
|
| 53 |
|
| 54 |
+
# Simplified metadata extraction
|
| 55 |
metadata = {
|
| 56 |
'title': None,
|
| 57 |
'artist': 'Unknown Artist',
|
|
|
|
| 60 |
|
| 61 |
# Get filename as fallback
|
| 62 |
original_filename = os.path.splitext(os.path.basename(filepath))[0]
|
| 63 |
+
|
|
|
|
|
|
|
| 64 |
try:
|
| 65 |
+
# Quick duration check
|
| 66 |
if hasattr(audio.info, 'length'):
|
| 67 |
+
metadata['duration'] = int(audio.info.length) # Convert to int for faster processing
|
| 68 |
|
| 69 |
# Simplified tag extraction
|
| 70 |
+
if hasattr(audio, 'tags') and audio.tags:
|
| 71 |
+
metadata['title'] = str(audio.tags.get('title', [original_filename])[0])
|
| 72 |
+
metadata['artist'] = str(audio.tags.get('artist', ['Unknown Artist'])[0])
|
| 73 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
except Exception as e:
|
| 75 |
logger.error(f"Error reading tags: {str(e)}")
|
| 76 |
metadata['title'] = original_filename
|
|
|
|
| 142 |
}), 400
|
| 143 |
|
| 144 |
results = []
|
|
|
|
| 145 |
|
| 146 |
def process_file(file):
|
| 147 |
try:
|
|
|
|
| 151 |
filename = timestamp + filename
|
| 152 |
|
| 153 |
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
| 154 |
+
|
| 155 |
+
# Use buffered write for faster file saving
|
| 156 |
+
with open(filepath, 'wb') as f:
|
| 157 |
+
while True:
|
| 158 |
+
chunk = file.read(8192) # Read in 8KB chunks
|
| 159 |
+
if not chunk:
|
| 160 |
+
break
|
| 161 |
+
f.write(chunk)
|
| 162 |
|
| 163 |
file_timestamps[filename] = datetime.now()
|
| 164 |
+
|
| 165 |
+
# Process metadata in parallel
|
| 166 |
metadata = extract_metadata(filepath)
|
| 167 |
|
|
|
|
| 168 |
return {
|
| 169 |
'filename': file.filename,
|
| 170 |
'success': True,
|
|
|
|
| 184 |
'error': 'Server error during upload'
|
| 185 |
}
|
| 186 |
|
| 187 |
+
# Process files in parallel with a larger chunk size
|
| 188 |
+
with THREAD_POOL as executor:
|
| 189 |
+
results = list(executor.map(process_file, files))
|
|
|
|
| 190 |
|
| 191 |
return jsonify({
|
| 192 |
'success': True,
|
|
|
|
| 203 |
|
| 204 |
atexit.register(cleanup)
|
| 205 |
|
| 206 |
+
# Add response compression
|
| 207 |
+
Compress(app)
|
| 208 |
+
|
| 209 |
+
# Add caching headers
|
| 210 |
+
@app.after_request
|
| 211 |
+
def add_header(response):
|
| 212 |
+
if 'Cache-Control' not in response.headers:
|
| 213 |
+
response.headers['Cache-Control'] = 'public, max-age=300'
|
| 214 |
+
return response
|
| 215 |
+
|
| 216 |
if __name__ == '__main__':
|
| 217 |
app.run(host='0.0.0.0', port=7860)
|
requirements.txt
CHANGED
|
@@ -1,3 +1,4 @@
|
|
| 1 |
flask==2.0.1
|
| 2 |
mutagen==1.45.1
|
| 3 |
-
Werkzeug==2.0.1
|
|
|
|
|
|
| 1 |
flask==2.0.1
|
| 2 |
mutagen==1.45.1
|
| 3 |
+
Werkzeug==2.0.1
|
| 4 |
+
flask-compress==1.10.1
|
static/js/main.js
CHANGED
|
@@ -1263,7 +1263,7 @@ function setupPlaylistControls() {
|
|
| 1263 |
});
|
| 1264 |
}
|
| 1265 |
|
| 1266 |
-
// Update handleFiles
|
| 1267 |
async function handleFiles(files) {
|
| 1268 |
console.log('Handling files:', files.length, 'files');
|
| 1269 |
|
|
@@ -1285,6 +1285,10 @@ async function handleFiles(files) {
|
|
| 1285 |
}
|
| 1286 |
|
| 1287 |
const formData = new FormData();
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1288 |
Array.from(files).forEach(file => {
|
| 1289 |
console.log('Adding file to upload:', file.name);
|
| 1290 |
formData.append('files[]', file);
|
|
@@ -1305,7 +1309,13 @@ async function handleFiles(files) {
|
|
| 1305 |
console.log('Starting file upload...');
|
| 1306 |
const response = await fetch('/upload', {
|
| 1307 |
method: 'POST',
|
| 1308 |
-
body: formData
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1309 |
});
|
| 1310 |
|
| 1311 |
if (!response.ok) {
|
|
|
|
| 1263 |
});
|
| 1264 |
}
|
| 1265 |
|
| 1266 |
+
// Update handleFiles function for faster uploads
|
| 1267 |
async function handleFiles(files) {
|
| 1268 |
console.log('Handling files:', files.length, 'files');
|
| 1269 |
|
|
|
|
| 1285 |
}
|
| 1286 |
|
| 1287 |
const formData = new FormData();
|
| 1288 |
+
const totalSize = Array.from(files).reduce((acc, file) => acc + file.size, 0);
|
| 1289 |
+
let uploadedSize = 0;
|
| 1290 |
+
|
| 1291 |
+
// Add files to FormData with optimized chunk size
|
| 1292 |
Array.from(files).forEach(file => {
|
| 1293 |
console.log('Adding file to upload:', file.name);
|
| 1294 |
formData.append('files[]', file);
|
|
|
|
| 1309 |
console.log('Starting file upload...');
|
| 1310 |
const response = await fetch('/upload', {
|
| 1311 |
method: 'POST',
|
| 1312 |
+
body: formData,
|
| 1313 |
+
// Add upload progress tracking
|
| 1314 |
+
onUploadProgress: (progressEvent) => {
|
| 1315 |
+
const percentComplete = (progressEvent.loaded / progressEvent.total) * 100;
|
| 1316 |
+
if (progressFill) progressFill.style.width = percentComplete + '%';
|
| 1317 |
+
if (progressText) progressText.textContent = Math.round(percentComplete) + '%';
|
| 1318 |
+
}
|
| 1319 |
});
|
| 1320 |
|
| 1321 |
if (!response.ok) {
|