diff --git a/src/lib/FileNameVideoMetaExtractor.ts b/src/lib/FileNameVideoMetaExtractor.ts index d81fa08..c71543d 100644 --- a/src/lib/FileNameVideoMetaExtractor.ts +++ b/src/lib/FileNameVideoMetaExtractor.ts @@ -242,13 +242,17 @@ export class FileNameVideoMetaExtractor { result.episode = "" + ep; } if (ep >= 0) { - if (sea < 0) { - sea = 1; - //assume season 1 - result.season = "1"; + // An episode with no season is left season-LESS on purpose: a season + // is only asserted when explicitly hinted (an S-token in the filename + // here, or the parent folder via computeSeasonFromParentFolder above). + // Absolute-numbered releases ("Show - 28") thus carry an episode and + // no season, so consumers bucket them under "Episodes" rather than a + // fabricated "Season 1". `increment` encodes a season, so it is only + // emitted when the season is known. + if (sea >= 0) { + //max ep is 9999 + result.increment = "" + (sea * 10000 + ep); } - //max ep is 9999 - result.increment = "" + (sea * 10000 + ep); } return result; } diff --git a/src/tests/FileNameVideoMetaExtractor.test.ts b/src/tests/FileNameVideoMetaExtractor.test.ts index ce21516..30fd49d 100644 --- a/src/tests/FileNameVideoMetaExtractor.test.ts +++ b/src/tests/FileNameVideoMetaExtractor.test.ts @@ -10,8 +10,9 @@ const watchFolders = [ '/public/bitTorrent/media/' ]; -// Helper to test series/anime (title, season, episode) -async function titleSeasonEpTester(title: string, season: string, episode: string, filePath: string) { +// Helper to test series/anime (title, season, episode). `season` is undefined +// for absolute-numbered releases that carry no explicit season hint. +async function titleSeasonEpTester(title: string, season: string | undefined, episode: string, filePath: string) { const extractor = new FileNameMetaExtractor(watchFolders); const data = await extractor.extractMetadata(filePath); expect(data.originalTitle).toEqual(title); @@ -96,8 +97,8 @@ describe('FileNameMetaExtractor', () => { '/data/watch/test-files/Series/Westworld S03 E08 - Crisis Theory.mp4'); }); - it('handles files named with only episode numbers assuming season 1', async () => { - await titleSeasonEpTester('MythBusters', '1', '1', + it('leaves season unset for files named with only an episode number', async () => { + await titleSeasonEpTester('MythBusters', undefined, '1', '/data/watch/test-files/Series/MythBusters/MythBusters - Episode 1.avi'); }); @@ -109,7 +110,7 @@ describe('FileNameMetaExtractor', () => { describe('Anime patterns', () => { it('[DB]Haibane Renmei_-_13_(Dual Audio_10bit_BD1080p_x265).mkv', async () => { - await titleSeasonEpTester('Haibane Renmei', '1', '13', + await titleSeasonEpTester('Haibane Renmei', undefined, '13', '/data/watch/test-files/Anime/[DB]Haibane Renmei_-_13_(Dual Audio_10bit_BD1080p_x265).mkv'); }); @@ -119,7 +120,7 @@ describe('FileNameMetaExtractor', () => { }); it('[SubsPlease] Shangri-La Frontier - 07 (1080p) [FC412C51].mkv', async () => { - await titleSeasonEpTester('Shangri-La Frontier', '1', '7', + await titleSeasonEpTester('Shangri-La Frontier', undefined, '7', '/data/watch/test-files/Anime/[SubsPlease] Shangri-La Frontier - 07 (1080p) [FC412C51].mkv'); }); @@ -129,7 +130,7 @@ describe('FileNameMetaExtractor', () => { }); it('_AnimeServ__Dakara_07__8bits__1A8C2326_.mp4', async () => { - await titleSeasonEpTester('Dakara', '1', '7', + await titleSeasonEpTester('Dakara', undefined, '7', '/data/watch/test-files/Anime/_AnimeServ__Dakara_07__8bits__1A8C2326_.mp4'); }); @@ -144,7 +145,7 @@ describe('FileNameMetaExtractor', () => { }); it('[Erai-raws] Mob Psycho 100 - 01 [1080p][FB7288A9].mkv', async () => { - await titleSeasonEpTester('Mob Psycho', '1', '1', + await titleSeasonEpTester('Mob Psycho', undefined, '1', '/data/watch/test-files/Anime/[Erai-raws] Mob Psycho 100 - 01 [1080p][FB7288A9].mkv'); }); });