Merge pull request #1003 from andrebk/movie-collections

Display movie collections on media detail page
This commit is contained in:
Xila Cai
2026-02-01 19:12:25 +01:00
committed by GitHub
3 changed files with 44 additions and 3 deletions

View File

@@ -161,9 +161,27 @@ def movie(media_id):
url,
params=params,
)
if response.get("belongs_to_collection", {}) is not None and (
collection_id := response.get("belongs_to_collection", {}).get("id")):
collection_response = services.api_request(
Sources.TMDB.value,
"GET",
f"{base_url}/collection/{collection_id}",
params={**base_params},
)
else:
collection_response = {}
except requests.exceptions.HTTPError as error:
handle_error(error)
# Filter out collection items from recommendations, to avoid duplicates
collection_items = get_collection(collection_response)
collection_ids = [item["media_id"] for item in collection_items]
recommended_items = response.get("recommendations", {}).get("results", [])
filtered_recommendations = [item for item in recommended_items
if item["id"] not in collection_ids]
data = {
"media_id": media_id,
"source": Sources.TMDB.value,
@@ -186,8 +204,9 @@ def movie(media_id):
"languages": get_languages(response["spoken_languages"]),
},
"related": {
collection_response.get("name", "collection"): collection_items,
"recommendations": get_related(
response.get("recommendations", {}).get("results", [])[:15],
filtered_recommendations[:15],
MediaTypes.MOVIE.value,
),
},
@@ -580,6 +599,23 @@ def get_related(related_medias, media_type, parent_response=None):
return related
def get_collection(collection_response):
"""Format media collection list to match related media."""
def date_key(media):
date = media.get("release_date", "")
if date is None or date == "":
# If release date is unknown, sort by title after known releases
title = get_title(media)
date = f"9999-99-99-{title}"
return date
parts = sorted(collection_response.get("parts", []), key=date_key)
return [{"source": Sources.TMDB.value,
"media_type": MediaTypes.MOVIE.value,
"image": get_image_url(media["poster_path"]),
"media_id": media["id"],
"title": get_title(media)} for media in parts]
def process_episodes(season_metadata, episodes_in_db):
"""Process the episodes for the selected season."""
episodes_metadata = []

View File

@@ -1,6 +1,6 @@
{% load app_tags %}
<div class="{% if secondary_color %}bg-[#39404b]{% else %}bg-[#2a2f35]{% endif %} rounded-lg overflow-hidden shadow-lg relative"
<div class="{% if secondary_color %}bg-[#39404b]{% else %}bg-[#2a2f35]{% endif %} rounded-lg overflow-hidden shadow-lg relative {% if active %}ring-2 ring-indigo-700{% endif %}"
x-data="{ trackOpen: false, listsOpen: false, historyOpen: false }">
<div class="relative">
<a href="{{ item|media_url }}">

View File

@@ -478,7 +478,12 @@
<h2 class="text-xl font-bold mb-4">{{ name|no_underscore|title }}</h2>
<div class="grid grid-cols-[repeat(auto-fill,minmax(150px,1fr))] gap-4">
{% for result in related_items %}
{% include "app/components/media_card.html" with item=result.item title=result.item.season_title|default:result.item.title media=result.media %}
{% if media_type != MediaTypes.TV.value and media_type != MediaTypes.SEASON.value %}
{# Set active to highlight the current movie in a collection. Avoid TV media, since seasons have same ID as the parent show #}
{% include "app/components/media_card.html" with item=result.item title=result.item.season_title|default:result.item.title media=result.media active=media.media_id|str_equals:result.item.media_id %}
{% else %}
{% include "app/components/media_card.html" with item=result.item title=result.item.season_title|default:result.item.title media=result.media %}
{% endif %}
{% endfor %}
</div>
</section>