feat: language preference persistence per channel#26
Conversation
When a user selects a language for a video from a specific channel, the app now remembers and automatically applies that preference when processing future videos from the same channel. Preferences are stored per platform and channel identifier (with fallback to channel name), persisted to settings.json, and gracefully handle backward compatibility with existing settings files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Mesa DescriptionTL;DRImplements automatic language preference persistence for each channel. When a user selects a language for a video from a specific channel, the app remembers and auto-applies that preference to future videos from the same channel. What changed?
Description generated by Mesa. Update settings |
There was a problem hiding this comment.
Performed full review of b9beb81...076eb7b
Analysis
-
Unbounded Storage Growth: The map-based storage for channel language preferences has no eviction policy, potentially causing unlimited growth for users who watch many channels.
-
Frontend Race Condition: Platform detection happens asynchronously, but preference lookup occurs immediately when metadata loads, which could lead to using 'unknown' as the platform identifier.
-
No User Interface for Management: Users cannot view or clear their saved channel preferences through any UI, limiting control over accumulated preferences.
-
Preference Saving Before Validation: Language preferences are saved in StartTranscription() before the transcription task begins, meaning preferences will be persisted even for failed transcriptions.
Tip
Help
Slash Commands:
/review- Request a full code review/review latest- Review only changes since the last review/describe- Generate PR description. This will update the PR body or issue comment depending on your configuration/help- Get help with Mesa commands and configuration options
0 files reviewed | 2 comments | Edit Agent Settings • Read Docs
| setVideoMetadata(metadata) | ||
| if (metadata.isValid && metadata.channel) { | ||
| try { | ||
| const preferredLang = await GetChannelLanguagePreference( |
There was a problem hiding this comment.
The platform variable may still be 'unknown' when this executes. Platform detection runs asynchronously via DetectPlatform(url), but there's no guarantee it completes before handleMetadataLoaded is called. If metadata loads first, the preference lookup will use 'unknown' as the platform key, likely returning no saved preference. Consider adding a check like if (platform === 'unknown') return or ensuring platform detection completes before querying preferences.
Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: STRRL/transcube-webapp#26
File: frontend/src/pages/NewTranscriptionPage.tsx#L189
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.
Feedback:
The `platform` variable may still be `'unknown'` when this executes. Platform detection runs asynchronously via `DetectPlatform(url)`, but there's no guarantee it completes before `handleMetadataLoaded` is called. If metadata loads first, the preference lookup will use `'unknown'` as the platform key, likely returning no saved preference. Consider adding a check like `if (platform === 'unknown') return` or ensuring platform detection completes before querying preferences.
| metadata.channel | ||
| ) | ||
| if (preferredLang) { | ||
| setSourceLang(preferredLang) |
There was a problem hiding this comment.
Race condition: If the user manually selects a different source language while GetChannelLanguagePreference is still pending, the delayed setSourceLang(preferredLang) will overwrite the user's manual selection. Consider tracking whether the user has made a manual selection (e.g., via a ref or flag) and skip the auto-selection if they have, or use an AbortController to cancel the pending update.
Prompt for Agent
Task: Address review feedback left on GitHub.
Repository: STRRL/transcube-webapp#26
File: frontend/src/pages/NewTranscriptionPage.tsx#L195
Action: Open this file location in your editor, inspect the highlighted code, and resolve the issue described below.
Feedback:
Race condition: If the user manually selects a different source language while `GetChannelLanguagePreference` is still pending, the delayed `setSourceLang(preferredLang)` will overwrite the user's manual selection. Consider tracking whether the user has made a manual selection (e.g., via a ref or flag) and skip the auto-selection if they have, or use an AbortController to cancel the pending update.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const handleMetadataLoaded = async (metadata: VideoMetadata) => { | ||
| setVideoMetadata(metadata) | ||
| if (metadata.isValid && metadata.channel) { | ||
| try { | ||
| const preferredLang = await GetChannelLanguagePreference( |
There was a problem hiding this comment.
Memoize metadata handler to avoid endless metadata refetches
VideoPreview’s useEffect depends on the onMetadataLoaded prop, so when this page now passes an inline handleMetadataLoaded function that is recreated every render, the effect reruns on every render even when the URL is unchanged (see VideoPreview.tsx where the effect depends on onMetadataLoaded). Each rerender schedules another ParseVideoUrl call and preference lookup every ~500 ms, producing continuous metadata fetches and state churn once the first metadata load updates state. The handler should be memoized (e.g., useCallback) or the dependency removed to prevent repeated backend calls.
Useful? React with 👍 / 👎.
The handleMetadataLoaded callback was causing VideoPreview's useEffect to re-run on every render because it was creating a new function reference each time. Wrapped with useCallback and proper dependencies to stabilize the reference. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Summary
Implements automatic language preference persistence for each channel. When a user selects a language for a video from a specific channel, the app remembers and auto-applies that preference to future videos from the same channel.
Implementation
ChannelLanguagePrefsmapGetChannelLanguagePreference()andSetChannelLanguagePreference()backend methodsStartTranscription()to save preferences automaticallyBehavior
{platform}:{channelID}with fallback to channel name~/.config/TransCube/settings.json🤖 Generated with Claude Code