bugfix
This commit is contained in:
@@ -126,13 +126,54 @@ export class FileNameVideoMetaExtractor {
|
|||||||
return this.cleanTitle(this.getParentFolder(filePath, 2));
|
return this.cleanTitle(this.getParentFolder(filePath, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a filename contains a season/episode pattern (indicates TV show)
|
||||||
|
*/
|
||||||
|
private filenameHasSeasonEpisodePattern(filename: string): boolean {
|
||||||
|
const cleanedFilename = this.serieFilesNameAnalysisTool.removeKeywordsFromFilename(filename);
|
||||||
|
const cleanedFilename2 = this.serieFilesNameAnalysisTool.removeSFV(cleanedFilename);
|
||||||
|
const cleanedFilename3 = this.fileNameCleaner.cleanSpecialChars(cleanedFilename2);
|
||||||
|
const cleanedFilename4 = this.fileNameCleaner.cleanSpace(cleanedFilename3);
|
||||||
|
const [season, episode] = this.serieFilesNameAnalysisTool.findSeasonAndEpisode(cleanedFilename4);
|
||||||
|
return season >= 0 || episode >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
computeTitleFromFilePath(filePath: string): string | undefined {
|
computeTitleFromFilePath(filePath: string): string | undefined {
|
||||||
let filename = this.fileNameCleaner.getFilenameFromPath(filePath);
|
let filename = this.fileNameCleaner.getFilenameFromPath(filePath);
|
||||||
let titleFromFileName = this.computeTitleFromFileName(filename);
|
let titleFromFileName = this.computeTitleFromFileName(filename);
|
||||||
let titleFromParentFolder = this.computeTitleFromParentFolder(filePath);
|
let titleFromParentFolder = this.computeTitleFromParentFolder(filePath);
|
||||||
let titleFromGrandParentFolder = this.computeTitleFromGrandParentFolder(filePath);
|
let titleFromGrandParentFolder = this.computeTitleFromGrandParentFolder(filePath);
|
||||||
let simpleTitle = this.stringArrayOperation.longestString([titleFromFileName, titleFromParentFolder, titleFromGrandParentFolder]);
|
let simpleTitle = this.stringArrayOperation.longestString([titleFromFileName, titleFromParentFolder, titleFromGrandParentFolder]);
|
||||||
|
|
||||||
|
// Check if filename contains season/episode pattern (indicates TV show)
|
||||||
|
const isTvShow = this.filenameHasSeasonEpisodePattern(filename);
|
||||||
|
|
||||||
let selectedTitle;
|
let selectedTitle;
|
||||||
|
|
||||||
|
if (isTvShow) {
|
||||||
|
// For TV shows, prefer the longer title between filename and folder
|
||||||
|
// This handles cases like "S01E01-The Fool.mkv" where "The Fool" is the episode name
|
||||||
|
// but "Lord of Mysteries" in the parent folder is the actual series title
|
||||||
|
const filenameTitleValid = titleFromFileName && titleFromFileName.length > MIN_TITLE_LENGTH;
|
||||||
|
const folderTitleValid = titleFromParentFolder && titleFromParentFolder.length > MIN_TITLE_LENGTH;
|
||||||
|
|
||||||
|
if (filenameTitleValid && folderTitleValid) {
|
||||||
|
// Both valid - prefer the longer one (series names are typically longer than episode names)
|
||||||
|
// Use strict > to avoid preferring folder when lengths are equal (e.g., "Dexter" vs "Series")
|
||||||
|
selectedTitle = titleFromParentFolder.length > titleFromFileName.length
|
||||||
|
? titleFromParentFolder
|
||||||
|
: titleFromFileName;
|
||||||
|
} else if (folderTitleValid) {
|
||||||
|
selectedTitle = titleFromParentFolder;
|
||||||
|
} else if (filenameTitleValid) {
|
||||||
|
selectedTitle = titleFromFileName;
|
||||||
|
} else if (titleFromGrandParentFolder && titleFromGrandParentFolder.length > MIN_TITLE_LENGTH) {
|
||||||
|
selectedTitle = titleFromGrandParentFolder;
|
||||||
|
} else {
|
||||||
|
selectedTitle = simpleTitle;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For non-TV shows (movies, etc.), use original logic: prefer filename
|
||||||
if (titleFromFileName && titleFromFileName.length > MIN_TITLE_LENGTH) {
|
if (titleFromFileName && titleFromFileName.length > MIN_TITLE_LENGTH) {
|
||||||
selectedTitle = titleFromFileName;
|
selectedTitle = titleFromFileName;
|
||||||
} else if (titleFromParentFolder && titleFromParentFolder.length > MIN_TITLE_LENGTH) {
|
} else if (titleFromParentFolder && titleFromParentFolder.length > MIN_TITLE_LENGTH) {
|
||||||
@@ -142,6 +183,7 @@ export class FileNameVideoMetaExtractor {
|
|||||||
} else {
|
} else {
|
||||||
selectedTitle = simpleTitle;
|
selectedTitle = simpleTitle;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedTitle && selectedTitle.length > MIN_TITLE_LENGTH) {
|
if (selectedTitle && selectedTitle.length > MIN_TITLE_LENGTH) {
|
||||||
return selectedTitle;
|
return selectedTitle;
|
||||||
|
|||||||
@@ -164,6 +164,14 @@ describe('FileNameMetaExtractor', () => {
|
|||||||
describe('Edge cases - title from folder (skipped)', () => {
|
describe('Edge cases - title from folder (skipped)', () => {
|
||||||
// These tests are skipped because the parser doesn't extract title from folder name
|
// These tests are skipped because the parser doesn't extract title from folder name
|
||||||
// when the filename doesn't contain the show title
|
// when the filename doesn't contain the show title
|
||||||
|
// Pattern: FolderWithTitle/S01E01-EpisodeName.mkv should extract title from folder
|
||||||
|
|
||||||
|
it('Lord of Mysteries - title from folder, filename is S01E01-EpisodeName pattern', async () => {
|
||||||
|
// Real-world case: folder contains title + quality info, filename is S01E01-EpisodeName format
|
||||||
|
// Expected: extract "Lord of Mysteries" from folder, not "The Fool" from filename
|
||||||
|
await titleSeasonEpTester('Lord of Mysteries', '1', '1',
|
||||||
|
'/data/watch/test-files/Anime/Lord of Mysteries S01 1080p Dual Audio WEBRip DD+ x265-EMBER/S01E01-The Fool [8A4E8B1F].mkv');
|
||||||
|
});
|
||||||
|
|
||||||
it.skip('handles files named with season in folder', async () => {
|
it.skip('handles files named with season in folder', async () => {
|
||||||
await titleSeasonEpTester('MythBusters', '2', '1',
|
await titleSeasonEpTester('MythBusters', '2', '1',
|
||||||
@@ -180,7 +188,7 @@ describe('FileNameMetaExtractor', () => {
|
|||||||
'/data/watch/test-files/Anime/Le Depart/13 it a new start.mkv');
|
'/data/watch/test-files/Anime/Le Depart/13 it a new start.mkv');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Akudama Drive - title from folder', async () => {
|
it('Akudama Drive - title from folder', async () => {
|
||||||
await titleSeasonEpTester('Akudama Drive', '1', '2',
|
await titleSeasonEpTester('Akudama Drive', '1', '2',
|
||||||
'/data/watch/test-files/Anime/Akudama Drive/S01E02-RESERVOIR DOGS [F1D64557].mkv');
|
'/data/watch/test-files/Anime/Akudama Drive/S01E02-RESERVOIR DOGS [F1D64557].mkv');
|
||||||
});
|
});
|
||||||
@@ -210,8 +218,8 @@ describe('FileNameMetaExtractor', () => {
|
|||||||
'/data/watch/test-files/Anime/K-Project/[CBM]_K_-_02_-_Kitten_[1080p-FLAC]_[A83DF131].mkv');
|
'/data/watch/test-files/Anime/K-Project/[CBM]_K_-_02_-_Kitten_[1080p-FLAC]_[A83DF131].mkv');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('Made in Abyss - title from folder', async () => {
|
it('Made in Abyss - title from folder', async () => {
|
||||||
await titleSeasonEpTester('Made In Abyss', '1', '2',
|
await titleSeasonEpTester('Made in Abyss', '1', '2',
|
||||||
'/data/watch/test-files/Anime/Made in Abyss/S01E02-Resurrection Festival [AE07AD68].mkv');
|
'/data/watch/test-files/Anime/Made in Abyss/S01E02-Resurrection Festival [AE07AD68].mkv');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user