diora-web/podcasts/migrations/0012_player_state.py
mrwnslz 3eb6a27ec3 Player-Sync: ein Player für alle Geräte (wie Spotify Connect)
Server: PlayerState und PlayerDevice (Migration 0012), /podcasts/player/
(Stand), report/ (das Gerät, das zu spielen anfängt, wird das aktive und
bleibt es auch pausiert, solange es online ist), command/ (Fernbedienung,
transfer auf ein anderes Gerät) und stream/ (Server-Sent Events, zugleich
die Anwesenheit der Geräte). seq steigt in einem UPDATE und nie zurück.

Browser: podcasts-web.js meldet Abspielen, Pause, Springen, Folgen- und
Senderwechsel (alle 10 s beim Spielen), hört den Stream, hört auf, wenn ein
anderes Gerät startet, führt Befehle aus, zeigt das andere Gerät als remote
und übernimmt, was ein verschwundenes Gerät zuletzt hatte. Eine pausierte
Folge folgt einem neueren Stand von anderswo; im Vordergrund wird nach
15 s neu geholt. Podcast-Seite neu kopiert, sw v58.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 15:18:38 +02:00

51 lines
2.7 KiB
Python

# Generated by Django 6.1 on 2026-10-02 12:50
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('podcasts', '0011_settings_import_downloads'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='PlayerState',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('kind', models.CharField(blank=True, choices=[('', 'Nichts'), ('podcast', 'Podcast'), ('radio', 'Radio')], default='', max_length=10)),
('station_url', models.CharField(blank=True, max_length=1000)),
('station_name', models.CharField(blank=True, max_length=300)),
('station_id', models.IntegerField(blank=True, null=True)),
('position_ms', models.PositiveBigIntegerField(default=0)),
('playing', models.BooleanField(default=False)),
('speed', models.FloatField(default=1.0)),
('device_id', models.CharField(blank=True, max_length=64)),
('device_name', models.CharField(blank=True, max_length=100)),
('updated_at', models.DateTimeField(blank=True, null=True)),
('seq', models.BigIntegerField(default=0)),
('command', models.JSONField(blank=True, null=True)),
('online_devices', models.JSONField(blank=True, default=list)),
('episode', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='podcasts.podcastepisode')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='player_state', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='PlayerDevice',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('device_id', models.CharField(max_length=64)),
('device_name', models.CharField(blank=True, max_length=100)),
('kind', models.CharField(blank=True, choices=[('', 'Unbekannt'), ('app', 'App'), ('web', 'Browser')], default='', max_length=10)),
('last_seen', models.DateTimeField()),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='player_devices', to=settings.AUTH_USER_MODEL)),
],
options={
'unique_together': {('user', 'device_id')},
},
),
]