import os import uuid from io import BytesIO from PIL import Image from django.db import models from core.models import BaseModel def album_cover_upload_to(instance, filename): ext = filename.split(".")[-1] return os.path.join("album_covers", f"{uuid.uuid4()}.{ext}") def artist_cover_upload_to(instance, filename): ext = filename.split(".")[-1] return os.path.join("artist_covers", f"{uuid.uuid4()}.{ext}") def track_upload_to(instance, filename): return os.path.join( "music", f"album_{instance.album_id}", filename, ) class Artist(BaseModel): name = models.CharField(max_length=200) cover_image = models.ImageField( upload_to=artist_cover_upload_to, null=True, blank=True ) def __str__(self): return f"{self.name}" class Album(BaseModel): artist = models.ForeignKey(Artist, on_delete=models.CASCADE, related_name="albums") name = models.CharField(max_length=200) release_date = models.PositiveSmallIntegerField(default=0) cover_image = models.ImageField( upload_to=album_cover_upload_to, null=True, blank=True ) preview_image = models.ImageField(null=True, blank=True) def __str__(self): return f"{self.artist} - {self.name}" def create_preview_image(self): # Placeholder for preview image creation logic img = Image.open(self.cover_image) target_height = 256 target_width = int((target_height / img.height) * img.width) img = img.resize((target_width, target_height), Image.LANCZOS) buffer = BytesIO() img.save(buffer, format="JPEG") buffer.seek(0) self.preview_image.save( os.path.join("album_previews", f"{uuid.uuid4()}.jpg"), buffer, save=False, ) buffer.close() def save(self, *args, **kwargs): if not self.preview_image and self.cover_image: self.create_preview_image() super().save(*args, **kwargs) class Track(BaseModel): title = models.CharField(max_length=200) album = models.ForeignKey(Album, on_delete=models.CASCADE, related_name="tracks") file = models.FileField(upload_to=track_upload_to) def __str__(self): return f"{self.album.artist} - {self.title}" class Playlist(BaseModel): name = models.CharField(max_length=200) tracks = models.ManyToManyField(Track, related_name="playlists") def __str__(self): return f"Playlist: {self.name}" class RecommendationPlaylist(BaseModel): class Meta: constraints = [ models.UniqueConstraint( fields=["is_actual"], condition=models.Q(is_actual=True), name="unique_actual_recommendation_playlist", ) ] name = models.CharField(max_length=200) description = models.TextField(blank=True) playlist = models.ForeignKey( Playlist, on_delete=models.CASCADE, related_name="recommendations" ) is_actual = models.BooleanField(default=False) def __str__(self): return f"Recommendation Playlist: {self.name}" def switch_actual(self): if not self.is_actual: (RecommendationPlaylist.objects .filter(is_actual=True) .update(is_actual=False)) self.is_actual = True self.save()