feat: auto-clean empty channel directories (#443)#459
Conversation
dialmaster
commented
Mar 15, 2026
- Add CHANNEL_CLEANUP_IGNORABLE_FILES constant for files (poster.jpg) that don't count as real content when deciding if a directory is empty
- Add isDirectoryEffectivelyEmpty() with case-insensitive matching for ignorable files
- Enhance cleanupEmptyChannelDirectory() with includeIgnorableFiles option that deletes ignorable files before rmdir; returns boolean; defaults to false for backward compatibility
- Add _tryCleanupChannelDirectory() to videoDeletionModule that runs best-effort after every successful deletion (nested and flat modes), with parent subfolder cleanup when channel dir is removed
- Replace duplicate 30-line cleanup implementation in downloadExecutor with delegation to shared directoryManager function
- Add CHANNEL_CLEANUP_IGNORABLE_FILES constant for files (poster.jpg) that don't count as real content when deciding if a directory is empty - Add isDirectoryEffectivelyEmpty() with case-insensitive matching for ignorable files - Enhance cleanupEmptyChannelDirectory() with includeIgnorableFiles option that deletes ignorable files before rmdir; returns boolean; defaults to false for backward compatibility - Add _tryCleanupChannelDirectory() to videoDeletionModule that runs best-effort after every successful deletion (nested and flat modes), with parent subfolder cleanup when channel dir is removed - Replace duplicate 30-line cleanup implementation in downloadExecutor with delegation to shared directoryManager function
|
Code Review: feat: auto-clean empty channel directories Overall this is a well-structured PR. The consolidation of duplicate cleanup logic is a clear improvement, and the test coverage is thorough. A few observations: Bug / Correctness: TOCTOU race in cleanupEmptyChannelDirectory with includeIgnorableFiles: true When includeIgnorableFiles is true, the function does:
If a real file is added between steps 1 and 2 (e.g., by a concurrent download), the function will unlink it — deleting actual video content — and then successfully rmdir the now-empty directory. The unlink loop does not filter against CHANNEL_CLEANUP_IGNORABLE_FILES; it blindly deletes everything from the second readdir result. The simplest fix: filter the entries in the unlink loop to only files in CHANNEL_CLEANUP_IGNORABLE_FILES (case-insensitively), consistent with how the emptiness check works. This prevents the data-loss risk. Minor: Missing explicit null-guard in _tryCleanupChannelDirectory When filePath is null, path.dirname(null) throws a TypeError which is silently caught by the outer try/catch. This works (the test covers it), but it relies on an error for control flow. An explicit early return would be clearer and avoids a spurious warn-level log in an expected code path. Observation: cleanupEmptyParents uses strict emptiness cleanupEmptyParents calls isDirectoryEmpty (not isDirectoryEffectivelyEmpty), so a subfolder parent containing only poster.jpg will not be cleaned up. Likely intentional since subfolder dirs are not channel dirs — just noting it in case full cleanup was the intent. Positive notes
|
📊 Test Coverage ReportBackend Coverage
Frontend Coverage
Coverage Requirements
Coverage report generated for commit 26f16d8 |