From 3761b13649e71a71beb6a13b21c9d9a7a13d7f05 Mon Sep 17 00:00:00 2001 From: marwin Date: Mon, 16 Mar 2026 21:01:51 +0100 Subject: [PATCH] Add Django admin, FeaturedStation model, crmfrsh is superuser --- accounts/admin.py | 14 ++++++++ radio/admin.py | 40 +++++++++++++++++++++++ radio/migrations/0005_featured_station.py | 29 ++++++++++++++++ radio/models.py | 16 +++++++++ radio/views.py | 9 ++++- static/css/app.css | 29 ++++++++++++++++ templates/radio/player.html | 16 +++++++++ 7 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 accounts/admin.py create mode 100644 radio/admin.py create mode 100644 radio/migrations/0005_featured_station.py diff --git a/accounts/admin.py b/accounts/admin.py new file mode 100644 index 0000000..bf36f58 --- /dev/null +++ b/accounts/admin.py @@ -0,0 +1,14 @@ +from django.contrib import admin +from .models import UserProfile + + +@admin.register(UserProfile) +class UserProfileAdmin(admin.ModelAdmin): + list_display = ('user', 'lastfm_username', 'lastfm_scrobble', 'has_background') + search_fields = ('user__username', 'lastfm_username') + raw_id_fields = ('user',) + + def has_background(self, obj): + return bool(obj.background_image_data) + has_background.boolean = True + has_background.short_description = 'Background' diff --git a/radio/admin.py b/radio/admin.py new file mode 100644 index 0000000..4a689e5 --- /dev/null +++ b/radio/admin.py @@ -0,0 +1,40 @@ +from django.contrib import admin +from .models import SavedStation, StationPlay, TrackHistory, FocusSession, FeaturedStation + + +@admin.register(FeaturedStation) +class FeaturedStationAdmin(admin.ModelAdmin): + list_display = ('name', 'url', 'tags', 'order', 'active') + list_editable = ('order', 'active') + search_fields = ('name', 'tags') + list_filter = ('active',) + + +@admin.register(SavedStation) +class SavedStationAdmin(admin.ModelAdmin): + list_display = ('name', 'user', 'url', 'is_favorite', 'created_at') + list_filter = ('is_favorite',) + search_fields = ('name', 'user__username', 'url') + raw_id_fields = ('user',) + + +@admin.register(TrackHistory) +class TrackHistoryAdmin(admin.ModelAdmin): + list_display = ('track', 'station_name', 'user', 'played_at', 'scrobbled') + list_filter = ('scrobbled',) + search_fields = ('track', 'station_name', 'user__username') + raw_id_fields = ('user',) + + +@admin.register(StationPlay) +class StationPlayAdmin(admin.ModelAdmin): + list_display = ('station_name', 'user', 'started_at', 'ended_at') + search_fields = ('station_name', 'user__username') + raw_id_fields = ('user',) + + +@admin.register(FocusSession) +class FocusSessionAdmin(admin.ModelAdmin): + list_display = ('user', 'station_name', 'duration_minutes', 'completed_at') + search_fields = ('user__username', 'station_name') + raw_id_fields = ('user',) diff --git a/radio/migrations/0005_featured_station.py b/radio/migrations/0005_featured_station.py new file mode 100644 index 0000000..cc5a948 --- /dev/null +++ b/radio/migrations/0005_featured_station.py @@ -0,0 +1,29 @@ +# Generated by Django 4.2.29 on 2026-03-16 20:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('radio', '0004_focussession'), + ] + + operations = [ + migrations.CreateModel( + name='FeaturedStation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=200)), + ('url', models.URLField(max_length=500)), + ('description', models.CharField(blank=True, max_length=300)), + ('favicon_url', models.URLField(blank=True, max_length=500)), + ('tags', models.CharField(blank=True, max_length=200)), + ('order', models.PositiveIntegerField(default=0)), + ('active', models.BooleanField(default=True)), + ], + options={ + 'ordering': ['order', 'name'], + }, + ), + ] diff --git a/radio/models.py b/radio/models.py index 93ecbb5..c8e23e3 100644 --- a/radio/models.py +++ b/radio/models.py @@ -57,6 +57,22 @@ class FocusSession(models.Model): ordering = ['-completed_at'] +class FeaturedStation(models.Model): + name = models.CharField(max_length=200) + url = models.URLField(max_length=500) + description = models.CharField(max_length=300, blank=True) + favicon_url = models.URLField(max_length=500, blank=True) + tags = models.CharField(max_length=200, blank=True) + order = models.PositiveIntegerField(default=0) + active = models.BooleanField(default=True) + + class Meta: + ordering = ['order', 'name'] + + def __str__(self): + return self.name + + class TrackHistory(models.Model): user = models.ForeignKey( User, null=True, blank=True, on_delete=models.SET_NULL, related_name='track_history' diff --git a/radio/views.py b/radio/views.py index 98d29f3..4659b38 100644 --- a/radio/views.py +++ b/radio/views.py @@ -19,7 +19,7 @@ from django.views.decorators.http import require_http_methods from .icy import stream_icy_metadata from . import lastfm as lastfm_module -from .models import SavedStation, StationPlay, TrackHistory, FocusSession +from .models import SavedStation, StationPlay, TrackHistory, FocusSession, FeaturedStation # --------------------------------------------------------------------------- @@ -54,10 +54,17 @@ def index(request): for entry in history: entry['played_at'] = entry['played_at'].isoformat() + featured = list( + FeaturedStation.objects.filter(active=True).values( + 'id', 'name', 'url', 'description', 'favicon_url', 'tags' + ) + ) + context = { 'saved_stations': saved_stations, 'history': history, 'amazon_enabled': settings.AMAZON_AFFILIATE_ENABLED, + 'featured_stations': featured, } return render(request, 'radio/player.html', context) diff --git a/static/css/app.css b/static/css/app.css index 95c409e..f9e8bc2 100644 --- a/static/css/app.css +++ b/static/css/app.css @@ -955,3 +955,32 @@ body.dnd-mode .timer-display { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(12px); } } + +.featured-section { + padding: 8px 0 12px; + border-bottom: 1px solid var(--border, #333); + margin-bottom: 12px; +} + +.featured-label { + font-size: 0.75rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--muted, #888); + margin: 0 0 8px; +} + +.featured-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 6px; +} + +.featured-list li { + display: flex; + align-items: center; + gap: 8px; +} diff --git a/templates/radio/player.html b/templates/radio/player.html index e341e56..dfcc89a 100644 --- a/templates/radio/player.html +++ b/templates/radio/player.html @@ -74,6 +74,22 @@