forked from rc/aircox
		
	add script to import playlists to sounds or to diffusions
This commit is contained in:
		@ -39,6 +39,11 @@ class Station(programs.Nameable):
 | 
			
		||||
        max_length = 32,
 | 
			
		||||
        choices = [ (name, name) for name in Plugins.registry.keys() ],
 | 
			
		||||
    )
 | 
			
		||||
    active = models.BooleanField(
 | 
			
		||||
        _('active'),
 | 
			
		||||
        default = True,
 | 
			
		||||
        help_text = _('this station is active')
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    plugin = None
 | 
			
		||||
    """
 | 
			
		||||
@ -127,24 +132,22 @@ class Station(programs.Nameable):
 | 
			
		||||
        if self.plugin_name:
 | 
			
		||||
            self.plugin = Plugins.registry.get(self.plugin_name)
 | 
			
		||||
 | 
			
		||||
    def play_logs(self, include_diffusions = True,
 | 
			
		||||
                  include_sounds = True,
 | 
			
		||||
                  exclude_archives = True):
 | 
			
		||||
    def get_played(self, models, archives = True):
 | 
			
		||||
        """
 | 
			
		||||
        Return a queryset with log of played elements on this station.
 | 
			
		||||
        Ordered by date ascending.
 | 
			
		||||
        """
 | 
			
		||||
        models = []
 | 
			
		||||
        if include_diffusions: models.append(programs.Diffusion)
 | 
			
		||||
        if include_sounds: models.append(programs.Sound)
 | 
			
		||||
        Return a queryset with log of played elements on this station,
 | 
			
		||||
        of the given models, ordered by date ascending.
 | 
			
		||||
 | 
			
		||||
        * model: a model or a list of models
 | 
			
		||||
        * archive: if false, exclude log of diffusion's archives from
 | 
			
		||||
            the queryset;
 | 
			
		||||
        """
 | 
			
		||||
        qs = Log.get_for(model = models) \
 | 
			
		||||
                .filter(station = station, type = Log.Type.play)
 | 
			
		||||
        if exclude_archives and self.dealer:
 | 
			
		||||
        if not archives and self.dealer:
 | 
			
		||||
            qs = qs.exclude(
 | 
			
		||||
                source = self.dealer.id_,
 | 
			
		||||
                related_type = ContentType.objects.get_for_model(
 | 
			
		||||
                    program.Sound
 | 
			
		||||
                    programs.Sound
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
        return qs.order_by('date')
 | 
			
		||||
@ -294,7 +297,6 @@ class Source(programs.Nameable):
 | 
			
		||||
            raise ValueError('can not save a dealer source')
 | 
			
		||||
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
        # TODO update controls
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Output (models.Model):
 | 
			
		||||
@ -326,7 +328,7 @@ class Output (models.Model):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Log(models.Model):
 | 
			
		||||
class Log(programs.Related):
 | 
			
		||||
    """
 | 
			
		||||
    Log sounds and diffusions that are played on the station.
 | 
			
		||||
 | 
			
		||||
@ -376,16 +378,6 @@ class Log(models.Model):
 | 
			
		||||
        max_length = 512,
 | 
			
		||||
        blank = True, null = True,
 | 
			
		||||
    )
 | 
			
		||||
    related_type = models.ForeignKey(
 | 
			
		||||
        ContentType,
 | 
			
		||||
        blank = True, null = True,
 | 
			
		||||
    )
 | 
			
		||||
    related_id = models.PositiveIntegerField(
 | 
			
		||||
        blank = True, null = True,
 | 
			
		||||
    )
 | 
			
		||||
    related = GenericForeignKey(
 | 
			
		||||
        'related_type', 'related_id',
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def end(self):
 | 
			
		||||
@ -407,29 +399,6 @@ class Log(models.Model):
 | 
			
		||||
        date = programs.date_or_default(date)
 | 
			
		||||
        return self.end < date
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get_for(cl, object = None, model = None):
 | 
			
		||||
        """
 | 
			
		||||
        Return a queryset that filter on the related object. If object is
 | 
			
		||||
        given, filter using it, otherwise only using model.
 | 
			
		||||
 | 
			
		||||
        If model is not given, uses object's type.
 | 
			
		||||
        """
 | 
			
		||||
        if not model and object:
 | 
			
		||||
            model = type(object)
 | 
			
		||||
 | 
			
		||||
        if type(model) in (list, tuple):
 | 
			
		||||
            model = [ ContentType.objects.get_for_model(m).id
 | 
			
		||||
                        for m in model ]
 | 
			
		||||
            qs = cl.objects.filter(related_type__pk__in = model)
 | 
			
		||||
        else:
 | 
			
		||||
            model = ContentType.objects.get_for_model(model)
 | 
			
		||||
            qs = cl.objects.filter(related_type__pk = model.id)
 | 
			
		||||
 | 
			
		||||
        if object:
 | 
			
		||||
            qs = qs.filter(related_id = object.pk)
 | 
			
		||||
        return qs
 | 
			
		||||
 | 
			
		||||
    def print(self):
 | 
			
		||||
        logger.info('log #%s: %s%s',
 | 
			
		||||
            str(self),
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,11 @@ class Monitor:
 | 
			
		||||
    Monitor should be able to be used after a crash a go back
 | 
			
		||||
    where it was playing, so we heavily use logs to be able to
 | 
			
		||||
    do that.
 | 
			
		||||
 | 
			
		||||
    We keep trace of played items on the generated stream:
 | 
			
		||||
    - sounds played on this stream;
 | 
			
		||||
    - scheduled diffusions
 | 
			
		||||
    - tracks for sounds of streamed programs
 | 
			
		||||
    """
 | 
			
		||||
    station = None
 | 
			
		||||
    controller = None
 | 
			
		||||
@ -22,11 +27,10 @@ class Monitor:
 | 
			
		||||
            self.station.prepare()
 | 
			
		||||
        self.controller = self.station.controller
 | 
			
		||||
 | 
			
		||||
        self.track()
 | 
			
		||||
        self.trace()
 | 
			
		||||
        self.handler()
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def log(**kwargs):
 | 
			
		||||
    def log(self, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
        Create a log using **kwargs, and print info
 | 
			
		||||
        """
 | 
			
		||||
@ -34,10 +38,10 @@ class Monitor:
 | 
			
		||||
        log.save()
 | 
			
		||||
        log.print()
 | 
			
		||||
 | 
			
		||||
    def track(self):
 | 
			
		||||
    def trace(self):
 | 
			
		||||
        """
 | 
			
		||||
        Check the current_sound of the station and update logs if
 | 
			
		||||
        needed
 | 
			
		||||
        needed.
 | 
			
		||||
        """
 | 
			
		||||
        self.controller.fetch()
 | 
			
		||||
        current_sound = self.controller.current_sound
 | 
			
		||||
@ -47,6 +51,11 @@ class Monitor:
 | 
			
		||||
 | 
			
		||||
        log = Log.get_for(model = programs.Sound) \
 | 
			
		||||
                    .filter(station = self.station).order_by('date').last()
 | 
			
		||||
 | 
			
		||||
        # only streamed
 | 
			
		||||
        if log and not log.related.diffusion:
 | 
			
		||||
            self.trace_sound_tracks(log)
 | 
			
		||||
 | 
			
		||||
        # TODO: expiration
 | 
			
		||||
        if log and (log.source == current_source.id_ and \
 | 
			
		||||
                    log.related.path == current_sound):
 | 
			
		||||
@ -56,12 +65,37 @@ class Monitor:
 | 
			
		||||
        self.log(
 | 
			
		||||
            type = Log.Type.play,
 | 
			
		||||
            source = current_source.id_,
 | 
			
		||||
            date = tz.make_aware(tz.datetime.now()),
 | 
			
		||||
 | 
			
		||||
            date = tz.now(),
 | 
			
		||||
            related = sound[0] if sound else None,
 | 
			
		||||
            comment = None if sound else current_sound,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def trace_sound_tracks(self, log):
 | 
			
		||||
        """
 | 
			
		||||
        Log tracks for the given sound (for streamed programs); Called by
 | 
			
		||||
        self.trace
 | 
			
		||||
        """
 | 
			
		||||
        logs = Log.get_for(model = programs.Track) \
 | 
			
		||||
                  .filter(pk__gt = log.pk)
 | 
			
		||||
        logs = [ log.pk for log in logs ]
 | 
			
		||||
 | 
			
		||||
        tracks = programs.Track.get_for(object = log.related)
 | 
			
		||||
                               .filter(pos_in_sec = True)
 | 
			
		||||
        if len(tracks) == len(logs):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        tracks = tracks.exclude(pk__in = logs).order_by('pos')
 | 
			
		||||
        now = tz.now()
 | 
			
		||||
        for track in tracks:
 | 
			
		||||
            pos = log.date + tz.timedelta(seconds = track.pos)
 | 
			
		||||
            if pos < now:
 | 
			
		||||
                self.log(
 | 
			
		||||
                    type = Log.Type.play,
 | 
			
		||||
                    source = log.source,
 | 
			
		||||
                    date = pos,
 | 
			
		||||
                    related = track
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
    def __current_diff(self):
 | 
			
		||||
        """
 | 
			
		||||
        Return a tuple with the currently running diffusion and the items
 | 
			
		||||
@ -70,24 +104,23 @@ class Monitor:
 | 
			
		||||
        station = self.station
 | 
			
		||||
        now = tz.make_aware(tz.datetime.now())
 | 
			
		||||
 | 
			
		||||
        diff_log = Log.get_for(model = programs.Diffusion) \
 | 
			
		||||
                        .filter(station = station, type = Log.Type.play) \
 | 
			
		||||
                        .order_by('date').last()
 | 
			
		||||
        diff_log = station.get_played(models = programs.Diffusion) \
 | 
			
		||||
                          .order_by('date').last()
 | 
			
		||||
 | 
			
		||||
        if not diff_log or \
 | 
			
		||||
                not diff_log.related.is_date_in_my_range(now):
 | 
			
		||||
            return None, []
 | 
			
		||||
 | 
			
		||||
        # sound has switched? assume it has been (forced to) stopped
 | 
			
		||||
        sound_log = Log.get_for(model = programs.Sound) \
 | 
			
		||||
                        .filter(station = station).order_by('date').last()
 | 
			
		||||
        if sound_log and sound_log.source != diff_log.source:
 | 
			
		||||
        sounds = station.get_played(models = programs.Sound)
 | 
			
		||||
        last_sound = sounds.order_by('date').last()
 | 
			
		||||
        if last_sound and last_sound.source != diff_log.source:
 | 
			
		||||
            return None, []
 | 
			
		||||
 | 
			
		||||
        # last diff is still playing: get the remaining playlist
 | 
			
		||||
        sounds = Log.get_for(model = programs.Sound) \
 | 
			
		||||
                    .filter(station = station, source = diff_log.source) \
 | 
			
		||||
                    .filter(pk__gt = diff.log.pk)
 | 
			
		||||
        sounds = sounds.filter(
 | 
			
		||||
            source = diff_log.source, pk__gt = diff_log.pk
 | 
			
		||||
        )
 | 
			
		||||
        sounds = [ sound.path for sound in sounds if not sound.removed ]
 | 
			
		||||
 | 
			
		||||
        return (
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user