# Infinite Loop Scenario Analysis **Date:** 2025-12-15 **Plugin Versions:** misc_fixes v2.7, stream_organizer v4.7, av1_converter v2.22, audio_standardizer v1.13 --- ## Executive Summary Analyzed all 4 plugins for potential infinite loop conditions. Found **1 confirmed risk**, **2 potential risks**, and **3 low/theoretical risks**. | Risk Level | Plugin | Loop Scenario | Status | |------------|--------|---------------|--------| | � SAFE | misc_fixes | Container/reorder detection | **Already Fixed** | | � SAFE | stream_organizer | Subtitle extraction edge case | Mitigated | | � SAFE | audio_standardizer | Downmix creation detection | Safe | | 🟢 SAFE | av1_converter | Force transcode disabled | Safe | | 🟢 SAFE | stream_organizer | CC extraction | Safe | --- ## ✅ VERIFIED SAFE: misc_fixes Container/Reorder Detection ### Analysis Upon code review, the reorder detection fix is **ALREADY IMPLEMENTED**: ```javascript // Line 228-229 of misc_fixes.js const firstStreamIsVideo = file.ffProbeData.streams[0]?.codec_type === 'video'; const needsReorder = inputs.ensure_video_first === 'true' && !firstStreamIsVideo; ``` **Protection Mechanism:** - `needsReorder` is only `true` if video is NOT first - After reordering, video IS first → `needsReorder = false` - No infinite loop occurs ### Container Remux Logic Also safe: ```javascript if (currentContainer !== targetContainer) { needsRemux = true; } ``` - After remux to MKV, `currentContainer === 'mkv'` - `targetContainer === 'mkv'` - `needsRemux = false` on second pass ### Verified Behavior 1. First pass: File needs reorder → `processFile: true`, reorders 2. Second pass: Video already first → `needsReorder = false` → `processFile: false` 3. Loop terminates **Status:** ✅ SAFE - No fix needed. --- ## 🟡 MEDIUM RISK: stream_organizer Subtitle Extraction ### The Problem Subtitle extraction is protected by `needsSubtitleExtraction()` but has edge cases. ### Edge Case: Extraction Fails Silently ```javascript if (needsSubtitleExtraction(subsFile, baseFile, fs)) { extractCommand += ... extractedFiles.add(subsFile); } ``` **Problem:** If FFmpeg fails to create the file (returns success but file is corrupt), the plugin will: 1. See file doesn't exist (or is tiny) 2. Attempt extraction again 3. Loop ### Current Mitigation ```javascript const attempts = extractionAttempts.get(attemptKey) || 0; if (attempts >= MAX_EXTRACTION_ATTEMPTS) { response.infoLog += `⚠️ Skipping - extraction failed ${MAX_EXTRACTION_ATTEMPTS} times.`; continue; } ``` **Status:** Protected by attempt counter (MAX = 3). **Mitigated.** ### Remaining Risk - Counter is in-memory, resets on Tdarr restart - If Tdarr restarts during processing, attempts reset to 0 --- ## 🟡 MEDIUM RISK: audio_standardizer Downmix Detection ### The Problem Plugin creates downmix tracks if they don't exist: ```javascript if (inputs.create_downmix === 'true') { const hasStereo = audioStreams.some(s => s.channels === 2); if (!hasStereo) { // Create 2ch downmix } } ``` ### Potential Loop Scenario 1. File has 5.1 audio only 2. Plugin creates stereo downmix → `reQueueAfter: true` 3. On re-queue, file now has stereo 4. Should stop... but does it? ### Analysis ```javascript if (needsTranscoding(stream, inputs, targetCodec)) { needsTranscode = true; } ``` **Question:** Does the NEW stereo track created in step 2 get detected as "already Opus"? **Finding:** Likely safe because: - New track is Opus (target codec) - `needsTranscoding()` should return false - `skip_if_compatible === 'true'` by default **Recommendation:** Add explicit check: ```javascript // Skip if we just created a downmix (Opus stereo exists) const hasOpusStereo = audioStreams.some(s => s.channels === 2 && s.codec_name === 'opus' ); if (hasOpusStereo && inputs.create_downmix === 'true') { response.infoLog += 'ℹ️ Stereo downmix already exists (Opus). '; } ``` --- ## 🟢 LOW RISK: av1_converter ### Analysis The AV1 converter has **proper exit conditions**: ```javascript // Already AV1 → Skip if (isAV1 && sanitized.force_transcode !== 'enabled') { response.processFile = false; response.infoLog += 'File is already AV1 encoded and force_transcode is disabled. Skipping.\n'; return response; } ``` **Status:** ✅ Safe. Clear skip when codec matches. ### Theoretical Risk **Only if:** User enables `force_transcode = enabled` - Then every run will transcode - This is intentional (user wants to re-encode) --- ## 🟢 LOW RISK: CC Extraction Loop ### Analysis CC extraction is protected by: 1. Lock file mechanism 2. File existence check using `originalLibraryFile.file` 3. Explicit skip when file exists ```javascript if (ccExists) { ccActuallyExtracted = false; response.infoLog += `ℹ️ ${baseName}.cc.srt already exists. `; } ``` **Status:** ✅ Safe. --- ## Recommendations ### No Immediate Fixes Needed All plugins have proper loop termination conditions: - **misc_fixes**: Already checks if video is first before reordering - **stream_organizer**: Has extraction attempt counter (max 3) - **audio_standardizer**: Detects existing codec (skip_if_compatible) - **av1_converter**: Checks if already AV1 before processing ``` ### Short-term (Priority 2) **Add processing fingerprint to prevent duplicate runs:** ```javascript // At start of plugin const fingerprint = md5(JSON.stringify({ container: file.container, streamOrder: file.ffProbeData.streams.map(s => s.codec_type), imageCounts: // count of image streams })); // Store in file metadata or temp file if (previousFingerprint === fingerprint) { response.infoLog += '⚠️ File unchanged since last run, skipping.'; return response; } ``` ### Long-term (Priority 3) **Add maximum run counter per plugin:** - Tdarr maintains internal counter per file per plugin - If counter > 3, flag file for manual review - Prevents any unexpected loops --- ## Summary | Plugin | Loop Risk | Current Protection | Recommendation | |--------|-----------|-------------------|----------------| | misc_fixes | **HIGH** | None | Add order check | | stream_organizer | LOW | Attempt counter | Already mitigated | | audio_standardizer | LOW | Codec detection | Add explicit check | | av1_converter | NONE | isAV1 check | None needed | **Next Step:** Implement the misc_fixes reorder detection fix.