[sorting] Derive browse date from filename, fall back to tag
This commit is contained in:
107
__tests__/util/arrays.test.js
Normal file
107
__tests__/util/arrays.test.js
Normal file
@ -0,0 +1,107 @@
|
||||
import { sortItems } from '../../src/js/util/arrays';
|
||||
|
||||
describe('sortItems', () => {
|
||||
describe('date sorting', () => {
|
||||
it('should prefer a date embedded in the filename over the tag date', () => {
|
||||
const tracks = [
|
||||
{
|
||||
name: 'Talk Python',
|
||||
uri: 'file:///media/podcasts/563-2026-09-22-EVE-Online.mp3',
|
||||
release_date: '2023-10-13',
|
||||
},
|
||||
{
|
||||
name: 'Up First',
|
||||
uri: 'file:///media/podcasts/2026-09-01_Up%20First.mp3',
|
||||
release_date: '2026-09-01',
|
||||
},
|
||||
];
|
||||
|
||||
expect(sortItems(tracks, 'date').map((track) => track.name)).toEqual([
|
||||
'Up First',
|
||||
'Talk Python',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should fall back to the tag date when the filename has no date', () => {
|
||||
const tracks = [
|
||||
{
|
||||
name: 'Newer',
|
||||
uri: 'spotify:track:newer',
|
||||
release_date: '2001-05-01',
|
||||
},
|
||||
{
|
||||
name: 'Older',
|
||||
uri: 'spotify:track:older',
|
||||
release_date: '1999-01-01',
|
||||
},
|
||||
];
|
||||
|
||||
expect(sortItems(tracks, 'date').map((track) => track.name)).toEqual([
|
||||
'Older',
|
||||
'Newer',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should sort year-only tag dates within their year', () => {
|
||||
const tracks = [
|
||||
{
|
||||
name: 'Year only',
|
||||
uri: 'spotify:track:year',
|
||||
release_date: '2026',
|
||||
},
|
||||
{
|
||||
name: 'Previous year',
|
||||
uri: 'spotify:track:previous',
|
||||
release_date: '2025-12-31',
|
||||
},
|
||||
];
|
||||
|
||||
expect(sortItems(tracks, 'date').map((track) => track.name)).toEqual([
|
||||
'Previous year',
|
||||
'Year only',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should sort tracks sharing a date by album and track number', () => {
|
||||
const tracks = [
|
||||
{
|
||||
name: 'Second',
|
||||
uri: 'file:///media/podcasts/2026-09-22_second.mp3',
|
||||
album: { name: 'Podcast' },
|
||||
track_number: 2,
|
||||
},
|
||||
{
|
||||
name: 'First',
|
||||
uri: 'file:///media/podcasts/2026-09-22_first.mp3',
|
||||
album: { name: 'Podcast' },
|
||||
track_number: 1,
|
||||
},
|
||||
];
|
||||
|
||||
expect(sortItems(tracks, 'date').map((track) => track.name)).toEqual([
|
||||
'First',
|
||||
'Second',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should reverse the order', () => {
|
||||
const tracks = [
|
||||
{
|
||||
name: 'Talk Python',
|
||||
uri: 'file:///media/podcasts/563-2026-09-22-EVE-Online.mp3',
|
||||
release_date: '2023-10-13',
|
||||
},
|
||||
{
|
||||
name: 'Up First',
|
||||
uri: 'file:///media/podcasts/2026-09-01_Up%20First.mp3',
|
||||
release_date: '2026-09-01',
|
||||
},
|
||||
];
|
||||
|
||||
expect(sortItems(tracks, 'date', true).map((track) => track.name)).toEqual([
|
||||
'Talk Python',
|
||||
'Up First',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -134,6 +134,23 @@ const createRange = function (indexes) {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract a YYYY-MM-DD date from an item's filename (URI)
|
||||
*
|
||||
* Tag dates can be year-only (or missing) for podcasts, so prefer a date embedded in
|
||||
* the file's name (eg 2026-09-22_Episode.mp3) where available.
|
||||
*
|
||||
* @param uri = string
|
||||
* @return string | null
|
||||
* */
|
||||
const dateFromUri = (uri) => {
|
||||
if (!uri) return null;
|
||||
|
||||
const filename = String(uri).split('/').pop() || '';
|
||||
const match = filename.match(/(\d{4}-\d{2}-\d{2})/);
|
||||
return match ? match[1] : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sort an array of objects
|
||||
* @param array = array to sort
|
||||
@ -160,16 +177,17 @@ const sortItems = (array, property, reverse = false) => {
|
||||
case 'user':
|
||||
return item.user ? item.user.id : undefined;
|
||||
case 'date':
|
||||
return item.release_date || '';
|
||||
return dateFromUri(item.uri) || item.release_date || '';
|
||||
default:
|
||||
return item[property];
|
||||
}
|
||||
};
|
||||
|
||||
// Special handling for date sort: sort by release date first, then track number
|
||||
// Special handling for date sort: sort by the date in the filename (where available),
|
||||
// then the tag date, album name and track number
|
||||
if (property === 'date') {
|
||||
return orderBy(array, [
|
||||
item => item.release_date || '',
|
||||
item => dateFromUri(item.uri) || item.release_date || '',
|
||||
item => item.album?.name || '',
|
||||
item => item.track_number || 0,
|
||||
], [reverse ? 'desc' : 'asc', 'asc', 'asc']);
|
||||
|
||||
Reference in New Issue
Block a user