Files
J621/backend/apps/library/urls.py
T
JakeBreath f8667c1037 Add a Random image endpoint and SPA page (with fastfetch mode)
Backend: GET /api/random/ (aliases /random and /random/) returns a random
library image with:
- rating=s,q,e filtering (comma separated, default any);
- fastfetch mode (?fastfetch=1 or any User-Agent containing "fastfetch")
  that only considers png/jpg/gif - what terminal viewers can show;
- JSON with j_id, filename, extension, rating, size, e621 id plus absolute
  url/download_url/thumbnail_url. Authenticated callers get signed URLs so
  fastfetch and image viewers can load them without headers; guests get
  unsigned URLs and never receive hidden_from_guests items.

Tests: apps/library/tests/test_random.py (8 tests) covering the response
contract, guest signatures, image-only default, the fastfetch format
restriction (flag and User-Agent), rating filters, guest visibility and the
short alias.

Frontend: /random page with rating pills, R to roll, Open/Download and a
library link, plus navigation and command palette entries; needs a backend,
hidden in local mode.

nginx: /random negotiates on Accept so browsers keep getting the SPA while
scripts get the JSON (verified with the proxy and frontend containers).

Also fixes a regression from the SSRF change: the guest download proxy
still referenced the removed 'parsed' variable on its success path, so
every proxied download would have 500'd. Redirect hops are now covered by
tests with a mocked requests.get.
2026-09-18 13:06:36 -05:00

54 lines
1.6 KiB
Python

from django.urls import include, path
from rest_framework.routers import DefaultRouter
from .tools import (
ClearTempView,
DeleteFilesView,
ExactDuplicatesView,
StorageView,
TagCloudView,
VisualGroupsView,
VisualMatchesView,
)
from .similarity import SimilarityCheckViewSet
from .uploads import TempUploadViewSet
from .views import (
ClientDownloadView,
DownloadTaskViewSet,
MatchTaskViewSet,
MediaItemViewSet,
RandomItemView,
)
router = DefaultRouter()
router.register("files", MediaItemViewSet, basename="file")
router.register("uploads", TempUploadViewSet, basename="upload")
router.register("online/downloads", DownloadTaskViewSet, basename="download")
router.register("matches", MatchTaskViewSet, basename="match")
router.register("similarity", SimilarityCheckViewSet, basename="similarity")
urlpatterns = [
path("", include(router.urls)),
path("random/", RandomItemView.as_view(), name="random_item"),
path("online/file/", ClientDownloadView.as_view(), name="client_download"),
path(
"duplicates/md5/",
ExactDuplicatesView.as_view(),
name="duplicates_md5",
),
path(
"duplicates/visual/",
VisualMatchesView.as_view(),
name="duplicates_visual",
),
path(
"duplicates/visual_groups/",
VisualGroupsView.as_view(),
name="duplicates_groups",
),
path("delete/", DeleteFilesView.as_view(), name="delete_files"),
path("temp/clear/", ClearTempView.as_view(), name="clear_temp"),
path("tags/cloud/", TagCloudView.as_view(), name="tag_cloud"),
path("storage/", StorageView.as_view(), name="storage_info"),
]