feat: Add video count to person API and frontend for enhanced media management
This commit introduces a new `video_count` field in the `PersonWithFaces` interface and updates the API to return video counts alongside face counts. The frontend has been modified to display video counts in the people list and includes functionality for selecting and unmatching videos. Additionally, the layout has been enhanced to support resizing of the people panel, improving user experience when managing faces and videos. Documentation has been updated to reflect these changes.
This commit is contained in:
+23
-3
@@ -50,16 +50,16 @@ def list_people_with_faces(
|
||||
last_name: str | None = Query(None, description="Filter by last name or maiden name (case-insensitive)"),
|
||||
db: Session = Depends(get_db),
|
||||
) -> PeopleWithFacesListResponse:
|
||||
"""List all people with face counts, sorted by last_name, first_name.
|
||||
"""List all people with face counts and video counts, sorted by last_name, first_name.
|
||||
|
||||
Optionally filter by last_name or maiden_name if provided (case-insensitive search).
|
||||
Returns all people, including those with zero faces.
|
||||
Returns all people, including those with zero faces or videos.
|
||||
"""
|
||||
# Query people with face counts using LEFT OUTER JOIN to include people with no faces
|
||||
query = (
|
||||
db.query(
|
||||
Person,
|
||||
func.count(Face.id).label('face_count')
|
||||
func.count(Face.id.distinct()).label('face_count')
|
||||
)
|
||||
.outerjoin(Face, Person.id == Face.person_id)
|
||||
.group_by(Person.id)
|
||||
@@ -75,6 +75,25 @@ def list_people_with_faces(
|
||||
|
||||
results = query.order_by(Person.last_name.asc(), Person.first_name.asc()).all()
|
||||
|
||||
# Get video counts separately for each person
|
||||
person_ids = [person.id for person, _ in results]
|
||||
video_counts = {}
|
||||
if person_ids:
|
||||
video_count_query = (
|
||||
db.query(
|
||||
PhotoPersonLinkage.person_id,
|
||||
func.count(PhotoPersonLinkage.id).label('video_count')
|
||||
)
|
||||
.join(Photo, PhotoPersonLinkage.photo_id == Photo.id)
|
||||
.filter(
|
||||
PhotoPersonLinkage.person_id.in_(person_ids),
|
||||
Photo.media_type == "video"
|
||||
)
|
||||
.group_by(PhotoPersonLinkage.person_id)
|
||||
)
|
||||
for person_id, video_count in video_count_query.all():
|
||||
video_counts[person_id] = video_count
|
||||
|
||||
items = [
|
||||
PersonWithFacesResponse(
|
||||
id=person.id,
|
||||
@@ -84,6 +103,7 @@ def list_people_with_faces(
|
||||
maiden_name=person.maiden_name,
|
||||
date_of_birth=person.date_of_birth,
|
||||
face_count=face_count or 0, # Convert None to 0 for people with no faces
|
||||
video_count=video_counts.get(person.id, 0), # Get video count or default to 0
|
||||
)
|
||||
for person, face_count in results
|
||||
]
|
||||
|
||||
@@ -66,3 +66,4 @@ def update_role_permissions(
|
||||
features = [RoleFeatureSchema(**feature) for feature in ROLE_FEATURES]
|
||||
return RolePermissionsResponse(features=features, permissions=permissions)
|
||||
|
||||
|
||||
|
||||
@@ -335,3 +335,4 @@ def get_video_file(
|
||||
response.headers["Cache-Control"] = "public, max-age=3600"
|
||||
return response
|
||||
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ class PersonWithFacesResponse(BaseModel):
|
||||
maiden_name: Optional[str] = None
|
||||
date_of_birth: Optional[date] = None
|
||||
face_count: int
|
||||
video_count: int
|
||||
|
||||
|
||||
class PeopleWithFacesListResponse(BaseModel):
|
||||
|
||||
@@ -40,3 +40,4 @@ class RolePermissionsUpdateRequest(BaseModel):
|
||||
def build_feature_list() -> list[RoleFeatureSchema]:
|
||||
return [RoleFeatureSchema(**feature) for feature in ROLE_FEATURES]
|
||||
|
||||
|
||||
|
||||
@@ -88,3 +88,4 @@ class RemoveVideoPersonResponse(BaseModel):
|
||||
removed: bool
|
||||
message: str
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user