525 lines
18 KiB
PHP
525 lines
18 KiB
PHP
@extends('layouts.app')
|
|
|
|
@section('title', 'Upload Video | ' . config('app.name'))
|
|
|
|
@section('extra_styles')
|
|
<style>
|
|
.upload-container {
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-input, .form-select, .form-textarea {
|
|
width: 100%;
|
|
background: #121212;
|
|
border: 1px solid var(--border-color);
|
|
border-radius: 8px;
|
|
padding: 12px 16px;
|
|
color: var(--text-primary);
|
|
font-size: 14px;
|
|
}
|
|
|
|
.form-input:focus, .form-select:focus, .form-textarea:focus {
|
|
outline: none;
|
|
border-color: var(--brand-red);
|
|
}
|
|
|
|
.form-textarea {
|
|
resize: vertical;
|
|
min-height: 100px;
|
|
}
|
|
|
|
/* Dropzone */
|
|
#dropzone, #thumbnail-dropzone {
|
|
border: 2px dashed var(--border-color);
|
|
border-radius: 12px;
|
|
padding: 40px 20px;
|
|
text-align: center;
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
/* Hide file input */
|
|
#video, #thumbnail {
|
|
display: none;
|
|
}
|
|
|
|
#dropzone:hover, #dropzone.dragover,
|
|
#thumbnail-dropzone:hover, #thumbnail-dropzone.dragover {
|
|
border-color: var(--brand-red);
|
|
background: rgba(230, 30, 30, 0.05);
|
|
}
|
|
|
|
#dropzone .icon, #thumbnail-dropzone .icon {
|
|
font-size: 48px;
|
|
color: var(--text-secondary);
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
#dropzone p, #thumbnail-dropzone p {
|
|
color: var(--text-secondary);
|
|
margin: 8px 0;
|
|
}
|
|
|
|
#dropzone .hint, #thumbnail-dropzone .hint {
|
|
font-size: 12px;
|
|
color: var(--text-secondary);
|
|
opacity: 0.7;
|
|
}
|
|
|
|
#file-info, #thumbnail-info {
|
|
display: none;
|
|
}
|
|
|
|
#file-info.active, #thumbnail-info.active {
|
|
display: block;
|
|
}
|
|
|
|
#file-info .filename, #thumbnail-info .filename {
|
|
color: var(--brand-red);
|
|
font-weight: 500;
|
|
}
|
|
|
|
/* Upload Row - Side by Side */
|
|
.upload-row {
|
|
display: flex;
|
|
gap: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.upload-row .form-group {
|
|
flex: 1;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
/* Progress Bar */
|
|
#progress-container {
|
|
display: none;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
#progress-container.active {
|
|
display: block;
|
|
}
|
|
|
|
.progress-bar-wrapper {
|
|
background: var(--border-color);
|
|
border-radius: 4px;
|
|
height: 8px;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-bar-fill {
|
|
background: var(--brand-red);
|
|
height: 100%;
|
|
width: 0%;
|
|
transition: width 0.3s;
|
|
}
|
|
|
|
.progress-text {
|
|
text-align: center;
|
|
color: var(--text-secondary);
|
|
font-size: 14px;
|
|
margin-top: 8px;
|
|
}
|
|
|
|
/* Status Message */
|
|
#status-message {
|
|
display: none;
|
|
padding: 16px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
#status-message.success {
|
|
display: block;
|
|
background: rgba(34, 197, 94, 0.2);
|
|
color: #22c55e;
|
|
border: 1px solid #22c55e;
|
|
}
|
|
|
|
#status-message.error {
|
|
display: block;
|
|
background: rgba(239, 68, 68, 0.2);
|
|
color: #ef4444;
|
|
border: 1px solid #ef4444;
|
|
}
|
|
|
|
/* Submit Button */
|
|
.btn-submit {
|
|
width: 100%;
|
|
background: var(--brand-red);
|
|
color: white;
|
|
border: none;
|
|
padding: 14px 24px;
|
|
border-radius: 8px;
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.btn-submit:hover {
|
|
background: #cc1a1a;
|
|
}
|
|
|
|
.btn-submit:disabled {
|
|
background: #555;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Upload Page Layout */
|
|
.upload-page .yt-main {
|
|
display: block;
|
|
margin-left: 0;
|
|
}
|
|
|
|
/* Visibility Options */
|
|
.visibility-options {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
.visibility-option {
|
|
display: block;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.visibility-option input {
|
|
display: none;
|
|
}
|
|
|
|
.visibility-content {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16px;
|
|
padding: 16px;
|
|
background: #1a1a1a;
|
|
border: 2px solid var(--border-color);
|
|
border-radius: 12px;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.visibility-option:hover .visibility-content {
|
|
border-color: var(--text-secondary);
|
|
}
|
|
|
|
.visibility-option.active .visibility-content {
|
|
border-color: var(--brand-red);
|
|
background: rgba(230, 30, 30, 0.1);
|
|
}
|
|
|
|
.visibility-content i {
|
|
font-size: 24px;
|
|
color: var(--text-secondary);
|
|
}
|
|
|
|
.visibility-option.active .visibility-content i {
|
|
color: var(--brand-red);
|
|
}
|
|
|
|
.visibility-title {
|
|
font-weight: 500;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.visibility-desc {
|
|
color: var(--text-secondary);
|
|
font-size: 14px;
|
|
}
|
|
|
|
@media (min-width: 992px) {
|
|
.upload-page .yt-main {
|
|
margin-left: 240px;
|
|
}
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="upload-container">
|
|
<h1 style="font-size: 24px; font-weight: 500; margin-bottom: 24px;">Upload Video</h1>
|
|
|
|
<form id="upload-form" enctype="multipart/form-data">
|
|
@csrf
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Title *</label>
|
|
<input type="text" name="title" required
|
|
class="form-input"
|
|
placeholder="Enter video title">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Description</label>
|
|
<textarea name="description" rows="4"
|
|
class="form-textarea"
|
|
placeholder="Tell viewers about your video"></textarea>
|
|
</div>
|
|
|
|
<div class="upload-row">
|
|
<div class="form-group">
|
|
<label class="form-label">Video File *</label>
|
|
<div id="dropzone">
|
|
<input type="file" name="video" id="video" accept="video/*" required>
|
|
<div id="dropzone-default">
|
|
<i class="bi bi-camera-video icon"></i>
|
|
<p>Click to select or drag video here</p>
|
|
<p class="hint">MP4, MOV, AVI, WebM up to 512MB</p>
|
|
</div>
|
|
<div id="file-info">
|
|
<p class="filename" id="filename"></p>
|
|
<p id="filesize"></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Thumbnail (optional)</label>
|
|
<div id="thumbnail-dropzone">
|
|
<input type="file" name="thumbnail" id="thumbnail" accept="image/*">
|
|
<div id="thumbnail-default">
|
|
<i class="bi bi-image icon"></i>
|
|
<p>Click to select or drag thumbnail</p>
|
|
<p class="hint">JPG, PNG, WebP up to 5MB</p>
|
|
</div>
|
|
<div id="thumbnail-info">
|
|
<p class="filename" id="thumbnail-filename"></p>
|
|
<p id="thumbnail-filesize"></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Privacy</label>
|
|
<div class="visibility-options">
|
|
<label class="visibility-option active">
|
|
<input type="radio" name="visibility" value="public" checked>
|
|
<div class="visibility-content">
|
|
<i class="bi bi-globe"></i>
|
|
<span class="visibility-title">Public</span>
|
|
<span class="visibility-desc">Everyone can see this video</span>
|
|
</div>
|
|
</label>
|
|
<label class="visibility-option">
|
|
<input type="radio" name="visibility" value="unlisted">
|
|
<div class="visibility-content">
|
|
<i class="bi bi-link-45deg"></i>
|
|
<span class="visibility-title">Unlisted</span>
|
|
<span class="visibility-desc">Only people with the link can see</span>
|
|
</div>
|
|
</label>
|
|
<label class="visibility-option">
|
|
<input type="radio" name="visibility" value="private">
|
|
<div class="visibility-content">
|
|
<i class="bi bi-lock"></i>
|
|
<span class="visibility-title">Private</span>
|
|
<span class="visibility-desc">Only you can see this video</span>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Progress Bar -->
|
|
<div id="progress-container">
|
|
<div class="progress-bar-wrapper">
|
|
<div id="progress-bar" class="progress-bar-fill"></div>
|
|
</div>
|
|
<p id="progress-text" class="progress-text">Uploading... 0%</p>
|
|
</div>
|
|
|
|
<!-- Status Message -->
|
|
<div id="status-message"></div>
|
|
|
|
<button type="submit" id="submit-btn" class="btn-submit">
|
|
Upload Video
|
|
</button>
|
|
</form>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('scripts')
|
|
<script>
|
|
// Video Dropzone
|
|
const dropzone = document.getElementById('dropzone');
|
|
const fileInput = document.getElementById('video');
|
|
|
|
// Add change event listener for video file selection
|
|
fileInput.addEventListener('change', function() {
|
|
handleFileSelect(this);
|
|
});
|
|
|
|
dropzone.addEventListener('click', () => fileInput.click());
|
|
|
|
dropzone.addEventListener('dragover', (e) => {
|
|
e.preventDefault();
|
|
dropzone.classList.add('dragover');
|
|
});
|
|
|
|
dropzone.addEventListener('dragleave', () => {
|
|
dropzone.classList.remove('dragover');
|
|
});
|
|
|
|
dropzone.addEventListener('drop', (e) => {
|
|
e.preventDefault();
|
|
dropzone.classList.remove('dragover');
|
|
if (e.dataTransfer.files.length) {
|
|
fileInput.files = e.dataTransfer.files;
|
|
handleFileSelect(fileInput);
|
|
}
|
|
});
|
|
|
|
function handleFileSelect(input) {
|
|
if (input.files && input.files[0]) {
|
|
const file = input.files[0];
|
|
const maxSize = 512 * 1024 * 1024; // 512MB in bytes
|
|
|
|
// Validate file type
|
|
const validTypes = ['video/mp4', 'video/webm', 'video/ogg', 'video/quicktime', 'video/x-msvideo', 'video/x-flv', 'video/x-matroska'];
|
|
const validExtensions = ['.mp4', '.webm', '.ogg', '.mov', '.avi', '.wmv', '.flv', '.mkv'];
|
|
|
|
let isValidType = validTypes.includes(file.type);
|
|
let fileExtension = '.' + file.name.split('.').pop().toLowerCase();
|
|
if (!isValidType) {
|
|
isValidType = validExtensions.includes(fileExtension);
|
|
}
|
|
|
|
if (!isValidType) {
|
|
alert('Invalid video format. Please select a valid video file (MP4, MOV, AVI, WebM, OGG, WMV, FLV, MKV).');
|
|
input.value = '';
|
|
document.getElementById('dropzone-default').style.display = 'block';
|
|
document.getElementById('file-info').classList.remove('active');
|
|
return;
|
|
}
|
|
|
|
if (file.size > maxSize) {
|
|
alert('File size exceeds 512MB limit. Please select a smaller video file.');
|
|
input.value = ''; // Clear the input
|
|
document.getElementById('dropzone-default').style.display = 'block';
|
|
document.getElementById('file-info').classList.remove('active');
|
|
return;
|
|
}
|
|
|
|
document.getElementById('filename').textContent = file.name;
|
|
document.getElementById('filesize').textContent = (file.size / 1024 / 1024).toFixed(2) + ' MB';
|
|
document.getElementById('dropzone-default').style.display = 'none';
|
|
document.getElementById('file-info').classList.add('active');
|
|
}
|
|
}
|
|
|
|
// Thumbnail Dropzone
|
|
const thumbnailDropzone = document.getElementById('thumbnail-dropzone');
|
|
const thumbnailInput = document.getElementById('thumbnail');
|
|
|
|
thumbnailDropzone.addEventListener('click', () => thumbnailInput.click());
|
|
|
|
thumbnailDropzone.addEventListener('dragover', (e) => {
|
|
e.preventDefault();
|
|
thumbnailDropzone.classList.add('dragover');
|
|
});
|
|
|
|
thumbnailDropzone.addEventListener('dragleave', () => {
|
|
thumbnailDropzone.classList.remove('dragover');
|
|
});
|
|
|
|
thumbnailDropzone.addEventListener('drop', (e) => {
|
|
e.preventDefault();
|
|
thumbnailDropzone.classList.remove('dragover');
|
|
if (e.dataTransfer.files.length) {
|
|
thumbnailInput.files = e.dataTransfer.files;
|
|
handleThumbnailSelect(thumbnailInput);
|
|
}
|
|
});
|
|
|
|
thumbnailInput.addEventListener('change', function() {
|
|
handleThumbnailSelect(this);
|
|
});
|
|
|
|
function handleThumbnailSelect(input) {
|
|
if (input.files && input.files[0]) {
|
|
const file = input.files[0];
|
|
document.getElementById('thumbnail-filename').textContent = file.name;
|
|
document.getElementById('thumbnail-filesize').textContent = (file.size / 1024 / 1024).toFixed(2) + ' MB';
|
|
document.getElementById('thumbnail-default').style.display = 'none';
|
|
document.getElementById('thumbnail-info').classList.add('active');
|
|
}
|
|
}
|
|
|
|
// Visibility option handling
|
|
const visibilityOptions = document.querySelectorAll('.visibility-option');
|
|
visibilityOptions.forEach(option => {
|
|
const radio = option.querySelector('input[type="radio"]');
|
|
radio.addEventListener('change', function() {
|
|
visibilityOptions.forEach(opt => opt.classList.remove('active'));
|
|
option.classList.add('active');
|
|
});
|
|
});
|
|
|
|
document.getElementById('upload-form').addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const formData = new FormData(this);
|
|
const xhr = new XMLHttpRequest();
|
|
|
|
document.getElementById('progress-container').classList.add('active');
|
|
document.getElementById('submit-btn').disabled = true;
|
|
document.getElementById('submit-btn').textContent = 'Uploading...';
|
|
document.getElementById('status-message').className = '';
|
|
|
|
xhr.upload.addEventListener('progress', function(e) {
|
|
if (e.lengthComputable) {
|
|
const percent = Math.round((e.loaded / e.total) * 100);
|
|
document.getElementById('progress-bar').style.width = percent + '%';
|
|
document.getElementById('progress-text').textContent = 'Uploading... ' + percent + '%';
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('load', function() {
|
|
document.getElementById('progress-bar').style.width = '100%';
|
|
document.getElementById('progress-text').textContent = 'Processing...';
|
|
|
|
try {
|
|
const response = JSON.parse(xhr.responseText);
|
|
if (response.success) {
|
|
document.getElementById('progress-text').textContent = 'Done! Redirecting...';
|
|
window.location.href = response.redirect;
|
|
} else {
|
|
showError(response.message || 'Upload failed');
|
|
}
|
|
} catch(e) {
|
|
showError('Invalid response from server');
|
|
}
|
|
});
|
|
|
|
xhr.addEventListener('error', function() {
|
|
showError('Upload failed. Please try again.');
|
|
});
|
|
|
|
xhr.open('POST', '{{ route("videos.store") }}');
|
|
xhr.setRequestHeader('X-CSRF-TOKEN', '{{ csrf_token() }}');
|
|
xhr.send(formData);
|
|
});
|
|
|
|
function showError(message) {
|
|
const status = document.getElementById('status-message');
|
|
status.textContent = message;
|
|
status.className = 'error';
|
|
document.getElementById('submit-btn').disabled = false;
|
|
document.getElementById('submit-btn').textContent = 'Upload Video';
|
|
}
|
|
</script>
|
|
@endsection
|
|
|