Add podcasts as new media type
This commit is contained in:
0
vrobbler/apps/podcasts/__init__.py
Normal file
0
vrobbler/apps/podcasts/__init__.py
Normal file
33
vrobbler/apps/podcasts/admin.py
Normal file
33
vrobbler/apps/podcasts/admin.py
Normal file
@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env python3
|
||||
from django.contrib import admin
|
||||
from podcasts.models import Episode, Podcast, Producer
|
||||
|
||||
|
||||
@admin.register(Producer)
|
||||
class ProducerAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = "created"
|
||||
list_display = ("name",)
|
||||
ordering = ("name",)
|
||||
|
||||
|
||||
@admin.register(Podcast)
|
||||
class PodcastAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = "created"
|
||||
list_display = (
|
||||
"name",
|
||||
"producer",
|
||||
"active",
|
||||
)
|
||||
ordering = ("name",)
|
||||
|
||||
|
||||
@admin.register(Episode)
|
||||
class EpisodeAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = "created"
|
||||
list_display = (
|
||||
"title",
|
||||
"podcast",
|
||||
"run_time",
|
||||
)
|
||||
list_filter = ("podcast",)
|
||||
ordering = ("-created",)
|
||||
5
vrobbler/apps/podcasts/apps.py
Normal file
5
vrobbler/apps/podcasts/apps.py
Normal file
@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class PodcastsConfig(AppConfig):
|
||||
name = 'podcasts'
|
||||
158
vrobbler/apps/podcasts/migrations/0001_initial.py
Normal file
158
vrobbler/apps/podcasts/migrations/0001_initial.py
Normal file
@ -0,0 +1,158 @@
|
||||
# Generated by Django 4.1.5 on 2023-01-12 17:18
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django_extensions.db.fields
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Producer',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID',
|
||||
),
|
||||
),
|
||||
(
|
||||
'created',
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name='created'
|
||||
),
|
||||
),
|
||||
(
|
||||
'modified',
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name='modified'
|
||||
),
|
||||
),
|
||||
('name', models.CharField(max_length=255)),
|
||||
(
|
||||
'uuid',
|
||||
models.UUIDField(
|
||||
blank=True,
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'get_latest_by': 'modified',
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Podcast',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID',
|
||||
),
|
||||
),
|
||||
(
|
||||
'created',
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name='created'
|
||||
),
|
||||
),
|
||||
(
|
||||
'modified',
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name='modified'
|
||||
),
|
||||
),
|
||||
('name', models.CharField(max_length=255)),
|
||||
(
|
||||
'uuid',
|
||||
models.UUIDField(
|
||||
blank=True,
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
('active', models.BooleanField(default=True)),
|
||||
('url', models.URLField(blank=True, null=True)),
|
||||
(
|
||||
'producer',
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
to='podcasts.producer',
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'get_latest_by': 'modified',
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Episode',
|
||||
fields=[
|
||||
(
|
||||
'id',
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name='ID',
|
||||
),
|
||||
),
|
||||
(
|
||||
'created',
|
||||
django_extensions.db.fields.CreationDateTimeField(
|
||||
auto_now_add=True, verbose_name='created'
|
||||
),
|
||||
),
|
||||
(
|
||||
'modified',
|
||||
django_extensions.db.fields.ModificationDateTimeField(
|
||||
auto_now=True, verbose_name='modified'
|
||||
),
|
||||
),
|
||||
('title', models.CharField(max_length=255)),
|
||||
(
|
||||
'uuid',
|
||||
models.UUIDField(
|
||||
blank=True,
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
'mopidy_uri',
|
||||
models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
(
|
||||
'podcast',
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
to='podcasts.producer',
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
'get_latest_by': 'modified',
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,32 @@
|
||||
# Generated by Django 4.1.5 on 2023-01-12 17:48
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('podcasts', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='episode',
|
||||
name='run_time',
|
||||
field=models.CharField(blank=True, max_length=8, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='episode',
|
||||
name='run_time_ticks',
|
||||
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='episode',
|
||||
name='podcast',
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
to='podcasts.podcast',
|
||||
),
|
||||
),
|
||||
]
|
||||
18
vrobbler/apps/podcasts/migrations/0003_episode_pub_date.py
Normal file
18
vrobbler/apps/podcasts/migrations/0003_episode_pub_date.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.5 on 2023-01-12 18:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('podcasts', '0002_episode_run_time_episode_run_time_ticks_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='episode',
|
||||
name='pub_date',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
18
vrobbler/apps/podcasts/migrations/0004_episode_number.py
Normal file
18
vrobbler/apps/podcasts/migrations/0004_episode_number.py
Normal file
@ -0,0 +1,18 @@
|
||||
# Generated by Django 4.1.5 on 2023-01-12 18:32
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('podcasts', '0003_episode_pub_date'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='episode',
|
||||
name='number',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
0
vrobbler/apps/podcasts/migrations/__init__.py
Normal file
0
vrobbler/apps/podcasts/migrations/__init__.py
Normal file
87
vrobbler/apps/podcasts/models.py
Normal file
87
vrobbler/apps/podcasts/models.py
Normal file
@ -0,0 +1,87 @@
|
||||
import logging
|
||||
from typing import Dict, Optional
|
||||
from uuid import uuid4
|
||||
|
||||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
BNULL = {"blank": True, "null": True}
|
||||
|
||||
|
||||
class Producer(TimeStampedModel):
|
||||
name = models.CharField(max_length=255)
|
||||
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
||||
|
||||
class Podcast(TimeStampedModel):
|
||||
name = models.CharField(max_length=255)
|
||||
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
||||
producer = models.ForeignKey(
|
||||
Producer, on_delete=models.DO_NOTHING, **BNULL
|
||||
)
|
||||
active = models.BooleanField(default=True)
|
||||
url = models.URLField(**BNULL)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.name}"
|
||||
|
||||
|
||||
class Episode(TimeStampedModel):
|
||||
title = models.CharField(max_length=255)
|
||||
uuid = models.UUIDField(default=uuid4, editable=False, **BNULL)
|
||||
podcast = models.ForeignKey(Podcast, on_delete=models.DO_NOTHING)
|
||||
number = models.IntegerField(**BNULL)
|
||||
pub_date = models.DateField(**BNULL)
|
||||
run_time = models.CharField(max_length=8, **BNULL)
|
||||
run_time_ticks = models.PositiveBigIntegerField(**BNULL)
|
||||
mopidy_uri = models.CharField(max_length=255, **BNULL)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.title}"
|
||||
|
||||
@classmethod
|
||||
def find_or_create(
|
||||
cls, podcast_dict: Dict, producer_dict: Dict, episode_dict: Dict
|
||||
) -> Optional["Episode"]:
|
||||
"""Given a data dict from Mopidy, finds or creates a podcast and
|
||||
producer before saving the epsiode so it can be scrobbled.
|
||||
|
||||
"""
|
||||
if not podcast_dict.get('name'):
|
||||
logger.warning(f"No name from source for podcast, not scrobbling")
|
||||
return
|
||||
|
||||
producer = None
|
||||
if producer_dict.get('name'):
|
||||
producer, producer_created = Producer.objects.get_or_create(
|
||||
**producer_dict
|
||||
)
|
||||
if producer_created:
|
||||
logger.debug(f"Created new producer {producer}")
|
||||
else:
|
||||
logger.debug(f"Found producer {producer}")
|
||||
|
||||
if producer:
|
||||
podcast_dict["producer_id"] = producer.id
|
||||
podcast, podcast_created = Podcast.objects.get_or_create(
|
||||
**podcast_dict
|
||||
)
|
||||
if podcast_created:
|
||||
logger.debug(f"Created new podcast {podcast}")
|
||||
else:
|
||||
logger.debug(f"Found podcast {podcast}")
|
||||
|
||||
episode_dict['podcast_id'] = podcast.id
|
||||
|
||||
episode, created = cls.objects.get_or_create(**episode_dict)
|
||||
if created:
|
||||
logger.debug(f"Created new episode: {episode}")
|
||||
else:
|
||||
logger.debug(f"Found episode {episode}")
|
||||
|
||||
return episode
|
||||
Reference in New Issue
Block a user