from django.conf import settings from django.db import models from django.utils.text import slugify from django.core.files.storage import get_storage_class import re import logging logger = logging.getLogger(__name__) try: library_storage = get_storage_class(settings.LIBRARY_STORAGE)() except (ImportError, AttributeError): library_storage = get_storage_class()() logger.info("Library storage: %s", library_storage.__class__.__name__) INSTRUMENTS = [ ('Score', 'Score'), ('S', 'Soprano'), ('A', 'Alto'), ('T', 'Tenor'), ('B', 'Bass'), ('V', 'Vocals'), ('Vln', 'Violin'), ('Vla', 'Viola'), ('Vc', 'Violoncello'), ('Cb', 'Contrabass'), ('Fl', 'Flute'), ('Picc', 'Piccolo'), ('Cl', 'Clarinet'), ('Ob', 'Oboe'), ('Hn', 'Horn'), ('Tpt', 'Trumpet'), ('Tbn', 'Trombone'), ('Tuba', 'Tuba'), ('Timp', 'Timpani'), ('Drum', 'Drupset'), ('Perc', 'Percussion'), ('Pno', 'Piano'), ('Hp', 'Harp'), ] ORCHESTRATIONS = { 'SATB': ('S', 'A', 'T', 'B'), 'String Quartet': ('Vln1', 'Vln2', 'Vla', 'Vc'), 'Chamber Orchestra': ('Vln1', 'Vln2', 'Vla', 'Vc', 'Cb', 'Fl1', 'Fl2', 'Cl1', 'Cl2', 'Hn1', 'Hn2', 'Tpt1', 'Tpt2', 'Tbn1', 'Tbn2', 'Tuba', 'Timp', 'Drum', 'Perc'), 'RWE': ('Fl1', 'Fl2', 'Cl', 'Tbn', 'Vln1', 'Vln2', 'Vla', 'Vc'), 'Custom': () } def tag_to_instrument(tag): m = re.match(r'([A-Za-z]+)(\d*)', tag) if not m: return tag l = m.groups() return "{0} {1}".format(dict(INSTRUMENTS).get(l[0],l[0]), l[1]).strip() class Work(models.Model): ensemble = models.ForeignKey('interface.Ensemble', on_delete=models.CASCADE, related_name="works") slug = models.SlugField(max_length=100, editable=False) name = models.CharField(max_length=255) orchestration = models.CharField(max_length=100, choices=[ (k, k) for k, v in ORCHESTRATIONS.items() ]) running_time = models.IntegerField(null=True, blank=True) notes = models.TextField(blank=True) projects = models.ManyToManyField('interface.Project', through='Playlist', related_name="works") class Meta: unique_together = ['ensemble', 'slug'] @property def parts(self): return Part.objects.filter(doc__work=self.pk) @property def instruments(self): tags = ORCHESTRATIONS.get(self.orchestration, 'Custom') return [ (tag, tag_to_instrument(tag)) for tag in tags ] def save(self): if not self.slug: self.slug = slugify(self.name) super(Work, self).save() def __str__(self): return self.name class Playlist(models.Model): project = models.ForeignKey('interface.Project', on_delete=models.CASCADE) work = models.ForeignKey('Work', on_delete=models.CASCADE) order = models.SmallIntegerField(default=0) class Meta: ordering = ['order', 'work'] def __str__(self): return f"<{self.project.slug}:{self.work.slug}>" def upload_filename(instance, filename): return f'{instance.work.ensemble.slug}/works/{instance.work.slug}/{filename}' class Document(models.Model): work = models.ForeignKey('Work', on_delete=models.CASCADE, related_name="docs") upload = models.FileField(upload_to=upload_filename, storage=library_storage) def __str__(self): return self.upload.name class Part(models.Model): doc = models.ForeignKey(Document, on_delete=models.CASCADE, related_name="parts") tag = models.SlugField(max_length=20) start = models.SmallIntegerField(null=True, blank=True) end = models.SmallIntegerField(null=True, blank=True) notes = models.TextField(blank=True) class Meta: ordering = ['doc', 'start', 'pk'] @property def instrument(self): return tag_to_instrument(self.tag) @property def filename(self): return slugify(f'{self.doc.work.name}_{self.instrument}') + '.pdf' @property def pagerange(self): if self.start: if self.end: return f"{self.start}-{self.end}" return str(self.start) return "all" def __str__(self): return f'{self.doc.upload} [{self.pagerange}]'