390 lines
12 KiB
PHP
390 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\Playlist;
|
|
use App\Models\Video;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
class PlaylistController extends Controller
|
|
{
|
|
public function __construct()
|
|
{
|
|
$this->middleware('auth')->except(['index', 'show', 'publicPlaylists', 'userPlaylists']);
|
|
}
|
|
|
|
// List user's playlists
|
|
public function index()
|
|
{
|
|
$user = Auth::user();
|
|
$playlists = $user->playlists()->orderBy('created_at', 'desc')->get();
|
|
|
|
return view('playlists.index', compact('playlists'));
|
|
}
|
|
|
|
// View a single playlist
|
|
public function show(Playlist $playlist)
|
|
{
|
|
// Check if user can view this playlist
|
|
if (! $playlist->canView(Auth::user())) {
|
|
abort(404, 'Playlist not found');
|
|
}
|
|
|
|
$videos = $playlist->videos()->orderBy('position')->paginate(20);
|
|
|
|
return view('playlists.show', compact('playlist', 'videos'));
|
|
}
|
|
|
|
// Create new playlist form
|
|
public function create()
|
|
{
|
|
return view('playlists.create');
|
|
}
|
|
|
|
// Store new playlist
|
|
public function store(Request $request)
|
|
{
|
|
$request->validate([
|
|
'name' => 'required|string|max:100',
|
|
'description' => 'nullable|string|max:500',
|
|
'visibility' => 'nullable|in:public,private',
|
|
'thumbnail' => 'nullable|image|mimes:jpeg,png,gif,webp|max:5120',
|
|
]);
|
|
|
|
$playlistData = [
|
|
'user_id' => Auth::id(),
|
|
'name' => $request->name,
|
|
'description' => $request->description,
|
|
'visibility' => $request->visibility ?? 'private',
|
|
'is_default' => false,
|
|
];
|
|
|
|
// Create playlist first to get ID for thumbnail naming
|
|
$playlist = Playlist::create($playlistData);
|
|
|
|
// Handle thumbnail upload
|
|
if ($request->hasFile('thumbnail')) {
|
|
$file = $request->file('thumbnail');
|
|
$filename = 'playlist_'.$playlist->id.'_'.time().'.'.$file->getClientOriginalExtension();
|
|
$file->storeAs('public/thumbnails', $filename);
|
|
$playlist->update(['thumbnail' => $filename]);
|
|
}
|
|
|
|
// Reload playlist with thumbnail
|
|
$playlist->refresh();
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'playlist' => [
|
|
'id' => $playlist->id,
|
|
'name' => $playlist->name,
|
|
'visibility' => $playlist->visibility,
|
|
'thumbnail_url' => $playlist->thumbnail_url,
|
|
],
|
|
]);
|
|
}
|
|
|
|
return redirect()->route('playlists.show', $playlist)->with('success', 'Playlist created!');
|
|
}
|
|
|
|
// Edit playlist form
|
|
public function edit(Playlist $playlist)
|
|
{
|
|
// Check ownership
|
|
if (! $playlist->canEdit(Auth::user())) {
|
|
abort(403, 'You do not have permission to edit this playlist.');
|
|
}
|
|
|
|
if (request()->expectsJson() || request()->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'playlist' => [
|
|
'id' => $playlist->id,
|
|
'name' => $playlist->name,
|
|
'description' => $playlist->description,
|
|
'visibility' => $playlist->visibility,
|
|
],
|
|
]);
|
|
}
|
|
|
|
return view('playlists.edit', compact('playlist'));
|
|
}
|
|
|
|
// Update playlist
|
|
public function update(Request $request, Playlist $playlist)
|
|
{
|
|
// Check ownership
|
|
if (! $playlist->canEdit(Auth::user())) {
|
|
abort(403, 'You do not have permission to edit this playlist.');
|
|
}
|
|
|
|
$request->validate([
|
|
'name' => 'required|string|max:100',
|
|
'description' => 'nullable|string|max:500',
|
|
'visibility' => 'nullable|in:public,private',
|
|
'thumbnail' => 'nullable|image|mimes:jpeg,png,gif,webp|max:5120',
|
|
]);
|
|
|
|
$updateData = [
|
|
'name' => $request->name,
|
|
'description' => $request->description,
|
|
'visibility' => $request->visibility ?? 'private',
|
|
];
|
|
|
|
// Handle thumbnail upload
|
|
if ($request->hasFile('thumbnail')) {
|
|
// Delete old thumbnail if exists
|
|
if ($playlist->thumbnail) {
|
|
$oldPath = storage_path('app/public/thumbnails/'.$playlist->thumbnail);
|
|
if (file_exists($oldPath)) {
|
|
unlink($oldPath);
|
|
}
|
|
}
|
|
|
|
// Upload new thumbnail
|
|
$file = $request->file('thumbnail');
|
|
$filename = 'playlist_'.$playlist->id.'_'.time().'.'.$file->getClientOriginalExtension();
|
|
$file->storeAs('public/thumbnails', $filename);
|
|
$updateData['thumbnail'] = $filename;
|
|
}
|
|
|
|
// Handle thumbnail removal
|
|
if ($request->input('remove_thumbnail') == '1') {
|
|
if ($playlist->thumbnail) {
|
|
$oldPath = storage_path('app/public/thumbnails/'.$playlist->thumbnail);
|
|
if (file_exists($oldPath)) {
|
|
unlink($oldPath);
|
|
}
|
|
$updateData['thumbnail'] = null;
|
|
}
|
|
}
|
|
|
|
$playlist->update($updateData);
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Playlist updated!',
|
|
'playlist' => [
|
|
'id' => $playlist->id,
|
|
'name' => $playlist->name,
|
|
'visibility' => $playlist->visibility,
|
|
],
|
|
]);
|
|
}
|
|
|
|
return redirect()->route('playlists.show', $playlist)->with('success', 'Playlist updated!');
|
|
}
|
|
|
|
// Delete playlist
|
|
public function destroy(Request $request, Playlist $playlist)
|
|
{
|
|
// Check ownership
|
|
if (! $playlist->canEdit(Auth::user())) {
|
|
abort(403, 'You do not have permission to delete this playlist.');
|
|
}
|
|
|
|
// Don't allow deleting default playlists
|
|
if ($playlist->is_default) {
|
|
abort(400, 'Cannot delete default playlist.');
|
|
}
|
|
|
|
$playlist->delete();
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Playlist deleted!',
|
|
]);
|
|
}
|
|
|
|
return redirect()->route('playlists.index')->with('success', 'Playlist deleted!');
|
|
}
|
|
|
|
// Add video to playlist
|
|
public function addVideo(Request $request, Playlist $playlist)
|
|
{
|
|
// Check ownership
|
|
if (! $playlist->canEdit(Auth::user())) {
|
|
abort(403, 'You do not have permission to edit this playlist.');
|
|
}
|
|
|
|
$request->validate([
|
|
'video_id' => 'required|exists:videos,id',
|
|
]);
|
|
|
|
$video = Video::findOrFail($request->video_id);
|
|
|
|
// Check if video can be viewed
|
|
if (! $video->canView(Auth::user())) {
|
|
abort(403, 'You cannot add this video to your playlist.');
|
|
}
|
|
|
|
$added = $playlist->addVideo($video);
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => $added ? 'Video added to playlist!' : 'Video is already in playlist.',
|
|
'video_count' => $playlist->video_count,
|
|
]);
|
|
}
|
|
|
|
return back()->with('success', $added ? 'Video added to playlist!' : 'Video is already in playlist.');
|
|
}
|
|
|
|
// Remove video from playlist
|
|
public function removeVideo(Request $request, Playlist $playlist, Video $video)
|
|
{
|
|
// Check ownership
|
|
if (! $playlist->canEdit(Auth::user())) {
|
|
abort(403, 'You do not have permission to edit this playlist.');
|
|
}
|
|
|
|
$removed = $playlist->removeVideo($video);
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Video removed from playlist.',
|
|
'video_count' => $playlist->video_count,
|
|
]);
|
|
}
|
|
|
|
return back()->with('success', 'Video removed from playlist.');
|
|
}
|
|
|
|
// Reorder videos in playlist
|
|
public function reorder(Request $request, Playlist $playlist)
|
|
{
|
|
// Check ownership
|
|
if (! $playlist->canEdit(Auth::user())) {
|
|
abort(403, 'You do not have permission to edit this playlist.');
|
|
}
|
|
|
|
$request->validate([
|
|
'video_ids' => 'required|array',
|
|
'video_ids.*' => 'integer|exists:videos,id',
|
|
]);
|
|
|
|
$playlist->reorderVideos($request->video_ids);
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Playlist reordered!',
|
|
]);
|
|
}
|
|
|
|
return back()->with('success', 'Playlist reordered!');
|
|
}
|
|
|
|
// Get user's playlists (for dropdown)
|
|
public function userPlaylists()
|
|
{
|
|
// Handle unauthenticated users
|
|
if (! Auth::check()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'playlists' => [],
|
|
'authenticated' => false,
|
|
]);
|
|
}
|
|
|
|
$user = Auth::user();
|
|
$playlists = $user->playlists()->orderBy('name')->get();
|
|
|
|
// Get video IDs for each playlist
|
|
$playlistsWithVideoIds = $playlists->map(function ($p) {
|
|
return [
|
|
'id' => $p->id,
|
|
'name' => $p->name,
|
|
'description' => $p->description,
|
|
'video_count' => $p->videos()->count(),
|
|
'formatted_duration' => $p->formatted_duration,
|
|
'is_default' => $p->is_default,
|
|
'visibility' => $p->visibility,
|
|
'thumbnail_url' => $p->thumbnail_url,
|
|
'video_ids' => $p->videos()->pluck('videos.id')->toArray(),
|
|
];
|
|
});
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'playlists' => $playlistsWithVideoIds,
|
|
'authenticated' => true,
|
|
]);
|
|
}
|
|
|
|
// Quick add to Watch Later
|
|
public function watchLater(Request $request, Video $video)
|
|
{
|
|
$watchLater = Playlist::getWatchLater(Auth::id());
|
|
$added = $watchLater->addVideo($video);
|
|
|
|
if ($request->expectsJson() || $request->ajax()) {
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => $added ? 'Added to Watch Later!' : 'Already in Watch Later.',
|
|
]);
|
|
}
|
|
|
|
return back()->with('success', $added ? 'Added to Watch Later!' : 'Already in Watch Later.');
|
|
}
|
|
|
|
// Update watch progress
|
|
public function updateProgress(Request $request, Playlist $playlist, Video $video)
|
|
{
|
|
$request->validate([
|
|
'seconds' => 'required|integer|min:0',
|
|
]);
|
|
|
|
$playlist->updateWatchProgress($video, $request->seconds);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
]);
|
|
}
|
|
|
|
// Play all videos in playlist (redirect to first video with playlist context)
|
|
public function playAll(Playlist $playlist)
|
|
{
|
|
if (! $playlist->canView(Auth::user())) {
|
|
abort(404, 'Playlist not found');
|
|
}
|
|
|
|
$firstVideo = $playlist->videos()->orderBy('position')->first();
|
|
|
|
if (! $firstVideo) {
|
|
return back()->with('error', 'Playlist is empty.');
|
|
}
|
|
|
|
// Redirect to first video with playlist parameter
|
|
return redirect()->route('videos.show', [
|
|
'video' => $firstVideo->id,
|
|
'playlist' => $playlist->id,
|
|
]);
|
|
}
|
|
|
|
// Shuffle play - redirect to random video
|
|
public function shuffle(Playlist $playlist)
|
|
{
|
|
if (! $playlist->canView(Auth::user())) {
|
|
abort(404, 'Playlist not found');
|
|
}
|
|
|
|
$randomVideo = $playlist->getRandomVideo();
|
|
|
|
if (! $randomVideo) {
|
|
return back()->with('error', 'Playlist is empty.');
|
|
}
|
|
|
|
return redirect()->route('videos.show', [
|
|
'video' => $randomVideo->id,
|
|
'playlist' => $playlist->id,
|
|
]);
|
|
}
|
|
}
|