api: add pagination (limit/offset) and downloaded filter to media endpoint
Nix Flake Check / Nix Flake Check (push) Successful in 1m34s
Build and Test / Build and Test (push) Failing after 7m49s

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
This commit is contained in:
2026-07-08 21:54:39 +00:00
parent 75fb7dd9d8
commit a2da433cdc
2 changed files with 45 additions and 6 deletions
+28 -4
View File
@@ -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 """
@@ -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