Language updates. New upload form. new classes.
This commit is contained in:
parent
4c2857b445
commit
8f3061ab99
62 changed files with 3107 additions and 1883 deletions
394
upload.php
394
upload.php
|
@ -1,148 +1,304 @@
|
|||
<?php
|
||||
// upload.php - Step 1: File upload and immediate processing
|
||||
// upload.php - One Page Upload and Details Submission
|
||||
|
||||
require_once 'includes/globals.php';
|
||||
require_once 'vendor/autoload.php';
|
||||
|
||||
use DJMixHosting\Upload;
|
||||
use DJMixHosting\CDN;
|
||||
use DJMixHosting\Database;
|
||||
use DJMixHosting\Genres;
|
||||
use DJMixHosting\DJs;
|
||||
|
||||
// Ensure user is authenticated
|
||||
if (!isset($_SESSION['user'])) {
|
||||
header("Location: login.php");
|
||||
$_SESSION['error'] = $locale['loginToUploadMix'];
|
||||
header("Location: /login");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Process the form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['mix_file'])) {
|
||||
// Get upload config from $config
|
||||
$tmpPath = rtrim($config['uploads']['tmp_path'], '/') . '/';
|
||||
$maxFileSize = $config['uploads']['max_file_size'];
|
||||
$allowedMimeTypes = $config['uploads']['allowed_mime_type'];
|
||||
$allowedFileTypes = $config['uploads']['allowed_file_types'];
|
||||
// If the form was submitted, check which step we're processing via an "action" field.
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Step 1: Handle file upload
|
||||
if (isset($_POST['action']) && $_POST['action'] === 'upload_file') {
|
||||
if (isset($_FILES['mix_file'])) {
|
||||
$upload = new Upload($_FILES['mix_file'], $config);
|
||||
|
||||
$file = $_FILES['mix_file'];
|
||||
|
||||
// Basic file validations
|
||||
if ($file['error'] !== UPLOAD_ERR_OK) {
|
||||
$_SESSION['error'] = "File upload error.";
|
||||
header("Location: upload.php");
|
||||
exit;
|
||||
}
|
||||
if ($file['size'] > $maxFileSize) {
|
||||
$_SESSION['error'] = "File is too large.";
|
||||
header("Location: upload.php");
|
||||
exit;
|
||||
}
|
||||
// Get file extension and mime type
|
||||
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, $allowedFileTypes)) {
|
||||
$_SESSION['error'] = "File type not allowed.";
|
||||
header("Location: upload.php");
|
||||
exit;
|
||||
}
|
||||
if (!in_array($file['type'], $allowedMimeTypes)) {
|
||||
$_SESSION['error'] = "MIME type not allowed.";
|
||||
header("Location: upload.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Create a unique temporary filename
|
||||
$uniqueName = uniqid() . "." . $ext;
|
||||
$destination = $tmpPath . $uniqueName;
|
||||
|
||||
if (!move_uploaded_file($file['tmp_name'], $destination)) {
|
||||
$_SESSION['error'] = "Failed to save uploaded file.";
|
||||
header("Location: upload.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Process the file: if mp3, extract metadata; if zip, extract each mp3's metadata.
|
||||
$uploadTask = [];
|
||||
$uploadTask['original_name'] = $file['name'];
|
||||
$uploadTask['local_path'] = $destination;
|
||||
$uploadTask['size'] = $file['size'];
|
||||
$uploadTask['ext'] = $ext;
|
||||
|
||||
if ($ext === "mp3") {
|
||||
// Process MP3 file using shell_exec calls (ensure you sanitize arguments)
|
||||
$escapedFile = escapeshellarg($destination);
|
||||
$artist = trim(shell_exec("eyed3 --query='%a%' $escapedFile"));
|
||||
$title = trim(shell_exec("eyed3 --query='%t%' $escapedFile"));
|
||||
$duration = trim(shell_exec("mp3info -p \"%S\" $escapedFile"));
|
||||
// You can extract additional info as needed
|
||||
$uploadTask['file_type'] = 'mp3';
|
||||
$uploadTask['metadata'] = [
|
||||
'artist' => $artist,
|
||||
'title' => $title,
|
||||
'duration' => $duration, // in seconds
|
||||
];
|
||||
$uploadTask['mediaplayer'] = 1;
|
||||
} elseif ($ext === "zip") {
|
||||
// Process ZIP file using ZipArchive
|
||||
$zip = new ZipArchive;
|
||||
if ($zip->open($destination) === true) {
|
||||
$totalDuration = 0;
|
||||
$tracklist = [];
|
||||
for ($i = 0; $i < $zip->numFiles; $i++) {
|
||||
$entryName = $zip->getNameIndex($i);
|
||||
$entryExt = strtolower(pathinfo($entryName, PATHINFO_EXTENSION));
|
||||
if ($entryExt === "mp3") {
|
||||
// Extract the MP3 temporarily to process metadata
|
||||
$tempDir = $tmpPath . uniqid('zip_');
|
||||
mkdir($tempDir);
|
||||
$tempFilePath = $tempDir . '/' . basename($entryName);
|
||||
$zip->extractTo($tempDir, $entryName);
|
||||
$escapedFile = escapeshellarg($tempFilePath);
|
||||
$title = trim(shell_exec("eyed3 --query='%t%' $escapedFile"));
|
||||
$duration = trim(shell_exec("mp3info -p \"%S\" $escapedFile"));
|
||||
$tracklist[] = $title ?: basename($entryName);
|
||||
$totalDuration += (int)$duration;
|
||||
unlink($tempFilePath);
|
||||
rmdir($tempDir);
|
||||
}
|
||||
// Validate the file
|
||||
if (!$upload->validate()) {
|
||||
$_SESSION['error'] = implode(", ", $upload->getErrors());
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
$zip->close();
|
||||
$uploadTask['file_type'] = 'zip';
|
||||
$uploadTask['metadata'] = [
|
||||
'tracklist' => $tracklist,
|
||||
'total_duration' => $totalDuration,
|
||||
];
|
||||
// Mark ZIPs as download only (no mediaplayer)
|
||||
$uploadTask['mediaplayer'] = 0;
|
||||
} else {
|
||||
$_SESSION['error'] = "Failed to open ZIP file.";
|
||||
header("Location: upload.php");
|
||||
// Move the file to the temporary directory
|
||||
if (!$upload->moveFile()) {
|
||||
$_SESSION['error'] = implode(", ", $upload->getErrors());
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
// Process the file (extract metadata for MP3/ZIP)
|
||||
$uploadTask = $upload->process();
|
||||
$_SESSION['upload_task'] = $uploadTask;
|
||||
// Reload the page so the details form can be shown
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
$_SESSION['error'] = "Unsupported file type.";
|
||||
header("Location: upload.php");
|
||||
}
|
||||
// Step 2: Handle mix details submission
|
||||
elseif (isset($_POST['action']) && $_POST['action'] === 'submit_details') {
|
||||
if (!isset($_SESSION['upload_task'])) {
|
||||
$_SESSION['error'] = $locale['noUploadedFileFound'];
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
|
||||
$uploadTask = $_SESSION['upload_task'];
|
||||
$title = trim($_POST['title'] ?? '');
|
||||
$description = trim($_POST['description'] ?? '');
|
||||
$recorded = trim($_POST['recorded'] ?? '');
|
||||
$selectedGenres = $_POST['genres'] ?? []; // array of genre IDs
|
||||
$dj1 = $_POST['dj1'] ?? 0;
|
||||
$dj2 = $_POST['dj2'] ?? 0;
|
||||
$dj3 = $_POST['dj3'] ?? 0;
|
||||
|
||||
// Basic validation: title is required
|
||||
if (empty($title)) {
|
||||
$_SESSION['error'] = $locale['mixTitleRequired'];
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Simple slugify function
|
||||
function slugify($text) {
|
||||
$text = preg_replace('~[^\pL\d]+~u', '-', $text);
|
||||
$text = iconv('utf-8', 'us-ascii//TRANSLIT', $text);
|
||||
$text = preg_replace('~[^-\w]+~', '', $text);
|
||||
$text = trim($text, '-');
|
||||
$text = preg_replace('~-+~', '-', $text);
|
||||
$text = strtolower($text);
|
||||
return empty($text) ? 'n-a' : $text;
|
||||
}
|
||||
$slug = slugify($title);
|
||||
|
||||
// Upload the file to the CDN
|
||||
$cdn = new CDN($config);
|
||||
$remotePath = "temp/mixes/" . uniqid() . "_" . basename($uploadTask['local_path']);
|
||||
$mimeType = ($uploadTask['ext'] === 'mp3') ? 'audio/mpeg' : 'application/zip';
|
||||
|
||||
try {
|
||||
$cdn->uploadFile($uploadTask['local_path'], $remotePath, $mimeType, 'private');
|
||||
} catch (Exception $e) {
|
||||
$_SESSION['error'] = $locale['errorUploadCDN'] . $e->getMessage();
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Insert the mix record into the database
|
||||
$db = new Database($config);
|
||||
$stmt = $db->prepare("INSERT INTO mix (title, slug, description, cover, url, seconds, mediaplayer, dj1, dj2, dj3, pending, recorded) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)");
|
||||
|
||||
if ($uploadTask['file_type'] === 'mp3') {
|
||||
$seconds = (int)$uploadTask['metadata']['duration'];
|
||||
$mediaplayer = 0;
|
||||
} elseif ($uploadTask['file_type'] === 'zip') {
|
||||
$seconds = (int)$uploadTask['metadata']['total_duration'];
|
||||
$mediaplayer = 1;
|
||||
} else {
|
||||
$seconds = 0;
|
||||
$mediaplayer = 1;
|
||||
}
|
||||
$url = $remotePath;
|
||||
$dj1 = (int)$dj1;
|
||||
$dj2 = (int)$dj2;
|
||||
$dj3 = (int)$dj3;
|
||||
$cover = "";
|
||||
$stmt->bind_param("sssssiiiiss", $title, $slug, $description, $cover, $url, $seconds, $mediaplayer, $dj1, $dj2, $dj3, $recorded);
|
||||
if (!$stmt->execute()) {
|
||||
$_SESSION['error'] = $locale['errorSavingMixDB'];
|
||||
header("Location: /upload");
|
||||
exit;
|
||||
}
|
||||
$mixId = $stmt->insert_id;
|
||||
$stmt->close();
|
||||
|
||||
// Insert mix_meta entries for genres and tracklist
|
||||
foreach ($selectedGenres as $genreId) {
|
||||
$stmt = $db->prepare("INSERT INTO mix_meta (mix_id, attribute, value) VALUES (?, 'genre', ?)");
|
||||
$stmt->bind_param("is", $mixId, $genreId);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
}
|
||||
if ($uploadTask['file_type'] === 'mp3' && !empty($uploadTask['metadata']['title'])) {
|
||||
$tracklist = $uploadTask['metadata']['title'];
|
||||
$stmt = $db->prepare("INSERT INTO mix_meta (mix_id, attribute, value) VALUES (?, 'tracklist', ?)");
|
||||
$stmt->bind_param("is", $mixId, $tracklist);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
} elseif ($uploadTask['file_type'] === 'zip' && !empty($uploadTask['metadata']['tracklist'])) {
|
||||
$tracklist = implode("\n", $uploadTask['metadata']['tracklist']);
|
||||
$stmt = $db->prepare("INSERT INTO mix_meta (mix_id, attribute, value) VALUES (?, 'tracklist', ?)");
|
||||
$stmt->bind_param("is", $mixId, $tracklist);
|
||||
$stmt->execute();
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
// Cleanup: delete the local temporary file and clear session upload task
|
||||
unlink($uploadTask['local_path']);
|
||||
unset($_SESSION['upload_task']);
|
||||
|
||||
$_SESSION['success'] = $locale['uploadedPendingApproval'];
|
||||
header("Location: profile.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
// Save the upload task details in session so step 2 can use them.
|
||||
$_SESSION['upload_task'] = $uploadTask;
|
||||
header("Location: upload_details.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once 'includes/header.php';
|
||||
?>
|
||||
<?php require_once 'includes/header.php'; ?>
|
||||
|
||||
<section class="upload-section py-5">
|
||||
<div class="container">
|
||||
<h2 class="mb-4">Upload a New Mix</h2>
|
||||
<?php
|
||||
// Display any error messages
|
||||
if (isset($_SESSION['error'])) {
|
||||
echo '<div class="alert alert-danger">' . htmlspecialchars($_SESSION['error']) . '</div>';
|
||||
unset($_SESSION['error']);
|
||||
}
|
||||
?>
|
||||
<form action="upload.php" method="post" enctype="multipart/form-data">
|
||||
<div class="mb-3">
|
||||
<label for="mix_file" class="form-label">Select Mix File (MP3 or ZIP)</label>
|
||||
<input type="file" class="form-control" id="mix_file" name="mix_file" accept=".mp3,.zip" required>
|
||||
// If no file has been uploaded, show the file upload form.
|
||||
if (!isset($_SESSION['upload_task'])):
|
||||
?>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title mb-4"><?php echo $locale['uploadHeader1'];?></h3>
|
||||
<!-- Info Alert -->
|
||||
<div class="alert alert-info">
|
||||
<h4 class="alert-heading">Important Upload Information</h4>
|
||||
<p>Utah's DJs is primarily an archival project dedicated to preserving the history and culture of EDM DJs in Utah. Your uploads contribute to this historical record.</p>
|
||||
</div>
|
||||
<!-- Requirements -->
|
||||
<h4 class="mb-3">Before You Upload</h4>
|
||||
<ul class="list-group list-group-flush mb-4">
|
||||
<li class="list-group-item">
|
||||
<i class="fas fa-check-circle text-success me-2"></i>
|
||||
Verify that all DJs involved are listed in our database. If a DJ is not listed, they must be added and approved before uploading.
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="fas fa-check-circle text-success me-2"></i>
|
||||
Check that appropriate genres are available for your mix. New genres require approval before they can be used.
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="fas fa-info-circle text-primary me-2"></i>
|
||||
You can submit new DJ or genre requests through your profile settings.
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Process Steps -->
|
||||
<h4 class="mb-3">Upload Process</h4>
|
||||
<ol class="list-group list-group-numbered mb-4">
|
||||
<li class="list-group-item">Upload your mix file (MP3 or ZIP format)</li>
|
||||
<li class="list-group-item">Enter mix details, including title, description, and recording date</li>
|
||||
<li class="list-group-item">Select relevant genres and DJs</li>
|
||||
<li class="list-group-item">Submit for review</li>
|
||||
</ol>
|
||||
<!-- Upload Form -->
|
||||
<div class="card mt-4">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title mb-4">Upload Your Mix</h4>
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="hidden" name="action" value="upload_file">
|
||||
<div class="mb-3">
|
||||
<label for="mix_file" class="form-label">Select Mix File (MP3 or ZIP)</label>
|
||||
<input type="file" class="form-control" id="mix_file" name="mix_file" accept=".mp3,.zip" required>
|
||||
<div class="form-text">Maximum file size: 500MB</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-upload me-2"></i>Upload File
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Optionally, add album art upload here later -->
|
||||
<button type="submit" class="btn btn-primary">Upload File</button>
|
||||
</form>
|
||||
<?php
|
||||
// If an upload task exists, show the mix details form.
|
||||
else:
|
||||
$uploadTask = $_SESSION['upload_task'];
|
||||
// Load available genres and DJs for the form
|
||||
$db = new Database($config);
|
||||
$genresObj = new Genres($db);
|
||||
$allGenres = $genresObj->get_all_genres();
|
||||
$djsObj = new DJs($db);
|
||||
$allDJs = $djsObj->get_all_djs();
|
||||
?>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title mb-4">Enter Mix Details</h3>
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5>File Summary</h5>
|
||||
<p><strong>Original Name:</strong> <?php echo htmlspecialchars($uploadTask['original_name']); ?></p>
|
||||
<p><strong>File Type:</strong> <?php echo htmlspecialchars(strtoupper($uploadTask['file_type'])); ?></p>
|
||||
<p><strong>Size:</strong> <?php echo round($uploadTask['size'] / 1024, 2); ?> KB</p>
|
||||
<?php if ($uploadTask['file_type'] === 'mp3'): ?>
|
||||
<p><strong>Duration:</strong> <?php echo htmlspecialchars($uploadTask['metadata']['duration']); ?> seconds</p>
|
||||
<?php elseif ($uploadTask['file_type'] === 'zip'): ?>
|
||||
<p><strong>Total Duration:</strong> <?php echo htmlspecialchars($uploadTask['metadata']['total_duration']); ?> seconds</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<form action="/upload" method="post" class="needs-validation" novalidate>
|
||||
<input type="hidden" name="action" value="submit_details">
|
||||
<div class="mb-3">
|
||||
<label for="title" class="form-label">Mix Title</label>
|
||||
<input type="text" class="form-control" id="title" name="title" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="description" class="form-label">Mix Description</label>
|
||||
<textarea class="form-control" id="description" name="description" rows="3"></textarea>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="recorded" class="form-label">Recorded Date</label>
|
||||
<input type="date" class="form-control" id="recorded" name="recorded" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="genres" class="form-label">Select Genres (type to search)</label>
|
||||
<select class="form-select" id="genres" name="genres[]" multiple required>
|
||||
<?php foreach ($allGenres as $genre): ?>
|
||||
<option value="<?php echo htmlspecialchars($genre['id']); ?>"><?php echo htmlspecialchars($genre['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Select DJs (Maximum 3)</label>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<select class="form-select" name="dj1" required>
|
||||
<option value="">Select DJ 1</option>
|
||||
<?php foreach ($allDJs as $dj): ?>
|
||||
<option value="<?php echo htmlspecialchars($dj['id']); ?>"><?php echo htmlspecialchars($dj['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="form-select" name="dj2">
|
||||
<option value="">Select DJ 2 (Optional)</option>
|
||||
<?php foreach ($allDJs as $dj): ?>
|
||||
<option value="<?php echo htmlspecialchars($dj['id']); ?>"><?php echo htmlspecialchars($dj['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select class="form-select" name="dj3">
|
||||
<option value="">Select DJ 3 (Optional)</option>
|
||||
<?php foreach ($allDJs as $dj): ?>
|
||||
<option value="<?php echo htmlspecialchars($dj['id']); ?>"><?php echo htmlspecialchars($dj['name']); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit Mix</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue