forked from rc/aircox
		
	work on it
This commit is contained in:
		@ -9,12 +9,12 @@ from .playlist import TracksInline
 | 
				
			|||||||
class SoundAdmin(admin.ModelAdmin):
 | 
					class SoundAdmin(admin.ModelAdmin):
 | 
				
			||||||
    fields = None
 | 
					    fields = None
 | 
				
			||||||
    list_display = ['id', 'name', 'program', 'type', 'duration', 'mtime',
 | 
					    list_display = ['id', 'name', 'program', 'type', 'duration', 'mtime',
 | 
				
			||||||
                    'public', 'good_quality', 'path']
 | 
					                    'is_public', 'is_good_quality', 'path']
 | 
				
			||||||
    list_filter = ('program', 'type', 'good_quality', 'public')
 | 
					    list_filter = ('program', 'type', 'is_good_quality', 'is_public')
 | 
				
			||||||
    fieldsets = [
 | 
					    fieldsets = [
 | 
				
			||||||
        (None, {'fields': ['name', 'path', 'type', 'program', 'diffusion']}),
 | 
					        (None, {'fields': ['name', 'path', 'type', 'program', 'diffusion']}),
 | 
				
			||||||
        (None, {'fields': ['embed', 'duration', 'public', 'mtime']}),
 | 
					        (None, {'fields': ['embed', 'duration', 'is_public', 'mtime']}),
 | 
				
			||||||
        (None, {'fields': ['good_quality']})
 | 
					        (None, {'fields': ['is_good_quality']})
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
    readonly_fields = ('path', 'duration',)
 | 
					    readonly_fields = ('path', 'duration',)
 | 
				
			||||||
    inlines = [TracksInline]
 | 
					    inlines = [TracksInline]
 | 
				
			||||||
 | 
				
			|||||||
@ -327,18 +327,17 @@ class Command(BaseCommand):
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        Check all files where quality has been set to bad
 | 
					        Check all files where quality has been set to bad
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        import aircox.management.commands.sounds_quality_check \
 | 
					        import aircox.management.commands.sounds_quality_check as quality_check
 | 
				
			||||||
            as quality_check
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # get available sound files
 | 
					        # get available sound files
 | 
				
			||||||
        sounds = Sound.objects.filter(good_quality=False) \
 | 
					        sounds = Sound.objects.filter(is_good_quality=False) \
 | 
				
			||||||
                      .exclude(type=Sound.Type.removed)
 | 
					                      .exclude(type=Sound.Type.removed)
 | 
				
			||||||
        if check:
 | 
					        if check:
 | 
				
			||||||
            self.check_sounds(sounds)
 | 
					            self.check_sounds(sounds)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        files = [
 | 
					        files = [
 | 
				
			||||||
            sound.path for sound in sounds
 | 
					            sound.path for sound in sounds
 | 
				
			||||||
            if os.path.exists(sound.path) and sound.good_quality is None
 | 
					            if os.path.exists(sound.path) and sound.is_good_quality is None
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # check quality
 | 
					        # check quality
 | 
				
			||||||
@ -358,7 +357,7 @@ class Command(BaseCommand):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        for sound_info in cmd.good:
 | 
					        for sound_info in cmd.good:
 | 
				
			||||||
            sound = Sound.objects.get(path=sound_info.path)
 | 
					            sound = Sound.objects.get(path=sound_info.path)
 | 
				
			||||||
            sound.good_quality = True
 | 
					            sound.is_good_quality = True
 | 
				
			||||||
            update_stats(sound_info, sound)
 | 
					            update_stats(sound_info, sound)
 | 
				
			||||||
            sound.save(check=False)
 | 
					            sound.save(check=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -326,7 +326,6 @@ class Program(models.Model):
 | 
				
			|||||||
                 .update(path=Concat('path', Substr(F('path'), len(path_))))
 | 
					                 .update(path=Concat('path', Substr(F('path'), len(path_))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class Stream(models.Model):
 | 
					class Stream(models.Model):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    When there are no program scheduled, it is possible to play sounds
 | 
					    When there are no program scheduled, it is possible to play sounds
 | 
				
			||||||
@ -522,74 +521,54 @@ class Schedule(models.Model):
 | 
				
			|||||||
        Return a new datetime with schedule time. Timezone is handled
 | 
					        Return a new datetime with schedule time. Timezone is handled
 | 
				
			||||||
        using `schedule.timezone`.
 | 
					        using `schedule.timezone`.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        time = self.time or self.date
 | 
					        date = tz.datetime.combine(date, self.time)
 | 
				
			||||||
        date = tz.datetime(date.year, date.month, date.day,
 | 
					        return self.tz.normalize(self.tz.localize(date))
 | 
				
			||||||
                           time.hour, time.minute, 0, 0)
 | 
					 | 
				
			||||||
        date = self.tz.localize(date)
 | 
					 | 
				
			||||||
        date = self.tz.normalize(date)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return date
 | 
					    def dates_of_month(self, date):
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def dates_of_month(self, date=None):
 | 
					 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return a list with all matching dates of date.month (=today)
 | 
					        Return a list with all matching dates of date.month (=today)
 | 
				
			||||||
        Ensure timezone awareness.
 | 
					        Ensure timezone awareness.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        :param datetime.date date: month and year
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.frequency == Schedule.Frequency.ponctual:
 | 
					        if self.frequency == Schedule.Frequency.ponctual:
 | 
				
			||||||
            return []
 | 
					            return []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # first day of month
 | 
					        sched_wday, freq = self.date.weekday(), self.frequency
 | 
				
			||||||
        date = utils.date_or_default(date, datetime.date).replace(day=1)
 | 
					        date = date.replace(day=1)
 | 
				
			||||||
        freq = self.frequency
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # last of the month
 | 
					        # last of the month
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if freq == Schedule.Frequency.last:
 | 
					        if freq == Schedule.Frequency.last:
 | 
				
			||||||
            date = date.replace(
 | 
					            date = date.replace(
 | 
				
			||||||
                day=calendar.monthrange(date.year, date.month)[1])
 | 
					                day=calendar.monthrange(date.year, date.month)[1])
 | 
				
			||||||
 | 
					            date_wday = date.weekday()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # end of month before the wanted weekday: move one week back
 | 
					            # end of month before the wanted weekday: move one week back
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if date.weekday() < self.date.weekday():
 | 
					            if date_wday < sched_wday:
 | 
				
			||||||
                date -= tz.timedelta(days=7)
 | 
					                date -= tz.timedelta(days=7)
 | 
				
			||||||
 | 
					            date += tz.timedelta(days=sched_wday - date_wday)
 | 
				
			||||||
            delta = self.date.weekday() - date.weekday()
 | 
					 | 
				
			||||||
            date += tz.timedelta(days=delta)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return [self.normalize(date)]
 | 
					            return [self.normalize(date)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # move to the first day of the month that matches the schedule's weekday
 | 
					        # move to the first day of the month that matches the schedule's weekday
 | 
				
			||||||
        # check on SO#3284452 for the formula
 | 
					        # check on SO#3284452 for the formula
 | 
				
			||||||
        first_weekday = date.weekday()
 | 
					        date_wday, month = date.weekday(), date.month
 | 
				
			||||||
        sched_weekday = self.date.weekday()
 | 
					        date += tz.timedelta(days=(7 if date_wday > sched_wday else 0) -
 | 
				
			||||||
        date += tz.timedelta(days=(7 if first_weekday > sched_weekday else 0)
 | 
					                                   date_wday + sched_wday)
 | 
				
			||||||
                             - first_weekday + sched_weekday)
 | 
					 | 
				
			||||||
        month = date.month
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        dates = []
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if freq == Schedule.Frequency.one_on_two:
 | 
					        if freq == Schedule.Frequency.one_on_two:
 | 
				
			||||||
            # check date base on a diff of dates base on a 14 days delta
 | 
					            # - adjust date with modulo 14 (= 2 weeks in days)
 | 
				
			||||||
            diff = utils.cast_date(date, datetime.date) - \
 | 
					            # - there are max 3 "weeks on two" per month
 | 
				
			||||||
                utils.cast_date(self.date, datetime.date)
 | 
					            if (date - self.date).days % 14:
 | 
				
			||||||
 | 
					 | 
				
			||||||
            if diff.days % 14:
 | 
					 | 
				
			||||||
                date += tz.timedelta(days=7)
 | 
					                date += tz.timedelta(days=7)
 | 
				
			||||||
 | 
					            dates = (date + tz.timedelta(days=14*i) for i in range(0, 3))
 | 
				
			||||||
            while date.month == month:
 | 
					 | 
				
			||||||
                dates.append(date)
 | 
					 | 
				
			||||||
                date += tz.timedelta(days=14)
 | 
					 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            week = 0
 | 
					            dates = (date + tz.timedelta(days=7*week) for week in range(0, 5)
 | 
				
			||||||
 | 
					                     if freq & (0b1 << week))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            while week < 5 and date.month == month:
 | 
					        return [self.normalize(date) for date in dates if date.month == month]
 | 
				
			||||||
                if freq & (0b1 << week):
 | 
					 | 
				
			||||||
                    dates.append(date)
 | 
					 | 
				
			||||||
                date += tz.timedelta(days=7)
 | 
					 | 
				
			||||||
                week += 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return [self.normalize(date) for date in dates]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def diffusions_of_month(self, date=None, exclude_saved=False):
 | 
					    def diffusions_of_month(self, date=None, exclude_saved=False):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
@ -625,6 +604,7 @@ class Schedule(models.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        # FIXME: daylight saving bug: delta misses an hour when diffusion and
 | 
					        # FIXME: daylight saving bug: delta misses an hour when diffusion and
 | 
				
			||||||
        #        rerun are not on the same daylight-saving timezone
 | 
					        #        rerun are not on the same daylight-saving timezone
 | 
				
			||||||
 | 
					        #       -> solution: add rerun=True param, and gen reruns from initial for each
 | 
				
			||||||
        diffusions += [
 | 
					        diffusions += [
 | 
				
			||||||
            Diffusion(
 | 
					            Diffusion(
 | 
				
			||||||
                program=self.program,
 | 
					                program=self.program,
 | 
				
			||||||
@ -922,6 +902,15 @@ class Diffusion(models.Model):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SoundQuerySet(models.QuerySet):
 | 
				
			||||||
 | 
					    def podcasts(self):
 | 
				
			||||||
 | 
					        """ Return sound available as podcasts """
 | 
				
			||||||
 | 
					        return self.filter(Q(embed__isnull=False) | Q(is_public=True))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def diffusion(self, diffusion):
 | 
				
			||||||
 | 
					        return self.filter(diffusion=diffusion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Sound(models.Model):
 | 
					class Sound(models.Model):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    A Sound is the representation of a sound file that can be either an excerpt
 | 
					    A Sound is the representation of a sound file that can be either an excerpt
 | 
				
			||||||
@ -942,10 +931,10 @@ class Sound(models.Model):
 | 
				
			|||||||
        help_text=_('program related to it'),
 | 
					        help_text=_('program related to it'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    diffusion = models.ForeignKey(
 | 
					    diffusion = models.ForeignKey(
 | 
				
			||||||
        'Diffusion',
 | 
					        Diffusion, models.SET_NULL,
 | 
				
			||||||
        verbose_name=_('diffusion'),
 | 
					        verbose_name=_('diffusion'),
 | 
				
			||||||
        blank=True, null=True,
 | 
					        blank=True, null=True,
 | 
				
			||||||
        on_delete=models.SET_NULL,
 | 
					        limit_choices_to={'initial__isnull': True},
 | 
				
			||||||
        help_text=_('initial diffusion related it')
 | 
					        help_text=_('initial diffusion related it')
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    type = models.SmallIntegerField(
 | 
					    type = models.SmallIntegerField(
 | 
				
			||||||
@ -980,17 +969,19 @@ class Sound(models.Model):
 | 
				
			|||||||
        blank=True, null=True,
 | 
					        blank=True, null=True,
 | 
				
			||||||
        help_text=_('last modification date and time'),
 | 
					        help_text=_('last modification date and time'),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    good_quality = models.NullBooleanField(
 | 
					    is_good_quality = models.BooleanField(
 | 
				
			||||||
        _('good quality'),
 | 
					        _('good quality'),
 | 
				
			||||||
        help_text=_('sound\'s quality is okay'),
 | 
					        help_text=_('sound meets quality requirements for diffusion'),
 | 
				
			||||||
        blank=True, null=True
 | 
					        blank=True, null=True
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    public = models.BooleanField(
 | 
					    is_public = models.BooleanField(
 | 
				
			||||||
        _('public'),
 | 
					        _('public'),
 | 
				
			||||||
        default=False,
 | 
					        default=False,
 | 
				
			||||||
        help_text=_('the sound is accessible to the public')
 | 
					        help_text=_('the sound is accessible to the public')
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    objects = SoundQuerySet.as_manager()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_mtime(self):
 | 
					    def get_mtime(self):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Get the last modification date from file
 | 
					        Get the last modification date from file
 | 
				
			||||||
@ -1080,7 +1071,7 @@ class Sound(models.Model):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if self.mtime != mtime:
 | 
					        if self.mtime != mtime:
 | 
				
			||||||
            self.mtime = mtime
 | 
					            self.mtime = mtime
 | 
				
			||||||
            self.good_quality = None
 | 
					            self.is_good_quality = None
 | 
				
			||||||
            logger.info('sound %s: m_time has changed. Reset quality info',
 | 
					            logger.info('sound %s: m_time has changed. Reset quality info',
 | 
				
			||||||
                        self.path)
 | 
					                        self.path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,12 @@ $body-background-color: $light;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** page **/
 | 
					/** page **/
 | 
				
			||||||
.page {
 | 
					.page {
 | 
				
			||||||
    .header {
 | 
					    & > .cover {
 | 
				
			||||||
 | 
					        float: right;
 | 
				
			||||||
 | 
					        max-width: 45%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    & > .header {
 | 
				
			||||||
        margin-bottom: 1.5em;
 | 
					        margin-bottom: 1.5em;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -132,6 +132,10 @@ class Page(StatusModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    objects = PageQueryset.as_manager()
 | 
					    objects = PageQueryset.as_manager()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @property
 | 
				
			||||||
 | 
					    def is_published(self):
 | 
				
			||||||
 | 
					        return self.status == self.STATUS.published
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def path(self):
 | 
					    def path(self):
 | 
				
			||||||
        return reverse(self.detail_url_name, kwargs={'slug': self.slug})
 | 
					        return reverse(self.detail_url_name, kwargs={'slug': self.slug})
 | 
				
			||||||
 | 
				
			|||||||
@ -7165,7 +7165,11 @@ label.panel-block {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
/** page **/
 | 
					/** page **/
 | 
				
			||||||
.page .header {
 | 
					.page > .cover {
 | 
				
			||||||
 | 
					  float: right;
 | 
				
			||||||
 | 
					  max-width: 45%; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.page > .header {
 | 
				
			||||||
  margin-bottom: 1.5em; }
 | 
					  margin-bottom: 1.5em; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.page .headline {
 | 
					.page .headline {
 | 
				
			||||||
 | 
				
			|||||||
@ -41,25 +41,35 @@ Context:
 | 
				
			|||||||
            </nav>
 | 
					            </nav>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div class="container">
 | 
					            <div class="container">
 | 
				
			||||||
                <div class="columns">
 | 
					                <div class="columns is-desktop">
 | 
				
			||||||
                    <main class="column page">
 | 
					                    <main class="column page">
 | 
				
			||||||
                        <header class="header">
 | 
					                        <header class="header">
 | 
				
			||||||
                            {% block header %}
 | 
					                            {% block header %}
 | 
				
			||||||
                            <h1 class="title is-1">{% block title %}{% endblock %}</h1>
 | 
					                            <h1 class="title is-1">{% block title %}{% endblock %}</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            {% if parent %}
 | 
				
			||||||
 | 
					                            <h4 class="subtitle is-size-3">
 | 
				
			||||||
 | 
					                                <a href="{{ parent.path }}">
 | 
				
			||||||
 | 
					                                    ❬ {{ parent.title }}</a></li>
 | 
				
			||||||
 | 
					                            </h4>
 | 
				
			||||||
 | 
					                            {% endif %}
 | 
				
			||||||
                            {% endblock %}
 | 
					                            {% endblock %}
 | 
				
			||||||
                        </header>
 | 
					                        </header>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        {% block main %}{% endblock main %}
 | 
					                        {% block main %}{% endblock main %}
 | 
				
			||||||
                    </main>
 | 
					                    </main>
 | 
				
			||||||
                    <aside class="column is-one-third">
 | 
					                    {% if nav_side %}
 | 
				
			||||||
                        {% block side_nav %}
 | 
					                    <aside class="column is-one-third-desktop">
 | 
				
			||||||
                        {% block cover %}
 | 
					                        {% block cover %}
 | 
				
			||||||
                        {% if cover is not None %}
 | 
					                        {% if cover is not None %}
 | 
				
			||||||
                        <img class="cover" src="{{ cover.url }}" class="cover"/>
 | 
					                        <img class="cover" src="{{ cover.url }}" class="cover"/>
 | 
				
			||||||
                        {% endif %}
 | 
					                        {% endif %}
 | 
				
			||||||
                        {% endblock %}
 | 
					                        {% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        {% block side_nav %}
 | 
				
			||||||
                        {% endblock %}
 | 
					                        {% endblock %}
 | 
				
			||||||
                    </aside>
 | 
					                    </aside>
 | 
				
			||||||
 | 
					                    {% endif %}
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -18,27 +18,27 @@ Context variables:
 | 
				
			|||||||
            class="small-cover">
 | 
					            class="small-cover">
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div class="media-content">
 | 
					    <div class="media-content">
 | 
				
			||||||
        <div>
 | 
					        <h5 class="subtitle is-size-5">
 | 
				
			||||||
            <h5 class="subtitle is-size-5 is-inline-block">
 | 
					 | 
				
			||||||
            {% if d_page %}
 | 
					            {% if d_page %}
 | 
				
			||||||
            <a href="{{ d_page.path }}">{{ d_page.title }}</a>
 | 
					            <a href="{{ d_page.path }}">{{ d_page.title }}</a>
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					        </h5>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <div class="">
 | 
				
			||||||
            {% if not page or p_page != page %}
 | 
					            {% if not page or p_page != page %}
 | 
				
			||||||
                {% if d_page %} — {% endif %}
 | 
					 | 
				
			||||||
            {% if p_page %}
 | 
					            {% if p_page %}
 | 
				
			||||||
            <a href="{{ p_page.path }}" class="has-text-grey-dark">
 | 
					            <a href="{{ p_page.path }}" class="has-text-grey-dark">
 | 
				
			||||||
                {{ p_page.title }}</a>
 | 
					                {{ p_page.title }}</a>
 | 
				
			||||||
            {% else %}
 | 
					            {% else %}
 | 
				
			||||||
            {{ program.name }}
 | 
					            {{ program.name }}
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					            {% if not hide_schedule %} — {% endif %}
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
            </h5>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            {% if not hide_schedule %}
 | 
					            {% if not hide_schedule %}
 | 
				
			||||||
            <time datetime="{{ object.start|date:"c" }}" title="{{ object.start }}"
 | 
					            <time datetime="{{ object.start|date:"c" }}" title="{{ object.start }}"
 | 
				
			||||||
                  class="has-text-weight-light is-size-6">
 | 
					                  class="has-text-weight-light is-size-6">
 | 
				
			||||||
                  — {{ object.start|date:"d M, H:i" }}
 | 
					                  {{ object.start|date:"d M, H:i" }}
 | 
				
			||||||
            </time>
 | 
					            </time>
 | 
				
			||||||
            {% endif %}
 | 
					            {% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										14
									
								
								aircox_web/templates/aircox_web/diffusion_page.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								aircox_web/templates/aircox_web/diffusion_page.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					{% extends "aircox_web/program_base.html" %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block main %}
 | 
				
			||||||
 | 
					{{ block.super }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% if podcasts %}
 | 
				
			||||||
 | 
					{% for object in podcasts %}
 | 
				
			||||||
 | 
					{% include "aircox_web/podcast_item.html" %}
 | 
				
			||||||
 | 
					{% endfor %}
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% endwith %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -12,18 +12,8 @@
 | 
				
			|||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block header %}
 | 
					 | 
				
			||||||
{{ block.super }}
 | 
					 | 
				
			||||||
{% if program %}
 | 
					 | 
				
			||||||
<h4 class="subtitle is-size-3">
 | 
					 | 
				
			||||||
    <a href="{% url "program-page" slug=program.slug %}">❬ {{ program.name }}</a></li>
 | 
					 | 
				
			||||||
</h4>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% block content %}
 | 
					{% block content %}
 | 
				
			||||||
<section class="section">
 | 
					<section>
 | 
				
			||||||
    {% for object in object_list %}
 | 
					    {% for object in object_list %}
 | 
				
			||||||
    {% include "aircox_web/diffusion_item.html" %}
 | 
					    {% include "aircox_web/diffusion_item.html" %}
 | 
				
			||||||
    {% endfor %}
 | 
					    {% endfor %}
 | 
				
			||||||
 | 
				
			|||||||
@ -27,10 +27,4 @@ Context:
 | 
				
			|||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block side_nav %}
 | 
					 | 
				
			||||||
{% if cover is not None %}
 | 
					 | 
				
			||||||
<img class="cover" src="{{ cover.url }}" class="cover"/>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										8
									
								
								aircox_web/templates/aircox_web/podcast_item.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								aircox_web/templates/aircox_web/podcast_item.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					<div class="podcast">
 | 
				
			||||||
 | 
					    {% if object.embed %}
 | 
				
			||||||
 | 
					    {{ object.embed }}
 | 
				
			||||||
 | 
					    {% else %}
 | 
				
			||||||
 | 
					    <audio src="{{ object.url }}" controls>
 | 
				
			||||||
 | 
					    {% endif %}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								aircox_web/templates/aircox_web/program_base.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								aircox_web/templates/aircox_web/program_base.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					{% extends "aircox_web/page.html" %}
 | 
				
			||||||
 | 
					{% load i18n %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% block side_nav %}
 | 
				
			||||||
 | 
					{{ block.super }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{% if diffusions %}
 | 
				
			||||||
 | 
					<section>
 | 
				
			||||||
 | 
					    <h4 class="subtitle is-size-4">{% trans "Last shows" %}</h4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {% for object in diffusions %}
 | 
				
			||||||
 | 
					    {% include "aircox_web/diffusion_item.html" %}
 | 
				
			||||||
 | 
					    {% endfor %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <br>
 | 
				
			||||||
 | 
					    <nav class="pagination is-centered">
 | 
				
			||||||
 | 
					        <ul class="pagination-list">
 | 
				
			||||||
 | 
					            <li>
 | 
				
			||||||
 | 
					                <a href="{% url "diffusion-list" program_slug=page.slug %}"
 | 
				
			||||||
 | 
					                    class="pagination-link"
 | 
				
			||||||
 | 
					                    aria-label="{% trans "Show all diffusions" %}">
 | 
				
			||||||
 | 
					                    {% trans "All diffusions" %}
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					            </li>
 | 
				
			||||||
 | 
					        </ul>
 | 
				
			||||||
 | 
					</section>
 | 
				
			||||||
 | 
					{% endif %}
 | 
				
			||||||
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1,38 +1,8 @@
 | 
				
			|||||||
{% extends "aircox_web/page.html" %}
 | 
					{% extends "aircox_web/program_base.html" %}
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
{% with page.program as program %}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block header %}
 | 
					{% block header %}
 | 
				
			||||||
{{ block.super }}
 | 
					{{ block.super }}
 | 
				
			||||||
{% include "aircox_web/program_header.html" %}
 | 
					{% include "aircox_web/program_header.html" %}
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% block side_nav %}
 | 
					 | 
				
			||||||
{{ block.super }}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% if diffusions %}
 | 
					 | 
				
			||||||
<section>
 | 
					 | 
				
			||||||
    <h4 class="subtitle is-size-4">{% trans "Last shows" %}</h4>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    {% for object in diffusions %}
 | 
					 | 
				
			||||||
    {% include "aircox_web/diffusion_item.html" %}
 | 
					 | 
				
			||||||
    {% endfor %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    <br>
 | 
					 | 
				
			||||||
    <nav class="pagination is-centered">
 | 
					 | 
				
			||||||
        <ul class="pagination-list">
 | 
					 | 
				
			||||||
            <li>
 | 
					 | 
				
			||||||
                <a href="{% url "diffusion-list" program_slug=page.slug %}"
 | 
					 | 
				
			||||||
                    class="pagination-link"
 | 
					 | 
				
			||||||
                    aria-label="{% trans "Show all diffusions" %}">
 | 
					 | 
				
			||||||
                    {% trans "All diffusions" %}
 | 
					 | 
				
			||||||
                </a>
 | 
					 | 
				
			||||||
            </li>
 | 
					 | 
				
			||||||
        </ul>
 | 
					 | 
				
			||||||
</section>
 | 
					 | 
				
			||||||
{% endif %}
 | 
					 | 
				
			||||||
{% endblock %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
{% endwith %}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -1,11 +1,10 @@
 | 
				
			|||||||
from collections import OrderedDict, deque
 | 
					from collections import OrderedDict, deque
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.db.models import Q
 | 
					from django.http import Http404
 | 
				
			||||||
from django.core.paginator import Paginator
 | 
					 | 
				
			||||||
from django.shortcuts import get_object_or_404
 | 
					from django.shortcuts import get_object_or_404
 | 
				
			||||||
from django.utils.translation import ugettext_lazy as _
 | 
					from django.utils.translation import ugettext_lazy as _
 | 
				
			||||||
from django.views.generic import TemplateView, DetailView, ListView
 | 
					from django.views.generic import DetailView, ListView
 | 
				
			||||||
from django.views.generic.base import TemplateResponseMixin, ContextMixin
 | 
					from django.views.generic.base import TemplateResponseMixin, ContextMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from content_editor.contents import contents_for_item
 | 
					from content_editor.contents import contents_for_item
 | 
				
			||||||
@ -36,9 +35,14 @@ def route_page(request, path=None, *args, model=None, site=None, **kwargs):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BaseView(TemplateResponseMixin, ContextMixin):
 | 
					class BaseView(TemplateResponseMixin, ContextMixin):
 | 
				
			||||||
    title = None
 | 
					 | 
				
			||||||
    cover = None
 | 
					 | 
				
			||||||
    site = None
 | 
					    site = None
 | 
				
			||||||
 | 
					    """ Current website """
 | 
				
			||||||
 | 
					    nav_side = False
 | 
				
			||||||
 | 
					    """ Show side navigation """
 | 
				
			||||||
 | 
					    title = None
 | 
				
			||||||
 | 
					    """ Page title """
 | 
				
			||||||
 | 
					    cover = None
 | 
				
			||||||
 | 
					    """ Page cover """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def dispatch(self, request, *args, site=None, **kwargs):
 | 
					    def dispatch(self, request, *args, site=None, **kwargs):
 | 
				
			||||||
        self.site = site if site is not None else \
 | 
					        self.site = site if site is not None else \
 | 
				
			||||||
@ -53,6 +57,7 @@ class BaseView(TemplateResponseMixin, ContextMixin):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        kwargs.setdefault('site', self.site)
 | 
					        kwargs.setdefault('site', self.site)
 | 
				
			||||||
        kwargs.setdefault('cover', self.cover)
 | 
					        kwargs.setdefault('cover', self.cover)
 | 
				
			||||||
 | 
					        kwargs.setdefault('nav_side', self.nav_side)
 | 
				
			||||||
        return super().get_context_data(**kwargs)
 | 
					        return super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -79,31 +84,52 @@ class PageView(BaseView, DetailView):
 | 
				
			|||||||
        return super().get_context_data(**kwargs)
 | 
					        return super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ProgramPageView(PageView):
 | 
					class BaseProgramView(PageView):
 | 
				
			||||||
    """ Base view class for pages. """
 | 
					    """ Base view class for programs and their sub-pages. """
 | 
				
			||||||
 | 
					    nav_side = True
 | 
				
			||||||
 | 
					    list_count=5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_diffusions_queryset(self, program, queryset=None):
 | 
				
			||||||
 | 
					        qs = get_diffusions_with_page() if queryset is None else queryset
 | 
				
			||||||
 | 
					        return qs.before().filter(program=program).order_by('-start')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, program, **kwargs):
 | 
				
			||||||
 | 
					        if not hasattr(program, 'page') or not program.page.is_published:
 | 
				
			||||||
 | 
					            raise Http404
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if 'diffusions' not in kwargs:
 | 
				
			||||||
 | 
					            diffs = self.get_diffusions_queryset(program)[:self.list_count]
 | 
				
			||||||
 | 
					            kwargs['diffusions'] = diffs
 | 
				
			||||||
 | 
					        return super().get_context_data(program=program, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ProgramPageView(BaseProgramView):
 | 
				
			||||||
    template_name = 'aircox_web/program_page.html'
 | 
					    template_name = 'aircox_web/program_page.html'
 | 
				
			||||||
    model = ProgramPage
 | 
					    model = ProgramPage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    list_count=10
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        return super().get_queryset().select_related('program')
 | 
					        return super().get_queryset().select_related('program')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, program=None, diffusions=None, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        program = program or self.object.program
 | 
					        kwargs.setdefault('program', self.object.program)
 | 
				
			||||||
        diffusions = diffusions or \
 | 
					        return super().get_context_data(**kwargs)
 | 
				
			||||||
                     get_diffusions_with_page().filter(program=program)
 | 
					 | 
				
			||||||
        return super().get_context_data(
 | 
					 | 
				
			||||||
            program=program,
 | 
					 | 
				
			||||||
            diffusions=diffusions.order_by('-start')[:self.list_count],
 | 
					 | 
				
			||||||
            **kwargs
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DiffusionPageView(PageView):
 | 
					class DiffusionPageView(BaseProgramView):
 | 
				
			||||||
    # template_name = 'aircox_web/diffusion.html'
 | 
					    template_name = 'aircox_web/program_base.html'
 | 
				
			||||||
    model = DiffusionPage
 | 
					    model = DiffusionPage
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_podcasts(self, diffusion):
 | 
				
			||||||
 | 
					        return aircox.Sound.objects.diffusion(diffusion).podcasts()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        diffusion = self.object.diffusion
 | 
				
			||||||
 | 
					        kwargs.setdefault('program', diffusion.program)
 | 
				
			||||||
 | 
					        kwargs.setdefault('parent', getattr(kwargs['program'], 'page', None))
 | 
				
			||||||
 | 
					        if not 'podcasts' in kwargs:
 | 
				
			||||||
 | 
					            kwargs['podcasts'] = self.get_podcasts(diffusion)
 | 
				
			||||||
 | 
					            print('get prodcasts...', kwargs['podcasts'], diffusion)
 | 
				
			||||||
 | 
					        return super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# TODO: pagination: in template, only a limited number of pages displayed
 | 
					# TODO: pagination: in template, only a limited number of pages displayed
 | 
				
			||||||
@ -133,7 +159,7 @@ class DiffusionsView(BaseView, ListView):
 | 
				
			|||||||
        program = kwargs.setdefault('program', self.program)
 | 
					        program = kwargs.setdefault('program', self.program)
 | 
				
			||||||
        if program is not None and hasattr(program, 'page'):
 | 
					        if program is not None and hasattr(program, 'page'):
 | 
				
			||||||
            kwargs.setdefault('cover', program.page.cover)
 | 
					            kwargs.setdefault('cover', program.page.cover)
 | 
				
			||||||
            kwargs.setdefault('page', program.page)
 | 
					            kwargs.setdefault('parent', program.page)
 | 
				
			||||||
        return super().get_context_data(**kwargs)
 | 
					        return super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user