Skip to content

Commit

Permalink
Merge pull request #862 from sarayourfriend/fix/numerical-file-sort
Browse files Browse the repository at this point in the history
Trim extensions when sorting filenames
  • Loading branch information
bpatrik authored Mar 30, 2024
2 parents fafab0d + c44110d commit 1e0dbc0
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 3 deletions.
15 changes: 14 additions & 1 deletion src/common/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ export class Utils {
}

static getOffsetMinutes(offsetString: string) { //Convert offset string (+HH:MM or -HH:MM) into a minute value
const regex = /^([+-](0[0-9]|1[0-4]):[0-5][0-9])$/; //checks if offset is between -14:00 and +14:00.
const regex = /^([+-](0[0-9]|1[0-4]):[0-5][0-9])$/; //checks if offset is between -14:00 and +14:00.
//-12:00 is the lowest valid UTC-offset, but we allow down to -14 for efficiency
if (regex.test(offsetString)) {
const hhmm = offsetString.split(":");
Expand Down Expand Up @@ -389,6 +389,19 @@ export class Utils {
const sign = (parts[3] === "N" || parts[3] === "E") ? 1 : -1;
return sign * (degrees + (minutes / 60.0))
}


public static sortableFilename(filename: string): string {
const lastDot = filename.lastIndexOf(".");

// Avoid 0 as well as -1 to prevent empty names for extensionless dot-files
if (lastDot > 0) {
return filename.substring(0, lastDot);
}

// Fallback to the full name
return filename;
}
}

export class LRU<V> {
Expand Down
16 changes: 14 additions & 2 deletions src/frontend/app/ui/gallery/navigator/sorting.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,20 @@ export class GallerySortingService {
}
switch (sorting.method) {
case SortByTypes.Name:
media.sort((a: PhotoDTO, b: PhotoDTO) =>
this.collator.compare(a.name, b.name)
media.sort((a: PhotoDTO, b: PhotoDTO) => {
const aSortable = Utils.sortableFilename(a.name)
const bSortable = Utils.sortableFilename(b.name)

if (aSortable === bSortable) {
// If the trimmed filenames match, use the full name as tie breaker
// This preserves a consistent final position for files named e.g.,
// 10.jpg and 10.png, even if their starting position in the list
// changes based on any previous sorting that's happened under different heuristics
return this.collator.compare(a.name, b.name)
}

return this.collator.compare(aSortable, bSortable)
}
);
break;
case SortByTypes.Date:
Expand Down
18 changes: 18 additions & 0 deletions test/common/unit/Utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,22 @@ describe('Utils', () => {
expect(Utils.equalsFilter({a: 0}, {b: 0})).to.be.equal(false);
expect(Utils.equalsFilter({a: 0}, {a: 0})).to.be.equal(true);
});

describe('sortableFilename', () => {
it('should trim extensions', () => {
expect(Utils.sortableFilename("10.jpg")).to.be.equal("10")
})

it('should not trim dotfiles to empty strings', () => {
expect(Utils.sortableFilename(".file")).to.be.equal(".file")
})

it('should trim dotfiles with extensions', () => {
expect(Utils.sortableFilename(".favourite.jpg")).to.be.equal(".favourite")
})

it('should not trim without dots', () => {
expect(Utils.sortableFilename("hello_world")).to.be.equal("hello_world")
})
})
});

0 comments on commit 1e0dbc0

Please sign in to comment.