id(); $music = Music::with(['image', 'playlist']) ->where('type', 'public') ->orWhere(function($query) use ($userId) { $query->where('type', 'private') ->where('user_id', $userId); }) ->orderBy('created_at', 'desc') ->get(); return response()->json([ 'data' => $music, 'total' => $music->count() ]); } public function getMusicByPlaylist($playlistId) { $playlist = MusicPlaylist::findOrFail($playlistId); $music = Music::where('playlist_id', $playlistId) ->where('is_active', true) ->with(['image', 'tags']) ->orderBy('order') ->get(); return response()->json([ 'playlist' => $playlist->load('image'), 'musics' => $music ]); } public function addToPlaylist(Request $request, $musicId) { $music = Music::where('id', $musicId) ->where(function($q) { $q->where('type', 'public') ->orWhere('user_id', auth()->id()); }) ->firstOrFail(); $data = $request->validate([ 'playlist_id' => 'required|exists:music_playlists,id', 'order' => 'nullable|integer', ]); $music->update([ 'playlist_id' => $data['playlist_id'], 'order' => $data['order'] ?? $music->order, ]); return response()->json([ 'message' => 'Music added to playlist successfully', 'music' => $music->load(['image', 'playlist']) ]); } public function removeFromPlaylist($musicId) { $music = Music::where('id', $musicId) ->where('user_id', auth()->id()) ->firstOrFail(); $music->update(['playlist_id' => null]); return response()->json(['message' => 'Music removed from playlist']); } public function updateOrder(Request $request) { $data = $request->validate([ 'musics' => 'required|array', 'musics.*.id' => 'required|exists:music,id', 'musics.*.order' => 'required|integer', ]); foreach ($data['musics'] as $item) { Music::where('id', $item['id']) ->where('user_id', auth()->id()) ->update(['order' => $item['order']]); } return response()->json(['message' => 'Order updated successfully']); } // ✅ Upload music public function store(Request $request) { try { $data = $request->validate([ 'title' => 'required|string|max:255', 'artist' => 'nullable|string|max:255', 'file' => 'required|mimes:mp3,wav,ogg|max:20971520', 'type' => 'nullable|in:public,private', 'image_id' => 'nullable|exists:images,id', 'playlist_id' => 'nullable|exists:music_playlists,id', 'duration' => 'nullable|string|regex:/^(?:\d+:)?[0-5]?\d:[0-5]\d$/', // validates mm:ss or hh:mm:ss ]); // Handle file upload if (!$request->hasFile('file')) { return response()->json([ 'message' => 'No file was uploaded' ], 400); } $file = $request->file('file'); // Validate file size if ($file->getSize() > 20971520) { return response()->json([ 'message' => 'File size exceeds 10MB limit' ], 422); } $path = $file->store('music', 'public'); if (!$path) { return response()->json([ 'message' => 'Failed to store the file' ], 500); } $music = Music::create([ 'user_id' => auth()->id(), 'title' => $data['title'], 'artist' => $data['artist'] ?? null, 'file_path' => $path, 'type' => $data['type'] ?? 'private', 'image_id' => $data['image_id'] ?? null, 'playlist_id' => $data['playlist_id'] ?? null, 'duration' => $data['duration'] ?? null, // Store as string 'order' => $this->getNextOrderInPlaylist($data['playlist_id'] ?? null), 'is_active' => true, ]); return response()->json([ 'message' => 'Music uploaded successfully', 'music' => $music->load(['image', 'playlist', 'tags']), 'url' => asset('storage/' . $path), ], 201); } catch (\Illuminate\Validation\ValidationException $e) { return response()->json([ 'message' => 'Validation failed', 'errors' => $e->errors() ], 422); } catch (\Exception $e) { return response()->json([ 'message' => 'An error occurred while uploading the music', 'error' => $e->getMessage() ], 500); } } // Helper method to get next order number in playlist private function getNextOrderInPlaylist($playlistId) { if (!$playlistId) { return 0; } $maxOrder = Music::where('playlist_id', $playlistId)->max('order'); return ($maxOrder ?? -1) + 1; } // ✅ Update music with string duration public function update(Request $request, $id) { try { $music = Music::where('id', $id)->where('user_id', auth()->id())->firstOrFail(); $data = $request->validate([ 'title' => 'nullable|string|max:255', 'artist' => 'nullable|string|max:255', 'type' => 'nullable|in:public,private', 'file' => 'nullable|mimes:mp3,wav,ogg|max:10240', 'image_id' => 'nullable|exists:images,id', 'playlist_id' => 'nullable|exists:music_playlists,id', 'duration' => 'nullable|string|regex:/^(?:\d+:)?[0-5]?\d:[0-5]\d$/', 'order' => 'nullable|integer', 'is_active' => 'nullable|boolean', ]); if ($request->hasFile('file')) { // Delete old file Storage::disk('public')->delete($music->file_path); $path = $request->file('file')->store('music', 'public'); $music->file_path = $path; } // Update only provided fields $music->fill($data); $music->save(); return response()->json([ 'message' => 'Music updated successfully', 'music' => $music->load(['image', 'playlist', 'tags']), 'url' => asset('storage/' . $music->file_path), ]); } catch (\Exception $e) { return response()->json([ 'message' => 'An error occurred while updating the music', 'error' => $e->getMessage() ], 500); } } // ✅ Get all public + user private music public function show($id) { $userId = auth()->id(); $music = Music::with(['image', 'playlist', 'tags']) ->where(function($query) use ($userId) { $query->where('type', 'public') ->orWhere(function($q) use ($userId) { $q->where('type', 'private') ->where('user_id', $userId); }); }) ->findOrFail($id); return response()->json($music); } // ✅ Delete music public function destroy($id) { $music = Music::where('id', $id)->where('user_id', auth()->id())->firstOrFail(); Storage::disk('public')->delete($music->file_path); $music->delete(); return response()->json(['message' => 'Music deleted successfully']); } }