From a2da433cdc322e9ef654e0a8b649f350d5fdf834 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Wed, 8 Jul 2026 21:54:39 +0000 Subject: [PATCH] api: add pagination (limit/offset) and downloaded filter to media endpoint The /api/v1/media endpoint was loading ALL media items from the database with no pagination, causing timeouts with large libraries (1800+ items per source). Now supports: - ?limit=N (default 50) - ?offset=N (default 0) - ?downloaded=true (filter to only downloaded media) - Ordered by uploaded_at desc --- lib/pinchflat/media/media.ex | 32 ++++++++++++++++--- .../api/v1/api_media_item_controller.ex | 19 +++++++++-- 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/pinchflat/media/media.ex b/lib/pinchflat/media/media.ex index abe2a0d..814a491 100644 --- a/lib/pinchflat/media/media.ex +++ b/lib/pinchflat/media/media.ex @@ -23,8 +23,20 @@ defmodule Pinchflat.Media do Returns [%MediaItem{}, ...]. """ - def list_media_items do - Repo.all(MediaItem) + def list_media_items(opts \\ []) do + limit = Keyword.get(opts, :limit, 50) + offset = Keyword.get(opts, :offset, 0) + downloaded_only = Keyword.get(opts, :downloaded_only, false) + + query = from mi in MediaItem, limit: ^limit, offset: ^offset, order_by: [desc: mi.uploaded_at] + + query = if downloaded_only do + from mi in query, where: not is_nil(mi.media_downloaded_at) + else + query + end + + Repo.all(query) end @doc """ @@ -72,8 +84,20 @@ defmodule Pinchflat.Media do Returns [%MediaItem{}, ...]. """ - def list_media_items_for_source(source_id) do - Repo.all(from mi in MediaItem, where: mi.source_id == ^source_id) + def list_media_items_for_source(source_id, opts \\ []) do + limit = Keyword.get(opts, :limit, 50) + offset = Keyword.get(opts, :offset, 0) + downloaded_only = Keyword.get(opts, :downloaded_only, false) + + query = from mi in MediaItem, where: mi.source_id == ^source_id, limit: ^limit, offset: ^offset, order_by: [desc: mi.uploaded_at] + + query = if downloaded_only do + from mi in query, where: not is_nil(mi.media_downloaded_at) + else + query + end + + Repo.all(query) end @doc """ diff --git a/lib/pinchflat_web/controllers/api/v1/api_media_item_controller.ex b/lib/pinchflat_web/controllers/api/v1/api_media_item_controller.ex index c4bf168..3d65f37 100644 --- a/lib/pinchflat_web/controllers/api/v1/api_media_item_controller.ex +++ b/lib/pinchflat_web/controllers/api/v1/api_media_item_controller.ex @@ -12,13 +12,17 @@ defmodule PinchflatWeb.Api.V1.ApiMediaItemController do alias Pinchflat.Downloading.MediaDownloadWorker def index(conn, params) do + limit = parse_param(params, "limit", 50) + offset = parse_param(params, "offset", 0) + downloaded_only = params["downloaded"] == "true" + media_items = case params do %{"source_id" => source_id} -> - Media.list_media_items_for_source(source_id) + Media.list_media_items_for_source(source_id, limit: limit, offset: offset, downloaded_only: downloaded_only) _ -> - Media.list_media_items() + Media.list_media_items(limit: limit, offset: offset, downloaded_only: downloaded_only) end media_items = Repo.preload(media_items, :source) @@ -93,4 +97,15 @@ defmodule PinchflatWeb.Api.V1.ApiMediaItemController do end) end) end + + defp parse_param(params, key, default) do + case Map.get(params, key) do + nil -> default + value -> + case Integer.parse(value) do + {n, _} -> n + :error -> default + end + end + end end