soundwave/backend/audio/models_local.py

150 lines
4.7 KiB
Python
Raw Permalink Normal View History

"""Models for user-uploaded local audio files"""
from django.db import models
from django.contrib.auth import get_user_model
import os
User = get_user_model()
class LocalAudio(models.Model):
"""User-uploaded local audio files"""
owner = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='local_audio_files',
help_text="User who uploaded this file"
)
# File info
title = models.CharField(max_length=500)
artist = models.CharField(max_length=200, blank=True)
album = models.CharField(max_length=200, blank=True)
year = models.IntegerField(null=True, blank=True)
genre = models.CharField(max_length=100, blank=True)
track_number = models.IntegerField(null=True, blank=True)
# File details
file = models.FileField(upload_to='local_audio/%Y/%m/', max_length=500)
file_size = models.BigIntegerField(help_text="File size in bytes")
duration = models.IntegerField(null=True, blank=True, help_text="Duration in seconds")
# Audio properties
audio_format = models.CharField(max_length=20, blank=True) # mp3, flac, m4a, etc.
bitrate = models.IntegerField(null=True, blank=True, help_text="Bitrate in kbps")
sample_rate = models.IntegerField(null=True, blank=True, help_text="Sample rate in Hz")
channels = models.IntegerField(null=True, blank=True, help_text="Number of audio channels")
# Cover art
cover_art = models.ImageField(upload_to='local_audio_covers/%Y/%m/', null=True, blank=True)
# Metadata
original_filename = models.CharField(max_length=500)
uploaded_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
# Playback tracking
play_count = models.IntegerField(default=0)
last_played = models.DateTimeField(null=True, blank=True)
# Tags and organization
tags = models.JSONField(default=list, blank=True, help_text="User-defined tags")
notes = models.TextField(blank=True, help_text="User notes about this file")
# Favorites
is_favorite = models.BooleanField(default=False)
class Meta:
ordering = ['-uploaded_date']
indexes = [
models.Index(fields=['owner', '-uploaded_date']),
models.Index(fields=['owner', 'is_favorite']),
models.Index(fields=['owner', 'artist']),
models.Index(fields=['owner', 'album']),
]
def __str__(self):
return f"{self.owner.username} - {self.title}"
@property
def file_size_mb(self):
"""Get file size in MB"""
return self.file_size / (1024 * 1024)
@property
def duration_formatted(self):
"""Get formatted duration (MM:SS)"""
if not self.duration:
return "00:00"
minutes = self.duration // 60
seconds = self.duration % 60
return f"{minutes:02d}:{seconds:02d}"
def delete(self, *args, **kwargs):
"""Override delete to remove files"""
# Delete the audio file
if self.file:
if os.path.isfile(self.file.path):
os.remove(self.file.path)
# Delete cover art
if self.cover_art:
if os.path.isfile(self.cover_art.path):
os.remove(self.cover_art.path)
super().delete(*args, **kwargs)
class LocalAudioPlaylist(models.Model):
"""Playlists for local audio files"""
owner = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='local_playlists'
)
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
# Playlist image
cover_image = models.ImageField(upload_to='local_playlist_covers/', null=True, blank=True)
# Timestamps
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_date']
indexes = [
models.Index(fields=['owner', '-created_date']),
]
def __str__(self):
return f"{self.owner.username} - {self.title}"
class LocalAudioPlaylistItem(models.Model):
"""Items in local audio playlist"""
playlist = models.ForeignKey(
LocalAudioPlaylist,
on_delete=models.CASCADE,
related_name='items'
)
audio = models.ForeignKey(
LocalAudio,
on_delete=models.CASCADE,
related_name='playlist_items'
)
position = models.IntegerField(default=0)
added_date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['position']
unique_together = ('playlist', 'audio')
def __str__(self):
return f"{self.playlist.title} - {self.audio.title}"