Auto-upload stems to Gokapi on completion, save share link
- New helpers: parse_stems_urls, upload_to_gokapi, process_stems_to_gokapi - Stems webhook handler now downloads stem files from MusicGPT CDN, zips them, uploads to Gokapi with 30-day expiry, saves the Gokapi download URL to stems_link in the DB - Download Stems button uses stems_link (Gokapi URL) when available, falls back to the zip endpoint if not - Config: GOKAPI_URL, GOKAPI_API_KEY, GOKAPI_EXPIRY_DAYS env vars - docker-compose: GOKAPI_* environment variables added
This commit is contained in:
parent
9df4c685a4
commit
ccc93ffb3b
5 changed files with 140 additions and 3 deletions
114
helpers.py
114
helpers.py
|
|
@ -34,6 +34,7 @@ from mutagen.easyid3 import EasyID3
|
|||
import requests
|
||||
|
||||
from models import update_request
|
||||
from config import Config
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -794,3 +795,116 @@ def get_musicgpt_cost_totals():
|
|||
"total_cost": rows["total_cost"] or 0,
|
||||
"stems_total": rows["stems_total"] or 0,
|
||||
}
|
||||
|
||||
|
||||
def parse_stems_urls(stems_url_field):
|
||||
"""
|
||||
Parse the stems_url DB field into a list of (label, url) tuples.
|
||||
The field can be:
|
||||
- "label1: url1; label2: url2" (multiple individual stem files)
|
||||
- A single bundle/zip URL
|
||||
- A bare URL
|
||||
"""
|
||||
if not stems_url_field:
|
||||
return []
|
||||
urls = []
|
||||
if ';' in stems_url_field or ': ' in stems_url_field:
|
||||
parts = stems_url_field.split(';')
|
||||
for part in parts:
|
||||
part = part.strip()
|
||||
if not part:
|
||||
continue
|
||||
if ': ' in part:
|
||||
label, url = part.split(': ', 1)
|
||||
urls.append((label.strip(), url.strip()))
|
||||
else:
|
||||
urls.append(('stem', part))
|
||||
else:
|
||||
urls.append(('stems', stems_url_field.strip()))
|
||||
return urls
|
||||
|
||||
|
||||
def upload_to_gokapi(file_bytes, filename, expiry_days=30):
|
||||
"""
|
||||
Upload a file to Gokapi and return the download URL.
|
||||
Returns (download_url, error_message).
|
||||
"""
|
||||
gokapi_url = Config.GOKAPI_URL.rstrip('/')
|
||||
api_key = Config.GOKAPI_API_KEY
|
||||
if not gokapi_url or not api_key:
|
||||
return None, 'Gokapi URL or API key not configured'
|
||||
try:
|
||||
resp = requests.post(
|
||||
f"{gokapi_url}/api/files/add",
|
||||
headers={"apikey": api_key},
|
||||
files={"file": (filename, file_bytes, "application/octet-stream")},
|
||||
data={
|
||||
"allowedDownloads": "0",
|
||||
"expiryDays": str(expiry_days),
|
||||
"password": "",
|
||||
},
|
||||
timeout=120,
|
||||
)
|
||||
if resp.status_code != 200:
|
||||
return None, f'Gokapi HTTP {resp.status_code}: {resp.text[:200]}'
|
||||
data = resp.json()
|
||||
if data.get('Result') != 'OK':
|
||||
return None, f"Gokapi error: {data.get('Result')}"
|
||||
file_info = data.get('FileInfo', {})
|
||||
download_url = file_info.get('UrlDownload')
|
||||
if not download_url:
|
||||
return None, 'Gokapi returned no download URL'
|
||||
return download_url, None
|
||||
except Exception as e:
|
||||
return None, str(e)
|
||||
|
||||
|
||||
def process_stems_to_gokapi(req):
|
||||
"""
|
||||
Download stem files from MusicGPT CDN, zip them, upload the zip to Gokapi,
|
||||
and return (gokapi_url, error_message).
|
||||
|
||||
Also updates the request row with the Gokapi download link in stems_link.
|
||||
"""
|
||||
import io
|
||||
import zipfile
|
||||
|
||||
stems_url = req.get('stems_url') or ''
|
||||
urls = parse_stems_urls(stems_url)
|
||||
if not urls:
|
||||
return None, 'No stems URL to process'
|
||||
|
||||
# If there's only one URL and it's already a .zip, upload it directly.
|
||||
if len(urls) == 1 and urls[0][1].endswith('.zip'):
|
||||
try:
|
||||
r = requests.get(urls[0][1], timeout=120)
|
||||
r.raise_for_status()
|
||||
zip_bytes = r.content
|
||||
except Exception as e:
|
||||
return None, f'Failed to download stems zip: {e}'
|
||||
else:
|
||||
# Download each stem file and bundle into a zip in memory.
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||||
for label, url in urls:
|
||||
try:
|
||||
r = requests.get(url, timeout=60)
|
||||
r.raise_for_status()
|
||||
filename = url.split('/')[-1] if '/' in url else f"{label}.mp3"
|
||||
if '.' not in filename:
|
||||
filename = f"{label}.mp3"
|
||||
zf.writestr(filename, r.content)
|
||||
except Exception:
|
||||
pass
|
||||
zip_bytes = buf.getvalue()
|
||||
|
||||
title = req.get('suno_title') or req.get('name') or f'request_{req["id"]}'
|
||||
zip_filename = f"stems_{title}.zip"
|
||||
|
||||
download_url, error = upload_to_gokapi(zip_bytes, zip_filename, Config.GOKAPI_EXPIRY_DAYS)
|
||||
if error:
|
||||
return None, error
|
||||
|
||||
# Save the Gokapi link to stems_link in the database.
|
||||
update_request(req['id'], stems_link=download_url)
|
||||
return download_url, None
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue