Lili Records v1.11
This commit is contained in:
parent
832958c654
commit
ee5b204fea
Binary file not shown.
18
core/migrations/0002_station_metadata_api_url.py
Normal file
18
core/migrations/0002_station_metadata_api_url.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-30 13:50
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='station',
|
||||
name='metadata_api_url',
|
||||
field=models.URLField(blank=True, help_text='Optional API URL to fetch current track metadata', null=True),
|
||||
),
|
||||
]
|
||||
Binary file not shown.
@ -3,6 +3,7 @@ from django.db import models
|
||||
class Station(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
stream_url = models.URLField(help_text="URL for the radio stream")
|
||||
metadata_api_url = models.URLField(blank=True, null=True, help_text="Optional API URL to fetch current track metadata")
|
||||
description = models.TextField(blank=True)
|
||||
color = models.CharField(max_length=7, default="#FF007F", help_text="Hex color for the vinyl")
|
||||
image = models.FileField(upload_to="stations/", blank=True, null=True)
|
||||
@ -19,4 +20,4 @@ class Track(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.artist} - {self.title}"
|
||||
return f"{self.artist} - {self.title}"
|
||||
@ -34,7 +34,7 @@
|
||||
<div class="v-bar"></div><div class="v-bar"></div><div class="v-bar"></div><div class="v-bar"></div><div class="v-bar"></div>
|
||||
<div class="v-bar"></div><div class="v-bar"></div><div class="v-bar"></div><div class="v-bar"></div><div class="v-bar"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="audio-controls mb-4 p-3 rounded-3 bg-dark bg-opacity-50 border border-secondary">
|
||||
<audio id="audio-player"></audio>
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
@ -53,10 +53,11 @@
|
||||
<h5 class="mb-3 text-uppercase small ls-wide fw-bold text-secondary">Available Stations</h5>
|
||||
<div class="list-group list-group-flush bg-transparent custom-scrollbar" style="max-height: 250px; overflow-y: auto;">
|
||||
{% for station in stations %}
|
||||
<button class="list-group-item list-group-item-action bg-transparent text-white border-0 py-3 rounded-3 mb-2 station-item"
|
||||
data-url="{{ station.stream_url }}"
|
||||
data-name="{{ station.name }}"
|
||||
data-color="{{ station.color }}">
|
||||
<button class="list-group-item list-group-item-action bg-transparent text-white border-0 py-3 rounded-3 mb-2 station-item"
|
||||
data-url="{{ station.stream_url }}"
|
||||
data-name="{{ station.name }}"
|
||||
data-color="{{ station.color }}"
|
||||
data-metadata-url="{{ station.metadata_api_url|default:'' }}">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="station-dot me-3" style="background-color: {{ station.color }}; box-shadow: 0 0 15px {{ station.color }};"></div>
|
||||
<div class="flex-grow-1">
|
||||
@ -120,6 +121,11 @@
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border-radius: 10px;
|
||||
}
|
||||
#current-track-info {
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
font-weight: 500;
|
||||
text-shadow: 0 0 10px rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
@ -134,10 +140,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const visualizer = document.getElementById('visualizer');
|
||||
const stationItems = document.querySelectorAll('.station-item');
|
||||
const stationNameDisplay = document.getElementById('current-station-name');
|
||||
const trackInfoDisplay = document.getElementById('current-track-info');
|
||||
const volumeControl = document.getElementById('volume-control');
|
||||
const volumeIndicator = document.getElementById('volume-indicator');
|
||||
|
||||
let isPlaying = false;
|
||||
let currentMetadataUrl = '';
|
||||
let metadataInterval = null;
|
||||
|
||||
function fetchMetadata() {
|
||||
if (!currentMetadataUrl) return;
|
||||
|
||||
fetch(currentMetadataUrl)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
let trackText = 'Virtual Broadcast';
|
||||
if (data.artist && data.title) {
|
||||
trackText = `${data.artist} - ${data.title}`;
|
||||
} else if (data.title) {
|
||||
trackText = data.title;
|
||||
}
|
||||
|
||||
if (trackInfoDisplay.textContent !== trackText) {
|
||||
trackInfoDisplay.style.opacity = 0;
|
||||
setTimeout(() => {
|
||||
trackInfoDisplay.textContent = trackText;
|
||||
trackInfoDisplay.style.opacity = 1;
|
||||
}, 500);
|
||||
}
|
||||
})
|
||||
.catch(err => console.error('Error fetching metadata:', err));
|
||||
}
|
||||
|
||||
function togglePlay() {
|
||||
if (isPlaying) {
|
||||
@ -146,6 +179,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
vinyl.classList.remove('spinning');
|
||||
tonearm.classList.remove('active');
|
||||
visualizer.classList.remove('playing');
|
||||
if (metadataInterval) clearInterval(metadataInterval);
|
||||
} else {
|
||||
if (audio.src && audio.src !== window.location.href) {
|
||||
audio.play().catch(e => {
|
||||
@ -156,6 +190,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
vinyl.classList.add('spinning');
|
||||
tonearm.classList.add('active');
|
||||
visualizer.classList.add('playing');
|
||||
|
||||
// Start fetching metadata
|
||||
fetchMetadata();
|
||||
metadataInterval = setInterval(fetchMetadata, 15000); // Every 15 seconds
|
||||
} else {
|
||||
alert('Please select a station first!');
|
||||
return;
|
||||
@ -171,13 +209,18 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const url = this.dataset.url;
|
||||
const name = this.dataset.name;
|
||||
const color = this.dataset.color;
|
||||
currentMetadataUrl = this.dataset.metadataUrl;
|
||||
|
||||
// Update UI
|
||||
stationItems.forEach(i => i.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
stationNameDisplay.textContent = name;
|
||||
vinylLabel.style.boxShadow = `0 0 30px ${color}`;
|
||||
|
||||
|
||||
// Reset track info
|
||||
trackInfoDisplay.textContent = 'Connecting...';
|
||||
if (metadataInterval) clearInterval(metadataInterval);
|
||||
|
||||
// Set source and play
|
||||
audio.src = url;
|
||||
isPlaying = false; // Reset state for toggle
|
||||
@ -191,4 +234,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user