AdityaAdaki commited on
Commit
feee5aa
·
1 Parent(s): 25e8e76
Files changed (3) hide show
  1. app.py +35 -28
  2. requirements.txt +2 -1
  3. 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=4) # Adjust based on your server capacity
42
 
43
  def allowed_file(filename):
44
  return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
45
 
46
- # Add function to extract metadata
47
  def extract_metadata(filepath):
48
  try:
49
- audio = File(filepath)
50
  if audio is None:
51
  return {}
52
 
53
- # Basic metadata that we absolutely need
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
- if '_' in original_filename:
63
- original_filename = '_'.join(original_filename.split('_')[2:])
64
-
65
  try:
66
- # Add basic audio info
67
  if hasattr(audio.info, 'length'):
68
- metadata['duration'] = round(audio.info.length)
69
 
70
  # Simplified tag extraction
71
- if isinstance(audio, (mutagen.flac.FLAC, mutagen.oggvorbis.OggVorbis)):
72
- metadata.update({
73
- 'title': audio.tags.get('TITLE', [original_filename])[0] if audio.tags else original_filename,
74
- 'artist': audio.tags.get('ARTIST', ['Unknown Artist'])[0] if audio.tags else 'Unknown Artist',
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
- file.save(filepath)
 
 
 
 
 
 
 
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
- futures = [THREAD_POOL.submit(process_file, file) for file in files]
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 to append new tracks
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) {