Skip to content

Commit 82f05ed

Browse files
committed
Add sorting by disc number and track number
1 parent e415ce6 commit 82f05ed

File tree

7 files changed

+171
-7
lines changed

7 files changed

+171
-7
lines changed

messages/en.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
"album": "Album",
3232
"release_date": "Release Date",
3333
"track_title": "Track Title",
34+
"disc_number": "Disc Number",
35+
"track_number": "Track Number",
3436
"ascending": "Ascending",
3537
"descending": "Descending",
3638
"no_rules_applied": "No rules applied yet",

messages/es.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
"album": "Álbum",
3131
"release_date": "Fecha de Lanzamiento",
3232
"track_title": "Título de la Pista",
33+
"disc_number": "Número de Disco",
34+
"track_number": "Número de Pista",
3335
"ascending": "Ascendente",
3436
"descending": "Descendente",
3537
"no_rules_applied": "Aún no se aplicaron reglas",

src/features/sorting/utils/sortRules.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,21 @@ describe('getSortKeyName', () => {
180180
})
181181

182182
test('should handle all sort keys', () => {
183-
const sortKeys: SortKey[] = ['artist', 'album', 'release_date', 'title']
183+
const sortKeys: SortKey[] = [
184+
'artist',
185+
'album',
186+
'release_date',
187+
'title',
188+
'disc_number',
189+
'track_number',
190+
]
184191
const expectedNames: Record<SortKey, string> = {
185192
artist: 'Artist',
186193
album: 'Album',
187194
release_date: 'Release Date',
188195
title: 'Track Title',
196+
disc_number: 'Disc Number',
197+
track_number: 'Track Number',
189198
}
190199

191200
sortKeys.forEach((key) => {

src/features/sorting/utils/sortRules.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
/**
22
* Sort key type.
33
*/
4-
export type SortKey = 'artist' | 'title' | 'album' | 'release_date'
4+
export type SortKey =
5+
| 'artist'
6+
| 'title'
7+
| 'album'
8+
| 'release_date'
9+
| 'disc_number'
10+
| 'track_number'
511

612
/**
713
* Sort oder type.
@@ -23,6 +29,8 @@ export const SORT_KEY_LABELS: Record<SortKey, string> = {
2329
album: m.album(),
2430
release_date: m.release_date(),
2531
title: m.track_title(),
32+
disc_number: m.disc_number(),
33+
track_number: m.track_number(),
2634
}
2735

2836
/**
@@ -62,6 +70,10 @@ function getSortKeyLabel(sortKey: SortKey): string {
6270
return m.release_date()
6371
case 'title':
6472
return m.track_title()
73+
case 'disc_number':
74+
return m.disc_number()
75+
case 'track_number':
76+
return m.track_number()
6577
default:
6678
return sortKey
6779
}
@@ -83,7 +95,14 @@ export function getSortKeyName(sortKey: SortKey): string {
8395
const sortRuleSeparator = ' '
8496
const sortKeyOrderSeparator = '/'
8597

86-
const validSortKeys = ['artist', 'album', 'release_date', 'title'] as const
98+
const validSortKeys = [
99+
'artist',
100+
'album',
101+
'release_date',
102+
'title',
103+
'disc_number',
104+
'track_number',
105+
] as const
87106
const validSortOrders: SortOrder[] = ['asc', 'desc']
88107

89108
const defaultSortOrder: SortOrder = 'asc'

src/features/sorting/utils/sortTracks.test.ts

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ function createTrack(
77
artistName: string,
88
albumName: string | null = 'Test Album',
99
releaseDate: string | null = '2024-01-01',
10+
discNumber: number = 1,
11+
trackNumber: number = 1,
1012
id = Math.random().toString(36).substring(7),
1113
): SpotifyApi.PlaylistTrackObject {
1214
return {
@@ -67,8 +69,8 @@ function createTrack(
6769
external_urls: { spotify: '' },
6870
type: 'track',
6971
popularity: 50,
70-
track_number: 1,
71-
disc_number: 1,
72+
track_number: trackNumber,
73+
disc_number: discNumber,
7274
preview_url: null,
7375
available_markets: [],
7476
is_playable: true,
@@ -83,6 +85,8 @@ function createTrack(
8385
function createMultiArtistTrack(
8486
name: string,
8587
artistNames: string[],
88+
discNumber: number = 1,
89+
trackNumber: number = 1,
8690
): SpotifyApi.PlaylistTrackObject {
8791
return {
8892
added_at: '2023-01-01',
@@ -140,8 +144,8 @@ function createMultiArtistTrack(
140144
external_urls: { spotify: '' },
141145
type: 'track',
142146
popularity: 50,
143-
track_number: 1,
144-
disc_number: 1,
147+
track_number: trackNumber,
148+
disc_number: discNumber,
145149
preview_url: null,
146150
available_markets: [],
147151
is_playable: true,
@@ -338,6 +342,94 @@ describe('sortTracks', () => {
338342
).toBe('2020-05-15')
339343
})
340344
})
345+
346+
describe('disc_number sorting', () => {
347+
test('should sort by disc_number ascending', () => {
348+
const tracks = [
349+
createTrack('Song 1', 'Artist', 'Album', '2024-01-01', 2, 1),
350+
createTrack('Song 2', 'Artist', 'Album', '2024-01-01', 1, 1),
351+
createTrack('Song 3', 'Artist', 'Album', '2024-01-01', 3, 1),
352+
]
353+
354+
const sortRules: SortRule[] = [['disc_number', 'asc']]
355+
sortTracks(tracks, sortRules)
356+
357+
expect(
358+
(tracks[0]?.track as SpotifyApi.TrackObjectFull).disc_number,
359+
).toBe(1)
360+
expect(
361+
(tracks[1]?.track as SpotifyApi.TrackObjectFull).disc_number,
362+
).toBe(2)
363+
expect(
364+
(tracks[2]?.track as SpotifyApi.TrackObjectFull).disc_number,
365+
).toBe(3)
366+
})
367+
368+
test('should sort by disc_number descending', () => {
369+
const tracks = [
370+
createTrack('Song 1', 'Artist', 'Album', '2024-01-01', 1, 1),
371+
createTrack('Song 2', 'Artist', 'Album', '2024-01-01', 2, 1),
372+
createTrack('Song 3', 'Artist', 'Album', '2024-01-01', 3, 1),
373+
]
374+
375+
const sortRules: SortRule[] = [['disc_number', 'desc']]
376+
sortTracks(tracks, sortRules)
377+
378+
expect(
379+
(tracks[0]?.track as SpotifyApi.TrackObjectFull).disc_number,
380+
).toBe(3)
381+
expect(
382+
(tracks[1]?.track as SpotifyApi.TrackObjectFull).disc_number,
383+
).toBe(2)
384+
expect(
385+
(tracks[2]?.track as SpotifyApi.TrackObjectFull).disc_number,
386+
).toBe(1)
387+
})
388+
})
389+
390+
describe('track_number sorting', () => {
391+
test('should sort by track_number ascending', () => {
392+
const tracks = [
393+
createTrack('Song 3', 'Artist', 'Album', '2024-01-01', 1, 3),
394+
createTrack('Song 1', 'Artist', 'Album', '2024-01-01', 1, 1),
395+
createTrack('Song 2', 'Artist', 'Album', '2024-01-01', 1, 2),
396+
]
397+
398+
const sortRules: SortRule[] = [['track_number', 'asc']]
399+
sortTracks(tracks, sortRules)
400+
401+
expect(
402+
(tracks[0]?.track as SpotifyApi.TrackObjectFull).track_number,
403+
).toBe(1)
404+
expect(
405+
(tracks[1]?.track as SpotifyApi.TrackObjectFull).track_number,
406+
).toBe(2)
407+
expect(
408+
(tracks[2]?.track as SpotifyApi.TrackObjectFull).track_number,
409+
).toBe(3)
410+
})
411+
412+
test('should sort by track_number descending', () => {
413+
const tracks = [
414+
createTrack('Song 1', 'Artist', 'Album', '2024-01-01', 1, 1),
415+
createTrack('Song 2', 'Artist', 'Album', '2024-01-01', 1, 2),
416+
createTrack('Song 3', 'Artist', 'Album', '2024-01-01', 1, 3),
417+
]
418+
419+
const sortRules: SortRule[] = [['track_number', 'desc']]
420+
sortTracks(tracks, sortRules)
421+
422+
expect(
423+
(tracks[0]?.track as SpotifyApi.TrackObjectFull).track_number,
424+
).toBe(3)
425+
expect(
426+
(tracks[1]?.track as SpotifyApi.TrackObjectFull).track_number,
427+
).toBe(2)
428+
expect(
429+
(tracks[2]?.track as SpotifyApi.TrackObjectFull).track_number,
430+
).toBe(1)
431+
})
432+
})
341433
})
342434

343435
describe('multi-rule sorting', () => {

src/features/sorting/utils/sortTracks.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import type { SortKey, SortRule } from '@/features/sorting/utils/sortRules'
22
import {
33
getAlbumName,
44
getArtistName,
5+
getDiscNumber,
56
getReleaseDate,
7+
getTrackNumber,
68
getTrackTitle,
79
} from '@/features/sorting/utils/trackTypeGuards'
810

@@ -15,6 +17,8 @@ const rulesCompareFunctions: Record<SortKey, CompareFunction> = {
1517
title: compareTitles,
1618
album: compareAlbums,
1719
release_date: compareReleaseDates,
20+
disc_number: compareDiscNumbers,
21+
track_number: compareTrackNumbers,
1822
}
1923

2024
export function sortTracks(
@@ -64,6 +68,24 @@ function compareTitles(trackA: PlaylistTrack, trackB: PlaylistTrack): number {
6468
return compareStrings(getTrackTitle(trackA), getTrackTitle(trackB))
6569
}
6670

71+
function compareDiscNumbers(
72+
trackA: PlaylistTrack,
73+
trackB: PlaylistTrack,
74+
): number {
75+
const discA = getDiscNumber(trackA)
76+
const discB = getDiscNumber(trackB)
77+
return discA - discB
78+
}
79+
80+
function compareTrackNumbers(
81+
trackA: PlaylistTrack,
82+
trackB: PlaylistTrack,
83+
): number {
84+
const trackNumA = getTrackNumber(trackA)
85+
const trackNumB = getTrackNumber(trackB)
86+
return trackNumA - trackNumB
87+
}
88+
6789
function compareStrings(str1: string, str2: string): number {
6890
if (!str1) {
6991
return -1

src/features/sorting/utils/trackTypeGuards.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,21 @@ export function getArtistName(track: PlaylistTrack): string {
6666
export function getTrackTitle(track: PlaylistTrack): string {
6767
return track.track?.name ?? ''
6868
}
69+
70+
/**
71+
* Safely extract disc number from a track
72+
* @returns Disc number or 0 if not available
73+
*/
74+
export function getDiscNumber(track: PlaylistTrack): number {
75+
const trackInfo = track.track as SpotifyApi.TrackObjectFull
76+
return trackInfo.disc_number ?? 0
77+
}
78+
79+
/**
80+
* Safely extract track number from a track
81+
* @returns Track number or 0 if not available
82+
*/
83+
export function getTrackNumber(track: PlaylistTrack): number {
84+
const trackInfo = track.track as SpotifyApi.TrackObjectFull
85+
return trackInfo.track_number ?? 0
86+
}

0 commit comments

Comments
 (0)