mirror of
https://github.com/immich-app/immich.git
synced 2026-07-25 05:50:40 +03:00
Compare commits
1 Commits
fix/min-fa
...
renovate/j
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
866ce9204e |
@@ -23,7 +23,7 @@ opentofu = "1.12.4"
|
||||
"github:extism/cli" = "1.6.3"
|
||||
"github:webassembly/binaryen" = "version_124"
|
||||
"github:extism/js-pdk" = "1.6.0"
|
||||
java = "21.0.2"
|
||||
java = "21.0.12+8.0.LTS"
|
||||
|
||||
[tools."github:jellyfin/jellyfin-ffmpeg"]
|
||||
version = "7.1.3-6"
|
||||
|
||||
@@ -50,12 +50,10 @@ class DriftPeopleRepository extends DriftDatabaseRepository {
|
||||
faces.isVisible.equals(true) &
|
||||
faces.deletedAt.isNull(),
|
||||
)
|
||||
..groupBy([
|
||||
people.id,
|
||||
], having: faces.assetId.count(distinct: true).isBiggerOrEqualValue(minFaces) | people.name.equals('').not())
|
||||
..groupBy([people.id], having: faces.id.count().isBiggerOrEqualValue(minFaces) | people.name.equals('').not())
|
||||
..orderBy([
|
||||
OrderingTerm(expression: people.name.equals('').not(), mode: OrderingMode.desc),
|
||||
OrderingTerm(expression: faces.assetId.count(distinct: true), mode: OrderingMode.desc),
|
||||
OrderingTerm(expression: faces.id.count(), mode: OrderingMode.desc),
|
||||
]);
|
||||
|
||||
return query.map((row) {
|
||||
|
||||
@@ -74,53 +74,4 @@ void main() {
|
||||
expect(people, isEmpty);
|
||||
});
|
||||
});
|
||||
|
||||
group('getAllPeople', () {
|
||||
test('counts distinct assets, not face records, against minFaces', () async {
|
||||
// Regression check: a person can have multiple face records on the same asset
|
||||
// (e.g., metadata import + ML detection), which must not inflate the count used
|
||||
// to compare against minFaces. An unnamed person with 2 distinct photos but 3
|
||||
// face records (2 of them on the same photo) must not pass a minFaces of 3.
|
||||
final user = await ctx.newUser();
|
||||
final asset1 = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final asset2 = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
|
||||
final person = await ctx.newPerson(ownerId: user.id, name: '');
|
||||
await ctx.newFace(assetId: asset1.id, personId: person.id);
|
||||
await ctx.newFace(assetId: asset1.id, personId: person.id);
|
||||
await ctx.newFace(assetId: asset2.id, personId: person.id);
|
||||
|
||||
final people = await sut.getAllPeople(minFaces: 3);
|
||||
|
||||
expect(people, isEmpty);
|
||||
});
|
||||
|
||||
test('returns unnamed people who meet minFaces based on distinct assets', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset1 = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final asset2 = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
final asset3 = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
|
||||
final person = await ctx.newPerson(ownerId: user.id, name: '');
|
||||
await ctx.newFace(assetId: asset1.id, personId: person.id);
|
||||
await ctx.newFace(assetId: asset2.id, personId: person.id);
|
||||
await ctx.newFace(assetId: asset3.id, personId: person.id);
|
||||
|
||||
final people = await sut.getAllPeople(minFaces: 3);
|
||||
|
||||
expect(people.map((p) => p.id), [person.id]);
|
||||
});
|
||||
|
||||
test('always returns named people regardless of minFaces', () async {
|
||||
final user = await ctx.newUser();
|
||||
final asset = await ctx.newRemoteAsset(ownerId: user.id);
|
||||
|
||||
final person = await ctx.newPerson(ownerId: user.id, name: 'Jane');
|
||||
await ctx.newFace(assetId: asset.id, personId: person.id);
|
||||
|
||||
final people = await sut.getAllPeople(minFaces: 3);
|
||||
|
||||
expect(people.map((p) => p.id), [person.id]);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ group by
|
||||
having
|
||||
(
|
||||
"person"."name" != $3
|
||||
or count(distinct ("asset_face"."assetId")) >= COALESCE(
|
||||
or count("asset_face"."assetId") >= COALESCE(
|
||||
(
|
||||
SELECT
|
||||
value -> 'people' ->> 'minimumFaces'
|
||||
@@ -59,7 +59,7 @@ order by
|
||||
"person"."isHidden" asc,
|
||||
"person"."isFavorite" desc,
|
||||
NULLIF(person.name, '') is null asc,
|
||||
count(distinct ("asset_face"."assetId")) desc,
|
||||
count("asset_face"."assetId") desc,
|
||||
NULLIF(person.name, '') asc nulls last,
|
||||
"person"."createdAt"
|
||||
limit
|
||||
|
||||
@@ -168,7 +168,7 @@ export class PersonRepository {
|
||||
eb.or([
|
||||
eb('person.name', '!=', ''),
|
||||
eb(
|
||||
(innerEb) => innerEb.fn.count(innerEb.fn('distinct', ['asset_face.assetId'])),
|
||||
(innerEb) => innerEb.fn.count('asset_face.assetId'),
|
||||
'>=',
|
||||
sql<number>`COALESCE(
|
||||
(SELECT value -> 'people' ->> 'minimumFaces'
|
||||
@@ -201,7 +201,7 @@ export class PersonRepository {
|
||||
.$if(!options?.closestFaceAssetId, (qb) =>
|
||||
qb
|
||||
.orderBy(sql`NULLIF(person.name, '') is null`, 'asc')
|
||||
.orderBy((eb) => eb.fn.count(eb.fn('distinct', ['asset_face.assetId'])), 'desc')
|
||||
.orderBy((eb) => eb.fn.count('asset_face.assetId'), 'desc')
|
||||
.orderBy(sql`NULLIF(person.name, '')`, (om) => om.asc().nullsLast())
|
||||
.orderBy('person.createdAt'),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user