forked from rc/aircox
		
	fix error in streamer and on_air
This commit is contained in:
		@ -54,10 +54,18 @@ class Monitor:
 | 
			
		||||
    Datetime of the next sync
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    _last_log = None
 | 
			
		||||
    """
 | 
			
		||||
    Last emitted log
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, station, **kwargs):
 | 
			
		||||
        self.station = station
 | 
			
		||||
        self.__dict__.update(kwargs)
 | 
			
		||||
 | 
			
		||||
        self._last_log = Log.objects.station(station).order_by('date') \
 | 
			
		||||
                            .last()
 | 
			
		||||
 | 
			
		||||
    def monitor(self):
 | 
			
		||||
        """
 | 
			
		||||
        Run all monitoring functions.
 | 
			
		||||
@ -81,6 +89,12 @@ class Monitor:
 | 
			
		||||
        log.save()
 | 
			
		||||
        log.print()
 | 
			
		||||
 | 
			
		||||
        # update last log
 | 
			
		||||
        if log.type != Log.Type.other and \
 | 
			
		||||
                self._last_log and not self._last_log.end:
 | 
			
		||||
            self._last_log.end = log.date
 | 
			
		||||
        self._last_log = log
 | 
			
		||||
 | 
			
		||||
    def trace(self):
 | 
			
		||||
        """
 | 
			
		||||
        Check the current_sound of the station and update logs if
 | 
			
		||||
@ -106,12 +120,12 @@ class Monitor:
 | 
			
		||||
                log.sound.path == current_sound):
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        sound = Sound.objects.filter(path = current_sound)
 | 
			
		||||
        sound = Sound.objects.filter(path = current_sound).first()
 | 
			
		||||
        self.log(
 | 
			
		||||
            type = Log.Type.play,
 | 
			
		||||
            type = Log.Type.on_air,
 | 
			
		||||
            source = current_source.id,
 | 
			
		||||
            date = tz.now(),
 | 
			
		||||
            sound = sound[0] if sound else None,
 | 
			
		||||
            sound = sound,
 | 
			
		||||
            # keep sound path (if sound is removed, we keep that info)
 | 
			
		||||
            comment = current_sound,
 | 
			
		||||
        )
 | 
			
		||||
@ -135,14 +149,13 @@ class Monitor:
 | 
			
		||||
        now = tz.now()
 | 
			
		||||
        for track in tracks:
 | 
			
		||||
            pos = log.date + tz.timedelta(seconds = track.position)
 | 
			
		||||
            if pos < now:
 | 
			
		||||
                self.log(
 | 
			
		||||
                    type = Log.Type.play,
 | 
			
		||||
                    source = log.source,
 | 
			
		||||
                    date = pos,
 | 
			
		||||
                    track = track,
 | 
			
		||||
                    comment = track,
 | 
			
		||||
                )
 | 
			
		||||
            if pos > now:
 | 
			
		||||
                break
 | 
			
		||||
            self.log(
 | 
			
		||||
                type = Log.Type.on_air, source = log.source,
 | 
			
		||||
                date = pos, track = track,
 | 
			
		||||
                comment = track,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
    def sync_playlists(self):
 | 
			
		||||
        """
 | 
			
		||||
@ -243,11 +256,16 @@ class Monitor:
 | 
			
		||||
        it is needed.
 | 
			
		||||
        """
 | 
			
		||||
        dealer = self.station.dealer
 | 
			
		||||
        if dealer.playlist != playlist:
 | 
			
		||||
            dealer.playlist = playlist
 | 
			
		||||
            if diff and not diff.is_live():
 | 
			
		||||
                self.log(type = Log.Type.load, source = source.id,
 | 
			
		||||
                         diffusion = diff, date = date)
 | 
			
		||||
        if dealer.playlist == playlist:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        dealer.playlist = playlist
 | 
			
		||||
        if diff and not diff.is_live():
 | 
			
		||||
            self.log(type = Log.Type.load,
 | 
			
		||||
                     source = source.id,
 | 
			
		||||
                     diffusion = diff,
 | 
			
		||||
                     date = date,
 | 
			
		||||
                     comment = '\n'.join(playlist))
 | 
			
		||||
 | 
			
		||||
    def handle_diff_start(self, source, diff, date):
 | 
			
		||||
        """
 | 
			
		||||
@ -257,18 +275,22 @@ class Monitor:
 | 
			
		||||
        if not diff or diff.start > date:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # TODO: user has not yet put the diffusion sound when diff started
 | 
			
		||||
        #       => live logged; what we want: if user put a sound after it
 | 
			
		||||
        #       has been logged as live, load and start this sound
 | 
			
		||||
 | 
			
		||||
        # live: just log it
 | 
			
		||||
        if diff.is_live():
 | 
			
		||||
            diff_ = Log.objects.station(self.station) \
 | 
			
		||||
                       .filter(diffusion = diff)
 | 
			
		||||
                       .filter(diffusion = diff, type = Log.Type.on_air)
 | 
			
		||||
            if not diff_.count():
 | 
			
		||||
                self.log(type = Log.Type.on_air, source = source.id,
 | 
			
		||||
                         diffusion = diff, date = date)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        # enable dealer
 | 
			
		||||
        if not dealer.active:
 | 
			
		||||
            dealer.active = True
 | 
			
		||||
        if not source.active:
 | 
			
		||||
            source.active = True
 | 
			
		||||
            self.log(type = Log.Type.play, source = source.id,
 | 
			
		||||
                     diffusion = diff, date = date)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -278,7 +278,7 @@ class Station(Nameable):
 | 
			
		||||
        for diff in diffs:
 | 
			
		||||
            if count and n >= count:
 | 
			
		||||
                break
 | 
			
		||||
            q = q | models.Q(date__gte = diff.start, date__lte = diff.end)
 | 
			
		||||
            q = q | models.Q(date__gte = diff.start, end__lte = diff.end)
 | 
			
		||||
            n += 1
 | 
			
		||||
        logs = logs.exclude(q, diffusion__isnull = True)
 | 
			
		||||
 | 
			
		||||
@ -1197,6 +1197,8 @@ class LogManager(models.Manager):
 | 
			
		||||
    def _at(self, date = None, qs = None, **kwargs):
 | 
			
		||||
        start, end = utils.date_range(date)
 | 
			
		||||
        qs = self if qs is None else qs
 | 
			
		||||
        # return qs.filter(models.Q(end__gte = start) |
 | 
			
		||||
        #                 models.Q(date__lte = end))
 | 
			
		||||
        return qs.filter(date__gte = start, date__lte = end, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def at(self, station = None, date = None, qs = None, **kwargs):
 | 
			
		||||
@ -1207,8 +1209,7 @@ class LogManager(models.Manager):
 | 
			
		||||
        qs = self._at(date, qs, **kwargs)
 | 
			
		||||
        return self.station(station, qs) if station else qs
 | 
			
		||||
 | 
			
		||||
    def played(self, station, archives = True, include_live = True,
 | 
			
		||||
                **kwargs):
 | 
			
		||||
    def played(self, station, archives = True, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
        Return a queryset of the played elements' log for the given
 | 
			
		||||
        station and model. This queryset is ordered by date ascending
 | 
			
		||||
@ -1219,11 +1220,8 @@ class LogManager(models.Manager):
 | 
			
		||||
        * include_live: include diffusion that have no archive
 | 
			
		||||
        * kwargs: extra filter kwargs
 | 
			
		||||
        """
 | 
			
		||||
        if include_live:
 | 
			
		||||
            qs = self.filter(type__in = (Log.Type.play, Log.Type.on_air),
 | 
			
		||||
                             **kwargs)
 | 
			
		||||
        else:
 | 
			
		||||
            qs = self.filter(type = Log.Type.play, **kwargs)
 | 
			
		||||
        qs = self.filter(type__in = (Log.Type.play, Log.Type.on_air),
 | 
			
		||||
                         **kwargs)
 | 
			
		||||
 | 
			
		||||
        if not archives and station.dealer:
 | 
			
		||||
            qs = qs.exclude(
 | 
			
		||||
@ -1247,9 +1245,8 @@ class Log(models.Model):
 | 
			
		||||
        """
 | 
			
		||||
        play = 0x01
 | 
			
		||||
        """
 | 
			
		||||
        Source has been started/changed and is running related_object
 | 
			
		||||
        If no related_object is available, comment is used to designate
 | 
			
		||||
        the sound.
 | 
			
		||||
        The related item has been started by the streamer or manually,
 | 
			
		||||
        and occured on air.
 | 
			
		||||
        """
 | 
			
		||||
        load = 0x02
 | 
			
		||||
        """
 | 
			
		||||
@ -1257,7 +1254,7 @@ class Log(models.Model):
 | 
			
		||||
        """
 | 
			
		||||
        on_air = 0x03
 | 
			
		||||
        """
 | 
			
		||||
        A diffusion occured, but in live (no sound played by Aircox)
 | 
			
		||||
        The related item has been detected occuring on air
 | 
			
		||||
        """
 | 
			
		||||
        other = 0x04
 | 
			
		||||
        """
 | 
			
		||||
@ -1287,6 +1284,12 @@ class Log(models.Model):
 | 
			
		||||
        default=tz.now,
 | 
			
		||||
        db_index = True,
 | 
			
		||||
    )
 | 
			
		||||
    # date of the next diffusion: used in order to ease on_air algo's
 | 
			
		||||
    end = models.DateTimeField(
 | 
			
		||||
        _('end'),
 | 
			
		||||
        default=tz.now,
 | 
			
		||||
        db_index = True,
 | 
			
		||||
    )
 | 
			
		||||
    comment = models.CharField(
 | 
			
		||||
        _('comment'),
 | 
			
		||||
        max_length = 512,
 | 
			
		||||
@ -1314,15 +1317,14 @@ class Log(models.Model):
 | 
			
		||||
 | 
			
		||||
    objects = LogManager()
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def end(self):
 | 
			
		||||
    def estimate_end(self):
 | 
			
		||||
        """
 | 
			
		||||
        Calculated end using self.related informations
 | 
			
		||||
        """
 | 
			
		||||
        if self.diffusion:
 | 
			
		||||
            return self.diffusion.end
 | 
			
		||||
        if self.sound:
 | 
			
		||||
            return self.date + to_timedelta(sound.duration)
 | 
			
		||||
            return self.date + utils.to_timedelta(self.sound.duration)
 | 
			
		||||
        return self.date
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
@ -1347,7 +1349,6 @@ class Log(models.Model):
 | 
			
		||||
        if self.track:
 | 
			
		||||
            r.append('track: ' + str(self.track_id))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        logger.info('log #%s: %s%s',
 | 
			
		||||
            str(self),
 | 
			
		||||
            self.comment or '',
 | 
			
		||||
@ -1359,3 +1360,8 @@ class Log(models.Model):
 | 
			
		||||
                self.pk, self.date.strftime('%Y/%m/%d %H:%M'), self.source
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        if not self.end:
 | 
			
		||||
            self.end = self.estimate_end()
 | 
			
		||||
        return super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,9 @@ from django.conf import settings
 | 
			
		||||
def ensure (key, default):
 | 
			
		||||
    globals()[key] = getattr(settings, key, default)
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Global & misc
 | 
			
		||||
########################################################################
 | 
			
		||||
# group to assign to users at their creation, along with the permissions
 | 
			
		||||
# to add to each group.
 | 
			
		||||
ensure('AIRCOX_DEFAULT_USER_GROUPS', {
 | 
			
		||||
@ -23,6 +26,24 @@ ensure('AIRCOX_DEFAULT_USER_GROUPS', {
 | 
			
		||||
ensure('AIRCOX_PROGRAMS_DIR',
 | 
			
		||||
       os.path.join(settings.MEDIA_ROOT, 'programs'))
 | 
			
		||||
 | 
			
		||||
# Directory for working data
 | 
			
		||||
ensure('AIRCOX_DATA_DIR',
 | 
			
		||||
       os.path.join(settings.PROJECT_ROOT, 'data'))
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Logs & Archives
 | 
			
		||||
########################################################################
 | 
			
		||||
# Directory where to save logs' archives
 | 
			
		||||
ensure('AIRCOX_LOGS_ARCHIVES_DIR',
 | 
			
		||||
       os.path.join(AIRCOX_DATA_DIR, 'archives')
 | 
			
		||||
)
 | 
			
		||||
# In days, minimal age of a log before it is archived
 | 
			
		||||
ensure('AIRCOX_LOGS_ARCHIVES_MIN_AGE', 60)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Sounds
 | 
			
		||||
########################################################################
 | 
			
		||||
# Default directory for the sounds that not linked to a program
 | 
			
		||||
ensure('AIRCOX_SOUND_DEFAULT_DIR',
 | 
			
		||||
       os.path.join(AIRCOX_PROGRAMS_DIR, 'defaults')),
 | 
			
		||||
@ -54,22 +75,26 @@ ensure(
 | 
			
		||||
    ('.ogg','.flac','.wav','.mp3','.opus')
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
# Stream for the scheduled diffusions
 | 
			
		||||
ensure('AIRCOX_SCHEDULED_STREAM', 0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Import playlist: columns for CSV file
 | 
			
		||||
ensure(
 | 
			
		||||
    'AIRCOX_IMPORT_PLAYLIST_CSV_COLS',
 | 
			
		||||
    ('artist', 'title', 'minutes', 'seconds', 'tags', 'info')
 | 
			
		||||
)
 | 
			
		||||
# Import playlist: column delimiter of csv text files
 | 
			
		||||
ensure('AIRCOX_IMPORT_PLAYLIST_CSV_DELIMITER', ';')
 | 
			
		||||
# Import playlist: text delimiter of csv text files
 | 
			
		||||
ensure('AIRCOX_IMPORT_PLAYLIST_CSV_TEXT_QUOTE', '"')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Streamer & Controllers
 | 
			
		||||
########################################################################
 | 
			
		||||
# Controllers working directory
 | 
			
		||||
ensure('AIRCOX_CONTROLLERS_WORKING_DIR', '/tmp/aircox')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
########################################################################
 | 
			
		||||
# Playlist import from CSV
 | 
			
		||||
########################################################################
 | 
			
		||||
# Columns for CSV file
 | 
			
		||||
ensure(
 | 
			
		||||
    'AIRCOX_IMPORT_PLAYLIST_CSV_COLS',
 | 
			
		||||
    ('artist', 'title', 'minutes', 'seconds', 'tags', 'info')
 | 
			
		||||
)
 | 
			
		||||
# Column delimiter of csv text files
 | 
			
		||||
ensure('AIRCOX_IMPORT_PLAYLIST_CSV_DELIMITER', ';')
 | 
			
		||||
# Text delimiter of csv text files
 | 
			
		||||
ensure('AIRCOX_IMPORT_PLAYLIST_CSV_TEXT_QUOTE', '"')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -37,14 +37,17 @@ def on_air(request):
 | 
			
		||||
    station = request.GET.get('station');
 | 
			
		||||
    if station:
 | 
			
		||||
        station = stations.stations.filter(name = station)
 | 
			
		||||
        if not station.count():
 | 
			
		||||
            return HttpResponse('')
 | 
			
		||||
    else:
 | 
			
		||||
        station = stations.stations.first()
 | 
			
		||||
        station = stations.stations
 | 
			
		||||
 | 
			
		||||
    station = station.first()
 | 
			
		||||
    on_air = station.on_air(count = 10).select_related('track','diffusion')
 | 
			
		||||
    if not on_air.count():
 | 
			
		||||
        return HttpResponse('')
 | 
			
		||||
 | 
			
		||||
    last = on_air.last()
 | 
			
		||||
    last = on_air.first()
 | 
			
		||||
    if last.track:
 | 
			
		||||
        last = {
 | 
			
		||||
            'type': 'track',
 | 
			
		||||
 | 
			
		||||
@ -185,7 +185,7 @@ def diffusion_post_saved(sender, instance, created, *args, **kwargs):
 | 
			
		||||
            page.save()
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if instance.page:
 | 
			
		||||
    if hasattr(instance, 'page'):
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    page = models.DiffusionPage.from_diffusion(
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user