funkwhale/api/funkwhale_api/playlists/models.py

120 wiersze
4.3 KiB
Python
Czysty Zwykły widok Historia

from django.conf import settings
from django.db import models
from django.db import transaction
from django.utils import timezone
from rest_framework import exceptions
from funkwhale_api.common import fields
class Playlist(models.Model):
name = models.CharField(max_length=50)
2017-12-15 23:36:06 +00:00
user = models.ForeignKey(
'users.User', related_name="playlists", on_delete=models.CASCADE)
creation_date = models.DateTimeField(default=timezone.now)
modification_date = models.DateTimeField(
auto_now=True)
privacy_level = fields.get_privacy_field()
def __str__(self):
return self.name
@transaction.atomic
def insert(self, plt, index=None):
"""
Given a PlaylistTrack, insert it at the correct index in the playlist,
and update other tracks index if necessary.
"""
old_index = plt.index
move = old_index is not None
if index is not None and index == old_index:
# moving at same position, just skip
return index
existing = self.playlist_tracks.select_for_update()
if move:
existing = existing.exclude(pk=plt.pk)
total = existing.filter(index__isnull=False).count()
if index is None:
# we simply increment the last track index by 1
index = total
if index > total:
raise exceptions.ValidationError('Index is not continuous')
if index < 0:
raise exceptions.ValidationError('Index must be zero or positive')
if move:
# we remove the index temporarily, to avoid integrity errors
plt.index = None
plt.save(update_fields=['index'])
if index > old_index:
# new index is higher than current, we decrement previous tracks
to_update = existing.filter(
index__gt=old_index, index__lte=index)
to_update.update(index=models.F('index') - 1)
if index < old_index:
# new index is lower than current, we increment next tracks
to_update = existing.filter(index__lt=old_index, index__gte=index)
to_update.update(index=models.F('index') + 1)
else:
to_update = existing.filter(index__gte=index)
to_update.update(index=models.F('index') + 1)
plt.index = index
plt.save(update_fields=['index'])
self.save(update_fields=['modification_date'])
return index
@transaction.atomic
def remove(self, index):
existing = self.playlist_tracks.select_for_update()
self.save(update_fields=['modification_date'])
to_update = existing.filter(index__gt=index)
return to_update.update(index=models.F('index') - 1)
@transaction.atomic
def insert_many(self, tracks):
existing = self.playlist_tracks.select_for_update()
now = timezone.now()
total = existing.filter(index__isnull=False).count()
if existing.count() + len(tracks) > settings.PLAYLISTS_MAX_TRACKS:
raise exceptions.ValidationError(
'Playlist would reach the maximum of {} tracks'.format(
settings.PLAYLISTS_MAX_TRACKS))
self.save(update_fields=['modification_date'])
start = total
plts = [
PlaylistTrack(
creation_date=now, playlist=self, track=track, index=start+i)
for i, track in enumerate(tracks)
]
return PlaylistTrack.objects.bulk_create(plts)
class PlaylistTrack(models.Model):
2017-12-15 23:36:06 +00:00
track = models.ForeignKey(
'music.Track',
related_name='playlist_tracks',
on_delete=models.CASCADE)
index = models.PositiveIntegerField(null=True, blank=True)
2017-12-15 23:36:06 +00:00
playlist = models.ForeignKey(
Playlist, related_name='playlist_tracks', on_delete=models.CASCADE)
creation_date = models.DateTimeField(default=timezone.now)
class Meta:
2018-03-19 13:06:51 +00:00
ordering = ('-playlist', 'index')
unique_together = ('playlist', 'index')
def delete(self, *args, **kwargs):
playlist = self.playlist
index = self.index
update_indexes = kwargs.pop('update_indexes', False)
r = super().delete(*args, **kwargs)
if index is not None and update_indexes:
playlist.remove(index)
return r