Skip to content

Commit

Permalink
feat(cli): add RSS feed generation and improve search results display
Browse files Browse the repository at this point in the history
 - Implement RSS feed generation functionality
 - Enhance search results presentation with header panels and improved formatting
 - Add new fields to PodcastUmbrella model
 - Introduce utility function for image selection
  • Loading branch information
bendikrb committed Sep 20, 2024
1 parent c947f58 commit eabf0b4
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 35 deletions.
106 changes: 71 additions & 35 deletions nrk_psapi/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@
from dataclasses import fields
import logging
import re
from _io import TextIOWrapper
from typing import TYPE_CHECKING, Callable

from rich import print as rprint
from rich.box import SIMPLE
from rich.console import Console
from rich.logging import RichHandler
from rich.panel import Panel
Expand All @@ -29,6 +31,7 @@
SearchResponseResultsResult,
SearchResultType,
)
from nrk_psapi.rss.feed import NrkPodcastFeed

if TYPE_CHECKING:
from nrk_psapi.models.common import BaseDataClassORJSONMixin
Expand Down Expand Up @@ -187,7 +190,11 @@ def header_panel(title: str, subtitle: str):
title,
subtitle,
)
return Panel(grid)
return Panel(
grid,
style="white on dark_red",
box=SIMPLE,
)


def highlight_context(
Expand Down Expand Up @@ -368,6 +375,21 @@ def main_parser() -> argparse.ArgumentParser:
recommendations_parser.add_argument("podcast_id", type=str, help="Podcast id.")
recommendations_parser.set_defaults(func=get_recommendations)

#
# RSS
#
rss_parser = subparsers.add_parser("rss", description="Get RSS feed.")
rss_parser.add_argument("podcast_id", type=str, help="Podcast id.")
rss_parser.add_argument("output_path", type=argparse.FileType("w", encoding="utf-8"), help="Output path.")
rss_parser.add_argument("--base_url", type=str, help="Base URL.")
parser.add_argument(
"--limit",
type=int,
default=None,
help="The number of episodes to include in the feed. Default is all episodes.",
)
rss_parser.set_defaults(func=get_rss_feed)

#
# Search
#
Expand Down Expand Up @@ -649,6 +671,18 @@ async def get_recommendations(args):
)


async def get_rss_feed(args):
"""Get RSS feed."""

output_file: TextIOWrapper = args.output_path
async with NrkPodcastAPI() as client:
rss = NrkPodcastFeed(client, args.base_url)
feed = await rss.build_podcast_rss(args.podcast_id, args.limit)
xml = feed.rss()
output_file.write(xml)
console.print(f"Wrote {len(xml)} bytes to {output_file.name}")


async def get_episode(args):
"""Get episode."""
async with NrkPodcastAPI() as client:
Expand Down Expand Up @@ -820,43 +854,45 @@ async def search(args):
search_results = await client.search(
args.query, per_page=args.limit, page=args.page, search_type=args.type
)
total_counts = search_results.total_count
for field in fields(search_results.results):
field_value: SearchResponseResultsResult = getattr(search_results.results, field.name)
if len(field_value.results) > 0:
# noinspection PyTypeChecker
res_fields = fields(field_value.results[0])
console.print([f.name for f in res_fields])
console.print(
pretty_dataclass_list(
field_value.results,
title=field.name,
hidden_fields=[
"id",
"type",
"images",
"square_images",
"score",
# "highlights",
"description",
"date",
"series_title",
"season_id",
],
field_formatters={
"highlights": pretty_highlights,
},
field_widths={
"highlights": 50,
},
field_order=[
"id",
"episode_id",
"series_id",
"title",
"highlights",
],
),
)
console.print(
header_panel(
field.name,
f"[bold]{getattr(total_counts, field.name)}[/bold] results",
)
)
console.print(
pretty_dataclass_list(
field_value.results,
hidden_fields=[
"id",
"type",
"images",
"square_images",
"score",
"description",
"date",
"series_title",
"season_id",
],
field_formatters={
"highlights": pretty_highlights,
},
field_widths={
"highlights": 50,
},
field_order=[
"id",
"episode_id",
"series_id",
"title",
"highlights",
],
),
)


def main():
Expand Down
7 changes: 7 additions & 0 deletions nrk_psapi/models/catalog.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,13 @@ class PodcastUmbrella(Podcast):
deserialize=lambda x: [SeasonEmbedded.from_dict(d) for d in x["seasons"]],
),
)
episodes: list[Episode] = field(
default_factory=list,
metadata=field_options(
alias="_embedded",
deserialize=lambda x: [Episode.from_dict(d) for d in x["episodes"]["_embedded"]["episodes"]],
)
)


@dataclass
Expand Down
10 changes: 10 additions & 0 deletions nrk_psapi/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
if TYPE_CHECKING:
from yarl import URL

from nrk_psapi.models import Image


def get_nested_items(data: dict[str, any], items_key: str) -> list[dict[str, any]]:
"""Get nested items from a dictionary based on the provided items_key."""
Expand All @@ -24,6 +26,14 @@ def get_nested_items(data: dict[str, any], items_key: str) -> list[dict[str, any
return items


def get_image(images: list[Image], min_size: int | None = None) -> Image | None:
candidates = [img for img in images if img.width is not None]
if min_size is None:
candidates.sort(key=lambda img: img.width, reverse=True)
return candidates[0] if candidates else None
return next((img for img in candidates if img.width >= min_size), None)


def sanitize_string(s: str, delimiter: str = "_"):
"""Sanitize a string to be used as a URL parameter."""

Expand Down

0 comments on commit eabf0b4

Please sign in to comment.