fix: Upgrade to youtube-transcript-api v1.0+#10456
Conversation
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the WalkthroughUpdated youtube-transcript-api dependency to version >=1.0.0,<2.0.0 and refactored the YouTubeTranscriptsComponent to use the new API with video ID extraction from URLs, transcript chunking logic, improved error handling, and comprehensive test coverage. Changes
Sequence DiagramsequenceDiagram
participant User
participant YouTubeComponent
participant YouTubeTranscriptApi
User->>YouTubeComponent: Provide YouTube URL
YouTubeComponent->>YouTubeComponent: _extract_video_id(url)
alt Valid Video ID
YouTubeComponent->>YouTubeTranscriptApi: list(video_id)
YouTubeTranscriptApi-->>YouTubeComponent: Available transcripts
alt Transcript Available
YouTubeComponent->>YouTubeTranscriptApi: fetch(video_id, language)
YouTubeTranscriptApi-->>YouTubeComponent: Transcript segments
alt Translation Requested
YouTubeComponent->>YouTubeTranscriptApi: fetch with translate
YouTubeTranscriptApi-->>YouTubeComponent: Translated segments
end
YouTubeComponent->>YouTubeComponent: _chunk_transcript(data)
YouTubeComponent->>YouTubeComponent: Generate outputs (DataFrame/Message/Data)
YouTubeComponent-->>User: Success response
else No Transcript Found
YouTubeComponent-->>User: Error: NoTranscriptFound
else Transcripts Disabled
YouTubeComponent-->>User: Error: TranscriptsDisabled
end
else Invalid Video ID
YouTubeComponent-->>User: Error: Invalid URL
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 error, 2 warnings)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. ❌ Your project status has failed because the head coverage (39.37%) is below the target coverage (60.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #10456 +/- ##
==========================================
- Coverage 31.32% 31.30% -0.02%
==========================================
Files 1324 1324
Lines 59920 59920
Branches 8966 8966
==========================================
- Hits 18769 18760 -9
- Misses 40254 40263 +9
Partials 897 897
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json (1)
1870-2065: Mirror the transcript fix in the serialized componentThis JSON embeds the same YouTubeTranscriptsComponent source, so it still has the hard-coded English lookup and
api.fetch(...)call. Please apply the identical fallback +transcript.fetch()change here (and keep the string literal in sync with the Python module) so flows created from this starter project get the corrected behavior.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
pyproject.toml(1 hunks)src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json(3 hunks)src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py(6 hunks)src/lfx/src/lfx/components/youtube/youtube_transcripts.py(3 hunks)
🧰 Additional context used
📓 Path-based instructions (8)
src/backend/tests/unit/components/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
src/backend/tests/unit/components/**/*.py: Mirror the component directory structure for unit tests in src/backend/tests/unit/components/
Use ComponentTestBaseWithClient or ComponentTestBaseWithoutClient as base classes for component unit tests
Provide file_names_mapping for backward compatibility in component tests
Create comprehensive unit tests for all new components
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
{src/backend/**/*.py,tests/**/*.py,Makefile}
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
src/backend/tests/unit/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)
Test component integration within flows using create_flow, build_flow, and get_build_events utilities
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
src/backend/tests/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)
src/backend/tests/**/*.py: Unit tests for backend code must be located in the 'src/backend/tests/' directory, with component tests organized by component subdirectory under 'src/backend/tests/unit/components/'.
Test files should use the same filename as the component under test, with an appropriate test prefix or suffix (e.g., 'my_component.py' → 'test_my_component.py').
Use the 'client' fixture (an async httpx.AsyncClient) for API tests in backend Python tests, as defined in 'src/backend/tests/conftest.py'.
When writing component tests, inherit from the appropriate base class in 'src/backend/tests/base.py' (ComponentTestBase, ComponentTestBaseWithClient, or ComponentTestBaseWithoutClient) and provide the required fixtures: 'component_class', 'default_kwargs', and 'file_names_mapping'.
Each test in backend Python test files should have a clear docstring explaining its purpose, and complex setups or mocks should be well-commented.
Test both sync and async code paths in backend Python tests, using '@pytest.mark.asyncio' for async tests.
Mock external dependencies appropriately in backend Python tests to isolate unit tests from external services.
Test error handling and edge cases in backend Python tests, including using 'pytest.raises' and asserting error messages.
Validate input/output behavior and test component initialization and configuration in backend Python tests.
Use the 'no_blockbuster' pytest marker to skip the blockbuster plugin in tests when necessary.
Be aware of ContextVar propagation in async tests; test both direct event loop execution and 'asyncio.to_thread' scenarios to ensure proper context isolation.
Test error handling by mocking internal functions using monkeypatch in backend Python tests.
Test resource cleanup in backend Python tests by using fixtures that ensure proper initialization and cleanup of resources.
Test timeout and performance constraints in backend Python tests using 'asyncio.wait_for' and timing assertions.
Test Langflow's Messag...
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
src/backend/**/*component*.py
📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)
In your Python component class, set the
iconattribute to a string matching the frontend icon mapping exactly (case-sensitive).
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
src/backend/**/components/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)
In your Python component class, set the
iconattribute to a string matching the frontend icon mapping exactly (case-sensitive).
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
**/{test_*.py,*.test.ts,*.test.tsx}
📄 CodeRabbit inference engine (coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt)
**/{test_*.py,*.test.ts,*.test.tsx}: Check if tests have too many mock objects that obscure what’s actually being tested
Warn when mocks are used instead of testing real behavior and interactions
Suggest using real objects or simpler test doubles when mocks become excessive
Ensure mocks are used only for external dependencies, not core business logic
Recommend integration tests when unit tests become overly mocked
Check that test files follow the project’s naming conventions (backend: test_*.py; frontend: *.test.ts/tsx)
Verify that tests actually exercise the new or changed functionality, not placeholder assertions
Test files should have descriptive test function names explaining what is being tested
Organize tests logically with proper setup and teardown
Include edge cases and error conditions for comprehensive coverage
Verify tests cover both positive (success) and negative (failure) scenarios
Ensure tests are not mere smoke tests; they should validate behavior thoroughly
Ensure tests follow the project’s testing frameworks (pytest for backend, Playwright for frontend)
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
**/test_*.py
📄 CodeRabbit inference engine (coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt)
**/test_*.py: Backend tests must be named test_*.py and use proper pytest structure (fixtures, assertions)
For async backend code, use proper pytest async patterns (e.g., pytest-asyncio)
For API endpoints, include tests for both success and error responses
Files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
🧠 Learnings (5)
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Mock external dependencies appropriately in backend Python tests to isolate unit tests from external services.
Applied to files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Use 'MockLanguageModel' for testing language model components without external API calls in backend Python tests.
Applied to files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
📚 Learning: 2025-08-05T22:51:27.961Z
Learnt from: edwinjosechittilappilly
PR: langflow-ai/langflow#0
File: :0-0
Timestamp: 2025-08-05T22:51:27.961Z
Learning: The TestComposioComponentAuth test in src/backend/tests/unit/components/bundles/composio/test_base_composio.py demonstrates proper integration testing patterns for external API components, including real API calls with mocking for OAuth completion, comprehensive resource cleanup, and proper environment variable handling with pytest.skip() fallbacks.
Applied to files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
📚 Learning: 2025-07-18T18:25:54.486Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-07-18T18:25:54.486Z
Learning: Applies to src/backend/tests/unit/components/**/*.py : Use ComponentTestBaseWithClient or ComponentTestBaseWithoutClient as base classes for component unit tests
Applied to files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : When writing component tests, inherit from the appropriate base class in 'src/backend/tests/base.py' (ComponentTestBase, ComponentTestBaseWithClient, or ComponentTestBaseWithoutClient) and provide the required fixtures: 'component_class', 'default_kwargs', and 'file_names_mapping'.
Applied to files:
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py
🧬 Code graph analysis (2)
src/lfx/src/lfx/components/youtube/youtube_transcripts.py (2)
src/lfx/src/lfx/schema/message.py (1)
Message(34-299)src/lfx/src/lfx/schema/data.py (1)
Data(26-288)
src/backend/tests/unit/components/bundles/youtube/test_youtube_transcript_component.py (1)
src/lfx/src/lfx/components/youtube/youtube_transcripts.py (4)
_extract_video_id(51-62)get_dataframe_output(147-165)get_message_output(167-179)get_data_output(181-206)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: codecov/project/lfx
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
- GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
- GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
- GitHub Check: Lint Backend / Run Mypy (3.10)
- GitHub Check: Lint Backend / Run Mypy (3.11)
- GitHub Check: Lint Backend / Run Mypy (3.12)
- GitHub Check: Run Frontend Tests / Determine Test Suites and Shard Distribution
- GitHub Check: Test Starter Templates
- GitHub Check: Update Component Index
- GitHub Check: test-starter-projects
- GitHub Check: Optimize new Python code in this PR
| if self.translation: | ||
| # Get any available transcript and translate it | ||
| transcript = transcript_list.find_transcript(["en"]) | ||
| transcript = transcript.translate(self.translation) | ||
| else: | ||
| # Try to get transcript in available languages | ||
| try: | ||
| transcript = transcript_list.find_transcript(["en"]) | ||
| except NoTranscriptFound: | ||
| # Try auto-generated English | ||
| transcript = transcript_list.find_generated_transcript(["en"]) | ||
|
|
||
| # Fetch the transcript data | ||
| transcript_data = api.fetch(transcript.video_id, [transcript.language_code]) | ||
|
|
||
| except (TranscriptsDisabled, NoTranscriptFound) as e: | ||
| error_type = type(e).__name__ | ||
| msg = ( | ||
| f"Could not retrieve transcripts for video '{video_id}'. " | ||
| "Possible reasons:\n" | ||
| "1. This video does not have captions/transcripts enabled\n" | ||
| "2. The video is private, restricted, or deleted\n" | ||
| f"\nTechnical error ({error_type}): {e}" | ||
| ) | ||
| raise RuntimeError(msg) from e | ||
| except Exception as e: | ||
| error_type = type(e).__name__ | ||
| msg = ( | ||
| f"Could not retrieve transcripts for video '{video_id}'. " | ||
| "Possible reasons:\n" | ||
| "1. This video does not have captions/transcripts enabled\n" | ||
| "2. The video is private, restricted, or deleted\n" | ||
| "3. YouTube is blocking automated requests\n" | ||
| f"\nTechnical error ({error_type}): {e}" | ||
| ) | ||
| raise RuntimeError(msg) from e | ||
|
|
||
| if as_chunks: | ||
| # Group into chunks based on chunk_size_seconds | ||
| return self._chunk_transcript(transcript_data) | ||
| # Return as continuous text |
There was a problem hiding this comment.
Fix translation fallback and fetching logic
When translation is set we always look for English captions, so videos that only expose (say) Portuguese captions still blow up with NoTranscriptFound even though they can be translated. On top of that we call YouTubeTranscriptApi.fetch(...) after translate(...), but v1.x expects you to call transcript.fetch() on the Transcript (or translated transcript) object—otherwise the translated snippets are never retrieved.
Please select an English transcript if it exists, fall back to generated-English, then fall back to any available transcript before translating, and use transcript.fetch() so the translation path actually returns translated snippets. That change also keeps the non-translation branch working for videos whose only captions are auto-generated in another language. Suggested patch:
- if self.translation:
- # Get any available transcript and translate it
- transcript = transcript_list.find_transcript(["en"])
- transcript = transcript.translate(self.translation)
- else:
- # Try to get transcript in available languages
- try:
- transcript = transcript_list.find_transcript(["en"])
- except NoTranscriptFound:
- # Try auto-generated English
- transcript = transcript_list.find_generated_transcript(["en"])
-
- # Fetch the transcript data
- transcript_data = api.fetch(transcript.video_id, [transcript.language_code])
+ if self.translation:
+ try:
+ transcript = transcript_list.find_transcript(["en"])
+ except NoTranscriptFound as en_error:
+ try:
+ transcript = transcript_list.find_generated_transcript(["en"])
+ except NoTranscriptFound:
+ try:
+ transcript = transcript_list[0]
+ except IndexError as exc: # pragma: no cover
+ raise en_error from exc
+ transcript = transcript.translate(self.translation)
+ else:
+ try:
+ transcript = transcript_list.find_transcript(["en"])
+ except NoTranscriptFound as en_error:
+ try:
+ transcript = transcript_list.find_generated_transcript(["en"])
+ except NoTranscriptFound:
+ try:
+ transcript = transcript_list[0]
+ except IndexError as exc: # pragma: no cover
+ raise en_error from exc
+
+ transcript_data = transcript.fetch()Once this is in place, update the unit tests to stub Transcript.fetch() (and .translate().fetch() in the translation case) instead of YouTubeTranscriptApi.fetch, and add a regression case where no English captions exist so we keep this flow covered.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if self.translation: | |
| # Get any available transcript and translate it | |
| transcript = transcript_list.find_transcript(["en"]) | |
| transcript = transcript.translate(self.translation) | |
| else: | |
| # Try to get transcript in available languages | |
| try: | |
| transcript = transcript_list.find_transcript(["en"]) | |
| except NoTranscriptFound: | |
| # Try auto-generated English | |
| transcript = transcript_list.find_generated_transcript(["en"]) | |
| # Fetch the transcript data | |
| transcript_data = api.fetch(transcript.video_id, [transcript.language_code]) | |
| except (TranscriptsDisabled, NoTranscriptFound) as e: | |
| error_type = type(e).__name__ | |
| msg = ( | |
| f"Could not retrieve transcripts for video '{video_id}'. " | |
| "Possible reasons:\n" | |
| "1. This video does not have captions/transcripts enabled\n" | |
| "2. The video is private, restricted, or deleted\n" | |
| f"\nTechnical error ({error_type}): {e}" | |
| ) | |
| raise RuntimeError(msg) from e | |
| except Exception as e: | |
| error_type = type(e).__name__ | |
| msg = ( | |
| f"Could not retrieve transcripts for video '{video_id}'. " | |
| "Possible reasons:\n" | |
| "1. This video does not have captions/transcripts enabled\n" | |
| "2. The video is private, restricted, or deleted\n" | |
| "3. YouTube is blocking automated requests\n" | |
| f"\nTechnical error ({error_type}): {e}" | |
| ) | |
| raise RuntimeError(msg) from e | |
| if as_chunks: | |
| # Group into chunks based on chunk_size_seconds | |
| return self._chunk_transcript(transcript_data) | |
| # Return as continuous text | |
| if self.translation: | |
| try: | |
| transcript = transcript_list.find_transcript(["en"]) | |
| except NoTranscriptFound as en_error: | |
| try: | |
| transcript = transcript_list.find_generated_transcript(["en"]) | |
| except NoTranscriptFound: | |
| try: | |
| transcript = transcript_list[0] | |
| except IndexError as exc: # pragma: no cover | |
| raise en_error from exc | |
| transcript = transcript.translate(self.translation) | |
| else: | |
| try: | |
| transcript = transcript_list.find_transcript(["en"]) | |
| except NoTranscriptFound as en_error: | |
| try: | |
| transcript = transcript_list.find_generated_transcript(["en"]) | |
| except NoTranscriptFound: | |
| try: | |
| transcript = transcript_list[0] | |
| except IndexError as exc: # pragma: no cover | |
| raise en_error from exc | |
| transcript_data = transcript.fetch() | |
| except (TranscriptsDisabled, NoTranscriptFound) as e: | |
| error_type = type(e).__name__ | |
| msg = ( | |
| f"Could not retrieve transcripts for video '{video_id}'. " | |
| "Possible reasons:\n" | |
| "1. This video does not have captions/transcripts enabled\n" | |
| "2. The video is private, restricted, or deleted\n" | |
| f"\nTechnical error ({error_type}): {e}" | |
| ) | |
| raise RuntimeError(msg) from e | |
| except Exception as e: | |
| error_type = type(e).__name__ | |
| msg = ( | |
| f"Could not retrieve transcripts for video '{video_id}'. " | |
| "Possible reasons:\n" | |
| "1. This video does not have captions/transcripts enabled\n" | |
| "2. The video is private, restricted, or deleted\n" | |
| "3. YouTube is blocking automated requests\n" | |
| f"\nTechnical error ({error_type}): {e}" | |
| ) | |
| raise RuntimeError(msg) from e | |
| if as_chunks: | |
| # Group into chunks based on chunk_size_seconds | |
| return self._chunk_transcript(transcript_data) | |
| # Return as continuous text |
🤖 Prompt for AI Agents
In src/lfx/src/lfx/components/youtube/youtube_transcripts.py around lines
78-118, the logic currently always searches for an English transcript when
translation is requested and calls YouTubeTranscriptApi.fetch(...) after
translate(), which prevents using transcripts available only in other languages
and fails to actually fetch translated snippets; change the selection order to:
try find English transcript, then find generated-English, then fall back to any
available transcript (transcript_list.find_transcript(None) or equivalent)
before translating if self.translation is set; after selecting (and optionally
translating) a Transcript object, call transcript.fetch() on that object (or
translated_transcript.fetch()) instead of api.fetch(...); finally update unit
tests to stub Transcript.fetch() and the translated transcript’s .fetch() (not
YouTubeTranscriptApi.fetch), and add a regression test where no English captions
exist to cover the fallback-to-any-language-then-translate path.
* fix youtube transcript api * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix youtube transcript api * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix youtube transcript api * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix youtube transcript api * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
* fix youtube transcript api * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This pull request updates the YouTube transcript analysis component to support the new
youtube-transcript-apiv1.0+ and refactors both the implementation and its tests for compatibility and robustness. The most important changes are grouped below:Component and Dependency Updates
youtube-transcript-apidependency inpyproject.tomlto require version>=1.0.0,<2.0.0, ensuring compatibility with the new API.YouTubeTranscriptsComponentinYoutube Analysis.jsonto use the new API, including extracting video IDs from URLs, handling transcript fetching and translation, and grouping transcript segments into time-based chunks. The implementation now robustly handles errors and supports both object and dict transcript formats.langchain_community). [1] [2]Testing Improvements
FetchedTranscriptSnippetMockclass to simulate transcript snippets using the new API format in unit tests.test_youtube_transcript_component.pyto use the new mock class and added a mock for transcript list objects, improving test coverage for the updated component logic.REC-20251030173612.mp4