setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, phone TEXT UNIQUE, name TEXT, created_at TEXT)"); $pdo->exec("CREATE TABLE IF NOT EXISTS songs (id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, artist TEXT, isrc TEXT, upc TEXT, language TEXT, release_date TEXT, cover TEXT, audio TEXT, status TEXT DEFAULT 'pending', uploaded_by TEXT, created_at TEXT)"); } catch (Exception $e) { die('DB error: ' . htmlspecialchars($e->getMessage())); } // Simple helper function e($s){ return htmlspecialchars($s, ENT_QUOTES); } // Routes handling (very small router) $action = $_REQUEST['action'] ?? 'home'; // --- Artist actions: signup / login (phone) --- if ($action === 'send_otp' && $_SERVER['REQUEST_METHOD']==='POST') { $phone = preg_replace('/\D+/', '', $_POST['phone'] ?? ''); if (!$phone) { echo json_encode(['ok'=>false,'msg'=>'Invalid phone']); exit; } // For demo generate a 4-digit OTP and store in session $otp = rand(1000,9999); $_SESSION['otp_for_' . $phone] = $otp; $_SESSION['otp_time_' . $phone] = time(); // In production: send via SMS provider. Here we'll return OTP for demo. echo json_encode(['ok'=>true,'otp'=>$otp,'msg'=>'OTP (demo) generated — use it to login.']); exit; } if ($action === 'verify_otp' && $_SERVER['REQUEST_METHOD']==='POST') { $phone = preg_replace('/\D+/', '', $_POST['phone'] ?? ''); $otp = $_POST['otp'] ?? ''; if (!$phone || !$otp) { echo json_encode(['ok'=>false,'msg'=>'Missing fields']); exit; } $key = 'otp_for_' . $phone; if (!isset($_SESSION[$key]) || $_SESSION[$key] != $otp || (time() - ($_SESSION['otp_time_'.$phone] ?? 0)) > 300) { echo json_encode(['ok'=>false,'msg'=>'OTP invalid or expired']); exit; } // create or fetch user $stmt = $pdo->prepare('SELECT * FROM users WHERE phone = :phone'); $stmt->execute([':phone'=>$phone]); $user = $stmt->fetch(PDO::FETCH_ASSOC); if (!$user) { $stmt = $pdo->prepare('INSERT INTO users (phone, name, created_at) VALUES (:phone, :name, :created_at)'); $stmt->execute([':phone'=>$phone, ':name'=>'Artist '.$phone, ':created_at'=>date('c')]); $userId = $pdo->lastInsertId(); } else { $userId = $user['id']; } $_SESSION['user_id'] = $userId; $_SESSION['user_phone'] = $phone; echo json_encode(['ok'=>true,'msg'=>'Logged in','user_id'=>$userId]); exit; } // Artist logout if ($action === 'artist_logout') { unset($_SESSION['user_id'], $_SESSION['user_phone']); header('Location: ?'); exit; } // Upload handler (AJAX) if ($action === 'upload_song' && $_SERVER['REQUEST_METHOD']==='POST') { if (empty($_SESSION['user_id'])) { echo json_encode(['ok'=>false,'msg'=>'Not logged in']); exit; } $title = trim($_POST['title'] ?? ''); $artist = trim($_POST['artist'] ?? ''); $isrc = trim($_POST['isrc'] ?? ''); $upc = trim($_POST['upc'] ?? ''); $language = trim($_POST['language'] ?? '']); $release_date = trim($_POST['release_date'] ?? '']); // Basic validation if (!$title || !$artist) { echo json_encode(['ok'=>false,'msg'=>'Title and artist required']); exit; } // Handle files $coverPath = null; $audioPath = null; if (!empty($_FILES['cover']) && $_FILES['cover']['error'] === UPLOAD_ERR_OK) { $f = $_FILES['cover']; $ext = strtolower(pathinfo($f['name'], PATHINFO_EXTENSION)); $allowedImg = ['jpg','jpeg','png','webp']; if (!in_array($ext, $allowedImg)) { echo json_encode(['ok'=>false,'msg'=>'Cover must be image (jpg/png/webp)']); exit; } $dest = $coverDir . '/' . time() . '_' . preg_replace('/[^a-z0-9._-]+/i','_', $f['name']); if (!move_uploaded_file($f['tmp_name'], $dest)) { echo json_encode(['ok'=>false,'msg'=>'Cover upload failed']); exit; } $coverPath = str_replace(__DIR__, '', $dest); } if (!empty($_FILES['audio']) && $_FILES['audio']['error'] === UPLOAD_ERR_OK) { $f = $_FILES['audio']; $ext = strtolower(pathinfo($f['name'], PATHINFO_EXTENSION)); $allowedAudio = ['mp3','wav','m4a','flac']; if (!in_array($ext, $allowedAudio)) { echo json_encode(['ok'=>false,'msg'=>'Audio must be mp3/wav/m4a/flac']); exit; } $dest = $audioDir . '/' . time() . '_' . preg_replace('/[^a-z0-9._-]+/i','_', $f['name']); if (!move_uploaded_file($f['tmp_name'], $dest)) { echo json_encode(['ok'=>false,'msg'=>'Audio upload failed']); exit; } $audioPath = str_replace(__DIR__, '', $dest); } $stmt = $pdo->prepare('INSERT INTO songs (title, artist, isrc, upc, language, release_date, cover, audio, uploaded_by, created_at) VALUES (:title,:artist,:isrc,:upc,:language,:release_date,:cover,:audio,:uploaded_by,:created_at)'); $stmt->execute([ ':title'=>$title,':artist'=>$artist,':isrc'=>$isrc,':upc'=>$upc,':language'=>$language,':release_date'=>$release_date,':cover'=>$coverPath,':audio'=>$audioPath,':uploaded_by'=>$_SESSION['user_phone'] ?? 'guest',':created_at'=>date('c') ]); echo json_encode(['ok'=>true,'msg'=>'Uploaded — pending admin approval']); exit; } // Admin login if ($action === 'admin_login' && $_SERVER['REQUEST_METHOD']==='POST') { $u = $_POST['username'] ?? ''; $p = $_POST['password'] ?? ''; if ($u === $adminUser && $p === $adminPass) { $_SESSION['admin'] = true; echo json_encode(['ok'=>true]); exit; } echo json_encode(['ok'=>false,'msg'=>'Invalid']); exit; } // Admin logout if ($action === 'admin_logout') { unset($_SESSION['admin']); header('Location:?'); exit; } // Admin approve/reject if ($action === 'admin_change_status' && $_SERVER['REQUEST_METHOD']==='POST') { if (empty($_SESSION['admin'])) { echo json_encode(['ok'=>false,'msg'=>'Not admin']); exit; } $id = intval($_POST['id'] ?? 0); $status = $_POST['status'] ?? 'pending'; $stmt = $pdo->prepare('UPDATE songs SET status = :status WHERE id = :id'); $stmt->execute([':status'=>$status, ':id'=>$id]); echo json_encode(['ok'=>true]); exit; } // Fetch songs (for listing) - used by JS if ($action === 'list_songs') { $for = $_GET['for'] ?? 'public'; // public/admin/my if ($for === 'admin' && empty($_SESSION['admin'])) { echo json_encode(['ok'=>false,'msg'=>'Not admin']); exit; } if ($for === 'my' && empty($_SESSION['user_id'])) { echo json_encode(['ok'=>false,'msg'=>'Not logged']); exit; } if ($for === 'admin') { $stmt = $pdo->query('SELECT * FROM songs ORDER BY id DESC'); } elseif ($for === 'my') { $phone = $_SESSION['user_phone']; $stmt = $pdo->prepare('SELECT * FROM songs WHERE uploaded_by = :phone ORDER BY id DESC'); $stmt->execute([':phone'=>$phone]); } else { $stmt = $pdo->query("SELECT * FROM songs WHERE status='approved' ORDER BY id DESC"); } $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); echo json_encode(['ok'=>true,'rows'=>$rows]); exit; } // File serving helper - allow direct file URL by path relative to __DIR__ // but for simplicity we'll rely on the relative paths stored in DB. // --- End backend. Now render front-end --- ?> Jhankar Studio — Upload Music Distribution
Jhankar Studio
Upload • Distribute • Monetize

Professional Music Distribution — Jhankar Studio

Upload your tracks, manage releases, and get distributed to streaming platforms. Fast review, clean dashboard, and monetization support.

Quick Stats
Tracks in system, pending approvals and more
Total Tracks

Pending
Approved

Upload Your Music

Fill details, attach cover art and audio file. Upload progress shown below.

Catalog

Browse approved tracks

Artist Panel (Demo OTP)

Enter phone to receive demo OTP (visible on screen for demo). No real SMS used.

Admin Panel

For demo: use admin@jhankar.local / Admin@123