{"record":{"id":"7625c2cb15dd9ccd","repo":"mifi/lossless-cut","slug":"no-vts-vob-files-found-in-folder","errorCode":null,"errorMessage":"No VTS vob files found in folder","messagePattern":"No VTS vob files found in folder","errorType":"exception","errorClass":"UserFacingError","httpStatus":null,"severity":"error","filePath":"src/renderer/src/util.ts","lineNumber":377,"sourceCode":"  if (working) {\n    if (progress != null) parts.push(`${(progress * 100).toFixed(1)}%`);\n    parts.push(working);\n  }\n\n  if (filePath) {\n    parts.push(basename(filePath));\n  }\n\n  parts.push(isStoreBuild ? appName : `${appName} ${appVersion}`);\n\n  document.title = parts.join(' - ');\n}\n\nexport async function readVideoTs(videoTsPath: string) {\n  const files = await readdir(videoTsPath);\n  const relevantFiles = files.filter((file) => /^vts_\\d+_\\d+\\.vob$/i.test(file) && !/^vts_\\d+_00\\.vob$/i.test(file)); // skip menu\n  const ret = sortBy(relevantFiles).map((file) => join(videoTsPath, file));\n  if (ret.length === 0) throw new UserFacingError(i18n.t('No VTS vob files found in folder'));\n  return ret;\n}\n\nexport async function readDirRecursively(dirPath: string) {\n  const files = await readdir(dirPath, { recursive: true });\n  const ret = (await pMap(files, async (path) => {\n    if (['.DS_Store'].includes(basename(path))) return [];\n\n    const absPath = join(dirPath, path);\n    const fileStat = await lstat(absPath); // readdir also returns directories...\n    if (!fileStat.isFile()) return [];\n\n    return [absPath];\n  }, { concurrency: 5 })).flat();\n\n  if (ret.length === 0) throw new UserFacingError(i18n.t('No files found in folder'));\n  return ret;\n}","sourceCodeStart":359,"sourceCodeEnd":395,"githubUrl":"https://github.com/mifi/lossless-cut/blob/3b9a59c288bf6e11076b583c932cfa48ddab3b02/src/renderer/src/util.ts#L359-L395","documentation":"Thrown by readVideoTs() when, after reading the directory and filtering for files matching ^vts_\\d+_\\d+\\.vob$ (case-insensitive) while excluding ^vts_\\d+_00\\.vob$ menu VOBs, the result list is empty. The function exists to gather the playable VTS (Video Title Set) VOBs of a DVD VIDEO_TS folder, so an empty result means this is not a usable DVD structure.","triggerScenarios":"Calling readVideoTs(dir) on a folder that contains no VTS_*_*.VOB files; pointing at a VIDEO_TS folder that only has menu VOBs (VTS_xx_00.VOB); selecting a regular folder that merely happens to be named VIDEO_TS but holds no DVD content.","commonSituations":"User selects the wrong folder (the parent of VIDEO_TS, or a BUP/IFO-only folder); an incompletely ripped DVD missing the title VOBs; a folder containing only the menu/title set metadata; a non-DVD folder passed to the DVD-open path.","solutions":["Confirm the folder is a real DVD VIDEO_TS directory containing VTS_01_1.VOB, VTS_01_2.VOB, etc.","Re-rip the DVD with a tool that produces the full VTS title VOBs, not just menus.","Point the open-folder dialog at the exact VIDEO_TS folder, not its parent.","If only a single VOB is needed, open the .vob file directly rather than via the DVD folder path."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { readdir } from 'fs/promises';\nexport async function hasVtsVobs(videoTsPath: string): Promise<boolean> {\n  const files = await readdir(videoTsPath);\n  return files.some((f) => /^vts_\\d+_\\d+\\.vob$/i.test(f) && !/^vts_\\d+_00\\.vob$/i.test(f));\n}\nif (!(await hasVtsVobs(folder))) showError('Not a DVD VIDEO_TS folder with title VOBs.');","typeGuard":null,"tryCatchPattern":"try {\n  return await readVideoTs(videoTsPath);\n} catch (err) {\n  if (err instanceof UserFacingError && /No VTS vob files/.test(err.message)) {\n    showError('The selected folder has no DVD title VOBs.');\n    return [];\n  }\n  throw err;\n}","preventionTips":["Point the dialog at the exact VIDEO_TS folder containing VTS_*_[1-9].VOB files.","Verify a complete DVD rip (not just menus/IFOs) before opening.","For single-VOB needs, open the .vob file directly instead of the folder."],"tags":["dvd","video-ts","vob","io","folder","validation"],"backgroundTag":null,"analyzedSha":"3b9a59c288bf6e11076b583c932cfa48ddab3b02","analyzedAt":"2026-08-12T20:54:25.651Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}