Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
7e880b2
Add 'Failed' translation state and update handling
T9es Jan 2, 2026
6fc52d3
Add GEMINI.md and improve null checks in services
T9es Jan 2, 2026
7a1f10f
feat(translation): implement batching and fallback splitting for defe…
T9es Jan 2, 2026
c4750ee
docs: add repair phase resilience to lessons learned
T9es Jan 2, 2026
6751fe0
Fix SSA indexing, improve markup cleaning, and add repair batching
T9es Jan 2, 2026
f1cfeb7
feat: Add subtitle discovery for externally-added subtitles
T9es Jan 9, 2026
eabddb6
fix: Add SignalR broadcast when worker claims translation job
T9es Jan 9, 2026
3cba489
fix: Remove duplicate InProgress reset causing race condition
T9es Jan 9, 2026
84b4501
fix: Add delayed re-queue to reset hung jobs after startup
T9es Jan 9, 2026
ac838a0
Update .gitignore
T9es Jan 18, 2026
d90d5f6
Update agents.md
T9es Jan 18, 2026
7f66019
feat: enhance media analysis, translation pipeline, and hashing robus…
T9es Jan 18, 2026
09a2f66
perf: optimize indexing and sync performance
T9es Jan 18, 2026
6fec07d
feat: enhance media analysis, translation pipeline, and performance o…
T9es Jan 18, 2026
5940529
fix: resolve duplicate key crash in ShowSync and correct job status r…
T9es Jan 18, 2026
8c50da3
perf: implement AsSplitQuery for media sync and optimize hierarchy lo…
T9es Jan 18, 2026
9654f0a
fix: automatically remove media from failed queue when re-enqueuing
T9es Jan 18, 2026
32554b1
fix: enhance sync resilience and job status reporting for large libra…
T9es Jan 18, 2026
9df966b
fix: add migration for unique SonarrId/RadarrId indexes with duplicat…
T9es Jan 18, 2026
f1647af
fix: handle FK constraints in migration by deleting embedded_subtitle…
T9es Jan 18, 2026
69bfabc
fix: skip embedded subtitle indexing for unpersisted episodes and re-…
T9es Jan 18, 2026
edac536
fix: skip embedded subtitle indexing for unpersisted episodes
T9es Jan 18, 2026
0984e19
Experimental fixes to a strange issue.
T9es Jan 18, 2026
bfbd1da
fix: force translation state update after media indexing
T9es Jan 18, 2026
88a801d
feat: include 'AwaitingSource' items in Bulk Integrity Check
T9es Jan 18, 2026
3b5822d
fix: include 'Unknown' items in Bulk Integrity Check
T9es Jan 18, 2026
83dee7d
Fix up more stuff.
T9es Jan 19, 2026
584f93d
Revert "Fix up more stuff."
T9es Jan 19, 2026
826dc62
Revert "fix: include 'Unknown' items in Bulk Integrity Check"
T9es Jan 19, 2026
c129fd3
Revert "feat: include 'AwaitingSource' items in Bulk Integrity Check"
T9es Jan 19, 2026
84259cf
Revert all changes since yesterday (restoring to agents.md update)
T9es Jan 19, 2026
f238925
Update package-lock.json
T9es Jan 19, 2026
9b3c6c4
Experimental.
T9es Jan 19, 2026
2562743
More experimental stuff.
T9es Jan 19, 2026
b878acf
Update AutomatedTranslationJob.cs
T9es Jan 19, 2026
96d0534
Rotate queue.
T9es Jan 20, 2026
9cc6d5d
Resolve API issue.
T9es Jan 20, 2026
94c5a42
fix(dashboard,logs,test): resolve multiple UI/UX and logic issues
T9es Jan 20, 2026
1a26bac
chore: ignore AI-generated analysis files (agents.md)
T9es Jan 20, 2026
84b4cc9
fix(logs): refactor log streaming to use event-driven channel + heart…
T9es Jan 20, 2026
ed4e685
fix(client): filter 'in progress' and 'failed' requests by search que…
T9es Jan 20, 2026
5905f65
Fix: Standardize batch translation context handling for CustomAI
T9es Jan 20, 2026
7585dc2
Update TranslationJob.cs
T9es Jan 20, 2026
cd9fbce
Fix: Add robust JSON array parsing to LocalAI and improve frontend se…
T9es Jan 20, 2026
acb4d7e
fix(sync): resolve FK constraint violation in show/movie cleanup
T9es Jan 25, 2026
6abbf3e
Update TranslationJob.cs
T9es Feb 3, 2026
386b298
fix: resolve update indicator bug and add hover-to-reextract feature …
T9es Feb 3, 2026
e4d175e
fix: upgrade vue from 3.5.25 to 3.5.26
snyk-bot Jan 26, 2026
408785d
fix: upgrade vue-router from 4.6.3 to 4.6.4
snyk-bot Jan 26, 2026
8a91281
Add missing translation keys for embedded subtitle re-extraction
T9es Feb 3, 2026
ae57c35
Fix: Dev build detection for update indicator
T9es Feb 3, 2026
c93a3f5
Fix race condition in TranslationJob subtitle extraction cleanup
T9es Feb 4, 2026
d7c8b7d
Increase Forced subtitle penalty from -10 to -50 in scoring system
T9es Feb 4, 2026
ee3efcd
feat: Add subtitle type validation to Integrity Check system (Phase 2)
T9es Feb 4, 2026
d30b36f
feat: Add subtitle tracking fields to TranslationRequest for audit/de…
T9es Feb 4, 2026
b61ef6e
Implement Phase 4: Manual Subtitle Selection UI
T9es Feb 4, 2026
15ec90f
Update Readme.MD
T9es Feb 8, 2026
2507c72
Update Readme.MD
T9es Feb 8, 2026
6e88660
Add .mindmodel docs, patterns, and examples
T9es Feb 9, 2026
331423b
Add retry tracking and exponential backoff
T9es Feb 10, 2026
b1be446
fix(db): add missing PostgreSQL migration for embedded_subtitles table
T9es Feb 10, 2026
c69010e
fix(db): add missing columns to embedded_subtitles table
T9es Feb 10, 2026
120d0ed
fix(db): add missing is_hearing_impaired column to embedded_subtitles
T9es Feb 10, 2026
3e2e09a
fix(db): correct embedded_subtitles migration with all columns
T9es Feb 10, 2026
4d416cd
Merge remote-tracking branch 'origin/latest'
T9es Feb 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,8 @@ EXAMPLE SUBTITLES/Jujutsu Kaisen (2020) - S01E14 - Kyoto Sister School Exchange
EXAMPLE SUBTITLES/Jujutsu Kaisen (2020) - S01E13 - Tomorrow \[v2 Bluray-1080p Proper\]\[Opus 2.0\]\[x265\]-Vodes.English-\[Kaizoku\].pl.-ai-sztuczna-inteligencja-.srt
EXAMPLE SUBTITLES/Jujutsu Kaisen (2020) - S01E13 - Tomorrow \[v2 Bluray-1080p Proper\]\[Opus 2.0\]\[x265\]-Vodes.eng.English-\[Kaizoku\].srt
EXAMPLE EPISODES/Jujutsu Kaisen (2020) - S02E02 - Hidden Inventory 2 \[Bluray-1080p\]\[Opus 2.0\]\[x265\]-Vodes.mkv
# AI / Agent Generation Files
agents.md
*.analysis.md
*_analysis.md
*.plan.md
194 changes: 194 additions & 0 deletions .mindmodel/conventions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
# Code Conventions

## C# Naming Conventions

### Classes & Types
- **Classes**: PascalCase (e.g., `TranslationWorkerService`)
- **Interfaces**: PascalCase with `I` prefix (e.g., `ITranslationService`)
- **Enums**: PascalCase (e.g., `TranslationState`)
- **Generic Type Parameters**: PascalCase with `T` prefix (e.g., `TEntity`)

### Members
- **Methods**: PascalCase (e.g., `GetMovies`, `TranslateAsync`)
- **Properties**: PascalCase (e.g., `public string Name { get; set; }`)
- **Public Fields**: PascalCase (avoid, use properties instead)
- **Private Fields**: `_camelCase` with underscore prefix (e.g., `_logger`, `_dbContext`)
- **Constants**: PascalCase (e.g., `MaxRetryAttempts`)
- **Async Methods**: Must have `Async` suffix (e.g., `TranslateAsync`)

### Parameters & Variables
- **Parameters**: camelCase (e.g., `translationRequest`)
- **Local Variables**: camelCase (e.g., `var requestCount = 0;`)
- **Lambda Parameters**: camelCase (e.g., `x => x.Id`)

## TypeScript/Vue Naming Conventions

### Components
- **Vue Components**: PascalCase with `Component` suffix (e.g., `CardComponent.vue`)
- **Single File Components**: PascalCase (e.g., `TranslationPage.vue`)

### Composables
- **Composables**: camelCase with `use` prefix (e.g., `useDebounce.ts`)

### Stores
- **Pinia Stores**: camelCase with `use` prefix + `Store` suffix (e.g., `useMovieStore.ts`)

### Types & Interfaces
- **Interfaces**: PascalCase with `I` prefix (e.g., `IMovie`, `ISettings`)
- **Types**: PascalCase (e.g., `TranslationStatus`)
- **Enums**: PascalCase (e.g., `MediaType`)

### Variables & Constants
- **Variables**: camelCase (e.g., `const requestCount = 0`)
- **Constants**: UPPER_SNAKE_CASE (e.g., `const MAX_RETRY_ATTEMPTS = 3`)
- **Boolean Variables**: Prefix with `is`, `has`, `should` (e.g., `isLoading`, `hasErrors`)

## Code Organization

### C# Files
```csharp
// 1. Using statements (System first, then third-party, then internal)
using System;
using Microsoft.EntityFrameworkCore;
using Lingarr.Core.Entities;

// 2. Namespace declaration
namespace Lingarr.Server.Services;

// 3. XML documentation for public APIs
/// <summary>
/// Service for managing translation operations.
/// </summary>
public class TranslationService : ITranslationService
{
// 4. Private readonly fields (injected dependencies)
private readonly ILogger<TranslationService> _logger;
private readonly LingarrDbContext _dbContext;

// 5. Constructor with XML docs
/// <summary>
/// Initializes a new instance of the TranslationService.
/// </summary>
public TranslationService(
ILogger<TranslationService> logger,
LingarrDbContext dbContext)
{
_logger = logger;
_dbContext = dbContext;
}

// 6. Public methods
// 7. Private methods
}
```

### Vue Files
```vue
<template>
<!-- Template content -->
</template>

<script setup lang="ts">
// 1. Vue imports
import { ref, computed, onMounted } from 'vue'

// 2. Third-party imports
import { useRouter } from 'vue-router'

// 3. Internal imports (using @/ alias)
import { useMovieStore } from '@/store/movie'
import type { IMovie } from '@/ts'

// 4. Props definition
const { movieId } = defineProps<{
movieId: number
}>()

// 5. Composables
const router = useRouter()
const movieStore = useMovieStore()

// 6. Reactive state
const isLoading = ref(false)

// 7. Computed properties
const movie = computed(() => movieStore.getMovieById(movieId))

// 8. Methods
async function loadMovie() {
// Implementation
}

// 9. Lifecycle hooks
onMounted(() => {
loadMovie()
})
</script>
```

### TypeScript Service Files
```typescript
// 1. External imports
import { AxiosError, AxiosResponse, AxiosStatic } from 'axios'

// 2. Internal imports
import { ITranslationRequest, ITranslationRequestService } from '@/ts'

// 3. Factory function pattern
const service = (
http: AxiosStatic,
resource = '/api/translationRequest'
): ITranslationRequestService => ({
// Service methods
})

// 4. Export factory
export const translationRequestService = (axios: AxiosStatic): ITranslationRequestService => {
return service(axios)
}
```

## Import Order

### C# Import Order
1. `System` namespaces
2. `Microsoft` namespaces
3. Third-party library namespaces
4. Internal project namespaces (most specific last)

### TypeScript Import Order
1. Vue core (`vue`, `vue-router`)
2. Third-party libraries (`axios`, `pinia`)
3. Internal types (`@/ts`)
4. Internal services/stores (`@/services`, `@/store`)
5. Internal composables (`@/composables`)

## Prettier Configuration

```json
{
"semi": false,
"tabWidth": 4,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"arrowParens": "always"
}
```

## Code Style Rules

### C#
- Use `var` when type is obvious from right-hand side
- Always use braces for control structures
- Prefer expression-bodied members for simple properties
- Use pattern matching where appropriate
- Use null-coalescing operators (`??`, `??=`)
- Use target-typed `new()` expressions

### TypeScript
- Prefer `interface` over `type` for object shapes
- Use explicit return types on exported functions
- Use `const` by default, `let` only when reassignment needed
- Prefer optional chaining (`?.`) over null checks
- Use nullish coalescing (`??`) over logical OR (`||`)
124 changes: 124 additions & 0 deletions .mindmodel/domain.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Domain Glossary

## Core Entities

### Media Entities
- **Movie**: Represents a movie with metadata (title, path, filename, images)
- **Show**: Represents a TV show with seasons and episodes
- **Season**: A season belonging to a show, contains episodes
- **Episode**: Individual episode with metadata and subtitle information
- **Image**: Associated images (posters, fanart) for movies/shows

### Translation Entities
- **TranslationRequest**: A request to translate subtitles for a media item
- Tracks source/target languages, status, progress
- Links to MediaId and MediaType
- Contains priority, queue position, timestamps

- **TranslationRequestLog**: Detailed logs for each translation request
- Level (Information, Warning, Error)
- Message and details
- Timestamp

- **EmbeddedSubtitle**: Subtitle tracks embedded in media files
- Stream index, language, title, codec
- IsForced, IsExtracted flags
- Entry count for quality assessment

### Configuration Entities
- **Setting**: Key-value configuration storage
- 50+ setting keys for various features
- Supports encryption for sensitive values

- **PathMapping**: Maps source paths to destination paths
- Used for container path translation

- **Statistics/DailyStatistics**: Translation metrics and usage stats

## Translation States (9-State Machine)

```csharp
public enum TranslationState
{
Unknown = 0, // Not yet analyzed
NotApplicable = 1, // No translation needed/possible
Pending = 2, // Ready for translation
InProgress = 3, // Translation active
Complete = 4, // All translations done
Stale = 5, // Needs re-analysis
NoSuitableSubtitles = 6, // No usable subtitle tracks
Failed = 7, // Previous translation failed
AwaitingSource = 8 // Waiting for source subtitle
}
```

## Translation Status

```csharp
public enum TranslationStatus
{
Pending,
InProgress,
Completed,
Failed,
Cancelled,
Interrupted
}
```

## Business Terms

### Media Management
- **Radarr**: Movie management integration (arr application)
- **Sonarr**: TV show management integration (arr application)
- **Arr Applications**: Collective term for Radarr/Sonarr

### Subtitle Operations
- **Subtitle Extraction**: Pull embedded subtitles from video files
- **Embedded Subtitle**: Subtitle track within video container
- **Source Language**: Original subtitle language
- **Target Language**: Desired translation language
- **ASS/SSA**: Advanced SubStation Alpha subtitle format
- **SRT**: SubRip subtitle format

### Translation Features
- **Batch Translation**: Translate multiple subtitles in one API call
- **Deferred Repair**: Queue failed translations for later retry
- **Translation Age Threshold**: Time before translations are considered stale
- **Subtitle Tagging**: Add custom tags to translated subtitles
- **Path Mapping**: Convert paths between host and container
- **Integrity Check**: Verify subtitle file consistency
- **Orphaned Subtitle**: Subtitle file without corresponding media
- **Queue Rotation**: Manage translation request priority
- **Media Hash**: Unique identifier for media files

### Translation Services (12 Types)
1. **AnthropicService**: Claude AI translation
2. **OpenAiService**: OpenAI GPT translation
3. **DeepSeekService**: DeepSeek AI translation
4. **GeminiService**: Google Gemini translation
5. **ChutesService**: Chutes AI translation
6. **LocalAiService**: Local AI model translation
7. **DeepLService**: DeepL API translation
8. **LibreService**: LibreTranslate self-hosted
9. **GTranslatorService**: Google Translate (unofficial)
10. **BingTranslator**: Microsoft Bing translation
11. **MicrosoftTranslator**: Microsoft Azure translation
12. **YandexTranslator**: Yandex translation

### Job Types (8 Background Jobs)
1. **TranslationJob**: Execute translation requests
2. **SyncMovieJob**: Sync movies from Radarr
3. **SyncShowJob**: Sync shows from Sonarr
4. **AutomatedTranslationJob**: Automated translation scheduling
5. **StatisticsJob**: Calculate usage statistics
6. **CleanupJob**: Clean up old data and files
7. **RetryFailedRequestsJob**: Retry failed translations
8. **BulkIntegrityCheckJob**: Verify subtitle integrity

### Settings Categories
- **Translation**: Service type, batch settings, context prompts
- **SubtitleValidation**: File size, length, duration limits
- **Automation**: Schedule, thresholds, exclusions
- **Integration**: Radarr/Sonarr connection settings
- **Services**: API keys, endpoints for translation services
24 changes: 24 additions & 0 deletions .mindmodel/examples/component-pattern.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!-- Component Pattern Example - CardComponent.vue -->
<!-- Demonstrates Vue 3 Composition API with TypeScript -->

<template>
<div class="from-secondary to-tertiary relative rounded-md bg-linear-to-br p-6 shadow-md">
<div class="mb-2 flex items-center justify-center space-x-3" v-if="title">
<div v-if="$slots.icon" class="text-primary-content h-6 w-6">
<slot name="icon"></slot>
</div>
<h2 class="text-primary-content text-2xl font-bold">{{ title }}</h2>
</div>
<p class="text-secondary-content/80 mb-6 text-center"><slot name="description"></slot></p>

<div class="space-y-4">
<slot name="content"></slot>
</div>
</div>
</template>

<script setup lang="ts">
const { title } = defineProps<{
title: string
}>()
</script>
Loading
Loading