+ @property
+ def url(self):
+ return f'https://wolnelektury.pl/katalog/lektura/{self.slug}/'
+
+ @property
+ def parts_count(self):
+ return type(self).objects.filter(slug=self.slug).count()
+
+ @property
+ def total_duration(self):
+ return type(self).objects.filter(slug=self.slug).aggregate(s=models.Sum('duration'))['s']
+
+ @property
+ def is_first(self):
+ return not type(self).objects.filter(slug=self.slug, index__lte=self.index).exclude(pk=self.pk).exists()
+
+ @property
+ def is_last(self):
+ return not type(self).objects.filter(slug=self.slug, index__gte=self.index).exclude(pk=self.pk).exists()
+
+ @property
+ def youtube_volume_count(self):
+ total = 0
+ prev_volume = None
+ for a in type(self).objects.filter(slug=self.slug).order_by("index"):
+ if not a.youtube_volume or a.youtube_volume != prev_volume:
+ total += 1
+ prev_volume = a.youtube_volume
+ return total
+
+ @property
+ def youtube_volume_index(self):
+ index = 0
+ prev_volume = None
+ for a in type(self).objects.filter(slug=self.slug, index__lte=self.index).order_by("index"):
+ if not a.youtube_volume or a.youtube_volume != prev_volume:
+ index += 1
+ prev_volume = a.youtube_volume
+ return index
+
+ @property
+ def is_youtube_publishable(self):
+ return (
+ not self.youtube_volume
+ or not type(self)
+ .objects.filter(slug=self.slug, youtube_volume=self.youtube_volume, index__lt=self.index)
+ .exists()
+ )
+
+ def youtube_publish(self):
+ if not self.is_youtube_publishable:
+ return False
+ self.youtube_status = status.QUEUED
+ self.youtube_queued = now()
+ self.save(update_fields=['youtube_status', 'youtube_queued'])
+