Files
hermes-agent 172c1ff264
Build, Lint, and Test / Build, Lint, and Test (push) Failing after 13m0s
Add JSON REST API for MCP integration
- Add /api/v1 namespace with Bearer token auth (PINCHFLAT_API_TOKEN env var)
- API controllers for sources, media items, media profiles, settings, tasks
- Support for all source actions: create, update, delete, force_download_pending,
  force_redownload, force_index, force_metadata_refresh, sync_files_on_disk
- Media item endpoints: list, show, search, force_download, update, delete
- Media profile CRUD endpoints
- Settings show/update and app_info endpoints
- Task listing endpoints
- Add Jason.Encoder for Task schema
- Comprehensive test suite for all API endpoints
- Gitea Actions CI workflow (runs existing checks + API-specific tests)
- API documentation in docs/API.md
2026-07-03 23:22:24 +00:00

128 lines
4.8 KiB
Elixir

defmodule PinchflatWeb.Router do
use PinchflatWeb, :router
import PinchflatWeb.Plugs
import Phoenix.LiveDashboard.Router
# IMPORTANT: `strip_trailing_extension` in endpoint.ex removes
# the extension from the path
pipeline :browser do
plug :basic_auth
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {PinchflatWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :allow_iframe_embed
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :api_auth do
plug PinchflatWeb.ApiAuthPlug
end
scope "/", PinchflatWeb do
pipe_through [:maybe_basic_auth, :token_protected_route]
# has to match before /sources/:id
get "/sources/opml", Podcasts.PodcastController, :opml_feed
end
# Routes in here _may not be_ protected by basic auth. This is necessary for
# media streaming to work for RSS podcast feeds.
scope "/", PinchflatWeb do
pipe_through :maybe_basic_auth
get "/sources/:uuid/feed", Podcasts.PodcastController, :rss_feed
get "/sources/:uuid/feed_image", Podcasts.PodcastController, :feed_image
get "/media/:uuid/episode_image", Podcasts.PodcastController, :episode_image
get "/media/:uuid/stream", MediaItems.MediaItemController, :stream
end
scope "/", PinchflatWeb do
pipe_through :browser
get "/", Pages.PageController, :home
resources "/media_profiles", MediaProfiles.MediaProfileController
resources "/search", Searches.SearchController, only: [:show], singleton: true
resources "/settings", Settings.SettingController, only: [:show, :update], singleton: true
get "/app_info", Settings.SettingController, :app_info
get "/download_logs", Settings.SettingController, :download_logs
resources "/sources", Sources.SourceController do
post "/force_download_pending", Sources.SourceController, :force_download_pending
post "/force_redownload", Sources.SourceController, :force_redownload
post "/force_index", Sources.SourceController, :force_index
post "/force_metadata_refresh", Sources.SourceController, :force_metadata_refresh
post "/sync_files_on_disk", Sources.SourceController, :sync_files_on_disk
resources "/media", MediaItems.MediaItemController, only: [:show, :edit, :update, :delete] do
post "/force_download", MediaItems.MediaItemController, :force_download
end
end
end
# No auth or CSRF protection for the health check endpoint
scope "/", PinchflatWeb do
pipe_through :api
get "/healthcheck", HealthController, :check, log: false
end
# JSON API for MCP integration and other programmatic clients.
# Protected by Bearer token auth (PINCHFLAT_API_TOKEN env var).
scope "/api/v1", PinchflatWeb.Api.V1 do
pipe_through [:api, :api_auth]
get "/sources", ApiSourceController, :index
get "/sources/:id", ApiSourceController, :show
post "/sources", ApiSourceController, :create
put "/sources/:id", ApiSourceController, :update
patch "/sources/:id", ApiSourceController, :update
delete "/sources/:id", ApiSourceController, :delete
post "/sources/:source_id/force_download_pending", ApiSourceController, :force_download_pending
post "/sources/:source_id/force_redownload", ApiSourceController, :force_redownload
post "/sources/:source_id/force_index", ApiSourceController, :force_index
post "/sources/:source_id/force_metadata_refresh", ApiSourceController, :force_metadata_refresh
post "/sources/:source_id/sync_files_on_disk", ApiSourceController, :sync_files_on_disk
get "/media", ApiMediaItemController, :index
get "/media/search", ApiMediaItemController, :search
get "/media/:id", ApiMediaItemController, :show
put "/media/:id", ApiMediaItemController, :update
patch "/media/:id", ApiMediaItemController, :update
delete "/media/:id", ApiMediaItemController, :delete
post "/media/:media_item_id/force_download", ApiMediaItemController, :force_download
get "/media_profiles", ApiMediaProfileController, :index
get "/media_profiles/:id", ApiMediaProfileController, :show
post "/media_profiles", ApiMediaProfileController, :create
put "/media_profiles/:id", ApiMediaProfileController, :update
patch "/media_profiles/:id", ApiMediaProfileController, :update
delete "/media_profiles/:id", ApiMediaProfileController, :delete
get "/settings", ApiSettingController, :show
put "/settings", ApiSettingController, :update
patch "/settings", ApiSettingController, :update
get "/app_info", ApiSettingController, :app_info
get "/tasks", ApiTaskController, :index
get "/tasks/:id", ApiTaskController, :show
end
scope "/dev" do
pipe_through :browser
live_dashboard "/dashboard",
metrics: PinchflatWeb.Telemetry,
ecto_repos: [Pinchflat.Repo]
end
end