Backend: - Perceptual hashes (aHash/dHash/pHash/wHash via imagehash, no imgdd) stored on items, computed on upload/download and by the new compute_visual_hashes command - Duplicates API: exact duplicates (multi-location items), visual matches for one item, union-find similarity groups with pagination - Delete API with ownership/staff checks, per-item and per-copy deletion, watched-folder path validation; storage overview and temp cleanup; file list accepts j_ids batches - Staged uploads are flagged visual_match with their library matches (threshold via VISUAL_MATCH_THRESHOLD) - Staff users API: list with upload counts, set role and avatar by J-ID; User.avatar FK with signed avatar URLs - Download threads close their DB connection and stale tasks are reaped, keeping behaviour Gunicorn-friendly Frontend: - /duplicates: exact duplicate groups with per-copy delete, visual similarity controls, search similar to a J-ID, paginated groups with selection, bulk delete and dismiss - /delete: storage cards, delete by J-ID with preview grid, temp cleanup - /users: staff directory with role selects and avatar J-ID inputs - Nav + command palette entries; top-bar avatar; upload cards and the metadata modal show library visual matches
42 lines
1.2 KiB
Python
42 lines
1.2 KiB
Python
from django.urls import include, path
|
|
from rest_framework.routers import DefaultRouter
|
|
|
|
from .tools import (
|
|
ClearTempView,
|
|
DeleteFilesView,
|
|
ExactDuplicatesView,
|
|
StorageView,
|
|
VisualGroupsView,
|
|
VisualMatchesView,
|
|
)
|
|
from .uploads import TempUploadViewSet
|
|
from .views import ClientDownloadView, DownloadTaskViewSet, MediaItemViewSet
|
|
|
|
router = DefaultRouter()
|
|
router.register("files", MediaItemViewSet, basename="file")
|
|
router.register("uploads", TempUploadViewSet, basename="upload")
|
|
router.register("online/downloads", DownloadTaskViewSet, basename="download")
|
|
|
|
urlpatterns = [
|
|
path("", include(router.urls)),
|
|
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("storage/", StorageView.as_view(), name="storage_info"),
|
|
]
|