feat: add detail image media and play list

This commit is contained in:
2026-06-06 19:08:27 +03:30
parent 0b578e15dd
commit fcf9c35697
5 changed files with 91 additions and 10 deletions
+24 -6
View File
@@ -30,6 +30,8 @@ public function store(Request $request)
'subcategory_ids.*' => 'integer|exists:sub_categories,id',
'image_id' => 'nullable|exists:images,id',
'image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'detail_image_id' => 'nullable|exists:images,id',
'detail_image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'duration' => 'nullable|integer',
'is_premium' => 'nullable|boolean',
'file' => 'nullable|file|extensions:mp3,wav,ogg,flac,aac,m4a,opus,mpga,wma,mp4,mov,m4v,webm,mkv,avi,3gp|max:512000',
@@ -47,6 +49,7 @@ public function store(Request $request)
// An uploaded image file takes precedence over a provided image_id.
$imageId = $this->uploadedImageId($request) ?? ($data['image_id'] ?? null);
$detailImageId = $this->uploadedImageId($request, 'detail_image') ?? ($data['detail_image_id'] ?? null);
// When a file is uploaded, expose its public URL as external_url too
// (older front-end versions read external_url for the playable source).
@@ -60,6 +63,7 @@ public function store(Request $request)
'file_path' => $path,
'external_url' => $externalUrl,
'image_id' => $imageId,
'detail_image_id' => $detailImageId,
'duration' => $data['duration'] ?? null,
'visibility' => $data['visibility'] ?? 'public',
'is_premium'=> $data['is_premium'] ?? false
@@ -80,12 +84,12 @@ public function store(Request $request)
}
return response()->json([
'message' => 'Media created successfully',
'media' => $media->load(['image', 'categories', 'subCategories', 'tags']),
'media' => $media->load(['image', 'detailImage', 'categories', 'subCategories', 'tags']),
]);
}
public function index(Request $request)
{
$query = Media::with(['image', 'categories', 'subCategories', 'myNote', 'tags','comments'])
$query = Media::with(['image', 'detailImage', 'categories', 'subCategories', 'myNote', 'tags','comments'])
->where(function ($q) {
$q->where('visibility', 'public')
->orWhere('user_id', auth()->id());
@@ -354,6 +358,7 @@ public function show($id)
{
$media = Media::with([
'image',
'detailImage',
'categories',
'subCategories',
'myNote',
@@ -392,6 +397,7 @@ public function show($id)
'updated_at' => $media->updated_at,
'is_premium' => $media->is_premium,
'image' => $media->image,
'detail_image' => $media->detailImage,
'categories' => $media->categories,
'sub_categories' => $media->subCategories,
'tags' => $media->tags,
@@ -482,6 +488,8 @@ public function update(Request $request, $id)
'is_premium' => 'nullable|boolean',
'image_id' => 'nullable|exists:images,id',
'image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'detail_image_id' => 'nullable|exists:images,id',
'detail_image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'duration' => 'nullable|integer',
'file' => 'nullable|file|extensions:mp3,wav,ogg,flac,aac,m4a,opus,mpga,wma,mp4,mov,m4v,webm,mkv,avi,3gp|max:512000',
'external_url' => 'nullable|string',
@@ -522,6 +530,16 @@ public function update(Request $request, $id)
$updateData['image_id'] = $media->image_id;
}
// --- Handle detail image (shown on the show-by-id screen) ---
$uploadedDetailImageId = $this->uploadedImageId($request, 'detail_image');
if ($uploadedDetailImageId !== null) {
$updateData['detail_image_id'] = $uploadedDetailImageId;
} elseif (array_key_exists('detail_image_id', $data)) {
$updateData['detail_image_id'] = $data['detail_image_id'];
} else {
$updateData['detail_image_id'] = $media->detail_image_id;
}
// --- update media ---
$media->update($updateData);
@@ -546,7 +564,7 @@ public function update(Request $request, $id)
return response()->json([
'message' => 'Media updated successfully',
'media' => $media->load(['image', 'categories', 'subCategories', 'tags']),
'media' => $media->load(['image', 'detailImage', 'categories', 'subCategories', 'tags']),
]);
}
@@ -583,7 +601,7 @@ public function toggleSaveMedia($id)
// GET saved
public function saved()
{
return auth()->user()->savedMedia()->with(['image','categories', 'subCategories', 'myNote' , 'tags'])->get();
return auth()->user()->savedMedia()->with(['image','detailImage','categories', 'subCategories', 'myNote' , 'tags'])->get();
}
// RECORD a play for the current user (feeds popular + recently played).
@@ -621,7 +639,7 @@ public function popular(Request $request)
})
->withCount('plays as listeners_count') // distinct users who played
->withSum('plays as plays_count', 'play_count') // total plays
->with(['image', 'categories', 'subCategories', 'tags'])
->with(['image', 'detailImage', 'categories', 'subCategories', 'tags'])
->orderByDesc('plays_count')
->orderByDesc('listeners_count')
->orderByDesc('created_at')
@@ -638,7 +656,7 @@ public function recentlyPlayed(Request $request)
$plays = MediaPlay::where('user_id', auth()->id())
->whereNotNull('last_played_at')
->with(['media' => fn ($q) => $q->with(['image', 'categories', 'subCategories', 'tags'])])
->with(['media' => fn ($q) => $q->with(['image', 'detailImage', 'categories', 'subCategories', 'tags'])])
->orderByDesc('last_played_at')
->limit($limit)
->get();
@@ -13,7 +13,7 @@ class MusicPlaylistController extends Controller
public function index(Request $request, $categoryId = null)
{
$query = MusicPlaylist::with(['categories', 'subcategories', 'image']);
$query = MusicPlaylist::with(['categories', 'subcategories', 'image', 'detailImage']);
$categoryId = $categoryId ?? $request->input('category_id');
@@ -46,6 +46,8 @@ public function store(Request $request)
'description' => 'nullable|string',
'image_id' => 'nullable|exists:images,id',
'image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'detail_image_id' => 'nullable|exists:images,id',
'detail_image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
@@ -61,6 +63,7 @@ public function store(Request $request)
// An uploaded image file takes precedence over a provided image_id.
$data['image_id'] = $this->uploadedImageId($request) ?? ($data['image_id'] ?? null);
$data['detail_image_id'] = $this->uploadedImageId($request, 'detail_image') ?? ($data['detail_image_id'] ?? null);
$playlist = MusicPlaylist::create($data);
@@ -69,7 +72,7 @@ public function store(Request $request)
return response()->json([
'message' => 'Playlist created successfully',
'playlist' => $playlist->load(['categories', 'subcategories', 'image'])
'playlist' => $playlist->load(['categories', 'subcategories', 'image', 'detailImage'])
], 201);
}
@@ -79,6 +82,7 @@ public function show($id)
'categories',
'subcategories',
'image',
'detailImage',
'musics' => function($q) {
$q->where('music.is_active', true)
->with(['image', 'tags'])
@@ -127,6 +131,8 @@ public function update(Request $request, $id)
'description' => 'nullable|string',
'image_id' => 'nullable|exists:images,id',
'image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'detail_image_id' => 'nullable|exists:images,id',
'detail_image' => 'nullable|file|extensions:jpg,jpeg,png,gif,webp,bmp,svg|max:8192',
'order' => 'nullable|integer',
'is_active' => 'nullable|boolean',
]);
@@ -139,6 +145,9 @@ public function update(Request $request, $id)
if (($uploadedImageId = $this->uploadedImageId($request)) !== null) {
$data['image_id'] = $uploadedImageId;
}
if (($uploadedDetailImageId = $this->uploadedImageId($request, 'detail_image')) !== null) {
$data['detail_image_id'] = $uploadedDetailImageId;
}
$playlist->update($data);
@@ -152,7 +161,7 @@ public function update(Request $request, $id)
return response()->json([
'message' => 'Playlist updated successfully',
'playlist' => $playlist->load(['categories', 'subcategories', 'image'])
'playlist' => $playlist->load(['categories', 'subcategories', 'image', 'detailImage'])
]);
}
+7
View File
@@ -13,6 +13,7 @@ class Media extends Model
protected $fillable = [
'user_id',
'image_id',
'detail_image_id',
'title',
'caption',
'type',
@@ -42,6 +43,12 @@ public function image()
return $this->belongsTo(Image::class);
}
// Image shown on the detail (show-by-id) screen; image() is the list thumbnail.
public function detailImage()
{
return $this->belongsTo(Image::class, 'detail_image_id');
}
public function categories()
{
return $this->belongsToMany(Category::class, 'category_media');
+7 -1
View File
@@ -15,7 +15,7 @@ class MusicPlaylist extends Model
protected $table = 'music_playlists';
protected $fillable = [
'name', 'slug', 'description', 'image_id', 'order', 'is_active'
'name', 'slug', 'description', 'image_id', 'detail_image_id', 'order', 'is_active'
];
protected $casts = [
@@ -55,6 +55,12 @@ public function image(): BelongsTo
return $this->belongsTo(Image::class);
}
// Image shown on the detail (show-by-id) screen; image() is the list thumbnail.
public function detailImage(): BelongsTo
{
return $this->belongsTo(Image::class, 'detail_image_id');
}
public function getActiveMusicsAttribute()
{
return $this->musics()->where('music.is_active', true)->orderBy('music_playlist.order')->get();
@@ -0,0 +1,41 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Add a second image reference: image_id = list/thumbnail image,
* detail_image_id = image shown on the detail (show-by-id) screen.
*/
public function up(): void
{
Schema::table('media', function (Blueprint $table) {
$table->unsignedBigInteger('detail_image_id')->nullable()->after('image_id');
$table->foreign('detail_image_id')->references('id')->on('images')->nullOnDelete();
});
Schema::table('music_playlists', function (Blueprint $table) {
$table->unsignedBigInteger('detail_image_id')->nullable()->after('image_id');
$table->foreign('detail_image_id')->references('id')->on('images')->nullOnDelete();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('media', function (Blueprint $table) {
$table->dropForeign(['detail_image_id']);
$table->dropColumn('detail_image_id');
});
Schema::table('music_playlists', function (Blueprint $table) {
$table->dropForeign(['detail_image_id']);
$table->dropColumn('detail_image_id');
});
}
};