Skip to content

Commit f11a133

Browse files
committed
fix leap year searching and tests. small metadatabuffer size optimization.
1 parent 7f30561 commit f11a133

File tree

5 files changed

+66
-18
lines changed

5 files changed

+66
-18
lines changed

src/backend/model/database/SearchManager.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ export class SearchManager {
764764
tq.frequency === DatePatternFrequency.days_ago)) {
765765

766766
if (isNaN(tq.agoNumber)) {
767-
throw new Error('ago number is missing on date patter search query with frequency: ' + DatePatternFrequency[tq.frequency] + ', ago number: ' + tq.agoNumber);
767+
throw new Error('ago number is missing on date pattern search query with frequency: ' + DatePatternFrequency[tq.frequency] + ', ago number: ' + tq.agoNumber);
768768
}
769769
const to = new Date();
770770
to.setHours(0, 0, 0, 0);
@@ -853,15 +853,16 @@ export class SearchManager {
853853
};
854854
switch (tq.frequency) {
855855
case DatePatternFrequency.every_year:
856-
if (tq.daysLength >= 365) { // trivial result includes all photos
856+
const d = new Date();
857+
if (tq.daysLength >= (Utils.isDateFromLeapYear(d) ? 366: 365)) { // trivial result includes all photos
857858
if (tq.negate) {
858859
q.andWhere('FALSE');
859860
}
860861
return q;
861862
}
862-
const d = new Date();
863-
const dayOfYear = Math.floor((d.getTime() - new Date(d.getFullYear(), 0, 0).getTime()) / 1000 / 60 / 60 / 24);
864-
addWhere('%j', dayOfYear - tq.daysLength < 0);
863+
864+
const dayOfYear = Utils.getDayOfYear(d);
865+
addWhere('%m%d', dayOfYear - tq.daysLength < 0);
865866
break;
866867
case DatePatternFrequency.every_month:
867868
if (tq.daysLength >= 31) { // trivial result includes all photos

src/backend/model/fileaccess/MetadataLoader.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export class MetadataLoader {
194194
translateValues: false, //don't translate orientation from numbers to strings etc.
195195
mergeOutput: false //don't merge output, because things like Microsoft Rating (percent) and xmp.rating will be merged
196196
};
197-
197+
198198
//function to convert timestamp into milliseconds taking offset into account
199199
const timestampToMS = (timestamp: string, offset: string) => {
200200
if (!timestamp) {
@@ -240,10 +240,21 @@ export class MetadataLoader {
240240
}
241241

242242
try {
243-
const data = Buffer.allocUnsafe(Config.Media.photoMetadataSize);
243+
let bufferSize = Config.Media.photoMetadataSize;
244+
try {
245+
const stat = fs.statSync(fullPath);
246+
metadata.fileSize = stat.size;
247+
//No reason to make the buffer larger than the actual file
248+
bufferSize = Math.min(Config.Media.photoMetadataSize, metadata.fileSize);
249+
metadata.creationDate = stat.mtime.getTime();
250+
} catch (err) {
251+
// ignoring errors
252+
}
253+
254+
const data = Buffer.allocUnsafe(bufferSize);
244255
fileHandle = await fs.promises.open(fullPath, 'r');
245256
try {
246-
await fileHandle.read(data, 0, Config.Media.photoMetadataSize, 0);
257+
await fileHandle.read(data, 0, bufferSize, 0);
247258
} catch (err) {
248259
Logger.error(LOG_TAG, 'Error during reading photo: ' + fullPath);
249260
console.error(err);
@@ -252,13 +263,6 @@ export class MetadataLoader {
252263
await fileHandle.close();
253264
}
254265
try {
255-
try {
256-
const stat = fs.statSync(fullPath);
257-
metadata.fileSize = stat.size;
258-
metadata.creationDate = stat.mtime.getTime();
259-
} catch (err) {
260-
// ignoring errors
261-
}
262266
try {
263267
//read the actual image size, don't rely on tags for this
264268
const info = imageSize(fullPath);

src/common/Utils.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,26 @@ export class Utils {
147147
}
148148
}
149149

150+
static isLeapYear(year: number) {
151+
return (0 == year % 4) && (0 != year % 100) || (0 == year % 400)
152+
}
153+
154+
static isDateFromLeapYear(date: Date) {
155+
return Utils.isLeapYear(date.getFullYear());
156+
}
157+
158+
// Get Day of Year
159+
static getDayOfYear(date: Date) {
160+
//Day-number at the start of Jan to Dec. A month baseline
161+
const dayCount = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
162+
const mn = date.getMonth();
163+
let dayOfYear = dayCount[mn] + date.getDate(); //add the date to the month baseline
164+
if (mn > 1 && Utils.isLeapYear((date.getFullYear()))) {
165+
dayOfYear++; //Add an extra day for march to december (mn>1) on leap years
166+
}
167+
return dayOfYear;
168+
};
169+
150170
static renderDataSize(size: number): string {
151171
const postFixes = ['B', 'KB', 'MB', 'GB', 'TB'];
152172
let index = 0;

src/frontend/app/ui/gallery/navigator/sorting.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ export class GallerySortingService {
184184
private getGroupByNameFn(grouping: GroupingMethod) {
185185
switch (grouping.method) {
186186
case SortByTypes.Date:
187-
return (m: MediaDTO) => this.datePipe.transform(m.metadata.creationDate, 'longDate', m.metadata.creationDateOffset);
187+
return (m: MediaDTO) => this.datePipe.transform(m.metadata.creationDate, 'longDate', m.metadata.creationDateOffset ? m.metadata.creationDateOffset : 'UTC');
188188

189189
case SortByTypes.Name:
190190
return (m: MediaDTO) => m.name.at(0).toUpperCase();

test/backend/unit/model/sql/SearchManager.spec.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,36 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
115115
subDir2 = TestHelper.getDirectoryEntry(directory, 'Return of the Jedi');
116116
p = TestHelper.getPhotoEntry1(directory);
117117
p.metadata.creationDate = Date.now();
118+
p.metadata.creationDateOffset = "+02:00";
118119
p2 = TestHelper.getPhotoEntry2(directory);
119120
p2.metadata.creationDate = Date.now() - 60 * 60 * 24 * 1000;
121+
p2.metadata.creationDateOffset = "+02:00";
120122
v = TestHelper.getVideoEntry1(directory);
121123
v.metadata.creationDate = Date.now() - 60 * 60 * 24 * 7 * 1000;
124+
v.metadata.creationDateOffset = "+02:00";
122125
gpx = TestHelper.getRandomizedGPXEntry(directory);
123126
p4 = TestHelper.getPhotoEntry4(subDir2);
124-
p4.metadata.creationDate = Date.now() - 60 * 60 * 24 * 366 * 1000;
127+
let d = new Date();
128+
//set creation date to one year and one day earlier
129+
p4.metadata.creationDate = d.getTime() - 60 * 60 * 24 * (Utils.isDateFromLeapYear(d) ? 367 : 366) * 1000;
130+
p4.metadata.creationDateOffset = "+02:00";
125131
const pFaceLessTmp = TestHelper.getPhotoEntry3(subDir);
126132
delete pFaceLessTmp.metadata.faces;
127-
pFaceLessTmp.metadata.creationDate = Date.now() - 60 * 60 * 24 * 32 * 1000;
133+
d = new Date();
134+
//we create a date 1 month and 1 day before now
135+
if ([1, 3, 5, 7, 8, 10, 0].includes(d.getMonth())) {
136+
//Now is a month after a long month: feb (1), april (3), june (5), august(7), september(8), november (10), january (0)
137+
pFaceLessTmp.metadata.creationDate = d.getTime() - 60 * 60 * 24 * 32 * 1000;
138+
} else if (d.getMonth() == 2 && Utils.isDateFromLeapYear(d)) {
139+
//march on leap years
140+
pFaceLessTmp.metadata.creationDate = d.getTime() - 60 * 60 * 24 * 30 * 1000;
141+
} else if (d.getMonth() == 2) {
142+
//march (and not leap years)
143+
pFaceLessTmp.metadata.creationDate = d.getTime() - 60 * 60 * 24 * 29 * 1000;
144+
} else { //all other months must come after a short month with 30 days, so we subtract 31
145+
pFaceLessTmp.metadata.creationDate = d.getTime() - 60 * 60 * 24 * 31 * 1000;
146+
}
147+
pFaceLessTmp.metadata.creationDateOffset = "+02:00";
128148

129149
dir = await DBTestHelper.persistTestDir(directory);
130150
subDir = dir.directories[0];
@@ -937,13 +957,16 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
937957
await setUpSqlDB();
938958
p5 = TestHelper.getBasePhotoEntry(subDir2, 'p5-23h-ago.jpg');
939959
p5.metadata.creationDate = Date.now() - 60 * 60 * 24 * 1000 - 1000;
960+
//p5.metadata.creationDateOffset = "+02:00";
940961
p6 = TestHelper.getBasePhotoEntry(subDir2, 'p6-300d-ago.jpg');
941962
p6.metadata.creationDate = Date.now() - 60 * 60 * 24 * 300 * 1000;
963+
//p6.metadata.creationDateOffset = "+02:00";
942964
p7 = TestHelper.getBasePhotoEntry(subDir2, 'p7-1y-1min-ago.jpg');
943965
const d = new Date();
944966
d.setUTCFullYear(d.getUTCFullYear() - 1);
945967
d.setUTCMinutes(d.getUTCMinutes() - 1);
946968
p7.metadata.creationDate = d.getTime();
969+
//p7.metadata.creationDateOffset = "+02:00";
947970

948971
subDir2 = await DBTestHelper.persistTestDir(subDir2) as any;
949972
p4 = subDir2.media[0];

0 commit comments

Comments
 (0)