lib.itmens/music/models.py
2022-11-11 18:40:02 +01:00

266 lines
7.8 KiB
Python

import uuid
import django.contrib.postgres.fields as postgres
from django.utils.translation import gettext_lazy as _
from django.db import models
from django.core.serializers.json import DjangoJSONEncoder
from django.shortcuts import reverse
from common.models import Entity, Mark, Review, Tag, SourceSiteEnum, MarkStatusEnum
from common.utils import ChoicesDictGenerator, GenerateDateUUIDMediaFilePath
from django.utils import timezone
from django.conf import settings
from simple_history.models import HistoricalRecords
MusicMarkStatusTranslation = {
MarkStatusEnum.DO.value: _("在听"),
MarkStatusEnum.WISH.value: _("想听"),
MarkStatusEnum.COLLECT.value: _("听过")
}
def song_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, settings.SONG_MEDIA_PATH_ROOT)
def album_cover_path(instance, filename):
return GenerateDateUUIDMediaFilePath(instance, filename, settings.ALBUM_MEDIA_PATH_ROOT)
class Album(Entity):
title = models.CharField(_("标题"), max_length=500)
release_date = models.DateField(
_('发行日期'), auto_now=False, auto_now_add=False, null=True, blank=True)
cover = models.ImageField(
_("封面"), upload_to=album_cover_path, default=settings.DEFAULT_ALBUM_IMAGE, blank=True)
duration = models.PositiveIntegerField(_("时长"), null=True, blank=True)
artist = postgres.ArrayField(
models.CharField(_("artist"), blank=True,
default='', max_length=200),
null=True,
blank=True,
default=list,
verbose_name=_("艺术家")
)
genre = models.CharField(_("流派"), blank=True,
default='', max_length=100)
company = postgres.ArrayField(
models.CharField(blank=True,
default='', max_length=500),
null=True,
blank=True,
default=list,
verbose_name=_("发行方")
)
track_list = models.TextField(_("曲目"), blank=True, default="")
history = HistoricalRecords()
def __str__(self):
return self.title
def get_json(self):
r = {
'artist': self.artist,
'release_date': self.release_date,
'genre': self.genre,
'publisher': self.company,
}
r.update(super().get_json())
return r
def get_embed_link(self):
if self.source_site == SourceSiteEnum.SPOTIFY.value:
return self.source_url.replace("open.spotify.com/", "open.spotify.com/embed/")
elif self.source_site == SourceSiteEnum.BANDCAMP.value and self.other_info and 'bandcamp_album_id' in self.other_info:
return f"https://bandcamp.com/EmbeddedPlayer/album={self.other_info['bandcamp_album_id']}/size=large/bgcol=ffffff/linkcol=19A2CA/artwork=small/transparent=true/"
else:
return None
def get_absolute_url(self):
return reverse("music:retrieve_album", args=[self.id])
@property
def wish_url(self):
return reverse("music:wish_album", args=[self.id])
def get_tags_manager(self):
return self.album_tags
@property
def verbose_category_name(self):
return _("专辑")
@property
def mark_class(self):
return AlbumMark
@property
def tag_class(self):
return AlbumTag
class Song(Entity):
'''
Song(track) entity, can point to entity Album
'''
title = models.CharField(_("标题"), max_length=500)
release_date = models.DateField(_('发行日期'), auto_now=False, auto_now_add=False, null=True, blank=True)
isrc = models.CharField(_("ISRC"),
blank=True, max_length=15, db_index=True, default='')
# duration in ms
duration = models.PositiveIntegerField(_("时长"), null=True, blank=True)
cover = models.ImageField(
_("封面"), upload_to=song_cover_path, default=settings.DEFAULT_SONG_IMAGE, blank=True)
artist = postgres.ArrayField(
models.CharField(blank=True,
default='', max_length=100),
null=True,
blank=True,
default=list,
verbose_name=_("艺术家")
)
genre = models.CharField(_("流派"), blank=True, default='', max_length=100)
album = models.ForeignKey(
Album, models.SET_NULL, "album_songs", null=True, blank=True, verbose_name=_("所属专辑"))
history = HistoricalRecords()
def __str__(self):
return self.title
def get_json(self):
r = {
'artist': self.artist,
'release_date': self.release_date,
'genre': self.genre,
}
r.update(super().get_json())
return r
def get_embed_link(self):
return self.source_url.replace("open.spotify.com/", "open.spotify.com/embed/") if self.source_site == SourceSiteEnum.SPOTIFY.value else None
def get_absolute_url(self):
return reverse("music:retrieve_song", args=[self.id])
@property
def wish_url(self):
return reverse("music:wish_song", args=[self.id])
def get_tags_manager(self):
return self.song_tags
@property
def verbose_category_name(self):
return _("单曲")
@property
def mark_class(self):
return SongMark
@property
def tag_class(self):
return SongTag
class SongMark(Mark):
song = models.ForeignKey(
Song, on_delete=models.CASCADE, related_name='song_marks', null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['owner', 'song'], name='unique_song_mark')
]
@property
def translated_status(self):
return MusicMarkStatusTranslation[self.status]
class SongReview(Review):
song = models.ForeignKey(
Song, on_delete=models.CASCADE, related_name='song_reviews', null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['owner', 'song'], name='unique_song_review')
]
@property
def url(self):
return reverse("music:retrieve_song_review", args=[self.id])
@property
def item(self):
return self.song
class SongTag(Tag):
song = models.ForeignKey(
Song, on_delete=models.CASCADE, related_name='song_tags', null=True)
mark = models.ForeignKey(
SongMark, on_delete=models.CASCADE, related_name='songmark_tags', null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['content', 'mark'], name="unique_songmark_tag")
]
@property
def item(self):
return self.song
class AlbumMark(Mark):
album = models.ForeignKey(
Album, on_delete=models.CASCADE, related_name='album_marks', null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['owner', 'album'], name='unique_album_mark')
]
@property
def translated_status(self):
return MusicMarkStatusTranslation[self.status]
class AlbumReview(Review):
album = models.ForeignKey(
Album, on_delete=models.CASCADE, related_name='album_reviews', null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['owner', 'album'], name='unique_album_review')
]
@property
def url(self):
return reverse("music:retrieve_album_review", args=[self.id])
@property
def item(self):
return self.album
class AlbumTag(Tag):
album = models.ForeignKey(
Album, on_delete=models.CASCADE, related_name='album_tags', null=True)
mark = models.ForeignKey(
AlbumMark, on_delete=models.CASCADE, related_name='albummark_tags', null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=['content', 'mark'], name="unique_albummark_tag")
]
@property
def item(self):
return self.album