zenjoul80 commited on
Commit
ad31a8a
Β·
verified Β·
1 Parent(s): 87e6d64

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -49
app.py CHANGED
@@ -1,9 +1,9 @@
1
- import time, requests, threading
2
- from flask import Flask, render_template, request, session
3
  from flask_socketio import SocketIO, emit
4
 
5
  app = Flask(__name__)
6
- app.config['SECRET_KEY'] = 'suno_studio_2026_secret'
7
  socketio = SocketIO(app, cors_allowed_origins="*")
8
 
9
  BASE_URL = "https://api.sunoapi.org/api/v1"
@@ -12,69 +12,66 @@ BASE_URL = "https://api.sunoapi.org/api/v1"
12
  def index():
13
  return render_template('index.html')
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  @socketio.on('save_token')
16
  def handle_token(data):
17
- token = data.get('token')
18
- if token:
19
- session['api_token'] = token
20
- emit('status', {'msg': 'πŸ”‘ Token saved. Checking balance...'})
21
- try:
22
- res = requests.get(f"{BASE_URL}/generate/credit", headers={"Authorization": f"Bearer {token}"})
23
- balance = res.json().get('data', 0)
24
- emit('credits', {'val': balance})
25
- except:
26
- emit('credits', {'val': 'Error'})
27
 
28
  @socketio.on('start_gen')
29
  def handle_gen(payload):
30
  token = session.get('api_token')
31
  if not token:
32
- emit('status', {'msg': '❌ Error: Connect your API Token first.'})
33
  return
34
 
35
- # Enforce model-specific rules from docs
36
- if payload.get('model') == 'V4_5ALL':
37
- emit('status', {'msg': '⚠️ V4_5ALL detected: Audio must be < 1 min.'})
38
-
39
  headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
40
 
 
 
 
 
41
  try:
42
- # Standard API call as per docs
43
  res = requests.post(f"{BASE_URL}/generate/upload-cover", json=payload, headers=headers)
44
  res_data = res.json()
45
 
46
- if res.status_code == 200 and res_data.get('data'):
47
- task_id = res_data['data'].get('taskId') # Fixed key from docs: 'taskId'
48
- emit('status', {'msg': f'πŸš€ Task Started! ID: {task_id}'})
49
- threading.Thread(target=poll_status, args=(task_id, request.sid, headers)).start()
50
  else:
51
- msg = res_data.get('msg', 'Unknown Error')
52
- emit('status', {'msg': f'❌ API Error: {msg}'})
53
-
54
  except Exception as e:
55
- emit('status', {'msg': f'❌ Script Error: {str(e)}'})
56
-
57
- def poll_status(task_id, sid, headers):
58
- # Poll for 10 mins max
59
- for _ in range(60):
60
- time.sleep(10)
61
- try:
62
- res = requests.get(f"{BASE_URL}/suno/cover/record-info?taskId={task_id}", headers=headers)
63
- data = res.json().get('data', {})
64
- status = data.get('status')
65
-
66
- if status == 'complete':
67
- socketio.emit('status', {
68
- 'msg': '✨ Success! Your cover is ready.',
69
- 'url': data.get('audio_url'),
70
- 'done': True
71
- }, room=sid)
72
- return
73
- elif status == 'failed':
74
- socketio.emit('status', {'msg': '❌ Generation failed on server.'}, room=sid)
75
- return
76
- except: break
77
- socketio.emit('status', {'msg': '⏱️ Task timed out.'}, room=sid)
78
 
79
  if __name__ == '__main__':
80
  socketio.run(app, host="0.0.0.0", debug=True)
 
1
+ import time, requests, threading, io
2
+ from flask import Flask, render_template, request, session, send_file
3
  from flask_socketio import SocketIO, emit
4
 
5
  app = Flask(__name__)
6
+ app.config['SECRET_KEY'] = 'suno_studio_full_2026'
7
  socketio = SocketIO(app, cors_allowed_origins="*")
8
 
9
  BASE_URL = "https://api.sunoapi.org/api/v1"
 
12
  def index():
13
  return render_template('index.html')
14
 
15
+ # --- NEW: CALLBACK ROUTE ---
16
+ @app.route('/callback', methods=['POST'])
17
+ def suno_callback():
18
+ """Suno calls this endpoint when the generation is finished."""
19
+ data = request.json
20
+ # The taskId and status are sent here
21
+ task_id = data.get('taskId')
22
+ status = data.get('status')
23
+ audio_url = data.get('audio_url')
24
+
25
+ print(f"Callback received for {task_id}: {status}")
26
+
27
+ # Alert the specific user via SocketIO
28
+ socketio.emit('status', {
29
+ 'msg': '✨ Callback Received: Track Ready!',
30
+ 'url': audio_url,
31
+ 'done': (status == 'complete')
32
+ })
33
+ return {"status": "success"}, 200
34
+
35
+ # --- PROXY DOWNLOAD (Fixes your download issue) ---
36
+ @app.route('/download_proxy')
37
+ def download_proxy():
38
+ url = request.args.get('url')
39
+ title = request.args.get('title', 'suno_track').replace(" ", "_")
40
+ try:
41
+ res = requests.get(url)
42
+ return send_file(io.BytesIO(res.content), mimetype="audio/mpeg", as_attachment=True, download_name=f"{title}.mp3")
43
+ except:
44
+ return "Download Failed", 500
45
+
46
  @socketio.on('save_token')
47
  def handle_token(data):
48
+ session['api_token'] = data.get('token')
49
+ emit('status', {'msg': 'πŸ”‘ Token connected.'})
 
 
 
 
 
 
 
 
50
 
51
  @socketio.on('start_gen')
52
  def handle_gen(payload):
53
  token = session.get('api_token')
54
  if not token:
55
+ emit('status', {'msg': '❌ Error: No Token.'})
56
  return
57
 
 
 
 
 
58
  headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
59
 
60
+ # Note: Replace this with your actual public URL (e.g., from Ngrok)
61
+ # If this is not a real public URL, Suno will fail to send the callback.
62
+ payload['callBackUrl'] = "https://zenjoul80-suno-api.hf.space/callback"
63
+
64
  try:
 
65
  res = requests.post(f"{BASE_URL}/generate/upload-cover", json=payload, headers=headers)
66
  res_data = res.json()
67
 
68
+ if res.status_code == 200:
69
+ task_id = res_data.get('data', {}).get('taskId')
70
+ emit('status', {'msg': f'πŸš€ Task {task_id} sent. Waiting for Callback...'})
 
71
  else:
72
+ emit('status', {'msg': f"❌ Error: {res_data.get('msg')}"})
 
 
73
  except Exception as e:
74
+ emit('status', {'msg': f"❌ Failed: {str(e)}"})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
 
76
  if __name__ == '__main__':
77
  socketio.run(app, host="0.0.0.0", debug=True)