[podcasts] Clean up lookup and creation
This commit is contained in:
34
PROJECT.org
34
PROJECT.org
@ -92,7 +92,7 @@ fetching and simple saving.
|
|||||||
:LOGBOOK:
|
:LOGBOOK:
|
||||||
CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20
|
CLOCK: [2025-07-09 Wed 09:55]--[2025-07-09 Wed 10:15] => 0:20
|
||||||
:END:
|
:END:
|
||||||
* Backlog [1/28]
|
* Backlog [3/27]
|
||||||
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :vrobbler:personal:bug:music:scrobbles:
|
** TODO [#C] Create small utility to clean up tracks scrobbled with wonky playback times :vrobbler:personal:bug:music:scrobbles:
|
||||||
** TODO [#C] Move to using more robust mopidy-webhooks pacakge form pypi :utility:improvement:
|
** TODO [#C] Move to using more robust mopidy-webhooks pacakge form pypi :utility:improvement:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
@ -471,27 +471,33 @@ TypeError: can only concatenate str (not "NoneType") to str
|
|||||||
an hour for part of the year. Also, we'd need to adjust any old scrobbles that
|
an hour for part of the year. Also, we'd need to adjust any old scrobbles that
|
||||||
took place with DST off to roll them back by an hour.
|
took place with DST off to roll them back by an hour.
|
||||||
|
|
||||||
** TODO [#A] Fix bug where podcast scrobbling creates duplicate Podcast :project:vrobbler:scrobbling:podcasts:bug:personal:
|
|
||||||
Rather than pick up an existing Podcast using the podcast title in the mopidy
|
|
||||||
file name, Vrobbler creates a new podcast with no enriched data. Not a big deal
|
|
||||||
for my use as the volume of podcasts I listen to makes manual fixes easy. But
|
|
||||||
it's annoying.
|
|
||||||
** TODO [#A] Allow scrobbling from the Food list page's start links :vrobbler:bug:food:scrobbling:personal:project:
|
** TODO [#A] Allow scrobbling from the Food list page's start links :vrobbler:bug:food:scrobbling:personal:project:
|
||||||
https://life.lab.unbl.ink/scrobble/e39779c8-62a5-46a6-bdef-fb7662810dc6/start/
|
https://life.lab.unbl.ink/scrobble/e39779c8-62a5-46a6-bdef-fb7662810dc6/start/
|
||||||
** TODO [#A] Allow reading comic books from readcomicsoline.ru :vrobbler:books:feature:comicbook:personal:project:scrobbling:
|
|
||||||
|
|
||||||
- Note taken on [2025-09-25 Thu 10:52]
|
|
||||||
|
|
||||||
Things to consider are whether we scrobble the issue on one page, send it to
|
|
||||||
archivebox? (yes), and how best to enrich the data
|
|
||||||
|
|
||||||
** TODO [#A] Puzzles (and all longplays) should have a "Completed?" column on their detail page :vrobbler:bug:puzzles:personal:project:
|
** TODO [#A] Puzzles (and all longplays) should have a "Completed?" column on their detail page :vrobbler:bug:puzzles:personal:project:
|
||||||
** TODO [#A] Fix raw text webpage title not truncating to 254 chars :vrobbler:personal:bug:webpages:
|
** TODO [#A] Fix raw text webpage title not truncating to 254 chars :vrobbler:personal:bug:webpages:
|
||||||
|
|
||||||
- Note taken on [2025-09-30 Tue 09:33]
|
- Note taken on [2025-09-30 Tue 09:33]
|
||||||
|
|
||||||
This may have already been resolved ... need to just confirm it.
|
This may have already been resolved ... need to just confirm it.
|
||||||
** TODO
|
** DONE [#A] Fix bug where podcast scrobbling creates duplicate Podcast :project:vrobbler:scrobbling:podcasts:bug:personal:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: 7377ef6c-5fa7-9e4e-9080-f9810a76118c
|
||||||
|
:END:
|
||||||
|
|
||||||
|
Rather than pick up an existing Podcast using the podcast title in the mopidy
|
||||||
|
file name, Vrobbler creates a new podcast with no enriched data. Not a big deal
|
||||||
|
for my use as the volume of podcasts I listen to makes manual fixes easy. But
|
||||||
|
it's annoying.
|
||||||
|
|
||||||
|
** DONE [#A] Allow reading comic books from readcomicsoline.ru :vrobbler:books:feature:comicbook:personal:project:scrobbling:
|
||||||
|
:PROPERTIES:
|
||||||
|
:ID: 7c7e9ecc-b675-68c3-764f-ef771ce5d88f
|
||||||
|
:END:
|
||||||
|
|
||||||
|
- Note taken on [2025-09-25 Thu 10:52]
|
||||||
|
|
||||||
|
Things to consider are whether we scrobble the issue on one page, send it to
|
||||||
|
archivebox? (yes), and how best to enrich the data
|
||||||
|
|
||||||
** DONE [#A] Add RSS feed lookups to podcasts :vrobbler:personal:feature:podcasts:
|
** DONE [#A] Add RSS feed lookups to podcasts :vrobbler:personal:feature:podcasts:
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
|||||||
@ -144,6 +144,7 @@ class PodcastEpisode(ScrobblableMixin):
|
|||||||
cls,
|
cls,
|
||||||
title: str,
|
title: str,
|
||||||
podcast_name: str,
|
podcast_name: str,
|
||||||
|
podcast_description: str,
|
||||||
pub_date: str,
|
pub_date: str,
|
||||||
number: int = 0,
|
number: int = 0,
|
||||||
mopidy_uri: str = "",
|
mopidy_uri: str = "",
|
||||||
@ -155,31 +156,33 @@ class PodcastEpisode(ScrobblableMixin):
|
|||||||
producer before saving the epsiode so it can be scrobbled.
|
producer before saving the epsiode so it can be scrobbled.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
log_context={"mopidy_uri": mopidy_uri, "media_type": "Podcast"}
|
||||||
producer = None
|
producer = None
|
||||||
if producer_name:
|
if producer_name:
|
||||||
producer = Producer.find_or_create(producer_name)
|
producer = Producer.find_or_create(producer_name)
|
||||||
|
|
||||||
podcast = Podcast.objects.filter(
|
podcast, created = Podcast.objects.get_or_create(name=podcast_name, defaults={"description": podcast_description})
|
||||||
name__iexact=podcast_name,
|
log_context["podcast_id"] = podcast.id
|
||||||
).first()
|
log_context["podcast_name"] = podcast.name
|
||||||
if not podcast:
|
if created:
|
||||||
podcast = Podcast.objects.create(
|
logger.info("Created new podcast", extra=log_context)
|
||||||
name=podcast_name, producer=producer
|
if enrich and created:
|
||||||
)
|
logger.info("Enriching new podcast", extra=log_context)
|
||||||
if enrich:
|
podcast.fix_metadata()
|
||||||
podcast.fix_metadata()
|
|
||||||
|
|
||||||
episode = cls.objects.filter(
|
episode, created = cls.objects.get_or_create(
|
||||||
title__iexact=title, podcast=podcast
|
title=title,
|
||||||
).first()
|
podcast=podcast,
|
||||||
if not episode:
|
defaults={
|
||||||
episode = cls.objects.create(
|
"run_time_seconds": run_time_seconds,
|
||||||
title=title,
|
"number": number,
|
||||||
podcast=podcast,
|
"pub_date": pub_date,
|
||||||
run_time_seconds=run_time_seconds,
|
"mopidy_uri": mopidy_uri,
|
||||||
number=number,
|
}
|
||||||
pub_date=pub_date,
|
)
|
||||||
mopidy_uri=mopidy_uri,
|
if created:
|
||||||
)
|
log_context["episode_id"] = episode.id
|
||||||
|
log_context["episode_title"] = episode.title
|
||||||
|
logger.info("Created new podcast episode", extra=log_context)
|
||||||
|
|
||||||
return episode
|
return episode
|
||||||
|
|||||||
@ -34,10 +34,15 @@ def fetch_metadata_from_rss(uri: str) -> dict[str, Any]:
|
|||||||
logger.warning("Tried to parse uri as RSS feed, but no target found", extra=log_context)
|
logger.warning("Tried to parse uri as RSS feed, but no target found", extra=log_context)
|
||||||
return podcast_data
|
return podcast_data
|
||||||
|
|
||||||
|
podcast_publisher = feed.feed.get("itunes_publisher")
|
||||||
|
podcast_owner = feed.feed.itunes_owner.get("name") if isinstance(feed.feed.itunes_owner, dict) else feed.feed.itunes_owner
|
||||||
|
podcast_other = feed.feed.get("managingeditor") or feed.feed.get("copyright")
|
||||||
|
|
||||||
podcast_data = {
|
podcast_data = {
|
||||||
"podcast_name": feed.feed.get("title", "Unknown Podcast"),
|
"podcast_name": feed.feed.get("title", "Unknown Podcast"),
|
||||||
"podcast_description": feed.feed.get("description", ""),
|
"podcast_description": feed.feed.get("description", ""),
|
||||||
"podcast_link": feed.feed.get("link", ""),
|
"podcast_link": feed.feed.get("link", ""),
|
||||||
|
"podcast_producer": podcast_publisher or podcast_owner or podcast_other
|
||||||
}
|
}
|
||||||
|
|
||||||
for entry in feed.entries:
|
for entry in feed.entries:
|
||||||
@ -110,24 +115,20 @@ def get_or_create_podcast(post_data: dict) -> PodcastEpisode:
|
|||||||
|
|
||||||
mopidy_uri = post_data.get("mopidy_uri", "")
|
mopidy_uri = post_data.get("mopidy_uri", "")
|
||||||
parsed_data = parse_mopidy_uri(mopidy_uri)
|
parsed_data = parse_mopidy_uri(mopidy_uri)
|
||||||
|
producer_name = parsed_data.get("podcast_producer", post_data.get("artist", ""))
|
||||||
producer_dict = {"name": post_data.get("artist")}
|
podcast_name = parsed_data.get("podcast_name", post_data.get("album", ""))
|
||||||
|
episode_name = parsed_data.get("episode_title", parsed_data.get("episode_filename", ""))
|
||||||
podcast_name = post_data.get("album")
|
|
||||||
if not podcast_name:
|
|
||||||
podcast_name = parsed_data.get("podcast_name")
|
|
||||||
podcast_dict = {"name": podcast_name}
|
|
||||||
|
|
||||||
episode_name = parsed_data.get("episode_filename")
|
|
||||||
run_time_seconds = parsed_data.get("episode_runtime_seconds", post_data.get("run_time", 2700))
|
run_time_seconds = parsed_data.get("episode_runtime_seconds", post_data.get("run_time", 2700))
|
||||||
|
|
||||||
episode_dict = {
|
episode_dict = {
|
||||||
"title": episode_name,
|
"title": episode_name,
|
||||||
"run_time_seconds": run_time_seconds,
|
"podcast_name": podcast_name,
|
||||||
"number": parsed_data.get("episode_num"),
|
"podcast_description": parsed_data.get("podcast_description"),
|
||||||
"pub_date": parsed_data.get("pub_date"),
|
"pub_date": parsed_data.get("pub_date"),
|
||||||
|
"number": parsed_data.get("episode_num"),
|
||||||
"mopidy_uri": mopidy_uri,
|
"mopidy_uri": mopidy_uri,
|
||||||
|
"producer_name": producer_name,
|
||||||
|
"run_time_seconds": run_time_seconds,
|
||||||
}
|
}
|
||||||
|
|
||||||
return PodcastEpisode.find_or_create(
|
return PodcastEpisode.find_or_create(**episode_dict)
|
||||||
podcast_dict, producer_dict, episode_dict
|
|
||||||
)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user